line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::OICQ::ServerEvent; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# $Id: ServerEvent.pm,v 1.4 2007/06/15 18:09:53 tans Exp $ |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
# Copyright (c) 2003 - 2006 Shufeng Tan. All rights reserved. |
6
|
|
|
|
|
|
|
# |
7
|
|
|
|
|
|
|
# This package is free software and is provided "as is" without express |
8
|
|
|
|
|
|
|
# or implied warranty. It may be used, redistributed and/or modified |
9
|
|
|
|
|
|
|
# under the terms of the Perl Artistic License (see |
10
|
|
|
|
|
|
|
# http://www.perl.com/perl/misc/Artistic.html) |
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
6830
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
42
|
|
13
|
1
|
|
|
1
|
|
8
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
52
|
|
14
|
|
|
|
|
|
|
|
15
|
1
|
|
|
1
|
|
9
|
eval "no encoding; use bytes;" if $] >= 5.008; |
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
59
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
6
|
|
16
|
|
|
|
|
|
|
|
17
|
1
|
|
|
1
|
|
6
|
use Crypt::OICQ qw(encrypt decrypt); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
74
|
|
18
|
1
|
|
|
1
|
|
7
|
use Net::OICQ::ClientEvent; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4837
|
|
19
|
|
|
|
|
|
|
our @ISA = qw(Net::OICQ::Event); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
my $InfoHeader = \@Net::OICQ::InfoHeader; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub new { |
24
|
0
|
|
|
0
|
0
|
|
my ($class, $data, $oicq) = @_; |
25
|
0
|
0
|
0
|
|
|
|
unless (defined $data and length($data) > 8) { |
26
|
0
|
0
|
|
|
|
|
$oicq->log_t("Discard data from server:\n", unpack("H*", $data)) if $oicq->{Debug}; |
27
|
0
|
|
|
|
|
|
return; |
28
|
|
|
|
|
|
|
} |
29
|
0
|
|
|
|
|
|
my $time = time; |
30
|
0
|
|
|
|
|
|
$oicq->{LastSvrAck} = $time; |
31
|
0
|
|
|
|
|
|
my $self = { |
32
|
|
|
|
|
|
|
Time => $time, |
33
|
|
|
|
|
|
|
OICQ => $oicq, |
34
|
|
|
|
|
|
|
Header => substr($data, 0, 7), |
35
|
|
|
|
|
|
|
}; |
36
|
0
|
|
|
|
|
|
bless $self, $class; |
37
|
0
|
|
|
|
|
|
my $cmdcode = $self->cmdcode; |
38
|
0
|
|
|
|
|
|
my $cmd = $self->cmd; |
39
|
0
|
0
|
0
|
|
|
|
if ($cmd eq 'login' || $cmd =~ /^reg_new_id_/) { |
40
|
0
|
|
|
|
|
|
$oicq->log_t("Cmd $cmd ($cmdcode):\n", $oicq->hexdump($data)); |
41
|
0
|
|
|
|
|
|
return undef; |
42
|
|
|
|
|
|
|
} |
43
|
0
|
0
|
|
|
|
|
if ($self->process) { |
44
|
0
|
|
|
|
|
|
my $crypt = substr($data, 7, -1); |
45
|
0
|
|
|
|
|
|
my $plain; |
46
|
0
|
|
|
|
|
|
eval { $plain = decrypt(undef, $crypt, $oicq->{Key}) }; |
|
0
|
|
|
|
|
|
|
47
|
0
|
0
|
|
|
|
|
$oicq->log_t("Error in new ServerEvent:", unpack("H*", $self->{Header}), "$cmd\n", $@) if $@; |
48
|
0
|
0
|
|
|
|
|
return undef unless defined $plain; |
49
|
0
|
|
|
|
|
|
$self->{Data} = $plain; |
50
|
0
|
0
|
|
|
|
|
$oicq->log_t("Server mesg header: ", unpack("H*", $self->{Header}), |
51
|
|
|
|
|
|
|
" $cmd: ", unpack("H*", $self->{Data})) if $oicq->{Debug}; |
52
|
|
|
|
|
|
|
} |
53
|
0
|
|
|
|
|
|
return $self; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Server replies with user info |
57
|
|
|
|
|
|
|
sub get_user_info { |
58
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
59
|
0
|
|
|
|
|
|
my $oicq = $self->{OICQ}; |
60
|
0
|
|
|
|
|
|
my $plain = $self->{Data}; |
61
|
0
|
|
|
|
|
|
my @field = split(/$Net::OICQ::FS/, $plain); |
62
|
|
|
|
|
|
|
|
63
|
0
|
0
|
|
|
|
|
return unless defined $field[0]; |
64
|
0
|
|
|
|
|
|
$self->{Info} = \@field; |
65
|
0
|
0
|
|
|
|
|
return if $field[0] =~ /^-/; |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# If the info is about myself, update MyInfo field. |
68
|
0
|
0
|
|
|
|
|
$oicq->{MyInfo} = [@field] if $field[0] == $oicq->{Id}; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# Initialize Info for the QQ id |
71
|
0
|
0
|
|
|
|
|
$oicq->{Info}->{$field[0]} = {} unless defined $oicq->{Info}->{$field[0]}; |
72
|
|
|
|
|
|
|
# Update nickname, age, sex, and face(or avatar) |
73
|
0
|
|
|
|
|
|
my $hashref = $oicq->{Info}->{$field[0]}; |
74
|
0
|
|
|
|
|
|
$hashref->{Nickname} = $field[1]; |
75
|
0
|
|
|
|
|
|
$hashref->{Age} = $field[7]; |
76
|
0
|
|
|
|
|
|
$hashref->{Sex} = $field[8]; |
77
|
0
|
|
|
|
|
|
$hashref->{Face} = $oicq->get_face($field[21]); |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# Update user info file |
80
|
0
|
|
|
|
|
|
my $datfile = "$oicq->{Dir}/$oicq->{Id}/$field[0].dat"; |
81
|
0
|
|
|
|
|
|
my $dat = new FileHandle(">$datfile"); |
82
|
0
|
0
|
|
|
|
|
if (defined $dat) { |
83
|
0
|
|
|
|
|
|
print $dat "\$_ = {\n"; |
84
|
0
|
|
|
|
|
|
for(my $j = 0; $j<=$#field; $j++) { |
85
|
0
|
|
|
|
|
|
printf $dat "%-15s => '%s',\n", $InfoHeader->[$j], $field[$j]; |
86
|
|
|
|
|
|
|
} |
87
|
0
|
|
|
|
|
|
print $dat "};\n"; |
88
|
0
|
|
|
|
|
|
$dat->close; |
89
|
|
|
|
|
|
|
} else { |
90
|
0
|
|
|
|
|
|
$oicq->log_t("Failed to open user info file >$datfile"); |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
0
|
|
|
|
|
|
return 1; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# Server return code is stored in $event->{ReturnCode} |
97
|
|
|
|
|
|
|
sub send_msg { |
98
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
99
|
0
|
|
|
|
|
|
my $oicq = $self->{OICQ}; |
100
|
0
|
|
|
|
|
|
my $hex = unpack("H*", $self->{Data}); |
101
|
0
|
|
|
|
|
|
$self->{ReturnCode} = $hex; |
102
|
0
|
|
|
|
|
|
return 1; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# recv_msg handles messages from QQ servers, other users, or groups |
106
|
|
|
|
|
|
|
# These event attributes will be set: SrcId, DstId, MsgType, MsgTime, Mesg, |
107
|
|
|
|
|
|
|
# SrcId2, DstId2, $oicq->{Info}->{$srcid}->{Client}, MsgSubtype, MsgSeq for user messages |
108
|
|
|
|
|
|
|
# GrpId, GrpType, SrcId2 for group messages |
109
|
|
|
|
|
|
|
# BotError if a chat bot is defined |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub recv_msg { |
112
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
113
|
0
|
|
|
|
|
|
my $oicq = $self->{OICQ}; |
114
|
0
|
|
|
|
|
|
my $plain = $self->{Data}; |
115
|
0
|
|
|
|
|
|
my ($srcid, $dstid, $x) = unpack('NNN', substr($plain, 0, 12)); |
116
|
0
|
|
|
|
|
|
$self->{SrcId} = $srcid; |
117
|
0
|
|
|
|
|
|
$self->{DstId} = $dstid; |
118
|
0
|
|
|
|
|
|
$self->{N8_12} = $x; |
119
|
0
|
|
|
|
|
|
my $srcaddr = $oicq->show_address(substr($plain, 12, 6)); |
120
|
0
|
|
|
|
|
|
my $msg_type = unpack('n', substr($plain, 18, 2)); |
121
|
0
|
|
|
|
|
|
$self->{SrcAddr} = $srcaddr; |
122
|
0
|
|
|
|
|
|
$self->{MsgType} = $msg_type; |
123
|
|
|
|
|
|
|
|
124
|
0
|
0
|
0
|
|
|
|
if ($srcid != 10000 and !defined($oicq->{Info}->{$srcid})) { |
125
|
0
|
|
|
|
|
|
$oicq->{Info}->{$srcid} = {}; |
126
|
|
|
|
|
|
|
} |
127
|
0
|
|
|
|
|
|
my $mesg; |
128
|
0
|
0
|
0
|
|
|
|
if (grep {$msg_type == $_} 0x09, 0x0a, 0x84, 0x85) { |
|
0
|
0
|
|
|
|
|
|
129
|
0
|
|
|
|
|
|
my ($client, $srcid2, $dstid2, $x, $subtype, $seq, $time) = |
130
|
|
|
|
|
|
|
unpack('H4NNH32nnN', substr($plain, 20, 34)); |
131
|
0
|
|
|
|
|
|
$oicq->{Info}->{$srcid}->{Client} = $client; |
132
|
0
|
|
|
|
|
|
$self->{SrcId2} = $srcid2; |
133
|
0
|
|
|
|
|
|
$self->{DstId2} = $dstid2; |
134
|
0
|
|
|
|
|
|
$self->{H30_46} = $x; |
135
|
0
|
|
|
|
|
|
$self->{Subtype} = $subtype; |
136
|
0
|
|
|
|
|
|
$self->{MsgSeq} = $seq; |
137
|
0
|
|
|
|
|
|
$self->{MsgTime} = $time; |
138
|
0
|
0
|
|
|
|
|
if ($subtype == 0x81) { # Request for file transfer, voice or video |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
139
|
|
|
|
|
|
|
#$mesg = unpack('H*', substr($plain, 54)); |
140
|
0
|
|
|
|
|
|
$self->{RequestId} = unpack('H*', substr($plain, 94, 2)); |
141
|
0
|
|
|
|
|
|
$self->{RequestIP} = $oicq->show_address(substr($plain, 96, 4)); |
142
|
0
|
0
|
|
|
|
|
if ($plain =~ /([^\x1f]+?)\x1f(\d+) \xd7\xd6\xbd\xda$/s) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
143
|
0
|
|
|
|
|
|
$self->{FileName} = $1; |
144
|
0
|
|
|
|
|
|
$self->{FileSize} = $2; |
145
|
|
|
|
|
|
|
} elsif ($plain =~ /(\xd3\xef\xd2\xf4\xc1\xc4\xcc\xec)/s) { |
146
|
0
|
|
|
|
|
|
$self->{VoiceChat} = $1; |
147
|
|
|
|
|
|
|
} elsif ($plain =~ /(\xd3\xef\xd2\xf4\xca\xd3\xc6\xb5\xc1\xc4\xcc\xec)/s) { |
148
|
0
|
|
|
|
|
|
$self->{VideoChat} = $1; |
149
|
|
|
|
|
|
|
} else { |
150
|
0
|
|
|
|
|
|
$self->{Ignore} = 1; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
} elsif ($subtype == 0x85) { # Cancel |
153
|
|
|
|
|
|
|
#$mesg = unpack('H*', substr($plain, 54)); |
154
|
0
|
|
|
|
|
|
$self->{RequestCancelled} = unpack('H*', substr($plain, 84, 2)); |
155
|
|
|
|
|
|
|
} elsif ($subtype == 0x35) { |
156
|
0
|
|
|
|
|
|
$self->{Ignore} = 1; |
157
|
|
|
|
|
|
|
#$mesg = unpack('H*', substr($plain, 54)); |
158
|
|
|
|
|
|
|
} elsif ($subtype == 0x0b) { |
159
|
0
|
|
|
|
|
|
$mesg = substr($plain, 73); |
160
|
|
|
|
|
|
|
} else { |
161
|
0
|
|
|
|
|
|
$mesg = substr($plain, 54); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
} elsif ($msg_type == 0x20 or $msg_type == 0x2b) { # Group message |
164
|
0
|
|
|
|
|
|
my ($gid, $gtype, $srcid2, $x1, $seq, $time, $x2, $len, $x3) = |
165
|
|
|
|
|
|
|
unpack('NH2NH4nNH8nH20', substr($plain, 20, 33)); |
166
|
0
|
|
|
|
|
|
$self->{GrpId} = $gid; |
167
|
0
|
|
|
|
|
|
$self->{GrpType} = $gtype; |
168
|
0
|
|
|
|
|
|
$self->{SrcId2} = $srcid2; |
169
|
0
|
|
|
|
|
|
$self->{H9_10} = $x1; |
170
|
0
|
|
|
|
|
|
$self->{MsgSeq} = $seq; |
171
|
0
|
|
|
|
|
|
$self->{MsgTime} = $time; |
172
|
0
|
|
|
|
|
|
$self->{H17_20} = $x2; |
173
|
0
|
|
|
|
|
|
$self->{MsgLen} = $len; |
174
|
0
|
|
|
|
|
|
$self->{MsgHead} = $x3; |
175
|
0
|
|
|
|
|
|
$mesg = substr($plain, 53); |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
# Let's process the message tail |
178
|
0
|
0
|
|
|
|
|
if ($mesg) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
179
|
0
|
|
|
|
|
|
my $tail_len = ord(substr($mesg, -1, 1)); |
180
|
0
|
|
|
|
|
|
my $tail = substr($mesg, -1-$tail_len); |
181
|
0
|
0
|
|
|
|
|
if ($tail =~ /^ \0/) { |
182
|
|
|
|
|
|
|
# get rid of tail from $mesg |
183
|
0
|
|
|
|
|
|
substr($mesg, -1-$tail_len) = ""; |
184
|
|
|
|
|
|
|
# don't care about bold, italic, or underscore |
185
|
0
|
|
|
|
|
|
$self->{FontSize} = ord(substr($tail, 2, 1)) & 0x1f; |
186
|
0
|
|
|
|
|
|
$self->{FontColor} = unpack('H*', substr($tail, 3, 3)); |
187
|
0
|
|
|
|
|
|
$tail =~ s/.$//; |
188
|
0
|
|
|
|
|
|
$self->{FontName} = substr($tail, 9); |
189
|
|
|
|
|
|
|
} |
190
|
0
|
0
|
|
|
|
|
if ($oicq->{LogChat}) { |
191
|
0
|
0
|
|
|
|
|
my $grpid = exists($self->{GrpId}) ? "(Group $self->{GrpId})" : ""; |
192
|
0
|
|
|
|
|
|
my $time = substr(localtime($self->{MsgTime}), 4, 16); |
193
|
0
|
|
|
|
|
|
$oicq->log_t("$time received message from $srcid$grpid:\n$mesg"); |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
} elsif ($msg_type == 0x18) { |
196
|
0
|
|
|
|
|
|
$self->{MsgHeader} = unpack("H*", substr($plain, 20, 5)); |
197
|
0
|
|
|
|
|
|
$mesg = substr($plain, 25); |
198
|
|
|
|
|
|
|
} elsif ($msg_type == 0x30) { |
199
|
0
|
|
|
|
|
|
$self->{MsgHeader} = unpack("H*", substr($plain, 20, 1)); |
200
|
0
|
|
|
|
|
|
$mesg = substr($plain, 21); |
201
|
|
|
|
|
|
|
} elsif ($msg_type == 0x34) { # Backdrop |
202
|
0
|
|
|
|
|
|
$self->{MsgTime} = unpack('N', substr($plain, -4)); |
203
|
0
|
0
|
|
|
|
|
if (length($plain) <= 30) { |
204
|
0
|
|
|
|
|
|
$self->{BackdropCancelled} = 1; |
205
|
0
|
|
|
|
|
|
$mesg = ""; |
206
|
|
|
|
|
|
|
} else { |
207
|
0
|
|
|
|
|
|
my $len = ord(substr($plain, 27, 1)); |
208
|
0
|
|
|
|
|
|
$self->{Backdrop} = substr($plain, 28, $len); |
209
|
0
|
|
|
|
|
|
$mesg = substr($plain, 20); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
} elsif ($msg_type == 0x41) { |
212
|
0
|
|
|
|
|
|
$self->{MsgHeader} = unpack("H*", substr($plain, 20, 9)); |
213
|
0
|
|
|
|
|
|
$mesg = substr($plain, 29); |
214
|
|
|
|
|
|
|
} elsif ($msg_type == 0x4c) { |
215
|
0
|
|
|
|
|
|
$self->{MsgHeader} = unpack("H*", substr($plain, 20, 7)); |
216
|
0
|
|
|
|
|
|
$mesg = substr($plain, 27); |
217
|
|
|
|
|
|
|
} elsif ($oicq->{Debug}) { |
218
|
0
|
|
|
|
|
|
$mesg = unpack('H*', substr($plain, 20)); |
219
|
0
|
|
|
|
|
|
$oicq->log_t("Unknown message type $msg_type from $srcid, $srcaddr:\n$mesg"); |
220
|
|
|
|
|
|
|
} |
221
|
0
|
|
|
|
|
|
$self->{Mesg} = $mesg; |
222
|
|
|
|
|
|
|
|
223
|
0
|
0
|
0
|
|
|
|
if (defined $oicq->{Socket} and defined $mesg and ! $self->{Ignore}) { |
|
|
|
0
|
|
|
|
|
224
|
0
|
|
|
|
|
|
$oicq->ack_msg($self->seq, $plain); |
225
|
|
|
|
|
|
|
} |
226
|
0
|
|
|
|
|
|
return 1; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# Response to get_online_friends is a list of fixed length (38 bytes) |
230
|
|
|
|
|
|
|
# records, will update $oicq->{Info}, $event->{OnlineFriends} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub get_online_friends { |
233
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
234
|
0
|
|
|
|
|
|
my $plain = $self->{Data}; |
235
|
0
|
|
|
|
|
|
my $oicq = $self->{OICQ}; |
236
|
0
|
|
|
|
|
|
my @list = (); |
237
|
0
|
|
|
|
|
|
my $info = $oicq->{Info}; |
238
|
0
|
|
|
|
|
|
for(my $i = 1; $i
|
239
|
0
|
|
|
|
|
|
my $fid = unpack('N', substr($plain, $i, 4)); |
240
|
0
|
|
|
|
|
|
my $addr = $oicq->show_address(substr($plain, $i+5, 6)); |
241
|
0
|
|
|
|
|
|
my $mode = ord(substr($plain, $i+12, 1)); |
242
|
0
|
|
|
|
|
|
my $key = substr($plain, $i+13, 20); |
243
|
0
|
0
|
|
|
|
|
defined $info->{$fid} or $info->{$fid} = {}; |
244
|
0
|
|
|
|
|
|
$info->{$fid}->{Key} = $key; |
245
|
0
|
|
|
|
|
|
$info->{$fid}->{Mode} = $mode; |
246
|
0
|
0
|
|
|
|
|
$info->{$fid}->{Addr} = $addr if $addr =~/[1-9]/; |
247
|
0
|
|
|
|
|
|
push @list, $fid; |
248
|
|
|
|
|
|
|
} |
249
|
0
|
|
|
|
|
|
$self->{OnlineFriends} = \@list; |
250
|
0
|
|
|
|
|
|
return 1; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
sub recv_service_msg { |
254
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
255
|
0
|
|
|
|
|
|
my $oicq = $self->{OICQ}; |
256
|
0
|
|
|
|
|
|
my ($code, $srcid, $myid, $mesg) = split(/$Net::OICQ::RS/, $self->{Data}); |
257
|
0
|
|
|
|
|
|
$self->{ServerCode} = $code; |
258
|
0
|
|
|
|
|
|
$self->{SrcId} = $srcid; |
259
|
0
|
|
|
|
|
|
$self->{DstId} = $myid; |
260
|
0
|
|
|
|
|
|
$self->{Mesg} = $mesg; |
261
|
0
|
0
|
|
|
|
|
if (defined $oicq->{Socket}) { |
262
|
0
|
|
|
|
|
|
$oicq->ack_service_msg($code, $srcid, $self->seq); |
263
|
|
|
|
|
|
|
} |
264
|
0
|
|
|
|
|
|
my $comment; |
265
|
0
|
0
|
0
|
|
|
|
if ($code eq "02" or $code eq "41") { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
266
|
0
|
|
|
|
|
|
$comment = "$srcid asked to add $myid"; |
267
|
|
|
|
|
|
|
} elsif ($code eq "03") { |
268
|
0
|
|
|
|
|
|
$comment = "$srcid accepted $myid"; |
269
|
|
|
|
|
|
|
} elsif ($code eq "04") { |
270
|
0
|
|
|
|
|
|
$comment = "$srcid rejected $myid"; |
271
|
|
|
|
|
|
|
} elsif ($srcid == 10000) { |
272
|
0
|
|
|
|
|
|
$comment = "garbage from $srcid"; |
273
|
|
|
|
|
|
|
} else { |
274
|
0
|
|
|
|
|
|
$comment = "unknown"; |
275
|
|
|
|
|
|
|
} |
276
|
0
|
|
|
|
|
|
$self->{Comment} = $comment; |
277
|
0
|
|
|
|
|
|
$oicq->log_t("$comment:\n$mesg"); |
278
|
0
|
|
|
|
|
|
return 1; |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# List of lists is stored in $event->{UserList} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
sub search_users { |
284
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
285
|
0
|
|
|
|
|
|
my $plain = $self->{Data}; |
286
|
0
|
|
|
|
|
|
my $oicq = $self->{OICQ}; |
287
|
0
|
|
|
|
|
|
my @list; |
288
|
0
|
|
|
|
|
|
foreach my $line (split(/$Net::OICQ::RS/, $plain)) { |
289
|
0
|
|
|
|
|
|
my @f = split(/$Net::OICQ::FS/, $line); |
290
|
0
|
0
|
|
|
|
|
next unless defined $f[3]; |
291
|
0
|
|
|
|
|
|
$f[3] = $oicq->get_face($f[3]); |
292
|
0
|
|
|
|
|
|
push @list, \@f; |
293
|
|
|
|
|
|
|
} |
294
|
0
|
|
|
|
|
|
$self->{UserList} = \@list; |
295
|
0
|
|
|
|
|
|
return 1; |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
sub keep_alive { |
299
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
300
|
0
|
|
|
|
|
|
my $oicq = $self->{OICQ}; |
301
|
0
|
|
|
|
|
|
my $plain = $self->{Data}; |
302
|
|
|
|
|
|
|
#my @field = split($Net::OICQ::RS, $plain); |
303
|
|
|
|
|
|
|
#$oicq->{UserCount} = $field[2]; |
304
|
|
|
|
|
|
|
#$self->{ServerInfo} = \@field; |
305
|
0
|
|
|
|
|
|
return 1; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub get_contact_id { |
309
|
0
|
|
|
0
|
0
|
|
my ($self, $seq) = @_; |
310
|
0
|
|
|
|
|
|
my $event; |
311
|
0
|
|
|
|
|
|
foreach my $e (@{$self->{OICQ}->{EventQueue}}) { |
|
0
|
|
|
|
|
|
|
312
|
0
|
0
|
|
|
|
|
next unless ref($e) =~ /Client/; |
313
|
0
|
0
|
|
|
|
|
if ($e->seq eq $seq) { |
314
|
0
|
|
|
|
|
|
$event = $e; |
315
|
0
|
|
|
|
|
|
last; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
} |
318
|
0
|
0
|
|
|
|
|
return 'Someone' unless defined $event; |
319
|
0
|
|
|
|
|
|
my ($id) = $event->{Data} =~ /^(\d+)/; |
320
|
0
|
|
|
|
|
|
return $id; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub add_contact_1 { |
324
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
325
|
0
|
|
|
|
|
|
my $plain = $self->{Data}; |
326
|
0
|
|
|
|
|
|
my ($id, $reply) = split(/$Net::OICQ::RS/, $plain); |
327
|
0
|
|
|
|
|
|
$self->{Id} = $id; |
328
|
0
|
|
|
|
|
|
$self->{Reply} = $reply; |
329
|
0
|
|
|
|
|
|
my $srcid = $self->get_contact_id($self->seq); |
330
|
0
|
0
|
|
|
|
|
if ($reply =~ /^\d+$/) { |
331
|
0
|
0
|
|
|
|
|
if ($reply > 0) { |
|
|
0
|
|
|
|
|
|
332
|
0
|
|
|
|
|
|
$self->{Comment} = "$srcid requires authentication message."; |
333
|
0
|
|
|
|
|
|
return 0; |
334
|
|
|
|
|
|
|
} elsif ($reply == 0) { |
335
|
0
|
|
|
|
|
|
$self->{Comment} = "$srcid has accepted your request."; |
336
|
0
|
|
|
|
|
|
return 1; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
} |
339
|
0
|
|
|
|
|
|
$self->{Comment} = "Unknown reply from add_contact_1 $srcid: $reply"; |
340
|
0
|
|
|
|
|
|
return; |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
|
343
|
0
|
|
|
0
|
0
|
|
sub add_contact_2 { |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
# get_friends_list provided by Chen Peng |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
sub get_friends_list { |
349
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
350
|
0
|
|
|
|
|
|
my $plain = $self->{Data}; |
351
|
0
|
|
|
|
|
|
my $oicq = $self->{OICQ}; |
352
|
0
|
|
|
|
|
|
my $flag = substr($plain, 0, 2); |
353
|
0
|
|
|
|
|
|
$self->{Flag} = unpack("H*", $flag); |
354
|
0
|
|
|
|
|
|
my $p = 2; |
355
|
0
|
|
|
|
|
|
my $len = length($plain); |
356
|
0
|
|
|
|
|
|
while ($p < $len) { |
357
|
0
|
|
|
|
|
|
my $fid = unpack('N', substr($plain, $p, 4)); |
358
|
0
|
|
|
|
|
|
$p += 4; # one 0x00 to seperate |
359
|
0
|
|
|
|
|
|
my $face = $oicq->get_face(ord(substr($plain, $p+1, 1))); $p += 2; |
|
0
|
|
|
|
|
|
|
360
|
0
|
|
|
|
|
|
my $age = ord(substr($plain, $p, 1)); $p += 1; |
|
0
|
|
|
|
|
|
|
361
|
0
|
|
|
|
|
|
my $sex = ord(substr($plain, $p, 1)); $p += 1; |
|
0
|
|
|
|
|
|
|
362
|
0
|
|
|
|
|
|
my $name_len = ord(substr($plain, $p, 1)); $p += 1; |
|
0
|
|
|
|
|
|
|
363
|
0
|
|
|
|
|
|
my $nickname = substr($plain, $p, $name_len); $p += $name_len; |
|
0
|
|
|
|
|
|
|
364
|
0
|
|
|
|
|
|
my $unknown = unpack("H*", substr($plain, $p, 4)); $p += 4; |
|
0
|
|
|
|
|
|
|
365
|
0
|
0
|
|
|
|
|
$oicq->{Info}->{$fid} = {} unless defined $oicq->{Info}->{$fid}; |
366
|
0
|
|
|
|
|
|
my $info = $oicq->{Info}->{$fid}; |
367
|
0
|
|
|
|
|
|
$info->{Sex} = $sex; |
368
|
0
|
|
|
|
|
|
$info->{Age} = $age; |
369
|
0
|
|
|
|
|
|
$info->{Face} = $face; |
370
|
0
|
|
|
|
|
|
$info->{Nickname} = $nickname; |
371
|
0
|
|
|
|
|
|
$info->{Friend} = 1; |
372
|
0
|
|
|
|
|
|
$info->{Unknown} = $unknown; |
373
|
|
|
|
|
|
|
} |
374
|
0
|
0
|
|
|
|
|
if ($flag ne "\xff\xff") { |
375
|
0
|
|
|
|
|
|
$oicq->get_friends_list($flag); |
376
|
|
|
|
|
|
|
} |
377
|
0
|
|
|
|
|
|
return 1; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
sub recv_friend_status { |
381
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
382
|
0
|
|
|
|
|
|
my $plain = $self->{Data}; |
383
|
0
|
|
|
|
|
|
my $oicq = $self->{OICQ}; |
384
|
0
|
|
|
|
|
|
my $srcid = unpack('N', substr($plain, 0, 4)); |
385
|
0
|
|
|
|
|
|
my $addr = $oicq->show_address(substr($plain, 5, 6)); |
386
|
0
|
|
|
|
|
|
$self->{Mode} = ord(substr($plain, 12, 1)); |
387
|
0
|
|
|
|
|
|
$self->{H13_33} = unpack("H*", substr($plain, 13, 20)); |
388
|
0
|
|
|
|
|
|
$self->{DstId} = unpack('N', substr($plain, 35, 4)); |
389
|
0
|
|
|
|
|
|
$self->{SrcId} = $srcid; |
390
|
0
|
0
|
|
|
|
|
$oicq->{Info}->{$srcid} = {} unless defined $oicq->{Info}->{$srcid}; |
391
|
0
|
|
|
|
|
|
my $info = $oicq->{Info}->{$srcid}; |
392
|
0
|
0
|
|
|
|
|
if ($addr =~ /[1-9]/) { |
393
|
0
|
|
|
|
|
|
$self->{Addr} = $addr; |
394
|
0
|
|
|
|
|
|
$info->{Addr} = $addr; |
395
|
|
|
|
|
|
|
} |
396
|
0
|
|
|
|
|
|
$info->{Mode} = $self->{Mode}; |
397
|
0
|
|
|
|
|
|
return 1; |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
sub do_group { |
401
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
402
|
0
|
|
|
|
|
|
my $plain = $self->{Data}; |
403
|
0
|
|
|
|
|
|
my $oicq = $self->{OICQ}; |
404
|
0
|
|
|
|
|
|
my ($sub_cmd, $reply) = unpack('H2H2', substr($plain, 0, 2)); |
405
|
0
|
|
|
|
|
|
$self->{SubCmd} = $sub_cmd; |
406
|
0
|
|
|
|
|
|
$self->{Reply} = $reply; |
407
|
0
|
0
|
|
|
|
|
if ($reply ne '00'){ |
408
|
0
|
|
|
|
|
|
$self->{Error} = substr($plain, 2); |
409
|
0
|
|
|
|
|
|
return; |
410
|
|
|
|
|
|
|
} |
411
|
0
|
0
|
|
|
|
|
if ($sub_cmd eq '06') { # search group |
412
|
0
|
|
|
|
|
|
my ($search_type, $int_gid, $ext_gid, $gtype, $x, $owner_id) = |
413
|
|
|
|
|
|
|
unpack('H2NNH2H8N', substr($plain, 2, 18)); |
414
|
0
|
|
|
|
|
|
my $gname_len = ord(substr($plain, 30, 1)); |
415
|
0
|
|
|
|
|
|
my $gname = substr($plain, 31, $gname_len); |
416
|
0
|
|
|
|
|
|
my $gauth_type = unpack('H*', substr($plain, 33+$gname_len, 1)); |
417
|
0
|
|
|
|
|
|
my $gdesc_len = ord(substr($plain, 34+$gname_len, 1)); |
418
|
0
|
|
|
|
|
|
my $gdesc = substr($plain, 35+$gname_len, $gdesc_len); |
419
|
0
|
|
|
|
|
|
$oicq->log_t("S_DO_GROUP $sub_cmd code $reply:\n", $oicq->hexdump($plain)); |
420
|
0
|
|
|
|
|
|
$self->{GrpIntId} = $int_gid; |
421
|
0
|
|
|
|
|
|
$self->{GrpExtId} = $ext_gid; |
422
|
0
|
|
|
|
|
|
$self->{GrpOwner} = $owner_id; |
423
|
0
|
|
|
|
|
|
$self->{GrpName} = $gname; |
424
|
0
|
|
|
|
|
|
$self->{GrpDesc} = $gdesc; |
425
|
0
|
|
|
|
|
|
return 1; |
426
|
|
|
|
|
|
|
} |
427
|
0
|
0
|
|
|
|
|
if ($sub_cmd eq '04') { # group info |
428
|
0
|
|
|
|
|
|
my ($int_gid, $ext_gid, $gtype, $owner_id, $gauth_type) = |
429
|
|
|
|
|
|
|
unpack('NNH2NH2', substr($plain, 2, 14)); |
430
|
0
|
|
|
|
|
|
my $cat = unpack("n",substr($plain, 18, 2)); |
431
|
0
|
|
|
|
|
|
my $gname_len = ord(substr($plain, 24, 1)); |
432
|
0
|
|
|
|
|
|
my $gname = substr($plain, 25, $gname_len); |
433
|
0
|
|
|
|
|
|
my $gnotice_len = ord(substr($plain, 27+$gname_len, 1)); |
434
|
0
|
|
|
|
|
|
my $gnotice = substr($plain, 28+$gname_len, $gnotice_len); |
435
|
0
|
|
|
|
|
|
my $gdesc_len = ord(substr($plain, 28+$gname_len+$gnotice_len, 1)); |
436
|
0
|
|
|
|
|
|
my $gdesc = substr($plain, 29+$gname_len+$gnotice_len, $gdesc_len); |
437
|
0
|
|
|
|
|
|
$self->{GrpIntId} = $int_gid; |
438
|
0
|
|
|
|
|
|
$self->{GrpName} = $gname; |
439
|
0
|
|
|
|
|
|
$self->{GrpNotice} = $gnotice; |
440
|
0
|
|
|
|
|
|
$self->{GrpDesc} = $gdesc; |
441
|
0
|
|
|
|
|
|
return 1; |
442
|
|
|
|
|
|
|
} |
443
|
0
|
0
|
|
|
|
|
if ($sub_cmd eq '0b') { # online group members |
444
|
0
|
|
|
|
|
|
$self->{GrpIntId} = unpack('N', substr($plain, 2, 4)); |
445
|
0
|
0
|
|
|
|
|
my @online_members = length($plain) >= 11 ? unpack('N*', substr($plain, 7)) : (); |
446
|
0
|
|
|
|
|
|
$self->{OnlineMembers} = \@online_members; |
447
|
0
|
|
|
|
|
|
return 1; |
448
|
|
|
|
|
|
|
} |
449
|
0
|
|
|
|
|
|
$self->{Unknown} = unpack("H*", substr($plain, 2)); |
450
|
0
|
|
|
|
|
|
return; |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
sub req_file_key { |
454
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
455
|
0
|
|
|
|
|
|
my $plain = $self->{Data}; |
456
|
0
|
|
|
|
|
|
my $oicq = $self->{OICQ}; |
457
|
0
|
0
|
0
|
|
|
|
unless (unpack('H4', $plain) eq '0400' and length($plain) > 18) { |
458
|
0
|
|
|
|
|
|
$oicq->log_t("Svr response to req_file_key:\n", $oicq->hexdump($plain)); |
459
|
0
|
|
|
|
|
|
return; |
460
|
|
|
|
|
|
|
} |
461
|
0
|
|
|
|
|
|
my $file_key = substr($plain, 2, 16); |
462
|
0
|
|
|
|
|
|
$self->{FileKey} = $file_key; |
463
|
0
|
|
|
|
|
|
$oicq->log_t("Received file transfer key from server: $file_key"); |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
1; |