libpurple/protocols/qq/buddy_list.c

changeset 23950
a974649cdb89
parent 23212
a39a33c79a3f
child 24018
91f0294f2377
equal deleted inserted replaced
23949:9ec519c1b341 23950:a974649cdb89
30 #include "notify.h" 30 #include "notify.h"
31 #include "utils.h" 31 #include "utils.h"
32 #include "packet_parse.h" 32 #include "packet_parse.h"
33 #include "buddy_info.h" 33 #include "buddy_info.h"
34 #include "buddy_list.h" 34 #include "buddy_list.h"
35 #include "buddy_status.h"
36 #include "buddy_opt.h" 35 #include "buddy_opt.h"
37 #include "char_conv.h" 36 #include "char_conv.h"
38 #include "crypt.h" 37 #include "crypt.h"
39 #include "header_info.h" 38 #include "header_info.h"
40 #include "keep_alive.h" 39 #include "qq_base.h"
41 #include "group.h" 40 #include "group.h"
42 #include "group_find.h" 41 #include "group_find.h"
43 #include "group_internal.h" 42 #include "group_internal.h"
44 #include "group_info.h" 43 #include "group_info.h"
45 44
46 #include "qq_network.h" 45 #include "qq_network.h"
47 46
48 #define QQ_GET_ONLINE_BUDDY_02 0x02 47 #define QQ_GET_ONLINE_BUDDY_02 0x02
49 #define QQ_GET_ONLINE_BUDDY_03 0x03 /* unknown function */ 48 #define QQ_GET_ONLINE_BUDDY_03 0x03 /* unknown function */
50 49
51 #define QQ_ONLINE_BUDDY_ENTRY_LEN 38 50 typedef struct _qq_buddy_online {
52 51 qq_buddy_status bs;
53 typedef struct _qq_friends_online_entry {
54 qq_buddy_status *s;
55 guint16 unknown1; 52 guint16 unknown1;
56 guint8 flag1; 53 guint8 ext_flag;
57 guint8 comm_flag; 54 guint8 comm_flag;
58 guint16 unknown2; 55 guint16 unknown2;
59 guint8 ending; /* 0x00 */ 56 guint8 ending; /* 0x00 */
60 } qq_friends_online_entry; 57 } qq_buddy_online;
61 58
62 /* get a list of online_buddies */ 59 /* get a list of online_buddies */
63 void qq_send_packet_get_buddies_online(PurpleConnection *gc, guint8 position) 60 void qq_send_packet_get_buddies_online(PurpleConnection *gc, guint8 position)
64 { 61 {
65 qq_data *qd; 62 qq_data *qd;
79 /* 002-002 */ 76 /* 002-002 */
80 bytes += qq_put8(raw_data + bytes, 0x00); 77 bytes += qq_put8(raw_data + bytes, 0x00);
81 /* 003-004 */ 78 /* 003-004 */
82 bytes += qq_put16(raw_data + bytes, 0x0000); 79 bytes += qq_put16(raw_data + bytes, 0x0000);
83 80
84 qq_send_cmd(qd, QQ_CMD_GET_FRIENDS_ONLINE, raw_data, 5); 81 qq_send_cmd(qd, QQ_CMD_GET_BUDDIES_ONLINE, raw_data, 5);
85 qd->last_get_online = time(NULL); 82 qd->last_get_online = time(NULL);
86 } 83 }
87 84
88 /* position starts with 0x0000, 85 /* position starts with 0x0000,
89 * server may return a position tag if list is too long for one packet */ 86 * server may return a position tag if list is too long for one packet */
100 * even can sending packets 00 and get no response. 97 * even can sending packets 00 and get no response.
101 * Now I tested that 00,00,00,00,00,01 work perfectly 98 * Now I tested that 00,00,00,00,00,01 work perfectly
102 * March 22, found the 00,00,00 starts to work as well */ 99 * March 22, found the 00,00,00 starts to work as well */
103 bytes += qq_put8(raw_data + bytes, 0x00); 100 bytes += qq_put8(raw_data + bytes, 0x00);
104 101
105 qq_send_cmd(qd, QQ_CMD_GET_FRIENDS_LIST, raw_data, bytes); 102 qq_send_cmd(qd, QQ_CMD_GET_BUDDIES_LIST, raw_data, bytes);
106 } 103 }
107 104
108 /* get all list, buddies & Quns with groupsid support */ 105 /* get all list, buddies & Quns with groupsid support */
109 void qq_send_packet_get_all_list_with_group(PurpleConnection *gc, guint32 position) 106 void qq_send_packet_get_all_list_with_group(PurpleConnection *gc, guint32 position)
110 { 107 {
121 bytes += qq_put32(raw_data + bytes, position); 118 bytes += qq_put32(raw_data + bytes, position);
122 119
123 qq_send_cmd(qd, QQ_CMD_GET_ALL_LIST_WITH_GROUP, raw_data, bytes); 120 qq_send_cmd(qd, QQ_CMD_GET_ALL_LIST_WITH_GROUP, raw_data, bytes);
124 } 121 }
125 122
126 static void _qq_buddies_online_reply_dump_unclear(qq_friends_online_entry *fe) 123 /* parse the data into qq_buddy_status */
127 { 124 static gint get_buddy_status(qq_buddy_status *bs, guint8 *data)
128 GString *dump; 125 {
129 126 gint bytes = 0;
130 g_return_if_fail(fe != NULL); 127
131 128 g_return_val_if_fail(data != NULL && bs != NULL, -1);
132 qq_buddy_status_dump_unclear(fe->s); 129
133 130 /* 000-003: uid */
134 dump = g_string_new(""); 131 bytes += qq_get32(&bs->uid, data + bytes);
135 g_string_append_printf(dump, "unclear fields for [%d]:\n", fe->s->uid); 132 /* 004-004: 0x01 */
136 g_string_append_printf(dump, "031-032: %04x (unknown)\n", fe->unknown1); 133 bytes += qq_get8(&bs->unknown1, data + bytes);
137 g_string_append_printf(dump, "033: %02x (flag1)\n", fe->flag1); 134 /* this is no longer the IP, it seems QQ (as of 2006) no longer sends
138 g_string_append_printf(dump, "034: %02x (comm_flag)\n", fe->comm_flag); 135 * the buddy's IP in this packet. all 0s */
139 g_string_append_printf(dump, "035-036: %04x (unknown)\n", fe->unknown2); 136 /* 005-008: ip */
140 137 bytes += qq_getIP(&bs->ip, data + bytes);
141 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Online buddy entry, %s", dump->str); 138 /* port info is no longer here either */
142 g_string_free(dump, TRUE); 139 /* 009-010: port */
143 } 140 bytes += qq_get16(&bs->port, data + bytes);
141 /* 011-011: 0x00 */
142 bytes += qq_get8(&bs->unknown2, data + bytes);
143 /* 012-012: status */
144 bytes += qq_get8(&bs->status, data + bytes);
145 /* 013-014: client_version */
146 bytes += qq_get16(&bs->unknown3, data + bytes);
147 /* 015-030: unknown key */
148 bytes += qq_getdata(&(bs->unknown_key[0]), QQ_KEY_LENGTH, data + bytes);
149
150 purple_debug(PURPLE_DEBUG_INFO, "QQ_STATUS",
151 "uid: %d, U1: %d, ip: %s:%d, U2:%d, status:%d, U3:%04X\n",
152 bs->uid, bs->unknown1, inet_ntoa(bs->ip), bs->port,
153 bs->unknown2, bs->status, bs->unknown3);
154
155 return bytes;
156 }
157
158 #define QQ_ONLINE_BUDDY_ENTRY_LEN 38
144 159
145 /* process the reply packet for get_buddies_online packet */ 160 /* process the reply packet for get_buddies_online packet */
146 void qq_process_get_buddies_online_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) 161 guint8 qq_process_get_buddies_online_reply(guint8 *buf, gint buf_len, PurpleConnection *gc)
147 { 162 {
148 qq_data *qd; 163 qq_data *qd;
149 gint len, bytes, bytes_buddy; 164 gint len, bytes, bytes_buddy;
150 gint count; 165 gint count;
151 guint8 *data, position; 166 guint8 *data, position;
152 PurpleBuddy *b; 167 PurpleBuddy *b;
153 qq_buddy *q_bud; 168 qq_buddy *q_bud;
154 qq_friends_online_entry *fe; 169 qq_buddy_online bo;
155 170
156 g_return_if_fail(buf != NULL && buf_len != 0); 171 g_return_val_if_fail(buf != NULL && buf_len != 0, -1);
157 172
158 qd = (qq_data *) gc->proto_data; 173 qd = (qq_data *) gc->proto_data;
159 len = buf_len; 174 len = buf_len;
160 data = g_newa(guint8, len); 175 data = g_newa(guint8, len);
161 176
162 purple_debug(PURPLE_DEBUG_INFO, "QQ", "processing get_buddies_online_reply\n"); 177 purple_debug(PURPLE_DEBUG_INFO, "QQ", "processing get_buddies_online_reply\n");
163 178
164 if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { 179 if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) {
165 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddies online"); 180 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddies online");
166 return; 181 return -1;
167 } 182 }
168 183
169 qq_show_packet("Get buddies online reply packet", data, len); 184 /* qq_show_packet("Get buddies online reply packet", data, len); */
170 185
171 bytes = 0; 186 bytes = 0;
172 bytes += qq_get8(&position, data + bytes); 187 bytes += qq_get8(&position, data + bytes);
173 188
174 fe = g_newa(qq_friends_online_entry, 1);
175 fe->s = g_newa(qq_buddy_status, 1);
176
177 count = 0; 189 count = 0;
178 while (bytes < len) { 190 while (bytes < len) {
191 if (len - bytes < QQ_ONLINE_BUDDY_ENTRY_LEN) {
192 purple_debug(PURPLE_DEBUG_ERROR, "QQ",
193 "[buddies online] only %d, need %d",
194 (len - bytes), QQ_ONLINE_BUDDY_ENTRY_LEN);
195 break;
196 }
197 memset(&bo, 0 ,sizeof(bo));
198
179 /* set flag */ 199 /* set flag */
180 bytes_buddy = bytes; 200 bytes_buddy = bytes;
181 /* based on one online buddy entry */ 201 /* based on one online buddy entry */
182 /* ATTTENTION! NEWED in the sub function, but FREED here */
183 /* 000-030 qq_buddy_status */ 202 /* 000-030 qq_buddy_status */
184 bytes += qq_buddy_status_read(fe->s, data + bytes); 203 bytes += get_buddy_status(&(bo.bs), data + bytes);
185 /* 031-032: unknown4 */ 204 /* 031-032: */
186 bytes += qq_get16(&fe->unknown1, data + bytes); 205 bytes += qq_get16(&bo.unknown1, data + bytes);
187 /* 033-033: flag1 */ 206 /* 033-033: ext_flag */
188 bytes += qq_get8(&fe->flag1, data + bytes); 207 bytes += qq_get8(&bo.ext_flag, data + bytes);
189 /* 034-034: comm_flag */ 208 /* 034-034: comm_flag */
190 bytes += qq_get8(&fe->comm_flag, data + bytes); 209 bytes += qq_get8(&bo.comm_flag, data + bytes);
191 /* 035-036: */ 210 /* 035-036: */
192 bytes += qq_get16(&fe->unknown2, data + bytes); 211 bytes += qq_get16(&bo.unknown2, data + bytes);
193 /* 037-037: */ 212 /* 037-037: */
194 bytes += qq_get8(&fe->ending, data + bytes); /* 0x00 */ 213 bytes += qq_get8(&bo.ending, data + bytes); /* 0x00 */
195 214
196 if (fe->s->uid == 0 || (bytes - bytes_buddy) != QQ_ONLINE_BUDDY_ENTRY_LEN) { 215 if (bo.bs.uid == 0 || (bytes - bytes_buddy) != QQ_ONLINE_BUDDY_ENTRY_LEN) {
197 purple_debug(PURPLE_DEBUG_ERROR, "QQ", 216 purple_debug(PURPLE_DEBUG_ERROR, "QQ",
198 "uid=0 or entry complete len(%d) != %d", 217 "uid=0 or entry complete len(%d) != %d",
199 (bytes - bytes_buddy), QQ_ONLINE_BUDDY_ENTRY_LEN); 218 (bytes - bytes_buddy), QQ_ONLINE_BUDDY_ENTRY_LEN);
200 g_free(fe->s->ip);
201 g_free(fe->s->unknown_key);
202 continue; 219 continue;
203 } /* check if it is a valid entry */ 220 } /* check if it is a valid entry */
204 221
205 if (QQ_DEBUG) { 222 /* update buddy information */
206 _qq_buddies_online_reply_dump_unclear(fe); 223 b = purple_find_buddy(purple_connection_get_account(gc),
224 uid_to_purple_name(bo.bs.uid) );
225 q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data;
226 if (q_bud == NULL) {
227 purple_debug(PURPLE_DEBUG_ERROR, "QQ",
228 "Got an online buddy %d, but not in my buddy list\n", bo.bs.uid);
229 continue;
207 } 230 }
208 231 /* we find one and update qq_buddy */
209 /* update buddy information */ 232 /*
210 b = purple_find_buddy(purple_connection_get_account(gc), uid_to_purple_name(fe->s->uid)); 233 if(0 != fe->s->client_version)
211 q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; 234 q_bud->client_version = fe->s->client_version;
212 235 */
213 if (q_bud != NULL) { /* we find one and update qq_buddy */ 236 q_bud->ip.s_addr = bo.bs.ip.s_addr;
214 if(0 != fe->s->client_version) 237 q_bud->port = bo.bs.port;
215 q_bud->client_version = fe->s->client_version; 238 q_bud->status = bo.bs.status;
216 g_memmove(q_bud->ip, fe->s->ip, 4); 239 q_bud->ext_flag = bo.ext_flag;
217 q_bud->port = fe->s->port; 240 q_bud->comm_flag = bo.comm_flag;
218 q_bud->status = fe->s->status; 241 qq_update_buddy_contact(gc, q_bud);
219 q_bud->flag1 = fe->flag1; 242 count++;
220 q_bud->comm_flag = fe->comm_flag;
221 qq_update_buddy_contact(gc, q_bud);
222 count++;
223 } else {
224 purple_debug(PURPLE_DEBUG_ERROR, "QQ",
225 "Got an online buddy %d, but not in my buddy list\n", fe->s->uid);
226 }
227
228 g_free(fe->s->ip);
229 g_free(fe->s->unknown_key);
230 } 243 }
231 244
232 if(bytes > len) { 245 if(bytes > len) {
233 purple_debug(PURPLE_DEBUG_ERROR, "QQ", 246 purple_debug(PURPLE_DEBUG_ERROR, "QQ",
234 "qq_process_get_buddies_online_reply: Dangerous error! maybe protocol changed, notify developers!\n"); 247 "qq_process_get_buddies_online_reply: Dangerous error! maybe protocol changed, notify developers!\n");
235 } 248 }
236 249
237 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d online buddies, nextposition=%u\n", 250 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d online buddies, nextposition=%u\n",
238 count, (guint) position); 251 count, (guint) position);
239 if (position != QQ_FRIENDS_ONLINE_POSITION_END 252 return position;
240 && position != QQ_FRIENDS_ONLINE_POSITION_START) {
241 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Requesting for more online buddies\n");
242 qq_send_packet_get_buddies_online(gc, position);
243 } else {
244 purple_debug(PURPLE_DEBUG_INFO, "QQ", "All online buddies received\n");
245 qq_send_packet_get_buddies_levels(gc);
246 qq_refresh_all_buddy_status(gc);
247 }
248 } 253 }
249 254
250 255
251 /* process reply for get_buddies_list */ 256 /* process reply for get_buddies_list */
252 void qq_process_get_buddies_list_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) 257 guint16 qq_process_get_buddies_list_reply(guint8 *buf, gint buf_len, PurpleConnection *gc)
253 { 258 {
254 qq_data *qd; 259 qq_data *qd;
255 qq_buddy *q_bud; 260 qq_buddy *q_bud;
256 gint len, bytes_expected, count; 261 gint len, bytes_expected, count;
257 gint bytes, buddy_bytes; 262 gint bytes, buddy_bytes;
258 guint16 position, unknown; 263 guint16 position, unknown;
259 guint8 *data, pascal_len; 264 guint8 *data, pascal_len;
260 gchar *name; 265 gchar *name;
261 PurpleBuddy *b; 266 PurpleBuddy *b;
262 267
263 g_return_if_fail(buf != NULL && buf_len != 0); 268 g_return_val_if_fail(buf != NULL && buf_len != 0, -1);
264 269
265 qd = (qq_data *) gc->proto_data; 270 qd = (qq_data *) gc->proto_data;
266 len = buf_len; 271 len = buf_len;
267 data = g_newa(guint8, len); 272 data = g_newa(guint8, len);
268 273
269 if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { 274 if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) {
270 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddies list"); 275 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddies list");
271 return; 276 return -1;
272 } 277 }
273 bytes = 0; 278 bytes = 0;
274 bytes += qq_get16(&position, data + bytes); 279 bytes += qq_get16(&position, data + bytes);
275 /* the following data is buddy list in this packet */ 280 /* the following data is buddy list in this packet */
276 count = 0; 281 count = 0;
289 294
290 pascal_len = convert_as_pascal_string(data + bytes, &q_bud->nickname, QQ_CHARSET_DEFAULT); 295 pascal_len = convert_as_pascal_string(data + bytes, &q_bud->nickname, QQ_CHARSET_DEFAULT);
291 bytes += pascal_len; 296 bytes += pascal_len;
292 297
293 bytes += qq_get16(&unknown, data + bytes); 298 bytes += qq_get16(&unknown, data + bytes);
294 /* flag1: (0-7) 299 bytes += qq_get8(&q_bud->ext_flag, data + bytes);
295 * bit1 => qq show
296 * comm_flag: (0-7)
297 * bit1 => member
298 * bit4 => TCP mode
299 * bit5 => open mobile QQ
300 * bit6 => bind to mobile
301 * bit7 => whether having a video
302 */
303 bytes += qq_get8(&q_bud->flag1, data + bytes);
304 bytes += qq_get8(&q_bud->comm_flag, data + bytes); 300 bytes += qq_get8(&q_bud->comm_flag, data + bytes);
305 301
306 bytes_expected = 12 + pascal_len; 302 bytes_expected = 12 + pascal_len;
307 303
308 if (q_bud->uid == 0 || (bytes - buddy_bytes) != bytes_expected) { 304 if (q_bud->uid == 0 || (bytes - buddy_bytes) != bytes_expected) {
315 count++; 311 count++;
316 } 312 }
317 313
318 if (QQ_DEBUG) { 314 if (QQ_DEBUG) {
319 purple_debug(PURPLE_DEBUG_INFO, "QQ", 315 purple_debug(PURPLE_DEBUG_INFO, "QQ",
320 "buddy [%09d]: flag1=0x%02x, comm_flag=0x%02x, nick=%s\n", 316 "buddy [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n",
321 q_bud->uid, q_bud->flag1, q_bud->comm_flag, q_bud->nickname); 317 q_bud->uid, q_bud->ext_flag, q_bud->comm_flag, q_bud->nickname);
322 } 318 }
323 319
324 name = uid_to_purple_name(q_bud->uid); 320 name = uid_to_purple_name(q_bud->uid);
325 b = purple_find_buddy(gc->account, name); 321 b = purple_find_buddy(gc->account, name);
326 g_free(name); 322 g_free(name);
339 "qq_process_get_buddies_list_reply: Dangerous error! maybe protocol changed, notify developers!"); 335 "qq_process_get_buddies_list_reply: Dangerous error! maybe protocol changed, notify developers!");
340 } 336 }
341 337
342 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d buddies, nextposition=%u\n", 338 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d buddies, nextposition=%u\n",
343 count, (guint) position); 339 count, (guint) position);
344 if (position != QQ_FRIENDS_LIST_POSITION_START 340 return position;
345 && position != QQ_FRIENDS_LIST_POSITION_END) { 341 }
346 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Requesting for more buddies\n"); 342
347 qq_send_packet_get_buddies_list(gc, position); 343 guint32 qq_process_get_all_list_with_group_reply(guint8 *buf, gint buf_len, PurpleConnection *gc)
348 } else {
349 purple_debug(PURPLE_DEBUG_INFO, "QQ", "All buddies received. Requesting for online buddies list\n");
350 qq_send_packet_get_buddies_online(gc, QQ_FRIENDS_LIST_POSITION_START);
351 }
352 }
353
354 void qq_process_get_all_list_with_group_reply(guint8 *buf, gint buf_len, PurpleConnection *gc)
355 { 344 {
356 qq_data *qd; 345 qq_data *qd;
357 gint len, i, j; 346 gint len, i, j;
358 gint bytes = 0; 347 gint bytes = 0;
359 guint8 *data; 348 guint8 *data;
361 guint32 unknown, position; 350 guint32 unknown, position;
362 guint32 uid; 351 guint32 uid;
363 guint8 type, groupid; 352 guint8 type, groupid;
364 qq_group *group; 353 qq_group *group;
365 354
366 g_return_if_fail(buf != NULL && buf_len != 0); 355 g_return_val_if_fail(buf != NULL && buf_len != 0, -1);
367 356
368 qd = (qq_data *) gc->proto_data; 357 qd = (qq_data *) gc->proto_data;
369 len = buf_len; 358 len = buf_len;
370 data = g_newa(guint8, len); 359 data = g_newa(guint8, len);
371 360
372 if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { 361 if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) {
373 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt all list with group"); 362 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt all list with group");
374 return; 363 return -1;
375 } 364 }
376 365
377 bytes += qq_get8(&sub_cmd, data + bytes); 366 bytes += qq_get8(&sub_cmd, data + bytes);
378 g_return_if_fail(sub_cmd == 0x01); 367 g_return_val_if_fail(sub_cmd == 0x01, -1);
379 368
380 bytes += qq_get8(&reply_code, data + bytes); 369 bytes += qq_get8(&reply_code, data + bytes);
381 if(0 != reply_code) { 370 if(0 != reply_code) {
382 purple_debug(PURPLE_DEBUG_WARNING, "QQ", 371 purple_debug(PURPLE_DEBUG_WARNING, "QQ",
383 "Get all list with group reply, reply_code(%d) is not zero", reply_code); 372 "Get all list with group reply, reply_code(%d) is not zero", reply_code);
427 if(bytes > len) { 416 if(bytes > len) {
428 purple_debug(PURPLE_DEBUG_ERROR, "QQ", 417 purple_debug(PURPLE_DEBUG_ERROR, "QQ",
429 "qq_process_get_all_list_with_group_reply: Dangerous error! maybe protocol changed, notify developers!"); 418 "qq_process_get_all_list_with_group_reply: Dangerous error! maybe protocol changed, notify developers!");
430 } 419 }
431 420
432 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Get all list done, %d buddies and %d Quns\n", i, j);
433 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d buddies and %d groups, nextposition=%u\n", i, j, (guint) position); 421 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d buddies and %d groups, nextposition=%u\n", i, j, (guint) position);
434 422 return position;
435 if (position != QQ_FRIENDS_ALL_LIST_POSITION_START 423 }
436 && position != QQ_FRIENDS_ALL_LIST_POSITION_END) { 424
437 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Requesting for more buddies and groups\n"); 425 #define QQ_MISC_STATUS_HAVING_VIIDEO 0x00000001
438 qq_send_packet_get_all_list_with_group(gc, position); 426 #define QQ_CHANGE_ONLINE_STATUS_REPLY_OK 0x30 /* ASCII value of "0" */
427
428 /* TODO: figure out what's going on with the IP region. Sometimes I get valid IP addresses,
429 * but the port number's weird, other times I get 0s. I get these simultaneously on the same buddy,
430 * using different accounts to get info. */
431
432 /* check if status means online or offline */
433 gboolean is_online(guint8 status)
434 {
435 switch(status) {
436 case QQ_BUDDY_ONLINE_NORMAL:
437 case QQ_BUDDY_ONLINE_AWAY:
438 case QQ_BUDDY_ONLINE_INVISIBLE:
439 return TRUE;
440 case QQ_BUDDY_ONLINE_OFFLINE:
441 return FALSE;
442 }
443 return FALSE;
444 }
445
446 /* Help calculate the correct icon index to tell the server. */
447 gint get_icon_offset(PurpleConnection *gc)
448 {
449 PurpleAccount *account;
450 PurplePresence *presence;
451
452 account = purple_connection_get_account(gc);
453 presence = purple_account_get_presence(account);
454
455 if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) {
456 return 2;
457 } else if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_AWAY)
458 || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_EXTENDED_AWAY)
459 || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE)) {
460 return 1;
439 } else { 461 } else {
440 purple_debug(PURPLE_DEBUG_INFO, "QQ", "All buddies and groups received\n"); 462 return 0;
441 } 463 }
442 } 464 }
465
466 /* send a packet to change my online status */
467 void qq_send_packet_change_status(PurpleConnection *gc)
468 {
469 qq_data *qd;
470 guint8 raw_data[16] = {0};
471 gint bytes = 0;
472 guint8 away_cmd;
473 guint32 misc_status;
474 gboolean fake_video;
475 PurpleAccount *account;
476 PurplePresence *presence;
477
478 account = purple_connection_get_account(gc);
479 presence = purple_account_get_presence(account);
480
481 qd = (qq_data *) gc->proto_data;
482 if (!qd->logged_in)
483 return;
484
485 if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) {
486 away_cmd = QQ_BUDDY_ONLINE_INVISIBLE;
487 } else if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_AWAY)
488 || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_EXTENDED_AWAY)
489 || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE)) {
490 away_cmd = QQ_BUDDY_ONLINE_AWAY;
491 } else {
492 away_cmd = QQ_BUDDY_ONLINE_NORMAL;
493 }
494
495 misc_status = 0x00000000;
496 fake_video = purple_prefs_get_bool("/plugins/prpl/qq/show_fake_video");
497 if (fake_video)
498 misc_status |= QQ_MISC_STATUS_HAVING_VIIDEO;
499
500 bytes = 0;
501 bytes += qq_put8(raw_data + bytes, away_cmd);
502 bytes += qq_put32(raw_data + bytes, misc_status);
503
504 qq_send_cmd(qd, QQ_CMD_CHANGE_ONLINE_STATUS, raw_data, bytes);
505 }
506
507 /* parse the reply packet for change_status */
508 void qq_process_change_status_reply(guint8 *buf, gint buf_len, PurpleConnection *gc)
509 {
510 qq_data *qd;
511 gint len, bytes;
512 guint8 *data, reply;
513 PurpleBuddy *b;
514 qq_buddy *q_bud;
515 gchar *name;
516
517 g_return_if_fail(buf != NULL && buf_len != 0);
518
519 qd = (qq_data *) gc->proto_data;
520 len = buf_len;
521 data = g_newa(guint8, len);
522
523 if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &len) ) {
524 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt chg status reply\n");
525 return;
526 }
527
528 bytes = 0;
529 bytes = qq_get8(&reply, data + bytes);
530 if (reply != QQ_CHANGE_ONLINE_STATUS_REPLY_OK) {
531 purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Change status fail 0x%02X\n", reply);
532 return;
533 }
534
535 /* purple_debug(PURPLE_DEBUG_INFO, "QQ", "Change status OK\n"); */
536 name = uid_to_purple_name(qd->uid);
537 b = purple_find_buddy(gc->account, name);
538 g_free(name);
539 q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data;
540 if (q_bud != NULL) {
541 qq_update_buddy_contact(gc, q_bud);
542 }
543 }
544
545 /* it is a server message indicating that one of my buddies has changed its status */
546 void qq_process_buddy_change_status(guint8 *buf, gint buf_len, PurpleConnection *gc)
547 {
548 qq_data *qd;
549 gint bytes;
550 guint32 my_uid;
551 guint8 *data;
552 gint data_len;
553 PurpleBuddy *b;
554 qq_buddy *q_bud;
555 qq_buddy_status bs;
556 gchar *name;
557
558 g_return_if_fail(buf != NULL && buf_len != 0);
559
560 qd = (qq_data *) gc->proto_data;
561 data_len = buf_len;
562 data = g_newa(guint8, data_len);
563
564 if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &data_len) ) {
565 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[buddy status change] Failed decrypt\n");
566 return;
567 }
568
569 if (data_len < 35) {
570 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[buddy status change] only %d, need 35 bytes\n", data_len);
571 return;
572 }
573
574 memset(&bs, 0, sizeof(bs));
575 bytes = 0;
576 /* 000-030: qq_buddy_status */
577 bytes += get_buddy_status(&bs, data + bytes);
578 /* 031-034: Unknow, maybe my uid */
579 /* This has a value of 0 when we've changed our status to
580 * QQ_BUDDY_ONLINE_INVISIBLE */
581 bytes += qq_get32(&my_uid, data + bytes);
582
583 name = uid_to_purple_name(bs.uid);
584 b = purple_find_buddy(gc->account, name);
585 g_free(name);
586 q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data;
587 if (q_bud == NULL) {
588 purple_debug(PURPLE_DEBUG_ERROR, "QQ",
589 "got information of unknown buddy %d\n", bs.uid);
590 return;
591 }
592
593 purple_debug(PURPLE_DEBUG_INFO, "QQ", "status:.uid = %d, q_bud->uid = %d\n", bs.uid , q_bud->uid);
594 if(bs.ip.s_addr != 0) {
595 q_bud->ip.s_addr = bs.ip.s_addr;
596 q_bud->port = bs.port;
597 }
598 q_bud->status =bs.status;
599
600 if (q_bud->status == QQ_BUDDY_ONLINE_NORMAL) {
601 qq_send_packet_get_level(gc, q_bud->uid);
602 }
603 qq_update_buddy_contact(gc, q_bud);
604 }
605
606 /*TODO: maybe this should be qq_update_buddy_status() ?*/
607 void qq_update_buddy_contact(PurpleConnection *gc, qq_buddy *q_bud)
608 {
609 gchar *name;
610 PurpleBuddy *bud;
611 gchar *status_id;
612
613 g_return_if_fail(q_bud != NULL);
614
615 name = uid_to_purple_name(q_bud->uid);
616 bud = purple_find_buddy(gc->account, name);
617
618 if (bud == NULL) {
619 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "unknown buddy: %d\n", q_bud->uid);
620 g_free(name);
621 return;
622 }
623
624 purple_blist_server_alias_buddy(bud, q_bud->nickname); /* server */
625 q_bud->last_refresh = time(NULL);
626
627 /* purple supports signon and idle time
628 * but it is not much use for QQ, I do not use them */
629 /* serv_got_update(gc, name, online, 0, q_bud->signon, q_bud->idle, bud->uc); */
630 status_id = "available";
631 switch(q_bud->status) {
632 case QQ_BUDDY_OFFLINE:
633 status_id = "offline";
634 break;
635 case QQ_BUDDY_ONLINE_NORMAL:
636 status_id = "available";
637 break;
638 case QQ_BUDDY_ONLINE_OFFLINE:
639 status_id = "offline";
640 break;
641 case QQ_BUDDY_ONLINE_AWAY:
642 status_id = "away";
643 break;
644 case QQ_BUDDY_ONLINE_INVISIBLE:
645 status_id = "invisible";
646 break;
647 default:
648 status_id = "invisible";
649 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "unknown status: %x\n", q_bud->status);
650 break;
651 }
652 purple_debug(PURPLE_DEBUG_INFO, "QQ", "buddy %d %s\n", q_bud->uid, status_id);
653 purple_prpl_got_user_status(gc->account, name, status_id, NULL);
654
655 if (q_bud->comm_flag & QQ_COMM_FLAG_MOBILE && q_bud->status != QQ_BUDDY_OFFLINE)
656 purple_prpl_got_user_status(gc->account, name, "mobile", NULL);
657 else
658 purple_prpl_got_user_status_deactive(gc->account, name, "mobile");
659
660 if (q_bud->comm_flag & QQ_COMM_FLAG_VIDEO && q_bud->status != QQ_BUDDY_OFFLINE)
661 purple_prpl_got_user_status(gc->account, name, "video", NULL);
662 else
663 purple_prpl_got_user_status_deactive(gc->account, name, "video");
664
665 g_free(name);
666 }
667
668 /* refresh all buddies online/offline,
669 * after receiving reply for get_buddies_online packet */
670 void qq_refresh_all_buddy_status(PurpleConnection *gc)
671 {
672 time_t now;
673 GList *list;
674 qq_data *qd;
675 qq_buddy *q_bud;
676
677 qd = (qq_data *) (gc->proto_data);
678 now = time(NULL);
679 list = qd->buddies;
680
681 while (list != NULL) {
682 q_bud = (qq_buddy *) list->data;
683 if (q_bud != NULL && now > q_bud->last_refresh + QQ_UPDATE_ONLINE_INTERVAL
684 && q_bud->status != QQ_BUDDY_ONLINE_INVISIBLE) {
685 q_bud->status = QQ_BUDDY_ONLINE_OFFLINE;
686 qq_update_buddy_contact(gc, q_bud);
687 }
688 list = list->next;
689 }
690 }

mercurial