| 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; |