00001
00023
00024
00025 #include "debug.h"
00026 #include "internal.h"
00027 #include "notify.h"
00028 #include "request.h"
00029
00030 #include "utils.h"
00031 #include "packet_parse.h"
00032 #include "buddy_info.h"
00033 #include "buddy_list.h"
00034 #include "buddy_opt.h"
00035 #include "char_conv.h"
00036 #include "crypt.h"
00037 #include "header_info.h"
00038 #include "keep_alive.h"
00039 #include "im.h"
00040 #include "send_core.h"
00041
00042 #define GAIM_GROUP_QQ_FORMAT "QQ (%s)"
00043 #define GAIM_GROUP_QQ_UNKNOWN "QQ Unknown"
00044 #define GAIM_GROUP_QQ_BLOCKED "QQ Blocked"
00045
00046 #define QQ_REMOVE_BUDDY_REPLY_OK 0x00
00047 #define QQ_REMOVE_SELF_REPLY_OK 0x00
00048 #define QQ_ADD_BUDDY_AUTH_REPLY_OK 0x30 // ASCii value of "0"
00049
00050 enum {
00051 QQ_MY_AUTH_APPROVE = 0x30,
00052 QQ_MY_AUTH_REJECT = 0x31,
00053 QQ_MY_AUTH_REQUEST = 0x32,
00054 };
00055
00056 typedef struct _qq_add_buddy_request {
00057 guint32 uid;
00058 guint16 seq;
00059 } qq_add_buddy_request;
00060
00061
00062
00063 void _qq_send_packet_remove_buddy(GaimConnection * gc, guint32 uid)
00064 {
00065 gchar *uid_str;
00066
00067 g_return_if_fail(gc != NULL && uid > 0);
00068
00069 uid_str = g_strdup_printf("%d", uid);
00070 qq_send_cmd(gc, QQ_CMD_DEL_FRIEND, TRUE, 0, TRUE, uid_str, strlen(uid_str));
00071
00072 g_free(uid_str);
00073 }
00074
00075
00076
00077 void _qq_send_packet_remove_self_from(GaimConnection * gc, guint32 uid)
00078 {
00079 guint8 *raw_data, *cursor;
00080
00081 g_return_if_fail(gc != NULL && gc->proto_data != NULL && uid > 0);
00082
00083 raw_data = g_newa(guint8, 4);
00084 cursor = raw_data;
00085 create_packet_dw(raw_data, &cursor, uid);
00086
00087 qq_send_cmd(gc, QQ_CMD_REMOVE_SELF, TRUE, 0, TRUE, raw_data, 4);
00088
00089 }
00090
00091
00092
00093 void _qq_send_packet_add_buddy(GaimConnection * gc, guint32 uid)
00094 {
00095 qq_data *qd;
00096 qq_add_buddy_request *req;
00097 gchar *uid_str;
00098
00099 g_return_if_fail(gc != NULL && gc->proto_data != NULL && uid > 0);
00100
00101
00102 uid_str = g_strdup_printf("%d", uid);
00103 qq_send_cmd(gc, QQ_CMD_ADD_FRIEND_WO_AUTH, TRUE, 0, TRUE, uid_str, strlen(uid_str));
00104 g_free(uid_str);
00105
00106
00107 qd = (qq_data *) gc->proto_data;
00108 req = g_new0(qq_add_buddy_request, 1);
00109 req->seq = qd->send_seq;
00110 req->uid = uid;
00111 qd->add_buddy_request = g_list_append(qd->add_buddy_request, req);
00112 }
00113
00114
00115
00116 void _qq_send_packet_buddy_auth(GaimConnection * gc, guint32 uid, const gchar response, const gchar * text)
00117 {
00118 gchar *text_qq, *uid_str;
00119 guint8 bar, *cursor, *raw_data;
00120
00121 g_return_if_fail(gc != NULL && uid != 0);
00122
00123 uid_str = g_strdup_printf("%d", uid);
00124 bar = 0x1f;
00125 raw_data = g_newa(guint8, QQ_MSG_IM_MAX);
00126 cursor = raw_data;
00127
00128 create_packet_data(raw_data, &cursor, uid_str, strlen(uid_str));
00129 create_packet_b(raw_data, &cursor, bar);
00130 create_packet_b(raw_data, &cursor, response);
00131
00132 if (text != NULL) {
00133 text_qq = utf8_to_qq(text, QQ_CHARSET_DEFAULT);
00134 create_packet_b(raw_data, &cursor, bar);
00135 create_packet_data(raw_data, &cursor, text_qq, strlen(text_qq));
00136 g_free(text_qq);
00137 }
00138
00139 qq_send_cmd(gc, QQ_CMD_BUDDY_AUTH, TRUE, 0, TRUE, raw_data, cursor - raw_data);
00140 g_free(uid_str);
00141 }
00142
00143
00144
00145 void _qq_send_packet_add_buddy_auth_with_gc_and_uid(gc_and_uid * g, const gchar * text) {
00146 GaimConnection *gc;
00147 guint32 uid;
00148 g_return_if_fail(g != NULL);
00149
00150 gc = g->gc;
00151 uid = g->uid;
00152 g_return_if_fail(gc != NULL && uid != 0);
00153
00154 _qq_send_packet_buddy_auth(gc, uid, QQ_MY_AUTH_REQUEST, text);
00155 g_free(g);
00156 }
00157
00158
00159
00160 void _qq_reject_add_request_real(gc_and_uid * g, const gchar * reason)
00161 {
00162 gint uid;
00163 GaimConnection *gc;
00164
00165 g_return_if_fail(g != NULL);
00166
00167 gc = g->gc;
00168 uid = g->uid;
00169 g_return_if_fail(gc != NULL && uid != 0);
00170
00171 _qq_send_packet_buddy_auth(gc, uid, QQ_MY_AUTH_REJECT, reason);
00172 g_free(g);
00173 }
00174
00175
00176
00177 void qq_approve_add_request_with_gc_and_uid(gc_and_uid * g)
00178 {
00179 gint uid;
00180 GaimConnection *gc;
00181
00182 g_return_if_fail(g != NULL);
00183
00184 gc = g->gc;
00185 uid = g->uid;
00186 g_return_if_fail(gc != NULL && uid != 0);
00187
00188 _qq_send_packet_buddy_auth(gc, uid, QQ_MY_AUTH_APPROVE, NULL);
00189 g_free(g);
00190 }
00191
00192
00193 void qq_do_nothing_with_gc_and_uid(gc_and_uid * g, const gchar * msg)
00194 {
00195 g_free(g);
00196 }
00197
00198
00199
00200 void qq_reject_add_request_with_gc_and_uid(gc_and_uid * g)
00201 {
00202 gint uid;
00203 gchar *msg1, *msg2;
00204 GaimConnection *gc;
00205 gc_and_uid *g2;
00206
00207 g_return_if_fail(g != NULL);
00208
00209 gc = g->gc;
00210 uid = g->uid;
00211 g_return_if_fail(gc != NULL && uid != 0);
00212
00213 g_free(g);
00214
00215 g2 = g_new0(gc_and_uid, 1);
00216 g2->gc = gc;
00217 g2->uid = uid;
00218
00219 msg1 = g_strdup_printf(_("You rejected %d's request"), uid);
00220 msg2 = g_strdup(_("Input your reason:"));
00221
00222 gaim_request_input(gc, _("Reject request"), msg1, msg2,
00223 _("Sorry, you are not my type..."), TRUE, FALSE,
00224 NULL, _("Reject"), G_CALLBACK(_qq_reject_add_request_real), _("Cancel"), NULL, g2);
00225
00226 }
00227
00228
00229 void qq_add_buddy_with_gc_and_uid(gc_and_uid * g)
00230 {
00231 gint uid;
00232 GaimConnection *gc;
00233
00234 g_return_if_fail(g != NULL);
00235
00236 gc = g->gc;
00237 uid = g->uid;
00238 g_return_if_fail(gc != NULL && uid != 0);
00239
00240 _qq_send_packet_add_buddy(gc, uid);
00241 g_free(g);
00242 }
00243
00244
00245 void qq_block_buddy_with_gc_and_uid(gc_and_uid * g)
00246 {
00247 guint32 uid;
00248 GaimConnection *gc;
00249 GaimBuddy buddy;
00250 GaimGroup group;
00251
00252 g_return_if_fail(g != NULL);
00253
00254 gc = g->gc;
00255 uid = g->uid;
00256 g_return_if_fail(gc != NULL && uid > 0);
00257
00258 buddy.name = uid_to_gaim_name(uid);
00259 group.name = GAIM_GROUP_QQ_BLOCKED;
00260
00261 qq_remove_buddy(gc, &buddy, &group);
00262 _qq_send_packet_remove_self_from(gc, uid);
00263
00264 }
00265
00266
00267
00268 void qq_process_add_buddy_auth_reply(guint8 * buf, gint buf_len, GaimConnection * gc) {
00269 qq_data *qd;
00270 gint len;
00271 guint8 *data, *cursor, reply;
00272 gchar **segments, *msg_utf8;
00273
00274 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00275 g_return_if_fail(buf != NULL && buf_len != 0);
00276
00277 qd = (qq_data *) gc->proto_data;
00278 len = buf_len;
00279 data = g_newa(guint8, len);
00280 cursor = data;
00281
00282 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
00283 read_packet_b(data, &cursor, len, &reply);
00284 if (reply != QQ_ADD_BUDDY_AUTH_REPLY_OK) {
00285 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Add buddy with auth request fails\n");
00286 if (NULL == (segments = split_data(data, len, "\x1f", 2)))
00287 return;
00288 msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT);
00289 gaim_notify_error(gc, NULL, _("Add buddy with auth request fails"), msg_utf8);
00290 g_free(msg_utf8);
00291 } else
00292 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Add buddy with auth request OK\n");
00293 } else
00294 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt add buddy with auth reply\n");
00295
00296 }
00297
00298
00299
00300 void qq_process_remove_buddy_reply(guint8 * buf, gint buf_len, GaimConnection * gc) {
00301 qq_data *qd;
00302 gint len;
00303 guint8 *data, *cursor, reply;
00304
00305 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00306 g_return_if_fail(buf != NULL && buf_len != 0);
00307
00308 qd = (qq_data *) gc->proto_data;
00309 len = buf_len;
00310 data = g_newa(guint8, len);
00311
00312 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
00313 cursor = data;
00314 read_packet_b(data, &cursor, len, &reply);
00315 if (reply != QQ_REMOVE_BUDDY_REPLY_OK)
00316
00317 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Remove buddy fails\n");
00318 else {
00319 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Remove buddy OK\n");
00320 gaim_notify_info(gc, NULL, _("You have successfully removed a buddy"), NULL);
00321 }
00322 } else
00323 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt remove buddy reply\n");
00324
00325 }
00326
00327
00328
00329
00330 void qq_process_remove_self_reply(guint8 * buf, gint buf_len, GaimConnection * gc) {
00331 qq_data *qd;
00332 gint len;
00333 guint8 *data, *cursor, reply;
00334
00335 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00336 g_return_if_fail(buf != NULL && buf_len != 0);
00337
00338 qd = (qq_data *) gc->proto_data;
00339 len = buf_len;
00340 data = g_newa(guint8, len);
00341
00342 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
00343 cursor = data;
00344 read_packet_b(data, &cursor, len, &reply);
00345 if (reply != QQ_REMOVE_SELF_REPLY_OK)
00346
00347 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Remove self fails\n");
00348 else {
00349 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Remove self from a buddy OK\n");
00350 gaim_notify_info(gc, NULL, _("You have successfully removed yourself from a buddy"), NULL);
00351 }
00352 } else
00353 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt remove self reply\n");
00354
00355 }
00356
00357
00358 void qq_process_add_buddy_reply(guint8 * buf, gint buf_len, guint16 seq, GaimConnection * gc) {
00359 qq_data *qd;
00360 gint len, for_uid;
00361 gchar *msg, *data, **segments, *uid, *reply;
00362 GList *list;
00363 GaimBuddy *b;
00364 gc_and_uid *g;
00365 qq_add_buddy_request *req;
00366
00367 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00368 g_return_if_fail(buf != NULL && buf_len != 0);
00369
00370 for_uid = 0;
00371 qd = (qq_data *) gc->proto_data;
00372 len = buf_len;
00373
00374 list = qd->add_buddy_request;
00375 while (list != NULL) {
00376 req = (qq_add_buddy_request *) list->data;
00377 if (req->seq == seq) {
00378 for_uid = req->uid;
00379 qd->add_buddy_request = g_list_remove(qd->add_buddy_request, qd->add_buddy_request->data);
00380 g_free(req);
00381 break;
00382 }
00383 list = list->next;
00384 }
00385
00386 if (for_uid == 0) {
00387 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "We have no record for add buddy reply [%d], discard\n", seq);
00388 return;
00389 } else
00390 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Add buddy reply [%d] is for id [%d]\n", seq, for_uid);
00391
00392 data = g_newa(guint8, len);
00393
00394 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
00395 if (NULL == (segments = split_data(data, len, "\x1f", 2)))
00396 return;
00397 uid = segments[0];
00398 reply = segments[1];
00399 if (strtol(uid, NULL, 10) != qd->uid) {
00400 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Add buddy reply is to [%s], not me!", uid);
00401 g_strfreev(segments);
00402 return;
00403 }
00404
00405 if (strtol(reply, NULL, 10) > 0) {
00406 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Add buddy attempt fails, need authentication\n");
00407 b = gaim_find_buddy(gc->account, uid_to_gaim_name(for_uid));
00408 if (b != NULL)
00409 gaim_blist_remove_buddy(b);
00410 g = g_new0(gc_and_uid, 1);
00411 g->gc = gc;
00412 g->uid = for_uid;
00413 msg = g_strdup_printf(_("User %d needs authentication"), for_uid);
00414 gaim_request_input(gc, NULL, msg,
00415 _("Input request here"),
00416 _("Would you be my friend?"),
00417 TRUE, FALSE, NULL, _("Send"),
00418 G_CALLBACK
00419 (_qq_send_packet_add_buddy_auth_with_gc_and_uid),
00420 _("Cancel"), G_CALLBACK(qq_do_nothing_with_gc_and_uid), g);
00421 g_free(msg);
00422 } else {
00423 qq_add_buddy_by_recv_packet(gc, for_uid, TRUE, TRUE);
00424 msg = g_strdup_printf(_("You have added %d in buddy list"), for_uid);
00425 gaim_notify_info(gc, NULL, msg, NULL);
00426 g_free(msg);
00427 }
00428 g_strfreev(segments);
00429 } else
00430 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt add buddy reply\n");
00431
00432 }
00433
00434
00435 GaimGroup *qq_get_gaim_group(const gchar * group_name)
00436 {
00437 GaimGroup *g;
00438
00439 g_return_val_if_fail(group_name != NULL, NULL);
00440
00441 g = gaim_find_group(group_name);
00442 if (g == NULL) {
00443 g = gaim_group_new(group_name);
00444 gaim_blist_add_group(g, NULL);
00445 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Add new group: %s\n", group_name);
00446 }
00447
00448 return g;
00449 }
00450
00451
00452
00453
00454 GaimBuddy *qq_add_buddy_by_recv_packet(GaimConnection * gc, guint32 uid, gboolean is_known, gboolean create) {
00455 GaimAccount *a;
00456 GaimBuddy *b;
00457 GaimGroup *g;
00458 qq_data *qd;
00459 qq_buddy *q_bud;
00460 gchar *name, *group_name;
00461
00462 g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL);
00463
00464 a = gc->account;
00465 qd = (qq_data *) gc->proto_data;
00466 g_return_val_if_fail(a != NULL && uid != 0, NULL);
00467
00468 group_name = is_known ?
00469 g_strdup_printf(GAIM_GROUP_QQ_FORMAT, gaim_account_get_username(a)) : g_strdup(GAIM_GROUP_QQ_UNKNOWN);
00470
00471 g = qq_get_gaim_group(group_name);
00472
00473 name = uid_to_gaim_name(uid);
00474 b = gaim_find_buddy(gc->account, name);
00475
00476
00477 if (b != NULL)
00478 gaim_blist_remove_buddy(b);
00479
00480 b = gaim_buddy_new(a, name, NULL);
00481
00482 if (!create)
00483 b->proto_data = NULL;
00484 else {
00485 q_bud = g_new0(qq_buddy, 1);
00486 q_bud->uid = uid;
00487 b->proto_data = q_bud;
00488 qd->buddies = g_list_append(qd->buddies, q_bud);
00489 qq_send_packet_get_info(gc, q_bud->uid, FALSE);
00490 qq_send_packet_get_buddies_online(gc, QQ_FRIENDS_ONLINE_POSITION_START);
00491 }
00492
00493 gaim_blist_add_buddy(b, NULL, g, NULL);
00494 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Add new buddy: [%s]\n", name);
00495
00496 g_free(name);
00497 g_free(group_name);
00498
00499 return b;
00500 }
00501
00502
00503
00504
00505
00506
00507 void qq_add_buddy(GaimConnection * gc, GaimBuddy * buddy, GaimGroup * group) {
00508 qq_data *qd;
00509 guint32 uid;
00510 GaimBuddy *b;
00511
00512 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00513
00514 qd = (qq_data *) gc->proto_data;
00515 if (!qd->logged_in)
00516 return;
00517
00518 uid = gaim_name_to_uid(buddy->name);
00519 if (uid > 0)
00520 _qq_send_packet_add_buddy(gc, uid);
00521 else {
00522 b = gaim_find_buddy(gc->account, buddy->name);
00523 if (b != NULL)
00524 gaim_blist_remove_buddy(b);
00525 gaim_notify_error(gc, NULL,
00526 _("QQid Error"),
00527 _("Invalid QQid, to add buddy 1234567, \nyou should input qq-1234567"));
00528 }
00529 }
00530
00531
00532
00533 void qq_remove_buddy(GaimConnection * gc, GaimBuddy * buddy, GaimGroup * group) {
00534 qq_data *qd;
00535 GaimBuddy *b;
00536 qq_buddy *q_bud;
00537 guint32 uid;
00538
00539 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00540
00541 qd = (qq_data *) gc->proto_data;
00542 uid = gaim_name_to_uid(buddy->name);
00543
00544 if (!qd->logged_in)
00545 return;
00546
00547 if (uid > 0)
00548 _qq_send_packet_remove_buddy(gc, uid);
00549
00550 b = gaim_find_buddy(gc->account, buddy->name);
00551 if (b != NULL) {
00552 q_bud = (qq_buddy *) b->proto_data;
00553 if (q_bud != NULL)
00554 qd->buddies = g_list_remove(qd->buddies, q_bud);
00555 else
00556 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "We have no qq_buddy record for %s\n", buddy->name);
00557
00558
00559
00560 if (g_ascii_strcasecmp(group->name, GAIM_GROUP_QQ_BLOCKED)
00561 == 0)
00562 gaim_blist_remove_buddy(b);
00563 }
00564 }
00565
00566
00567
00568 void qq_add_buddy_request_free(qq_data * qd)
00569 {
00570 gint i;
00571 qq_add_buddy_request *p;
00572
00573 g_return_if_fail(qd != NULL);
00574
00575 i = 0;
00576 while (qd->add_buddy_request) {
00577 p = (qq_add_buddy_request *) (qd->add_buddy_request->data);
00578 qd->add_buddy_request = g_list_remove(qd->add_buddy_request, p);
00579 g_free(p);
00580 i++;
00581 }
00582 gaim_debug(GAIM_DEBUG_INFO, "QQ", "%d add buddy requests are freed!\n", i);
00583 }
00584
00585
00586
00587 void qq_buddies_list_free(qq_data * qd)
00588 {
00589 gint i;
00590 qq_buddy *p;
00591
00592 g_return_if_fail(qd != NULL);
00593
00594 i = 0;
00595 while (qd->buddies) {
00596 p = (qq_buddy *) (qd->buddies->data);
00597 qd->buddies = g_list_remove(qd->buddies, p);
00598 g_free(p);
00599 i++;
00600 }
00601 gaim_debug(GAIM_DEBUG_INFO, "QQ", "%d qq_buddy structures are freed!\n", i);
00602
00603 }
00604
00605
00606