our
$VERSION
=
"7.6"
;
sub
new {
my
$class
=
shift
;
my
%p
=
@_
;
my
$agent
=
'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062'
;
my
(
$second
,
$microsecond
)=gettimeofday;
my
$send_msg_id
=
$second
*1000+
$microsecond
;
$send_msg_id
=(
$send_msg_id
-
$send_msg_id
%1000)/1000;
$send_msg_id
=(
$send_msg_id
%10000)*10000;
my
$self
= {
cookie_jar
=> HTTP::Cookies->new(
hide_cookie2
=>1),
qq_param
=> {
qq
=>
undef
,
pwd
=>
undef
,
is_need_img_verifycode
=> 0,
img_verifycode_source
=>
'TTY'
,
send_msg_id
=>
$send_msg_id
,
clientid
=> 53999199,
psessionid
=>
'null'
,
vfwebqq
=>
undef
,
ptwebqq
=>
undef
,
status
=>
$p
{status} ||
'online'
,
passwd_sig
=>
''
,
verifycode
=>
undef
,
verifysession
=>
undef
,
pt_verifysession
=>
undef
,
md5_salt
=>
undef
,
cap_cd
=>
undef
,
isRandSalt
=> 0,
ptvfsession
=>
undef
,
api_check_sig
=>
undef
,
g_pt_version
=>
undef
,
g_login_sig
=>
undef
,
g_style
=> 5,
g_mibao_css
=>
'm_webqq'
,
g_daid
=> 164,
g_appid
=> 1003903,
g_pt_version
=> 10092,
rc
=> 1,
},
qq_database
=> {
user
=> {},
friends
=> [],
group_list
=> [],
discuss_list
=> [],
group
=> [],
discuss
=> [],
},
is_first_login
=> -1,
cache_for_uin_to_qq
=> Webqq::Client::Cache->new,
cache_for_group_sig
=> Webqq::Client::Cache->new,
cache_for_stranger
=> Webqq::Client::Cache->new,
cache_for_friend
=> Webqq::Client::Cache->new,
cache_for_single_long_nick
=> Webqq::Client::Cache->new,
cache_for_group
=> Webqq::Client::Cache->new,
cache_for_group_member
=> Webqq::Client::Cache->new,
cache_for_discuss
=> Webqq::Client::Cache->new,
cache_for_discuss_member
=> Webqq::Client::Cache->new,
cache_for_metacpan
=> Webqq::Client::Cache->new,
on_receive_message
=>
undef
,
on_receive_offpic
=>
undef
,
on_send_message
=>
undef
,
on_login
=>
undef
,
on_new_friend
=>
undef
,
on_new_group
=>
undef
,
on_new_discuss
=>
undef
,
on_new_group_member
=>
undef
,
on_loss_group_member
=>
undef
,
on_new_discuss_member
=>
undef
,
on_loss_discuss_member
=>
undef
,
on_input_img_verifycode
=>
undef
,
on_run
=>
undef
,
receive_message_queue
=> Webqq::Message::Queue->new,
send_message_queue
=> Webqq::Message::Queue->new,
debug
=>
$p
{debug},
login_state
=>
"init"
,
watchers
=> {},
type
=>
$p
{type} ||
'smartqq'
,
plugin_num
=> 0,
plugins
=> {},
ua_retry_times
=> 5,
je
=>
undef
,
last_dispatch_time
=>
undef
,
send_interval
=> 3,
poll_failure_count_max
=> 3,
poll_failure_count
=> 0,
};
$self
->{ua} = LWP::UserAgent->new(
cookie_jar
=>
$self
->{cookie_jar},
agent
=>
$agent
,
timeout
=> 300,
ssl_opts
=> {
verify_hostname
=> 0},
);
$self
->{asyn_ua} = Webqq::UserAgent->new(
cookie_jar
=>
$self
->{cookie_jar},
agent
=>
$agent
,
request_timeout
=> 300,
inactivity_timeout
=> 300,
);
$self
->{qq_param}{from_uin} =
$self
->{qq_param}{
qq};
if($self->{debug}
){
$self
->{ua}->add_handler(
request_send
=>
sub
{
my
(
$request
,
$ua
,
$h
) =
@_
;
print
$request
->as_string;
return
;
});
$self
->{ua}->add_handler(
response_header
=>
sub
{
my
(
$response
,
$ua
,
$h
) =
@_
;
print
$response
->as_string;
return
;
});
}
$self
->{default_qq_param} = dclone(
$self
->{qq_param});
$self
->{default_qq_database} = dclone(
$self
->{qq_database});
bless
$self
,
$class
;
$self
->_prepare();
$Webqq::Client::_CLIENT
=
$self
;
return
$self
;
}
sub
on_send_message :lvalue {
my
$self
=
shift
;
$self
->{on_send_message};
}
sub
on_receive_message :lvalue{
my
$self
=
shift
;
$self
->{on_receive_message};
}
sub
on_receive_offpic :lvalue{
my
$self
=
shift
;
$self
->{on_receive_offpic};
}
sub
on_login :lvalue {
my
$self
=
shift
;
$self
->{on_login};
}
sub
on_run :lvalue {
my
$self
=
shift
;
$self
->{on_run};
}
sub
on_new_friend :lvalue {
my
$self
=
shift
;
$self
->{on_new_friend};
}
sub
on_new_group :lvalue {
my
$self
=
shift
;
$self
->{on_new_group};
}
sub
on_new_group_member :lvalue {
my
$self
=
shift
;
$self
->{on_new_group_member};
}
sub
on_loss_group_member :lvalue {
my
$self
=
shift
;
$self
->{on_loss_group_member};
}
sub
on_new_discuss :lvalue {
my
$self
=
shift
;
$self
->{on_new_discuss};
}
sub
on_new_discuss_member :lvalue {
my
$self
=
shift
;
$self
->{on_new_discuss_member};
}
sub
on_loss_discuss_member :lvalue {
my
$self
=
shift
;
$self
->{on_loss_discuss_member};
}
sub
on_input_img_verifycode :lvalue {
my
$self
=
shift
;
$self
->{on_input_img_verifycode};
}
sub
login{
my
$self
=
shift
;
my
%p
=
@_
;
if
(
$self
->{is_first_login} == -1){
$self
->{is_first_login} = 1;
}
elsif
(
$self
->{is_first_login} == 1){
$self
->{is_first_login} = 0;
}
@{
$self
->{default_qq_param}}{
qw(qq pwd)
} =
@p
{
qw(qq pwd)
};
@{
$self
->{qq_param}}{
qw(qq pwd)
} =
@p
{
qw(qq pwd)
};
$self
->{qq_param}{status} =
$p
{status}
if
defined
$p
{status} and
grep
{
$_
eq
$p
{status}}
qw(online away busy silent hidden offline)
;
console
"QQ账号: $self->{default_qq_param}{qq} 密码: $self->{default_qq_param}{pwd}\n"
;
$self
->{qq_param}{
qq} = $self->{default_qq_param}
{
qq};
$self->{default_qq_param}
{pwd} =
lc
$self
->{default_qq_param}{pwd};
$self
->{qq_param}{pwd} =
$self
->{default_qq_param}{pwd} ;
if
(
$self
->_prepare_for_login()
&&
$self
->_check_verify_code()
&&
$self
->_get_img_verify_code()
){
while
(){
my
$ret
=
$self
->_login1();
if
(
$ret
== -1){
$self
->_get_img_verify_code();
next
;
}
elsif
(
$ret
== 1){
$self
->_report()
&&
$self
->_check_sig()
&&
$self
->_get_vfwebqq()
&&
$self
->_login2();
last
;
}
else
{
last
;
}
}
}
if
(
$self
->{login_state} ne
'success'
){
console
"登录失败,客户端退出(可能网络不稳定,请多尝试几次)\n"
;
exit
;
}
else
{
console
"登录成功\n"
;
}
$self
->update_user_info();
$self
->welcome();
$self
->update_friends_info();
$self
->update_group_info();
$self
->update_discuss_info();
if
(
ref
$self
->{on_login} eq
'CODE'
){
eval
{
$self
->{on_login}->();
};
console $@ .
"\n"
if
$@;
}
return
1;
}
sub
relogin{
my
$self
=
shift
;
console
"正在重新登录...\n"
;
$self
->logout();
$self
->{login_state} =
'relogin'
;
$self
->{cookie_jar} = HTTP::Cookies->new(
hide_cookie2
=>1);
$self
->{ua}->cookie_jar(
$self
->{cookie_jar});
$self
->{asyn_ua}->{cookie_jar} =
$self
->{cookie_jar};
$self
->{cache_for_uin_to_qq} = Webqq::Client::Cache->new;
$self
->{cache_for_group_sig} = Webqq::Client::Cache->new;
$self
->{cache_for_group} = Webqq::Client::Cache->new;
$self
->{cache_for_group_member} = Webqq::Client::Cache->new;
$self
->{cache_for_discuss} = Webqq::Client::Cache->new;
$self
->{cache_for_discuss_member} = Webqq::Client::Cache->new;
$self
->{cache_for_friend} = Webqq::Client::Cache->new;
$self
->{cache_for_stranger} = Webqq::Client::Cache->new;
$self
->{cache_for_single_long_nick} = Webqq::Client::Cache->new;
$self
->{qq_param} = dclone(
$self
->{default_qq_param});
$self
->{qq_database} = dclone(
$self
->{default_qq_database});
$self
->login(
qq=>$self->{default_qq_param}{qq},pwd=
>
$self
->{default_qq_param}{pwd});
}
sub
_get_vfwebqq;
sub
_prepare_for_login;
sub
_check_verify_code;
sub
_get_img_verify_code;
sub
_check_sig;
sub
_login1;
sub
_login2;
sub
_get_user_info;
sub
_get_friend_info;
sub
_get_group_info;
sub
_get_group_list_info;
sub
_get_user_friends;
sub
_get_discuss_list_info;
sub
_send_message;
sub
_send_group_message;
sub
_get_msg_tip;
sub
change_status;
sub
get_qq_from_uin;
sub
get_single_long_nick;
sub
_report;
sub
_cookie_proxy;
sub
_get_offpic;
sub
_relink;
sub
_get_discuss_list_info;
sub
_get_discuss_info;
sub
change_status;
sub
send_message{
my
$self
=
shift
;
if
(
@_
== 1 and
ref
$_
[0] eq
'Webqq::Message::Message::Send'
){
my
$msg
=
shift
;
$self
->{send_message_queue}->put(
$msg
);
}
else
{
my
$msg
=
$self
->_create_msg(
@_
,
type
=>
'message'
);
$self
->{send_message_queue}->put(
$msg
);
}
};
sub
send_sess_message{
my
$self
=
shift
;
if
(
@_
== 1 and
ref
$_
[0] eq
'Webqq::Message::SessMessage::Send'
){
my
$msg
=
shift
;
$self
->{send_message_queue}->put(
$msg
);
}
else
{
my
$msg
=
$self
->_create_msg(
@_
,
type
=>
'sess_message'
);
$self
->{send_message_queue}->put(
$msg
);
}
}
sub
send_discuss_message {
my
$self
=
shift
;
if
(
@_
== 1 and
ref
$_
[0] eq
'Webqq::Message::DiscussMessage::Send'
){
my
$msg
=
shift
;
$self
->{send_message_queue}->put(
$msg
);
}
else
{
my
$msg
=
$self
->_create_msg(
@_
,
type
=>
'discuss_message'
);
$self
->{send_message_queue}->put(
$msg
);
}
};
sub
send_group_message{
my
$self
=
shift
;
if
(
@_
== 1 and
ref
$_
[0] eq
'Webqq::Message::GroupMessage::Send'
){
my
$msg
=
shift
;
$self
->{send_message_queue}->put(
$msg
);
}
else
{
my
$msg
=
$self
->_create_msg(
@_
,
type
=>
'group_message'
);
$self
->{send_message_queue}->put(
$msg
);
}
};
sub
welcome{
my
$self
=
shift
;
my
$w
=
$self
->{qq_database}{user};
console
"欢迎回来, $w->{nick}($w->{province})\n"
;
console
"个性签名: "
. (
$w
->{single_long_nick}?
$w
->{single_long_nick}:
"(无)"
) .
"\n"
};
sub
logout;
sub
_prepare {
my
$self
=
shift
;
$self
->_load_extra_accessor();
$self
->{receive_message_queue}->get(
sub
{
my
$msg
=
shift
;
if
(
$msg
->{type} eq
'message'
){
if
(
ref
$self
->{on_receive_offpic} eq
'CODE'
){
for
(@{
$msg
->{raw_content}}){
if
(
$_
->{type} eq
'offpic'
){
$self
->_get_offpic(
$_
->{file_path},
$msg
->{from_uin},
$self
->{on_receive_offpic});
}
}
}
$self
->_detect_new_friend(
$msg
->{from_uin});
}
elsif
(
$msg
->{type} eq
'group_message'
){
$self
->_detect_new_group(
$msg
->{group_code});
$self
->_detect_new_group_member(
$msg
->{group_code},
$msg
->{send_uin});
}
elsif
(
$msg
->{type} eq
'discuss_message'
){
$self
->_detect_new_discuss(
$msg
->{did});
$self
->_detect_new_discuss_member(
$msg
->{did},
$msg
->{send_uin});
}
if
(
ref
$self
->{on_receive_message} eq
'CODE'
){
eval
{
$self
->{on_receive_message}->(
$msg
);
};
console $@ .
"\n"
if
$@;
}
});
$self
->{send_message_queue}->get(
sub
{
my
$msg
=
shift
;
if
(
$msg
->{ttl} <= 0){
my
$status
= {
is_success
=>0,
status
=>
"发送失败"
};
my
$send_message_callback
=
$msg
->{cb} ||
$self
->{on_send_message};
if
(
ref
$send_message_callback
eq
'CODE'
){
$send_message_callback
->(
$msg
,
$status
->{is_success},
$status
->{status},
);
}
return
;
}
$msg
->{ttl}--;
my
$rand_watcher_id
=
rand
();
my
$delay
= 0;
my
$now
=
time
;
if
(
defined
$self
->{last_dispatch_time}){
$delay
=
$now
<
$self
->{last_dispatch_time}+
$self
->{send_interval}?
$self
->{last_dispatch_time}+
$self
->{send_interval}-
$now
: 0;
}
$self
->{watchers}{
$rand_watcher_id
} = AE::timer
$delay
,0,
sub
{
delete
$self
->{watchers}{
$rand_watcher_id
};
$msg
->{msg_time} =
time
;
$msg
->{type} eq
'message'
?
$self
->_send_message(
$msg
)
:
$msg
->{type} eq
'group_message'
?
$self
->_send_group_message(
$msg
)
:
$msg
->{type} eq
'sess_message'
?
$self
->_send_sess_message(
$msg
)
:
$msg
->{type} eq
'discuss_message'
?
$self
->_send_discuss_message(
$msg
)
:
undef
;
};
$self
->{last_dispatch_time} =
$now
+
$delay
;
});
};
sub
run{
my
$self
=
shift
;
$self
->{watchers}{
rand
()} = AE::timer 600,600,
sub
{
$self
->update_group_info();
};
$self
->{watchers}{
rand
()} = AE::timer 600*2,600,
sub
{
$self
->update_discuss_info();
};
console
"开始接收消息\n"
;
$self
->_recv_message();
if
(
ref
$self
->{on_run} eq
'CODE'
){
eval
{
$self
->{on_run}->();
};
console
"$@\n"
if
$@;
}
console
"客户端运行中...\n"
;
$self
->{cv} = AE::cv;
$self
->{cv}->
recv
;
}
sub
search_cookie{
my
(
$self
,
$cookie
) =
@_
;
my
$result
=
undef
;
$self
->{cookie_jar}->scan(
sub
{
my
(
$version
,
$key
,
$val
,
$path
,
$domain
,
$port
,
$path_spec
,
$secure
,
$expires
,
$discard
,
$rest
) =
@_
;
if
(
$key
eq
$cookie
){
$result
=
$val
;
return
;
}
});
return
$result
;
}
sub
search_friend {
my
(
$self
,
$uin
) =
@_
;
my
$cache_data
=
$self
->{cache_for_friend}->retrieve(
$uin
);
return
$cache_data
if
defined
$cache_data
;
for
my
$f
( @{
$self
->{qq_database}{friends} }){
if
(
$f
->{uin} eq
$uin
){
my
$f_clone
= dclone(
$f
);
$self
->{cache_for_friend}->store(
$uin
,
$f_clone
);
return
$f_clone
;
}
}
return
undef
;
}
sub
search_member_in_group{
my
(
$self
,
$gcode
,
$member_uin
) =
@_
;
my
$cache_data
=
$self
->{cache_for_group_member}->retrieve(
"$gcode|$member_uin"
);
return
$cache_data
if
defined
$cache_data
;
for
my
$g
(@{
$self
->{qq_database}{group}}){
if
(
$g
->{ginfo}{code} eq
$gcode
){
if
(
exists
$g
->{minfo} and
ref
$g
->{minfo} eq
'ARRAY'
){
for
my
$m
(@{
$g
->{minfo} }){
if
(
$m
->{uin} eq
$member_uin
){
my
$m_clone
= dclone(
$m
);
$self
->{cache_for_group_member}->store(
"$gcode|$member_uin"
,
$m_clone
);
return
$m_clone
;
}
}
return
undef
;
}
else
{
my
$group_info
=
$self
->_get_group_info(
$g
->{ginfo}{code});
if
(
defined
$group_info
and
ref
$group_info
->{minfo} eq
'ARRAY'
){
$self
->update_group_info(
$group_info
);
for
my
$m
(@{
$group_info
->{minfo}}){
if
(
$m
->{uin} eq
$member_uin
){
my
$m_clone
= dclone(
$m
);
$self
->{cache_for_group_member}->store(
"$gcode|$member_uin"
,
$m_clone
);
return
$m_clone
;
}
}
return
undef
;
}
else
{
return
undef
;
}
}
}
}
return
undef
;
}
sub
search_member_in_discuss {
my
(
$self
,
$did
,
$member_uin
) =
@_
;
my
$cache_data
=
$self
->{cache_for_discuss_member}->retrieve(
"$did|$member_uin"
);
return
$cache_data
if
defined
$cache_data
;
for
my
$d
(@{
$self
->{qq_database}{discuss}}){
if
(
$d
->{dinfo}{did} eq
$did
){
if
(
exists
$d
->{minfo} and
ref
$d
->{minfo} eq
'ARRAY'
){
for
my
$m
(@{
$d
->{minfo} }){
if
(
$m
->{uin} eq
$member_uin
){
my
$m_clone
= dclone(
$m
);
$self
->{cache_for_discuss_member}->store(
"$did|$member_uin"
,
$m_clone
);
return
$m_clone
;
}
}
return
undef
;
}
else
{
my
$discuss_info
=
$self
->_get_discuss_info(
$d
->{dinfo}{did});
if
(
defined
$discuss_info
and
ref
$discuss_info
->{minfo} eq
'ARRAY'
){
$self
->update_discuss_info(
$discuss_info
);
for
my
$m
(@{
$discuss_info
->{minfo}}){
if
(
$m
->{uin} eq
$member_uin
){
my
$m_clone
= dclone(
$m
);
$self
->{cache_for_discuss_member}->store(
"$did|$member_uin"
,
$m_clone
);
return
$m_clone
;
}
}
return
undef
;
}
else
{
return
undef
;
}
}
}
}
return
undef
;
}
sub
search_discuss{
my
$self
=
shift
;
my
$did
=
shift
;
my
$cache_data
=
$self
->{cache_for_discuss}->retrieve(
$did
);
return
$cache_data
if
defined
$cache_data
;
for
(@{
$self
->{qq_database}{discuss} }){
if
(
$_
->{dinfo}{did} eq
$did
){
my
$clone
= dclone(
$_
->{dinfo});
$self
->{cache_for_discuss}->store(
$did
,
$clone
);
return
$clone
;
}
}
return
undef
;
}
sub
search_stranger{
my
(
$self
,
$tuin
) =
@_
;
my
$cache_data
=
$self
->{cache_for_stranger}->retrieve(
$tuin
);
return
$cache_data
if
defined
$cache_data
;
for
my
$g
( @{
$self
->{qq_database}{group}} ){
for
my
$m
(@{
$g
->{minfo} }){
if
(
$m
->{uin} eq
$tuin
){
my
$m_clone
= dclone(
$m
);
$self
->{cache_for_stranger}->store(
$tuin
,
$m_clone
);
return
$m_clone
;
}
}
}
$self
->_get_stranger_info(
$tuin
) or
undef
;
}
sub
search_group{
my
(
$self
,
$gcode
) =
@_
;
my
$cache_data
=
$self
->{cache_for_group}->retrieve(
$gcode
);
return
$cache_data
if
defined
$cache_data
;
for
(@{
$self
->{qq_database}{group} }){
if
(
$_
->{ginfo}{code} eq
$gcode
){
my
$clone
= dclone(
$_
->{ginfo});
$self
->{cache_for_group}->store(
$gcode
,
$clone
);
return
$clone
;
}
}
return
undef
;
}
sub
update_user_info{
my
$self
=
shift
;
console
"更新个人信息...\n"
;
my
$user_info
=
$self
->_get_user_info();
if
(
defined
$user_info
){
for
my
$key
(
keys
%{
$user_info
}){
if
(
$key
eq
'birthday'
){
$self
->{qq_database}{user}{birthday} =
encode(
"utf8"
,
join
(
"-"
,@{
$user_info
->{birthday}}{
qw(year month day)
} ) );
}
else
{
$self
->{qq_database}{user}{
$key
} = encode(
"utf8"
,
$user_info
->{
$key
});
}
}
my
$single_long_nick
=
$self
->get_single_long_nick(
$self
->{qq_param}{
qq});
if(defined $single_long_nick){
$self->{qq_database}
{user}{single_long_nick} =
$single_long_nick
;
}
}
else
{console
"更新个人信息失败\n"
;}
}
sub
update_friends_info{
my
$self
=
shift
;
my
$friend
=
shift
;
if
(
defined
$friend
){
for
(@{
$self
->{qq_database}{friends} }){
if
(
$_
->{uin} eq
$friend
->{uin}){
$_
=
$friend
;
return
;
}
}
push
@{
$self
->{qq_database}{friends} },
$friend
;
return
;
}
console
"更新好友信息...\n"
;
my
$friends_info
=
$self
->_get_user_friends();
if
(
defined
$friends_info
){
my
%categories
;
my
%info
;
my
%marknames
;
my
%vipinfo
;
for
(@{
$friends_info
->{categories}}){
$categories
{
$_
->{
'index'
} } = {
'sort'
=>
$_
->{
'sort'
},
name
=>encode(
"utf8"
,
$_
->{name}) };
}
$categories
{0} = {
sort
=>0,
name
=>
'我的好友'
};
for
(@{
$friends_info
->{info}}){
$info
{
$_
->{uin}} = {
face
=>
$_
->{face},
flag
=>
$_
->{flag},
nick
=>encode(
"utf8"
,
$_
->{nick}),};
}
for
(@{
$friends_info
->{marknames} }){
$marknames
{
$_
->{uin}} = {
markname
=>encode(
"utf8"
,
$_
->{markname}),
type
=>
$_
->{type}};
}
for
(@{
$friends_info
->{vipinfo} }){
$vipinfo
{
$_
->{u}} = {
vip_level
=>
$_
->{vip_level},
is_vip
=>
$_
->{is_vip}};
}
$self
->{qq_database}{friends} =
$friends_info
->{friends};
for
(@{
$self
->{qq_database}{friends} }){
my
$uin
=
$_
->{uin};
$_
->{categorie} =
$categories
{
$_
->{categories}}{name};
$_
->{nick} =
$info
{
$uin
}{nick};
$_
->{face} =
$info
{
$uin
}{face};
$_
->{markname} =
$marknames
{
$uin
}{markname};
$_
->{is_vip} =
$vipinfo
{
$uin
}{is_vip};
$_
->{vip_level} =
$vipinfo
{
$uin
}{vip_level};
}
}
else
{console
"更新好友信息失败\n"
;}
}
sub
update_discuss_info {
my
$self
=
shift
;
my
$discuss
=
shift
;
my
$is_init
= 1
if
@{
$self
->{qq_database}{discuss}} == 0;
if
(
defined
$discuss
){
for
( @{
$self
->{qq_database}{discuss}} ){
if
(
$_
->{dinfo}{did} eq
$discuss
->{dinfo}{did} ){
$self
->_detect_loss_discuss_member(
$_
,
$discuss
);
$self
->_detect_new_discuss_member2(
$_
,
$discuss
);
$_
=
$discuss
;
return
;
}
}
push
@{
$self
->{qq_database}{discuss}},
$discuss
;
if
(!
$is_init
and
ref
$self
->{on_new_discuss} eq
'CODE'
){
eval
{
$self
->{on_new_discuss}->(dclone(
$discuss
));
};
console $@ .
"\n"
if
$@;
}
return
;
}
$self
->update_discuss_list_info();
for
my
$dl
(@{
$self
->{qq_database}{discuss_list} }){
console
"更新[ $dl->{name} ]讨论组信息...\n"
;
my
$discuss_info
=
$self
->_get_discuss_info(
$dl
->{did});
if
(
defined
$discuss_info
){
if
(
ref
$discuss_info
->{minfo} ne
'ARRAY'
){
console
"更新[ $dl->{name} ]讨论组成功,但暂时没有获取到讨论组成员信息...\n"
;
}
my
$flag
= 0;
for
( @{
$self
->{qq_database}{discuss}} ){
if
(
$_
->{dinfo}{did} eq
$discuss_info
->{dinfo}{did} ){
$self
->_detect_loss_discuss_member(
$_
,
$discuss_info
);
$self
->_detect_new_discuss_member2(
$_
,
$discuss_info
);
$_
=
$discuss_info
if
ref
$discuss_info
->{minfo} eq
'ARRAY'
;
$flag
= 1;
last
;
}
}
if
(
$flag
== 0){
push
@{
$self
->{qq_database}{discuss} },
$discuss_info
;
if
( !
$is_init
and
ref
$self
->{on_new_discuss} eq
'CODE'
){
eval
{
$self
->{on_new_discuss}->(dclone(
$discuss_info
));
};
console $@ .
"\n"
if
$@;
}
}
}
else
{console
"更新[ $dl->{name} ]讨论组信息失败\n"
;}
}
}
sub
update_discuss_list_info {
my
$self
=
shift
;
my
$discuss
=
shift
;
if
(
defined
$discuss
){
for
(@{
$self
->{qq_database}{discuss_list} }){
if
(
$_
->{did} eq
$discuss
->{did}){
$_
=
$discuss
;
return
;
}
}
push
@{
$self
->{qq_database}{discuss_list} },
$discuss
;
return
;
}
console
"更新讨论组列表信息...\n"
;
my
$discuss_list_info
=
$self
->_get_discuss_list_info();
if
(
defined
$discuss_list_info
){
$self
->{qq_database}{discuss_list} =
$discuss_list_info
;
}
else
{console
"更新讨论组列表信息失败\n"
;}
}
sub
update_group_info{
my
$self
=
shift
;
my
$group
=
shift
;
my
$is_init
= 1
if
@{
$self
->{qq_database}{group}} == 0;
if
(
defined
$group
){
for
( @{
$self
->{qq_database}{group}} ){
if
(
$_
->{ginfo}{code} eq
$group
->{ginfo}{code} ){
$self
->_detect_loss_group_member(
$_
,
$group
);
$self
->_detect_new_group_member2(
$_
,
$group
);
$_
=
$group
;
return
;
}
}
push
@{
$self
->{qq_database}{group}},
$group
;
if
(!
$is_init
and
ref
$self
->{on_new_group} eq
'CODE'
){
eval
{
$self
->{on_new_group}->(dclone(
$group
));
};
console $@ .
"\n"
if
$@;
}
return
;
}
$self
->update_group_list_info();
for
my
$gl
(@{
$self
->{qq_database}{group_list} }){
console
"更新[ $gl->{name} ]群信息...\n"
;
my
$group_info
=
$self
->_get_group_info(
$gl
->{code});
if
(
defined
$group_info
){
if
(
ref
$group_info
->{minfo} ne
'ARRAY'
){
console
"更新[ $gl->{name} ]成功,但暂时没有获取到群成员信息...\n"
;
}
my
$flag
= 0;
for
( @{
$self
->{qq_database}{group}} ){
if
(
$_
->{ginfo}{code} eq
$group_info
->{ginfo}{code} ){
$self
->_detect_loss_group_member(
$_
,
$group_info
);
$self
->_detect_new_group_member2(
$_
,
$group_info
);
$_
=
$group_info
if
ref
$group_info
->{minfo} eq
'ARRAY'
;
$flag
= 1;
last
;
}
}
if
(
$flag
== 0){
push
@{
$self
->{qq_database}{group} },
$group_info
;
if
( !
$is_init
and
ref
$self
->{on_new_group} eq
'CODE'
){
eval
{
$self
->{on_new_group}->(dclone(
$group_info
));
};
console $@ .
"\n"
if
$@;
}
}
}
else
{console
"更新[ $gl->{name} ]群信息失败\n"
;}
}
}
sub
update_group_list_info{
my
$self
=
shift
;
my
$group
=
shift
;
if
(
defined
$group
){
for
(@{
$self
->{qq_database}{group_list} }){
if
(
$_
->{code} eq
$group
->{code}){
$_
=
$group
;
return
;
}
}
push
@{
$self
->{qq_database}{group_list} },
$group
;
return
;
}
console
"更新群列表信息...\n"
;
my
$group_list_info
=
$self
->_get_group_list_info();
if
(
defined
$group_list_info
){
$self
->{qq_database}{group_list} =
$group_list_info
->{gnamelist};
my
%gmarklist
;
for
(@{
$group_list_info
->{gmarklist} }){
$gmarklist
{
$_
->{uin}} =
$_
->{markname};
}
for
(@{
$self
->{qq_database}{group_list} }){
$_
->{markname} =
$gmarklist
{
$_
->{gid}};
$_
->{name} = encode(
"utf8"
,
$_
->{name});
}
}
else
{console
"更新群列表信息失败\n"
;}
}
sub
get_group_code_from_gid {
my
$self
=
shift
;
my
$gid
=
shift
;
my
$group_code
=
undef
;
for
my
$g
(@{
$self
->{qq_database}{group_list} }){
if
(
$g
->{gid} eq
$gid
){
$group_code
=
$g
->{code};
last
;
}
}
return
$group_code
;
}
sub
_detect_new_friend{
my
$self
=
shift
;
my
$uin
=
shift
;
return
if
defined
$self
->search_friend(
$uin
);
my
$friend
=
$self
->_get_friend_info(
$uin
);
if
(
defined
$friend
){
$self
->{cache_for_friend}->store(
$uin
,
$friend
);
push
@{
$self
->{qq_database}{friends} },
$friend
;
if
(
ref
$self
->{on_new_friend} eq
'CODE'
){
eval
{
$self
->{on_new_friend}->(
$friend
);
};
console $@ .
"\n"
if
$@;
}
return
;
}
else
{
my
$default_friend
= {
uin
=>
$uin
,
categories
=>
"陌生人"
,
nick
=>
undef
,
};
push
@{
$self
->{qq_database}{friends} },
$default_friend
;
return
;
}
}
sub
_detect_new_group{
my
$self
=
shift
;
my
$gcode
=
shift
;
return
if
defined
$self
->search_group(
$gcode
);
my
$group_info
=
$self
->_get_group_info(
$gcode
);
if
(
defined
$group_info
){
$self
->update_group_list_info({
name
=>
$group_info
->{ginfo}{name},
gid
=>
$group_info
->{ginfo}{gid},
code
=>
$group_info
->{ginfo}{code},
});
push
@{
$self
->{qq_database}{group}},
$group_info
;
if
(
ref
$self
->{on_new_group} eq
'CODE'
){
eval
{
$self
->{on_new_group}->(dclone(
$group_info
));
};
console $@ .
"\n"
if
$@;
}
return
;
}
else
{
return
;
}
}
sub
_detect_new_group_member{
my
$self
=
shift
;
my
(
$gcode
,
$member_uin
) =
@_
;
my
$default_member
= {
nick
=>
undef
,
province
=>
undef
,
gender
=>
undef
,
uin
=>
$member_uin
,
country
=>
undef
,
city
=>
undef
,
card
=>
undef
,
};
my
$group
;
for
my
$g
(@{
$self
->{qq_database}{group}}){
if
(
$g
->{ginfo}{code} eq
$gcode
){
$group
=
$g
;
last
;
}
}
return
unless
defined
$group
;
if
(
exists
$group
->{minfo}){
return
if
defined
$self
->search_member_in_group(
$gcode
,
$member_uin
);
my
$new_group_member
= {};
my
$group_info
=
$self
->_get_group_info(
$gcode
);
if
(
defined
$group_info
and
ref
$group_info
->{minfo} eq
'ARRAY'
){
my
$flag
= 0;
for
my
$m
(@{
$group_info
->{minfo}}){
if
(
$m
->{uin} eq
$member_uin
){
$self
->{cache_for_group_member}->store(
"$gcode|$member_uin"
,dclone(
$m
));
$new_group_member
=
$m
;
$flag
=1;
last
;
}
}
$new_group_member
=
$default_member
if
$flag
==0;
}
else
{
$new_group_member
=
$default_member
;
}
push
@{
$group
->{minfo}},
$new_group_member
;
if
(
ref
$self
->{on_new_group_member} eq
'CODE'
){
eval
{
$self
->{on_new_group_member}->(dclone(
$group
),dclone(
$new_group_member
));
};
console $@ .
"\n"
if
$@;
}
return
;
}
else
{
return
;
}
}
sub
_detect_new_group_member2 {
my
$self
=
shift
;
my
(
$group_old
,
$group_new
) =
@_
;
return
if
ref
$group_old
->{minfo} ne
'ARRAY'
;
return
if
ref
$group_new
->{minfo} ne
'ARRAY'
;
my
%e
=
map
{
$_
->{uin} =>
undef
} @{
$group_old
->{minfo}};
for
my
$new
(@{
$group_new
->{minfo}}){
unless
(
exists
$e
{
$new
->{uin}}){
if
(
ref
$self
->{on_new_group_member} eq
'CODE'
){
eval
{
$self
->{on_new_group_member}->(dclone(
$group_new
),dclone(
$new
));
};
console $@ .
"\n"
if
$@;
};
}
}
}
sub
_detect_loss_group_member {
my
$self
=
shift
;
my
(
$group_old
,
$group_new
) =
@_
;
return
if
ref
$group_old
->{minfo} ne
'ARRAY'
;
return
if
ref
$group_new
->{minfo} ne
'ARRAY'
;
my
%e
=
map
{
$_
->{uin} =>
undef
} @{
$group_new
->{minfo}};
for
my
$old
(@{
$group_old
->{minfo}}){
unless
(
exists
$e
{
$old
->{uin}}){
if
(
ref
$self
->{on_loss_group_member} eq
'CODE'
){
eval
{
$self
->{on_loss_group_member}->(dclone(
$group_old
),dclone(
$old
));
};
console $@ .
"\n"
if
$@;
};
}
$self
->{cache_for_group_member}->
delete
(
$group_old
->{ginfo}{code} .
"|"
.
$old
->{uin});
}
}
sub
_detect_new_discuss{
my
$self
=
shift
;
my
$did
=
shift
;
return
if
defined
$self
->search_discuss(
$did
);
my
$discuss_info
=
$self
->_get_discuss_info(
$did
);
if
(
defined
$discuss_info
){
$self
->update_discuss_list_info({
name
=>
$discuss_info
->{dinfo}{name},
did
=>
$discuss_info
->{dinfo}{did},
});
push
@{
$self
->{qq_database}{discuss}},
$discuss_info
;
if
(
ref
$self
->{on_new_discuss} eq
'CODE'
){
eval
{
$self
->{on_new_discuss}->(dclone(
$discuss_info
));
};
console $@ .
"\n"
if
$@;
}
return
;
}
else
{
return
;
}
}
sub
_detect_loss_discuss_member {
my
$self
=
shift
;
my
(
$discuss_old
,
$discuss_new
) =
@_
;
return
if
ref
$discuss_old
->{minfo} ne
'ARRAY'
;
return
if
ref
$discuss_new
->{minfo} ne
'ARRAY'
;
my
%e
=
map
{
$_
->{uin} =>
undef
} @{
$discuss_new
->{minfo}};
for
my
$old
(@{
$discuss_old
->{minfo}}){
unless
(
exists
$e
{
$old
->{uin}}){
if
(
ref
$self
->{on_loss_discuss_member} eq
'CODE'
){
eval
{
$self
->{on_loss_discuss_member}->(dclone(
$discuss_old
),dclone(
$old
));
};
console $@ .
"\n"
if
$@;
};
}
$self
->{cache_for_discuss_member}->
delete
(
$discuss_old
->{dinfo}{did} .
"|"
.
$old
->{uin});
}
}
sub
_detect_new_discuss_member {
my
$self
=
shift
;
my
(
$did
,
$member_uin
) =
@_
;
my
$default_member
= {
nick
=>
undef
,
uin
=>
$member_uin
,
};
my
$discuss
;
for
my
$d
(@{
$self
->{qq_database}{discuss}}){
if
(
$d
->{dinfo}{did} eq
$did
){
$discuss
=
$d
;
last
;
}
}
return
unless
defined
$discuss
;
if
(
exists
$discuss
->{minfo}){
return
if
defined
$self
->search_member_in_discuss(
$did
,
$member_uin
);
my
$new_discuss_member
= {};
my
$discuss_info
=
$self
->_get_discuss_info(
$did
);
if
(
defined
$discuss_info
and
ref
$discuss_info
->{minfo} eq
'ARRAY'
){
my
$flag
= 0;
for
my
$m
(@{
$discuss_info
->{minfo}}){
if
(
$m
->{uin} eq
$member_uin
){
$self
->{cache_for_discuss_member}->store(
"$did|$member_uin"
,dclone(
$m
));
$new_discuss_member
=
$m
;
$flag
=1;
last
;
}
}
$new_discuss_member
=
$default_member
if
$flag
==0;
}
else
{
$new_discuss_member
=
$default_member
;
}
push
@{
$discuss
->{minfo}},
$new_discuss_member
;
if
(
ref
$self
->{on_new_discuss_member} eq
'CODE'
){
eval
{
$self
->{on_new_discuss_member}->(dclone(
$discuss
),dclone(
$new_discuss_member
));
};
console $@ .
"\n"
if
$@;
}
return
;
}
else
{
return
;
}
}
sub
_detect_new_discuss_member2 {
my
$self
=
shift
;
my
(
$discuss_old
,
$discuss_new
) =
@_
;
return
if
ref
$discuss_old
->{minfo} ne
'ARRAY'
;
return
if
ref
$discuss_new
->{minfo} ne
'ARRAY'
;
my
%e
=
map
{
$_
->{uin} =>
undef
} @{
$discuss_old
->{minfo}};
for
my
$new
(@{
$discuss_new
->{minfo}}){
unless
(
exists
$e
{
$new
->{uin}}){
if
(
ref
$self
->{on_new_discuss_member} eq
'CODE'
){
eval
{
$self
->{on_new_discuss_member}->(dclone(
$discuss_new
),dclone(
$new
));
};
console $@ .
"\n"
if
$@;
};
}
}
}
1;