comparison libpurple/protocols/qq/buddy_opt.c @ 24093:f4f29fac96c6

2008.10.20 - ccpaging <ccpaging(at)gmail.com> * Support incoming authorization of 'buddy_adding' protocol of QQ2007/2008
author SHiNE CsyFeK <csyfek@gmail.com>
date Tue, 28 Oct 2008 16:45:10 +0000
parents 7c0a56c5fea0
children 7f5433ffbf8d
comparison
equal deleted inserted replaced
24092:7c0a56c5fea0 24093:f4f29fac96c6
48 QQ_MY_AUTH_REJECT = 0x31, /* ASCII value of "1" */ 48 QQ_MY_AUTH_REJECT = 0x31, /* ASCII value of "1" */
49 QQ_MY_AUTH_REQUEST = 0x32, /* ASCII value of "2" */ 49 QQ_MY_AUTH_REQUEST = 0x32, /* ASCII value of "2" */
50 }; 50 };
51 51
52 typedef struct _qq_buddy_req { 52 typedef struct _qq_buddy_req {
53 PurpleConnection *gc;
53 guint32 uid; 54 guint32 uid;
54 PurpleConnection *gc; 55 guint8 *auth;
56 guint8 auth_len;
55 } qq_buddy_req; 57 } qq_buddy_req;
58
59 void buddy_add_authorize_input(PurpleConnection *gc, guint32 uid,
60 guint8 *auth, guint8 auth_len);
61
62 static void buddy_add_req_free(qq_buddy_req *add_req)
63 {
64 g_return_if_fail(add_req != NULL);
65 if (add_req->auth) g_free(add_req->auth);
66 g_free(add_req);
67 }
56 68
57 PurpleGroup *qq_group_find_or_new(const gchar *group_name) 69 PurpleGroup *qq_group_find_or_new(const gchar *group_name)
58 { 70 {
59 PurpleGroup *g; 71 PurpleGroup *g;
60 72
268 } 280 }
269 281
270 if (cmd == QQ_AUTH_INFO_BUDDY && sub_cmd == QQ_AUTH_INFO_REMOVE_BUDDY) { 282 if (cmd == QQ_AUTH_INFO_BUDDY && sub_cmd == QQ_AUTH_INFO_REMOVE_BUDDY) {
271 g_return_if_fail(auth != NULL && auth_len > 0); 283 g_return_if_fail(auth != NULL && auth_len > 0);
272 request_buddy_remove_2007(gc, uid, auth, auth_len); 284 request_buddy_remove_2007(gc, uid, auth, auth_len);
285 return;
273 } 286 }
274 if (cmd == QQ_AUTH_INFO_BUDDY && sub_cmd == QQ_AUTH_INFO_ADD_BUDDY) { 287 if (cmd == QQ_AUTH_INFO_BUDDY && sub_cmd == QQ_AUTH_INFO_ADD_BUDDY) {
288 buddy_add_authorize_input(gc, uid, auth, auth_len);
289 return;
275 } 290 }
276 purple_debug_info("QQ", "Got auth info cmd 0x%x, sub 0x%x, reply 0x%x\n", 291 purple_debug_info("QQ", "Got auth info cmd 0x%x, sub 0x%x, reply 0x%x\n",
277 cmd, sub_cmd, reply); 292 cmd, sub_cmd, reply);
278 } 293 }
279 294
298 g_return_if_fail(uid > 0); 313 g_return_if_fail(uid > 0);
299 314
300 /* we need to send the ascii code of this uid to qq server */ 315 /* we need to send the ascii code of this uid to qq server */
301 g_snprintf(uid_str, sizeof(uid_str), "%d", uid); 316 g_snprintf(uid_str, sizeof(uid_str), "%d", uid);
302 qq_send_cmd_mess(gc, QQ_CMD_BUDDY_ADD_NO_AUTH, 317 qq_send_cmd_mess(gc, QQ_CMD_BUDDY_ADD_NO_AUTH,
318 (guint8 *) uid_str, strlen(uid_str), 0, uid);
319 }
320
321 static void request_buddy_add_no_auth_ex(PurpleConnection *gc, guint32 uid)
322 {
323 gchar uid_str[11];
324
325 g_return_if_fail(uid > 0);
326
327 /* we need to send the ascii code of this uid to qq server */
328 g_snprintf(uid_str, sizeof(uid_str), "%d", uid);
329 qq_send_cmd_mess(gc, QQ_CMD_BUDDY_ADD_NO_AUTH_EX,
303 (guint8 *) uid_str, strlen(uid_str), 0, uid); 330 (guint8 *) uid_str, strlen(uid_str), 0, uid);
304 } 331 }
305 332
306 /* this buddy needs authentication, text conversion is done at lowest level */ 333 /* this buddy needs authentication, text conversion is done at lowest level */
307 static void request_buddy_auth(PurpleConnection *gc, guint32 uid, const gchar response, const gchar *text) 334 static void request_buddy_auth(PurpleConnection *gc, guint32 uid, const gchar response, const gchar *text)
328 } 355 }
329 356
330 qq_send_cmd(gc, QQ_CMD_BUDDY_ADD_AUTH, raw_data, bytes); 357 qq_send_cmd(gc, QQ_CMD_BUDDY_ADD_AUTH, raw_data, bytes);
331 } 358 }
332 359
360 static void request_buddy_auth_2007(PurpleConnection *gc, guint32 uid,
361 const gchar *text, guint8 *auth, guint8 auth_len)
362 {
363 guint8 *raw_data;
364 gint bytes = 0;
365 gchar *msg;
366
367 g_return_if_fail(uid != 0);
368
369 raw_data = g_newa(guint8, QQ_MSG_IM_MAX);
370 bytes = 0;
371 bytes += qq_put8(raw_data + bytes, 0x02);
372 bytes += qq_put32(raw_data + bytes, uid);
373 bytes += qq_put16(raw_data + bytes, 0);
374
375 bytes += qq_put8(raw_data + bytes, 0);
376 if (auth == NULL || auth_len <= 0) {
377 bytes += qq_put8(raw_data + bytes, 0);
378 } else {
379 bytes += qq_put8(raw_data + bytes, auth_len);
380 bytes += qq_putdata(raw_data + bytes, auth, auth_len);
381 }
382 bytes += qq_put8(raw_data + bytes, 1); /* ALLOW ADD ME FLAG */
383 bytes += qq_put8(raw_data + bytes, 0); /* Destination group */
384 if (text == NULL) {
385 bytes += qq_put8(raw_data + bytes, 0);
386 } else {
387 msg = utf8_to_qq(text, QQ_CHARSET_DEFAULT);
388 bytes += qq_put8(raw_data + bytes, strlen(msg));
389 bytes += qq_putdata(raw_data + bytes, (guint8 *)msg, strlen(msg));
390 g_free(msg);
391 }
392 qq_send_cmd(gc, QQ_CMD_BUDDY_ADD_AUTH_EX, raw_data, bytes);
393 }
394
333 static void request_buddy_add_auth_cb(qq_buddy_req *add_req, const gchar *text) 395 static void request_buddy_add_auth_cb(qq_buddy_req *add_req, const gchar *text)
334 { 396 {
397 qq_data *qd;
335 g_return_if_fail(add_req != NULL); 398 g_return_if_fail(add_req != NULL);
336 if (add_req->gc == NULL || add_req->uid == 0) { 399 if (add_req->gc == NULL || add_req->uid == 0) {
337 g_free(add_req); 400 buddy_add_req_free(add_req);
338 return; 401 return;
339 } 402 }
340 403
341 request_buddy_auth(add_req->gc, add_req->uid, QQ_MY_AUTH_REQUEST, text); 404 qd = (qq_data *)add_req->gc->proto_data;
342 g_free(add_req); 405 if (qd->client_version > 2005) {
406 request_buddy_auth_2007(add_req->gc, add_req->uid,
407 text, add_req->auth, add_req->auth_len);
408 } else {
409 request_buddy_auth(add_req->gc, add_req->uid, QQ_MY_AUTH_REQUEST, text);
410 }
411 buddy_add_req_free(add_req);
343 } 412 }
344 413
345 /* the real packet to reject and request is sent from here */ 414 /* the real packet to reject and request is sent from here */
346 static void buddy_add_deny_reason_cb(qq_buddy_req *add_req, const gchar *reason) 415 static void buddy_add_deny_reason_cb(qq_buddy_req *add_req, const gchar *reason)
347 { 416 {
348 g_return_if_fail(add_req != NULL); 417 g_return_if_fail(add_req != NULL);
349 if (add_req->gc == NULL || add_req->uid == 0) { 418 if (add_req->gc == NULL || add_req->uid == 0) {
350 g_free(add_req); 419 buddy_add_req_free(add_req);
351 return; 420 return;
352 } 421 }
353 422
354 request_buddy_auth(add_req->gc, add_req->uid, QQ_MY_AUTH_REJECT, reason); 423 request_buddy_auth(add_req->gc, add_req->uid, QQ_MY_AUTH_REJECT, reason);
355 g_free(add_req); 424 buddy_add_req_free(add_req);
356 } 425 }
357 426
358 static void buddy_add_deny_noreason_cb(qq_buddy_req *add_req) 427 static void buddy_add_deny_noreason_cb(qq_buddy_req *add_req)
359 { 428 {
360 buddy_add_deny_reason_cb(add_req, NULL); 429 buddy_add_deny_reason_cb(add_req, NULL);
365 { 434 {
366 qq_buddy_req *add_req = (qq_buddy_req *)data; 435 qq_buddy_req *add_req = (qq_buddy_req *)data;
367 436
368 g_return_if_fail(add_req != NULL); 437 g_return_if_fail(add_req != NULL);
369 if (add_req->gc == NULL || add_req->uid == 0) { 438 if (add_req->gc == NULL || add_req->uid == 0) {
370 g_free(add_req); 439 buddy_add_req_free(add_req);
371 return; 440 return;
372 } 441 }
373 442
374 request_buddy_auth(add_req->gc, add_req->uid, QQ_MY_AUTH_APPROVE, NULL); 443 request_buddy_auth(add_req->gc, add_req->uid, QQ_MY_AUTH_APPROVE, NULL);
375 g_free(add_req); 444 buddy_add_req_free(add_req);
376 } 445 }
377 446
378 /* we reject other's request of adding me as friend */ 447 /* we reject other's request of adding me as friend */
379 static void buddy_add_deny_cb(gpointer data) 448 static void buddy_add_deny_cb(gpointer data)
380 { 449 {
387 purple_connection_get_account(add_req->gc), who, NULL, 456 purple_connection_get_account(add_req->gc), who, NULL,
388 add_req); 457 add_req);
389 g_free(who); 458 g_free(who);
390 } 459 }
391 460
392 /* add a buddy and send packet to QQ server 461 static void buddy_cancel_cb(qq_buddy_req *add_req, const gchar *msg)
393 * note that when purple load local cached buddy list into its blist 462 {
394 * it also calls this funtion, so we have to 463 g_return_if_fail(add_req != NULL);
395 * define qd->is_login=TRUE AFTER LOGIN */ 464 buddy_add_req_free(add_req);
396 void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) 465 }
466
467 static void buddy_add_no_auth_cb(qq_buddy_req *add_req)
397 { 468 {
398 qq_data *qd; 469 qq_data *qd;
399 guint32 uid;
400
401 g_return_if_fail(NULL != gc && NULL != gc->proto_data);
402 g_return_if_fail(buddy != NULL);
403
404 qd = (qq_data *) gc->proto_data;
405 if (!qd->is_login)
406 return; /* IMPORTANT ! */
407
408 uid = purple_name_to_uid(buddy->name);
409 if (uid > 0) {
410 request_buddy_add_no_auth(gc, uid);
411 return;
412 }
413
414 purple_notify_error(gc, _("QQ Buddy"), _("Add buddy"), _("Invalid QQ Number"));
415 if (buddy == NULL) {
416 return;
417 }
418
419 purple_debug_info("QQ", "Remove buddy with invalid QQ number %d\n", uid);
420 qq_buddy_free(buddy);
421 }
422
423 static void buddy_cancel_cb(qq_buddy_req *add_req, const gchar *msg)
424 {
425 g_return_if_fail(add_req != NULL);
426 g_free(add_req);
427 }
428
429 static void buddy_add_no_auth_cb(qq_buddy_req *add_req)
430 {
431 g_return_if_fail(add_req != NULL); 470 g_return_if_fail(add_req != NULL);
432 if (add_req->gc == NULL || add_req->uid == 0) { 471 if (add_req->gc == NULL || add_req->uid == 0) {
433 g_free(add_req); 472 buddy_add_req_free(add_req);
434 return; 473 return;
435 } 474 }
436 475
437 request_buddy_add_no_auth(add_req->gc, add_req->uid); 476 qd = (qq_data *) add_req->gc->proto_data;
438 g_free(add_req); 477 if (qd->client_version > 2005) {
439 } 478 request_buddy_add_no_auth_ex(add_req->gc, add_req->uid);
440 479 } else {
441 /* process reply to add_buddy_auth request */ 480 request_buddy_add_no_auth(add_req->gc, add_req->uid);
442 void qq_process_buddy_add_auth(guint8 *data, gint data_len, PurpleConnection *gc) 481 }
443 { 482 buddy_add_req_free(add_req);
444 qq_data *qd; 483 }
445 gchar **segments, *msg_utf8; 484
446 485 void buddy_add_authorize_input(PurpleConnection *gc, guint32 uid,
447 g_return_if_fail(data != NULL && data_len != 0); 486 guint8 *auth, guint8 auth_len)
448 487 {
449 qd = (qq_data *) gc->proto_data; 488 gchar *who, *msg;
450
451 if (data[0] == '0') {
452 purple_debug_info("QQ", "Reply OK for sending authorize\n");
453 return;
454 }
455
456 if (NULL == (segments = split_data(data, data_len, "\x1f", 2))) {
457 purple_notify_error(gc, _("QQ Buddy"), _("Failed sending authorize"), NULL);
458 return;
459 }
460 msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT);
461 purple_notify_error(gc, _("QQ Buddy"), _("Failed sending authorize"), msg_utf8);
462 g_free(msg_utf8);
463 }
464
465 /* process the server reply for my request to remove a buddy */
466 void qq_process_buddy_remove(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid)
467 {
468 PurpleBuddy *buddy = NULL;
469 gchar *msg;
470
471 g_return_if_fail(data != NULL && data_len != 0);
472 g_return_if_fail(uid != 0);
473
474 buddy = qq_buddy_find(gc, uid);
475 if (data[0] != 0) {
476 msg = g_strdup_printf(_("Failed removing buddy %d"), uid);
477 purple_notify_info(gc, _("QQ Buddy"), msg, NULL);
478 g_free(msg);
479 }
480
481 purple_debug_info("QQ", "Reply OK for removing buddy\n");
482 /* remove buddy again */
483 if (buddy != NULL) {
484 qq_buddy_free(buddy);
485 }
486 }
487
488 /* process the server reply for my request to remove myself from a buddy */
489 void qq_process_buddy_remove_me(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid)
490 {
491 qq_data *qd;
492 gchar *msg;
493
494 g_return_if_fail(data != NULL && data_len != 0);
495 qd = (qq_data *) gc->proto_data;
496
497 if (data[0] == 0) {
498 purple_debug_info("QQ", "Reply OK for removing me from %d's buddy list\n", uid);
499 return;
500 }
501 msg = g_strdup_printf(_("Failed removing me from %d's buddy list"), uid);
502 purple_notify_info(gc, _("QQ Buddy"), msg, NULL);
503 g_free(msg);
504 }
505
506 void qq_process_buddy_add_no_auth(guint8 *data, gint data_len, guint32 uid, PurpleConnection *gc)
507 {
508 qq_data *qd;
509 gchar *msg, **segments, *dest_uid, *reply;
510 PurpleBuddy *buddy;
511 qq_buddy_req *add_req; 489 qq_buddy_req *add_req;
512 gchar *who; 490 g_return_if_fail(uid != 0);
513 491
514 g_return_if_fail(data != NULL && data_len != 0);
515
516 qd = (qq_data *) gc->proto_data;
517
518 if (uid == 0) {
519 purple_debug_error("QQ", "Process buddy add, unknow id\n");
520 return;
521 }
522 purple_debug_info("QQ", "Process buddy add for id [%d]\n", uid);
523 qq_show_packet("buddy_add_no_auth", data, data_len);
524
525 if (NULL == (segments = split_data(data, data_len, "\x1f", 2)))
526 return;
527
528 dest_uid = segments[0];
529 reply = segments[1];
530 if (strtol(dest_uid, NULL, 10) != qd->uid) { /* should not happen */
531 purple_debug_error("QQ", "Add buddy reply is to [%s], not me!", dest_uid);
532 g_strfreev(segments);
533 return;
534 }
535
536 if (strtol(reply, NULL, 10) == 0) {
537 /* add OK */
538 qq_buddy_find_or_new(gc, uid);
539
540 qq_request_buddy_info(gc, uid, 0, 0);
541 if (qd->client_version >= 2007) {
542 qq_request_get_level_2007(gc, uid);
543 } else {
544 qq_request_get_level(gc, uid);
545 }
546 qq_request_get_buddies_online(gc, 0, 0);
547
548 purple_debug_info("QQ", "Successed adding into %d's buddy list", uid);
549 g_strfreev(segments);
550 return;
551 }
552
553 /* need auth */
554 purple_debug_warning("QQ", "Failed adding buddy, need authorize\n");
555
556 buddy = qq_buddy_find(gc, uid);
557 if (buddy == NULL) {
558 buddy = qq_buddy_new(gc, uid);
559 }
560 if (buddy != NULL && buddy->proto_data != NULL) {
561 /* Not authorized now, free buddy data */
562 qq_buddy_data_free(buddy->proto_data);
563 buddy->proto_data = NULL;
564 }
565
566 who = uid_to_purple_name(uid);
567 add_req = g_new0(qq_buddy_req, 1); 492 add_req = g_new0(qq_buddy_req, 1);
568 add_req->gc = gc; 493 add_req->gc = gc;
569 add_req->uid = uid; 494 add_req->uid = uid;
495 add_req->auth = NULL;
496 add_req->auth_len = 0;
497 if (auth != NULL && auth_len > 0) {
498 add_req->auth = g_new0(guint8, auth_len);
499 g_memmove(add_req->auth, auth, auth_len);
500 add_req->auth_len = auth_len;
501 }
502
503 who = uid_to_purple_name(uid);
570 msg = g_strdup_printf(_("%d needs authentication"), uid); 504 msg = g_strdup_printf(_("%d needs authentication"), uid);
571 purple_request_input(gc, _("Add buddy authorize"), msg, 505 purple_request_input(gc, _("Add buddy authorize"), msg,
572 _("Input request here"), 506 _("Input request here"),
573 _("Would you be my friend?"), 507 _("Would you be my friend?"),
574 TRUE, FALSE, NULL, 508 TRUE, FALSE, NULL,
577 purple_connection_get_account(gc), who, NULL, 511 purple_connection_get_account(gc), who, NULL,
578 add_req); 512 add_req);
579 513
580 g_free(msg); 514 g_free(msg);
581 g_free(who); 515 g_free(who);
516 }
517
518 /* add a buddy and send packet to QQ server
519 * note that when purple load local cached buddy list into its blist
520 * it also calls this funtion, so we have to
521 * define qd->is_login=TRUE AFTER LOGIN */
522 void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
523 {
524 qq_data *qd;
525 guint32 uid;
526
527 g_return_if_fail(NULL != gc && NULL != gc->proto_data);
528 g_return_if_fail(buddy != NULL);
529
530 qd = (qq_data *) gc->proto_data;
531 if (!qd->is_login)
532 return; /* IMPORTANT ! */
533
534 uid = purple_name_to_uid(buddy->name);
535 if (uid > 0) {
536 if (qd->client_version > 2005) {
537 request_buddy_add_no_auth_ex(gc, uid);
538 } else {
539 request_buddy_add_no_auth(gc, uid);
540 }
541 return;
542 }
543
544 purple_notify_error(gc, _("QQ Buddy"), _("Add buddy"), _("Invalid QQ Number"));
545 if (buddy == NULL) {
546 return;
547 }
548
549 purple_debug_info("QQ", "Remove buddy with invalid QQ number %d\n", uid);
550 qq_buddy_free(buddy);
551 }
552
553 /* process reply to add_buddy_auth request */
554 void qq_process_buddy_add_auth(guint8 *data, gint data_len, PurpleConnection *gc)
555 {
556 qq_data *qd;
557 gchar **segments, *msg_utf8;
558
559 g_return_if_fail(data != NULL && data_len != 0);
560
561 qd = (qq_data *) gc->proto_data;
562
563 if (data[0] == '0') {
564 purple_debug_info("QQ", "Reply OK for sending authorize\n");
565 return;
566 }
567
568 if (NULL == (segments = split_data(data, data_len, "\x1f", 2))) {
569 purple_notify_error(gc, _("QQ Buddy"), _("Failed sending authorize"), NULL);
570 return;
571 }
572 msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT);
573 purple_notify_error(gc, _("QQ Buddy"), _("Failed sending authorize"), msg_utf8);
574 g_free(msg_utf8);
575 }
576
577 /* process the server reply for my request to remove a buddy */
578 void qq_process_buddy_remove(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid)
579 {
580 PurpleBuddy *buddy = NULL;
581 gchar *msg;
582
583 g_return_if_fail(data != NULL && data_len != 0);
584 g_return_if_fail(uid != 0);
585
586 buddy = qq_buddy_find(gc, uid);
587 if (data[0] != 0) {
588 msg = g_strdup_printf(_("Failed removing buddy %d"), uid);
589 purple_notify_info(gc, _("QQ Buddy"), msg, NULL);
590 g_free(msg);
591 }
592
593 purple_debug_info("QQ", "Reply OK for removing buddy\n");
594 /* remove buddy again */
595 if (buddy != NULL) {
596 qq_buddy_free(buddy);
597 }
598 }
599
600 /* process the server reply for my request to remove myself from a buddy */
601 void qq_process_buddy_remove_me(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid)
602 {
603 qq_data *qd;
604 gchar *msg;
605
606 g_return_if_fail(data != NULL && data_len != 0);
607 qd = (qq_data *) gc->proto_data;
608
609 if (data[0] == 0) {
610 purple_debug_info("QQ", "Reply OK for removing me from %d's buddy list\n", uid);
611 return;
612 }
613 msg = g_strdup_printf(_("Failed removing me from %d's buddy list"), uid);
614 purple_notify_info(gc, _("QQ Buddy"), msg, NULL);
615 g_free(msg);
616 }
617
618 void qq_process_buddy_add_no_auth(PurpleConnection *gc,
619 guint8 *data, gint data_len, guint32 uid)
620 {
621 qq_data *qd;
622 gchar **segments;
623 gchar *dest_uid, *reply;
624 PurpleBuddy *buddy;
625
626 g_return_if_fail(data != NULL && data_len != 0);
627 g_return_if_fail(uid != 0);
628
629 qd = (qq_data *) gc->proto_data;
630
631 purple_debug_info("QQ", "Process buddy add for id [%d]\n", uid);
632 qq_show_packet("buddy_add_no_auth", data, data_len);
633
634 if (NULL == (segments = split_data(data, data_len, "\x1f", 2)))
635 return;
636
637 dest_uid = segments[0];
638 reply = segments[1];
639 if (strtol(dest_uid, NULL, 10) != qd->uid) { /* should not happen */
640 purple_debug_error("QQ", "Add buddy reply is to [%s], not me!", dest_uid);
641 g_strfreev(segments);
642 return;
643 }
644
645 if (strtol(reply, NULL, 10) == 0) {
646 /* add OK */
647 qq_buddy_find_or_new(gc, uid);
648
649 qq_request_buddy_info(gc, uid, 0, 0);
650 if (qd->client_version >= 2007) {
651 qq_request_get_level_2007(gc, uid);
652 } else {
653 qq_request_get_level(gc, uid);
654 }
655 qq_request_get_buddies_online(gc, 0, 0);
656
657 purple_debug_info("QQ", "Successed adding into %d's buddy list", uid);
658 g_strfreev(segments);
659 return;
660 }
661
662 /* need auth */
663 purple_debug_warning("QQ", "Failed adding buddy, need authorize\n");
664
665 buddy = qq_buddy_find(gc, uid);
666 if (buddy == NULL) {
667 buddy = qq_buddy_new(gc, uid);
668 }
669 if (buddy != NULL && buddy->proto_data != NULL) {
670 /* Not authorized now, free buddy data */
671 qq_buddy_data_free(buddy->proto_data);
672 buddy->proto_data = NULL;
673 }
674
675 buddy_add_authorize_input(gc, uid, NULL, 0);
582 g_strfreev(segments); 676 g_strfreev(segments);
677 }
678
679 void qq_process_buddy_add_no_auth_ex(PurpleConnection *gc,
680 guint8 *data, gint data_len, guint32 uid)
681 {
682 qq_data *qd;
683 gint bytes;
684 guint32 dest_uid;
685 guint8 reply;
686
687 g_return_if_fail(data != NULL && data_len >= 5);
688 g_return_if_fail(uid != 0);
689
690 qd = (qq_data *) gc->proto_data;
691
692 purple_debug_info("QQ", "Process buddy add no auth for id [%d]\n", uid);
693 qq_show_packet("buddy_add_no_auth_2007", data, data_len);
694
695 bytes = 0;
696 bytes += qq_get32(&dest_uid, data + bytes);
697 bytes += qq_get8(&reply, data + bytes);
698
699 g_return_if_fail(dest_uid == qd->uid);
700
701 if (reply == 0) {
702 /* need auth */
703 purple_debug_warning("QQ", "Failed adding buddy, need authorize\n");
704 qq_request_auth_info(gc, QQ_AUTH_INFO_BUDDY, QQ_AUTH_INFO_ADD_BUDDY, uid);
705 return;
706 }
707
708 /* add OK */
709 qq_buddy_find_or_new(gc, uid);
710
711 qq_request_buddy_info(gc, uid, 0, 0);
712 if (qd->client_version >= 2007) {
713 qq_request_get_level_2007(gc, uid);
714 } else {
715 qq_request_get_level(gc, uid);
716 }
717 qq_request_get_buddies_online(gc, 0, 0);
718
719 purple_debug_info("QQ", "Successed adding into %d's buddy list", uid);
720 return;
583 } 721 }
584 722
585 /* remove a buddy and send packet to QQ server accordingly */ 723 /* remove a buddy and send packet to QQ server accordingly */
586 void qq_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) 724 void qq_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
587 { 725 {
614 752
615 /* Do not call purple_blist_remove_buddy, 753 /* Do not call purple_blist_remove_buddy,
616 * otherwise purple segmentation fault */ 754 * otherwise purple segmentation fault */
617 } 755 }
618 756
757 static void buddy_add_request(PurpleConnection *gc, guint32 uid, gchar *reason)
758 {
759 PurpleAccount *account = purple_connection_get_account(gc);
760 qq_buddy_req *add_req;
761 gchar *who;
762
763 g_return_if_fail(uid != 0 && reason != NULL);
764
765 purple_debug_info("QQ", "Buddy %d request adding, msg: %s\n", uid, reason);
766
767 add_req = g_new0(qq_buddy_req, 1);
768 add_req->gc = gc;
769 add_req->uid = uid;
770
771 if (purple_prefs_get_bool("/plugins/prpl/qq/auto_get_authorize_info")) {
772 qq_request_buddy_info(gc, add_req->uid, 0, QQ_BUDDY_INFO_DISPLAY);
773 }
774 who = uid_to_purple_name(add_req->uid);
775
776 purple_account_request_authorization(account,
777 who, NULL,
778 NULL, reason,
779 purple_find_buddy(account, who) != NULL,
780 buddy_add_authorize_cb,
781 buddy_add_deny_cb,
782 add_req);
783
784 g_free(who);
785 }
786
619 /* someone wants to add you to his buddy list */ 787 /* someone wants to add you to his buddy list */
620 static void server_buddy_add_request(PurpleConnection *gc, gchar *from, gchar *to, 788 static void server_buddy_add_request(PurpleConnection *gc, gchar *from, gchar *to,
621 guint8 *data, gint data_len) 789 guint8 *data, gint data_len)
622 { 790 {
623 PurpleAccount *account = purple_connection_get_account(gc); 791 guint32 uid;
624 qq_buddy_req *add_req;
625 gchar *who;
626 gchar *msg, *reason; 792 gchar *msg, *reason;
627 793
628 g_return_if_fail(from != NULL && to != NULL); 794 g_return_if_fail(from != NULL && to != NULL);
629 795 uid = strtol(from, NULL, 10);
630 add_req = g_new0(qq_buddy_req, 1); 796 g_return_if_fail(uid != 0);
631 add_req->gc = gc;
632 add_req->uid = strtol(from, NULL, 10);;
633 797
634 if (purple_prefs_get_bool("/plugins/prpl/qq/auto_get_authorize_info")) { 798 if (purple_prefs_get_bool("/plugins/prpl/qq/auto_get_authorize_info")) {
635 qq_request_buddy_info(gc, add_req->uid, 0, QQ_BUDDY_INFO_DISPLAY); 799 qq_request_buddy_info(gc, uid, 0, QQ_BUDDY_INFO_DISPLAY);
636 } 800 }
637 who = uid_to_purple_name(add_req->uid);
638 801
639 if (data_len <= 0) { 802 if (data_len <= 0) {
640 reason = g_strdup( _("No reason given") ); 803 reason = g_strdup( _("No reason given") );
641 } else { 804 } else {
642 msg = g_strndup((gchar *)data, data_len); 805 msg = g_strndup((gchar *)data, data_len);
643 reason = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); 806 reason = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
644 if (reason == NULL) reason = g_strdup( _("Unknown reason") ); 807 if (reason == NULL) reason = g_strdup( _("Unknown reason") );
645 g_free(msg); 808 g_free(msg);
646 } 809 }
647 purple_account_request_authorization(account, 810
648 from, NULL, 811 buddy_add_request(gc, uid, reason);
649 NULL, reason,
650 purple_find_buddy(account, who) != NULL,
651 buddy_add_authorize_cb,
652 buddy_add_deny_cb,
653 add_req);
654
655 g_free(reason); 812 g_free(reason);
656 g_free(who); 813 }
814
815 void qq_process_buddy_check_code(PurpleConnection *gc, guint8 *data, gint data_len, guint32 ship32)
816 {
817 qq_data *qd;
818 gint bytes;
819 guint8 cmd;
820 guint8 reply;
821 guint32 uid;
822 guint16 flag1, flag2;
823
824 g_return_if_fail(data != NULL && data_len >= 5);
825 g_return_if_fail(uid != 0);
826
827 qd = (qq_data *) gc->proto_data;
828
829 qq_show_packet("buddy_check_code", data, data_len);
830
831 bytes = 0;
832 bytes += qq_get8(&cmd, data + bytes); /* 0x03 */
833 bytes += qq_get8(&reply, data + bytes);
834
835 if (reply == 0) {
836 purple_debug_info("QQ", "Failed checking code\n");
837 return;
838 }
839
840 bytes += qq_get32(&uid, data + bytes);
841 g_return_if_fail(uid != 0);
842 bytes += qq_get16(&flag1, data + bytes);
843 bytes += qq_get16(&flag2, data + bytes);
844 purple_debug_info("QQ", "Check code reply Ok, uid %d, flag 0x%04X-0x%04X\n",
845 uid, flag1, flag2);
846 return;
847 }
848
849 static void request_buddy_check_code(PurpleConnection *gc,
850 gchar *from, guint8 *code, gint code_len)
851 {
852 guint8 *raw_data;
853 gint bytes;
854 guint32 uid;
855
856 g_return_if_fail(code != NULL && code_len > 0 && from != NULL);
857
858 uid = strtol(from, NULL, 10);
859 raw_data = g_newa(guint8, code_len + 16);
860 bytes = 0;
861 bytes += qq_put8(raw_data + bytes, 0x03);
862 bytes += qq_put8(raw_data + bytes, 0x01);
863 bytes += qq_put32(raw_data + bytes, uid);
864 bytes += qq_put16(raw_data + bytes, code_len);
865 bytes += qq_putdata(raw_data + bytes, code, code_len);
866
867 qq_send_cmd(gc, QQ_CMD_BUDDY_CHECK_CODE, raw_data, bytes);
868 }
869
870 static gint server_buddy_check_code(PurpleConnection *gc,
871 gchar *from, guint8 *data, gint data_len)
872 {
873 gint bytes;
874 guint8 *code;
875 guint16 code_len;
876
877 g_return_val_if_fail(data != NULL && data_len > 0, 0);
878
879 bytes = 0;
880 bytes += qq_get16(&code_len, data + bytes);
881 if (code_len <= 0) {
882 purple_debug_info("QQ", "Server msg for buddy has no code\n");
883 return bytes;
884 }
885 if (bytes + code_len < data_len) {
886 purple_debug_error("QQ", "Code len error in server msg for buddy\n");
887 qq_show_packet("server_buddy_check_code", data, data_len);
888 code_len = data_len - bytes;
889 }
890 code = g_newa(guint8, code_len);
891 bytes += qq_getdata(code, code_len, data + bytes);
892
893 request_buddy_check_code(gc, from, code, code_len);
894 return bytes;
895 }
896
897 static void server_buddy_add_request_ex(PurpleConnection *gc, gchar *from, gchar *to,
898 guint8 *data, gint data_len)
899 {
900 gint bytes;
901 guint32 uid;
902 gchar *msg;
903 guint8 allow_reverse;
904
905 g_return_if_fail(from != NULL && to != NULL);
906 g_return_if_fail(data != NULL && data_len >= 3);
907 uid = strtol(from, NULL, 10);
908 g_return_if_fail(uid != 0);
909
910 /* qq_show_packet("server_buddy_add_request_ex", data, data_len); */
911
912 bytes = 0;
913 bytes += qq_get_vstr(&msg, QQ_CHARSET_DEFAULT, data+bytes);
914 bytes += qq_get8(&allow_reverse, data + bytes); /* allow_reverse = 0x01, allowed */
915 server_buddy_check_code(gc, from, data + bytes, data_len - bytes);
916
917 if (strlen(msg) <= 0) {
918 g_free(msg);
919 msg = g_strdup( _("No reason given") );
920 }
921 buddy_add_request(gc, uid, msg);
922 g_free(msg);
657 } 923 }
658 924
659 /* when you are added by a person, QQ server will send sys message */ 925 /* when you are added by a person, QQ server will send sys message */
660 static void server_buddy_added(PurpleConnection *gc, gchar *from, gchar *to, 926 static void server_buddy_added(PurpleConnection *gc, gchar *from, gchar *to,
661 guint8 *data, gint data_len) 927 guint8 *data, gint data_len)
691 957
692 g_free(who); 958 g_free(who);
693 g_free(primary); 959 g_free(primary);
694 } 960 }
695 961
962 static void server_buddy_added_ex(PurpleConnection *gc, gchar *from, gchar *to,
963 guint8 *data, gint data_len)
964 {
965 gint bytes;
966 guint8 allow_reverse;
967 gchar *msg;
968
969 g_return_if_fail(from != NULL && to != NULL);
970 g_return_if_fail(data != NULL && data_len >= 3);
971
972 qq_show_packet("server_buddy_added_ex", data, data_len);
973
974 bytes = 0;
975 bytes += qq_get_vstr(&msg, QQ_CHARSET_DEFAULT, data+bytes); /* always empty msg */
976 purple_debug_info("QQ", "Buddy added msg: %s\n", msg);
977 bytes += qq_get8(&allow_reverse, data + bytes); /* allow_reverse = 0x01, allowed */
978 server_buddy_check_code(gc, from, data + bytes, data_len - bytes);
979
980 g_free(msg);
981 }
982
983 static void server_buddy_adding_ex(PurpleConnection *gc, gchar *from, gchar *to,
984 guint8 *data, gint data_len)
985 {
986 gint bytes;
987 guint8 allow_reverse;
988
989 g_return_if_fail(from != NULL && to != NULL);
990 g_return_if_fail(data != NULL && data_len >= 3);
991
992 qq_show_packet("server_buddy_adding_ex", data, data_len);
993
994 bytes = 0;
995 bytes += qq_get8(&allow_reverse, data + bytes); /* allow_reverse = 0x01, allowed */
996 server_buddy_check_code(gc, from, data + bytes, data_len - bytes);
997 }
998
696 /* the buddy approves your request of adding him/her as your friend */ 999 /* the buddy approves your request of adding him/her as your friend */
697 static void server_buddy_added_me(PurpleConnection *gc, gchar *from, gchar *to, 1000 static void server_buddy_added_me(PurpleConnection *gc, gchar *from, gchar *to,
698 guint8 *data, gint data_len) 1001 guint8 *data, gint data_len)
699 { 1002 {
700 PurpleAccount *account = purple_connection_get_account(gc); 1003 PurpleAccount *account = purple_connection_get_account(gc);
702 guint32 uid; 1005 guint32 uid;
703 1006
704 g_return_if_fail(from != NULL && to != NULL); 1007 g_return_if_fail(from != NULL && to != NULL);
705 1008
706 qd = (qq_data *) gc->proto_data; 1009 qd = (qq_data *) gc->proto_data;
1010
707 uid = strtol(from, NULL, 10); 1011 uid = strtol(from, NULL, 10);
708
709 g_return_if_fail(uid > 0); 1012 g_return_if_fail(uid > 0);
1013
1014 server_buddy_check_code(gc, from, data, data_len);
710 1015
711 qq_buddy_find_or_new(gc, uid); 1016 qq_buddy_find_or_new(gc, uid);
712 qq_request_buddy_info(gc, uid, 0, 0); 1017 qq_request_buddy_info(gc, uid, 0, 0);
713 qq_request_get_buddies_online(gc, 0, 0); 1018 qq_request_get_buddies_online(gc, 0, 0);
714 if (qd->client_version >= 2007) { 1019 if (qd->client_version >= 2007) {
725 guint8 *data, gint data_len) 1030 guint8 *data, gint data_len)
726 { 1031 {
727 guint32 uid; 1032 guint32 uid;
728 PurpleBuddy *buddy; 1033 PurpleBuddy *buddy;
729 gchar *msg, *msg_utf8; 1034 gchar *msg, *msg_utf8;
1035 gint bytes;
1036 gchar **segments;
730 gchar *primary, *secondary; 1037 gchar *primary, *secondary;
731 1038
732 g_return_if_fail(from != NULL && to != NULL); 1039 g_return_if_fail(from != NULL && to != NULL);
1040
1041 qq_show_packet("server_buddy_rejected_me", data, data_len);
733 1042
734 if (data_len <= 0) { 1043 if (data_len <= 0) {
735 msg = g_strdup( _("No reason given") ); 1044 msg = g_strdup( _("No reason given") );
736 } else { 1045 } else {
737 msg = g_strndup((gchar *)data, data_len); 1046 segments = g_strsplit((gchar *)data, "\x1f", 1);
1047 if (segments != NULL && segments[0] != NULL) {
1048 msg = g_strdup(segments[0]);
1049 g_strfreev(segments);
1050 bytes = strlen(msg) + 1;
1051 if (bytes < data_len) {
1052 server_buddy_check_code(gc, from, data + bytes, data_len - bytes);
1053 }
1054 } else {
1055 msg = g_strdup( _("No reason given") );
1056 }
738 } 1057 }
739 msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); 1058 msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
740 if (msg_utf8 == NULL) { 1059 if (msg_utf8 == NULL) {
741 msg_utf8 = g_strdup( _("Unknown reason") ); 1060 msg_utf8 = g_strdup( _("Unknown reason") );
742 } 1061 }
770 server_buddy_added(gc, from, to, data, data_len); 1089 server_buddy_added(gc, from, to, data, data_len);
771 break; 1090 break;
772 case QQ_SERVER_BUDDY_ADD_REQUEST: 1091 case QQ_SERVER_BUDDY_ADD_REQUEST:
773 server_buddy_add_request(gc, from, to, data, data_len); 1092 server_buddy_add_request(gc, from, to, data, data_len);
774 break; 1093 break;
775 case QQ_MSG_SYS_ADD_FRIEND_REQUEST_EX: 1094 case QQ_SERVER_BUDDY_ADD_REQUEST_EX:
776 // server_buddy_add_request_ex(gc, from, to, data, data_len); 1095 server_buddy_add_request_ex(gc, from, to, data, data_len);
777 break; 1096 break;
778 case QQ_SERVER_BUDDY_ADDED_ME: 1097 case QQ_SERVER_BUDDY_ADDED_ME:
779 server_buddy_added_me(gc, from, to, data, data_len); 1098 server_buddy_added_me(gc, from, to, data, data_len);
780 break; 1099 break;
781 case QQ_SERVER_BUDDY_REJECTED_ME: 1100 case QQ_SERVER_BUDDY_REJECTED_ME:
782 server_buddy_rejected_me(gc, from, to, data, data_len); 1101 server_buddy_rejected_me(gc, from, to, data, data_len);
783 break; 1102 break;
1103 case QQ_SERVER_BUDDY_ADDED_EX:
1104 server_buddy_added_ex(gc, from, to, data, data_len);
1105 break;
1106 case QQ_SERVER_BUDDY_ADDING_EX:
1107 case QQ_SERVER_BUDDY_ADDED_ANSWER:
1108 server_buddy_adding_ex(gc, from, to, data, data_len);
1109 break;
784 default: 1110 default:
785 purple_debug_warning("QQ", "Unknow buddy operate (%d) from server\n", funct); 1111 purple_debug_warning("QQ", "Unknow buddy operate (%d) from server\n", funct);
786 break; 1112 break;
787 } 1113 }
788 } 1114 }