# HG changeset patch # User SHiNE CsyFeK # Date 1224686978 0 # Node ID ec3f7d3e0445d35f21050f632ee554e861ac7090 # Parent a95c7e71064c68b7072fad04796e33cdf5141152 2008.10.04 - lonicerae * fixed a bug in qq_base.c diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/ChangeLog --- a/libpurple/protocols/qq/ChangeLog Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/ChangeLog Wed Oct 22 14:49:38 2008 +0000 @@ -1,12 +1,5 @@ -2008.10.05 - ccpaging - * Add my uid into buddy list - * Fixed a minor bug in qq_create_buddy. Not get new buddy's info. - * There are 38 fields in protocol 2008, one more than 2005/2007. - * The packet of Modifing buddy info is changed. Need sample to fix it. - -2008.10.04 - ccpaging - * Update protocol for 2007 - * Code cleanup +2008.10.04 - lonicerae + * fixed a bug in qq_base.c 2008.10.03 - ccpaging * 2007 protocol: diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/buddy_info.c --- a/libpurple/protocols/qq/buddy_info.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.c Wed Oct 22 14:49:38 2008 +0000 @@ -85,7 +85,7 @@ QQ_INFO_UNKNOW3, QQ_INFO_UNKNOW4, QQ_INFO_UNKNOW5, QQ_INFO_IS_PUB_MOBILE, QQ_INFO_IS_PUB_CONTACT, QQ_INFO_COLLEGE, QQ_INFO_HOROSCOPE, QQ_INFO_ZODIAC, QQ_INFO_BLOOD, QQ_INFO_SHOW, QQ_INFO_UNKNOW6, - QQ_INFO_LAST_2007, QQ_INFO_LAST, + QQ_INFO_LAST, }; enum { @@ -142,8 +142,7 @@ { QQ_FIELD_EXT, QQ_FIELD_CHOICE, "zodiac", N_("Zodiac"), zodiac_names, QQ_ZODIAC_SIZE }, { QQ_FIELD_EXT, QQ_FIELD_CHOICE, "blood", N_("Blood"), blood_types, QQ_BLOOD_SIZE }, { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "qq_show", "QQ Show", NULL, 0 }, - { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "unknow6", "Unknow6", NULL, 0 }, - { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "LAST_2005", "LAST_2005", NULL, 0 } + { QQ_FIELD_UNUSED, QQ_FIELD_STRING, "unknow6", "Unknow6", NULL, 0 } }; typedef struct _modify_info_request { @@ -569,53 +568,35 @@ } /* after getting info or modify myself, refresh the buddy list accordingly */ -static void qq_set_buddy_info(gchar **segments, PurpleConnection *gc) +static void qq_refresh_buddy_and_myself(gchar **segments, PurpleConnection *gc) { - PurpleBuddy *purple_buddy; + PurpleBuddy *b; qq_data *qd; - guint32 uid; - qq_buddy *buddy; + qq_buddy *q_bud; gchar *alias_utf8; gchar *purple_name; PurpleAccount *account = purple_connection_get_account(gc); qd = (qq_data *) gc->proto_data; - - uid = strtol(segments[QQ_INFO_UID], NULL, 10); - purple_name = uid_to_purple_name(uid); + purple_name = uid_to_purple_name(strtol(segments[QQ_INFO_UID], NULL, 10)); alias_utf8 = qq_to_utf8(segments[QQ_INFO_NICK], QQ_CHARSET_DEFAULT); if (qd->uid == strtol(segments[QQ_INFO_UID], NULL, 10)) { /* it is me */ - purple_debug_info("QQ", "Got my info\n"); qd->my_icon = strtol(segments[QQ_INFO_FACE], NULL, 10); if (alias_utf8 != NULL) purple_account_set_alias(account, alias_utf8); - - /* add me to buddy list */ - purple_buddy = purple_find_buddy(gc->account, purple_name); - if ( purple_buddy == NULL) { - purple_buddy = qq_create_buddy(gc, uid, TRUE, FALSE); - } - buddy = g_new0(qq_buddy, 1); - buddy->uid = uid; - buddy->status = QQ_BUDDY_ONLINE_NORMAL; - purple_buddy->proto_data = buddy; - qd->buddies = g_list_append(qd->buddies, buddy); } - /* update buddy list (including myself, if myself is the buddy) */ - purple_buddy = purple_find_buddy(gc->account, purple_name); - buddy = (purple_buddy == NULL) ? NULL : (qq_buddy *) purple_buddy->proto_data; - if (buddy != NULL) { /* I have this buddy */ - buddy->age = strtol(segments[QQ_INFO_AGE], NULL, 10); - buddy->gender = strtol(segments[QQ_INFO_GENDER], NULL, 10); - buddy->face = strtol(segments[QQ_INFO_FACE], NULL, 10); + b = purple_find_buddy(gc->account, purple_name); + q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; + if (q_bud != NULL) { /* I have this buddy */ + q_bud->age = strtol(segments[QQ_INFO_AGE], NULL, 10); + q_bud->gender = strtol(segments[QQ_INFO_GENDER], NULL, 10); + q_bud->face = strtol(segments[QQ_INFO_FACE], NULL, 10); if (alias_utf8 != NULL) - buddy->nickname = g_strdup(alias_utf8); - qq_update_buddy_contact(gc, buddy); - buddy_local_icon_upate(gc->account, purple_name, buddy->face); - } else { - purple_debug_info("QQ", "Can not find buddy data of %s\n", purple_name); + q_bud->nickname = g_strdup(alias_utf8); + qq_update_buddy_contact(gc, q_bud); + buddy_local_icon_upate(gc->account, purple_name, q_bud->face); } g_free(purple_name); g_free(alias_utf8); @@ -626,18 +607,12 @@ { qq_data *qd; gchar **segments; - gint field_count; g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - if (qd->client_version >= 2008) { - field_count = QQ_INFO_LAST; - } else { - field_count = QQ_INFO_LAST_2007; - } - if (NULL == (segments = split_data(data, data_len, "\x1e", field_count))) + if (NULL == (segments = split_data(data, data_len, "\x1e", QQ_INFO_LAST))) return; #ifdef DEBUG @@ -652,13 +627,13 @@ segments[QQ_INFO_FACE] = icon; request_modify_info(gc, segments); - qq_set_buddy_info(segments, gc); + qq_refresh_buddy_and_myself(segments, gc); } g_strfreev(segments); return; } - qq_set_buddy_info(segments, gc); + qq_refresh_buddy_and_myself(segments, gc); switch (action) { case QQ_BUDDY_INFO_DISPLAY: info_display_only(gc, segments); @@ -722,7 +697,7 @@ if ( qd->buddies == NULL) { return; } - + /* server only reply levels for online buddies */ size = 4 * g_list_length(qd->buddies) + 1 + 4; buf = g_newa(guint8, size); @@ -746,7 +721,7 @@ guint32 uid, onlineTime; guint16 level, timeRemainder; qq_buddy *buddy; - + while (data_len - bytes >= 12) { bytes += qq_get32(&uid, data + bytes); bytes += qq_get32(&onlineTime, data + bytes); @@ -809,11 +784,11 @@ buddy->onlineTime = onlineTime; buddy->level = level; buddy->timeRemainder = timeRemainder; - + /* extend bytes in qq2007*/ bytes += 4; /* skip 8 bytes */ - /* qq_show_packet("Buddies level", data + bytes, data_len - bytes); */ - + qq_show_packet("Buddies level", data + bytes, data_len - bytes); + do { bytes += qq_get16(&str_len, data + bytes); if (str_len <= 0 || bytes + str_len > data_len) { diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/buddy_list.c --- a/libpurple/protocols/qq/buddy_list.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Wed Oct 22 14:49:38 2008 +0000 @@ -101,7 +101,7 @@ if (qd->client_version >= 2007) { bytes += qq_put16(raw_data + bytes, 0x0000); } - + qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDIES_LIST, raw_data, bytes, update_class, 0); } @@ -251,13 +251,13 @@ guint16 qq_process_get_buddies_list_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - qq_buddy *buddy; + qq_buddy *q_bud; gint bytes_expected, count; gint bytes, buddy_bytes; - gint nickname_len; guint16 position, unknown; - gchar *purple_name; - PurpleBuddy *purple_buddy; + guint8 pascal_len; + gchar *name; + PurpleBuddy *b; g_return_val_if_fail(data != NULL && data_len != 0, -1); @@ -273,39 +273,40 @@ /* the following data is buddy list in this packet */ count = 0; while (bytes < data_len) { - buddy = g_new0(qq_buddy, 1); + q_bud = g_new0(qq_buddy, 1); /* set flag */ buddy_bytes = bytes; /* 000-003: uid */ - bytes += qq_get32(&buddy->uid, data + bytes); + bytes += qq_get32(&q_bud->uid, data + bytes); /* 004-005: icon index (1-255) */ - bytes += qq_get16(&buddy->face, data + bytes); + bytes += qq_get16(&q_bud->face, data + bytes); /* 006-006: age */ - bytes += qq_get8(&buddy->age, data + bytes); + bytes += qq_get8(&q_bud->age, data + bytes); /* 007-007: gender */ - bytes += qq_get8(&buddy->gender, data + bytes); + bytes += qq_get8(&q_bud->gender, data + bytes); - nickname_len = qq_get_vstr(&buddy->nickname, QQ_CHARSET_DEFAULT, data + bytes); - bytes += nickname_len; - qq_filter_str(buddy->nickname); + pascal_len = convert_as_pascal_string(data + bytes, &q_bud->nickname, QQ_CHARSET_DEFAULT); + bytes += pascal_len; + qq_filter_str(q_bud->nickname); /* Fixme: merge following as 32bit flag */ bytes += qq_get16(&unknown, data + bytes); - bytes += qq_get8(&buddy->ext_flag, data + bytes); - bytes += qq_get8(&buddy->comm_flag, data + bytes); - + bytes += qq_get8(&q_bud->ext_flag, data + bytes); + bytes += qq_get8(&q_bud->comm_flag, data + bytes); + if (qd->client_version >= 2007) { bytes += 4; /* skip 4 bytes */ - bytes_expected = 16 + nickname_len; + bytes_expected = 16 + pascal_len; } else { - bytes_expected = 12 + nickname_len; + bytes_expected = 12 + pascal_len; } - if (buddy->uid == 0 || (bytes - buddy_bytes) != bytes_expected) { + + if (q_bud->uid == 0 || (bytes - buddy_bytes) != bytes_expected) { purple_debug_info("QQ", "Buddy entry, expect %d bytes, read %d bytes\n", bytes_expected, bytes - buddy_bytes); - g_free(buddy->nickname); - g_free(buddy); + g_free(q_bud->nickname); + g_free(q_bud); continue; } else { count++; @@ -313,20 +314,20 @@ #if 1 purple_debug_info("QQ", "buddy [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", - buddy->uid, buddy->ext_flag, buddy->comm_flag, buddy->nickname); + q_bud->uid, q_bud->ext_flag, q_bud->comm_flag, q_bud->nickname); #endif - purple_name = uid_to_purple_name(buddy->uid); - purple_buddy = purple_find_buddy(gc->account, purple_name); - g_free(purple_name); + name = uid_to_purple_name(q_bud->uid); + b = purple_find_buddy(gc->account, name); + g_free(name); - if (purple_buddy == NULL) { - purple_buddy = qq_create_buddy(gc, buddy->uid, TRUE, FALSE); + if (b == NULL) { + b = qq_create_buddy(gc, q_bud->uid, TRUE, FALSE); } - purple_buddy->proto_data = buddy; - qd->buddies = g_list_append(qd->buddies, buddy); - qq_update_buddy_contact(gc, buddy); + b->proto_data = q_bud; + qd->buddies = g_list_append(qd->buddies, q_bud); + qq_update_buddy_contact(gc, q_bud); } if(bytes > data_len) { @@ -360,7 +361,7 @@ bytes += qq_get8(&reply_code, data + bytes); if(0 != reply_code) { - purple_debug_warning("QQ", "qq_process_get_buddies_and_rooms, %d\n", reply_code); + purple_debug_warning("QQ", "qq_process_get_buddies_and_rooms, %d", reply_code); } bytes += qq_get32(&unknown, data + bytes); @@ -491,7 +492,7 @@ } else { away_cmd = QQ_BUDDY_ONLINE_NORMAL; } - + misc_status = 0x00000000; fake_video = purple_prefs_get_bool("/plugins/prpl/qq/show_fake_video"); if (fake_video) diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/buddy_opt.c --- a/libpurple/protocols/qq/buddy_opt.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.c Wed Oct 22 14:49:38 2008 +0000 @@ -346,7 +346,7 @@ uid = purple_name_to_uid(who); g_return_if_fail(uid > 0); - + if (uid == qd->uid) { return; } @@ -501,13 +501,12 @@ /* we add new buddy, if the received packet is from someone not in my list * return the PurpleBuddy that is just created */ -PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid, - gboolean is_known, gboolean is_create_data) +PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid, gboolean is_known, gboolean create) { - PurpleBuddy *purple_buddy; + PurpleBuddy *buddy; PurpleGroup *group; qq_data *qd; - qq_buddy *buddy; + qq_buddy *q_bud; gchar *buddy_name, *group_name; g_return_val_if_fail(gc->account != NULL && uid != 0, NULL); @@ -523,13 +522,13 @@ group = qq_create_group(group_name); buddy_name = uid_to_purple_name(uid); - purple_buddy = purple_find_buddy(gc->account, buddy_name); + buddy = purple_find_buddy(gc->account, buddy_name); /* remove old, we can not simply return here * because there might be old local copy of this buddy */ - if (purple_buddy != NULL) - purple_blist_remove_buddy(purple_buddy); + if (buddy != NULL) + purple_blist_remove_buddy(buddy); - purple_buddy = purple_buddy_new(gc->account, buddy_name, NULL); + buddy = purple_buddy_new(gc->account, buddy_name, NULL); if ( !is_known) { if (purple_privacy_check(gc->account, buddy_name)) { purple_privacy_deny(gc->account, buddy_name, TRUE, FALSE); @@ -538,29 +537,29 @@ } } - if (!is_create_data) - purple_buddy->proto_data = NULL; + if (!create) + buddy->proto_data = NULL; else { - buddy = g_new0(qq_buddy, 1); - buddy->uid = uid; - purple_buddy->proto_data = buddy; - qd->buddies = g_list_append(qd->buddies, buddy); - qq_request_buddy_info(gc, uid, 0, 0); + q_bud = g_new0(qq_buddy, 1); + q_bud->uid = uid; + buddy->proto_data = q_bud; + qd->buddies = g_list_append(qd->buddies, q_bud); + qq_request_buddy_info(gc, qd->uid, 0, 0); qq_request_get_buddies_online(gc, 0, 0); if (qd->client_version >= 2007) { - qq_request_get_level_2007(gc, uid); + qq_request_get_level_2007(gc, q_bud->uid); } else { - qq_request_get_level(gc, uid); + qq_request_get_level(gc, q_bud->uid); } } - purple_blist_add_buddy(purple_buddy, NULL, group, NULL); + purple_blist_add_buddy(buddy, NULL, group, NULL); purple_debug_warning("QQ", "Add new buddy: [%s]\n", buddy_name); g_free(buddy_name); g_free(group_name); - return purple_buddy; + return buddy; } qq_buddy *qq_get_buddy(PurpleConnection *gc, guint32 uid) @@ -575,9 +574,9 @@ purple_buddy = purple_find_buddy(purple_connection_get_account(gc), purple_name); g_free(purple_name); if (purple_buddy == NULL) return NULL; - + if (purple_buddy->proto_data == NULL) { - purple_debug_error("QQ", "Can not find buddy data of %d\n", uid); + purple_debug_error("QQ", "Null data of buddy %d\n", uid); return NULL; } return (qq_buddy *) purple_buddy->proto_data; diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/buddy_opt.h --- a/libpurple/protocols/qq/buddy_opt.h Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.h Wed Oct 22 14:49:38 2008 +0000 @@ -36,8 +36,7 @@ const char *old_group, const char *new_group); void qq_remove_buddy_and_me(PurpleBlistNode * node); void qq_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); -PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid, - gboolean is_known, gboolean is_create_data); +PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid, gboolean is_known, gboolean create); void qq_buddies_list_free(PurpleAccount *account, qq_data *qd); void qq_process_buddy_remove(guint8 *buf, gint buf_len, PurpleConnection *gc); diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/char_conv.c --- a/libpurple/protocols/qq/char_conv.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/char_conv.c Wed Oct 22 14:49:38 2008 +0000 @@ -98,7 +98,7 @@ } /* convert a string from from_charset to to_charset, using g_convert */ -static gchar *do_convert(const gchar *str, gssize len, const gchar *to_charset, const gchar *from_charset) +static gchar *_my_convert(const gchar *str, gssize len, const gchar *to_charset, const gchar *from_charset) { GError *error = NULL; gchar *ret; @@ -128,18 +128,14 @@ * returns the number of bytes read, return -1 if fatal error * the converted UTF-8 will be saved in ret */ -gint qq_get_vstr(gchar **ret, const gchar *from_charset, guint8 *data) +gint convert_as_pascal_string(guint8 *data, gchar **ret, const gchar *from_charset) { guint8 len; g_return_val_if_fail(data != NULL && from_charset != NULL, -1); len = data[0]; - if (len == 0) { - *ret = g_strdup(""); - return 1; - } - *ret = do_convert((gchar *) (data + 1), (gssize) len, UTF8, from_charset); + *ret = _my_convert((gchar *) (data + 1), (gssize) len, UTF8, from_charset); return len + 1; } @@ -218,15 +214,15 @@ return ret; } -/* two convenience methods, using do_convert */ +/* two convenience methods, using _my_convert */ gchar *utf8_to_qq(const gchar *str, const gchar *to_charset) { - return do_convert(str, -1, to_charset, UTF8); + return _my_convert(str, -1, to_charset, UTF8); } gchar *qq_to_utf8(const gchar *str, const gchar *from_charset) { - return do_convert(str, -1, UTF8, from_charset); + return _my_convert(str, -1, UTF8, from_charset); } /* QQ uses binary code for smiley, while purple uses strings. diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/char_conv.h --- a/libpurple/protocols/qq/char_conv.h Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/char_conv.h Wed Oct 22 14:49:38 2008 +0000 @@ -29,7 +29,7 @@ #define QQ_CHARSET_DEFAULT "GB18030" -gint qq_get_vstr(gchar **ret, const gchar *from_charset, guint8 *data); +gint convert_as_pascal_string(guint8 *data, gchar **ret, const gchar *from_charset); gchar *qq_smiley_to_purple(gchar *text); gchar *purple_smiley_to_qq(gchar *text); diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/group_conv.c --- a/libpurple/protocols/qq/group_conv.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/group_conv.c Wed Oct 22 14:49:38 2008 +0000 @@ -74,64 +74,55 @@ gchar *member_name, *member_uid; PurpleConversation *conv; gint flag; - gboolean is_find; g_return_if_fail(group != NULL); - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - group->title_utf8, purple_connection_get_account(gc)); - - g_return_if_fail (conv != NULL && group->members != NULL); - names = NULL; flags = NULL; - - list = group->members; - while (list != NULL) { - member = (qq_buddy *) list->data; + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + group->title_utf8, purple_connection_get_account(gc)); + if (conv != NULL && group->members != NULL) { + list = group->members; + while (list != NULL) { + member = (qq_buddy *) list->data; - /* we need unique identifiers for everyone in the chat or else we'll - * run into problems with functions like get_cb_real_name from qq.c */ - member_name = (member->nickname != NULL && *(member->nickname) != '\0') ? - g_strdup_printf("%s (%u)", member->nickname, member->uid) : - g_strdup_printf("(%u)", member->uid); - member_uid = g_strdup_printf("(%u)", member->uid); + /* we need unique identifiers for everyone in the chat or else we'll + * run into problems with functions like get_cb_real_name from qq.c */ + member_name = (member->nickname != NULL && *(member->nickname) != '\0') ? + g_strdup_printf("%s (%u)", member->nickname, member->uid) : + g_strdup_printf("(%u)", member->uid); + member_uid = g_strdup_printf("(%u)", member->uid); - flag = 0; - /* TYPING to put online above OP and FOUNDER */ - if (is_online(member->status)) flag |= (PURPLE_CBFLAGS_TYPING | PURPLE_CBFLAGS_VOICE); - if(1 == (member->role & 1)) flag |= PURPLE_CBFLAGS_OP; - if(member->uid == group->creator_uid) flag |= PURPLE_CBFLAGS_FOUNDER; + flag = 0; + /* TYPING to put online above OP and FOUNDER */ + if (is_online(member->status)) + flag |= (PURPLE_CBFLAGS_TYPING | PURPLE_CBFLAGS_VOICE); + if(1 == (member->role & 1)) flag |= PURPLE_CBFLAGS_OP; + if(member->uid == group->creator_uid) flag |= PURPLE_CBFLAGS_FOUNDER; - is_find = TRUE; - if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(conv), member_name)) - { - purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(conv), - member_name, - flag); - } else if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(conv), member_uid)) - { - purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(conv), - member_uid, - flag); - purple_conv_chat_rename_user(PURPLE_CONV_CHAT(conv), member_uid, member_name); - } else { - is_find = FALSE; + if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(conv), member_name)) + { + purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(conv), + member_name, + flag); + } else if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(conv), member_uid)) + { + purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(conv), + member_uid, + flag); + purple_conv_chat_rename_user(PURPLE_CONV_CHAT(conv), member_uid, member_name); + } else { + /* always put it even offline */ + names = g_list_append(names, member_name); + flags = g_list_append(flags, GINT_TO_POINTER(flag)); + } + g_free(member_uid); + list = list->next; } - if (!is_find) { - /* always put it even offline */ - names = g_list_append(names, member_name); - flags = g_list_append(flags, GINT_TO_POINTER(flag)); - } else { - g_free(member_name); + + if (names != NULL && flags != NULL) { + purple_conv_chat_add_users(PURPLE_CONV_CHAT(conv), names, NULL, flags, FALSE); } - g_free(member_uid); - list = list->next; } - - if (names != NULL && flags != NULL) { - purple_conv_chat_add_users(PURPLE_CONV_CHAT(conv), names, NULL, flags, FALSE); - } - /* clean up names */ while (names != NULL) { member_name = (gchar *) names->data; diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/group_im.c --- a/libpurple/protocols/qq/group_im.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/group_im.c Wed Oct 22 14:49:38 2008 +0000 @@ -107,7 +107,7 @@ g_return_if_fail(ext_id > 0 && user_uid > 0); - bytes += qq_get_vstr(&reason_utf8, QQ_CHARSET_DEFAULT, data + bytes); + bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf(_("%d request to join Qun %d"), user_uid, ext_id); reason = g_strdup_printf(_("Message: %s"), reason_utf8); @@ -161,7 +161,7 @@ if (uid_from != 0) { buddy = qq_group_find_member_by_uid(group, uid_from); if (buddy == NULL || buddy->nickname == NULL) - from = g_strdup_printf("%d", uid_from); + from = uid_to_purple_name(uid_from); else from = g_strdup(buddy->nickname); } else { @@ -192,7 +192,7 @@ g_return_if_fail(ext_id > 0 && admin_uid > 0); - bytes += qq_get_vstr(&reason_utf8, QQ_CHARSET_DEFAULT, data + bytes); + bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf (_("Failed to join Qun %d, operated by admin %d"), ext_id, admin_uid); @@ -231,7 +231,7 @@ g_return_if_fail(ext_id > 0 && admin_uid > 0); /* it is also a "无" here, so do not display */ - bytes += qq_get_vstr(&reason, QQ_CHARSET_DEFAULT, data + bytes); + bytes += convert_as_pascal_string(data + bytes, &reason, QQ_CHARSET_DEFAULT); group = qq_room_search_id(gc, id); if (group != NULL) { @@ -317,7 +317,7 @@ } /* recv an IM from a group chat */ -void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 msg_type) +void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type) { gchar *msg_with_purple_smiley, *msg_utf8_encoded; qq_data *qd; @@ -353,7 +353,7 @@ bytes += qq_get32(&(packet.ext_id), data + bytes); bytes += qq_get8(&(packet.type8), data + bytes); - if(QQ_MSG_TEMP_QUN_IM == msg_type) { + if(QQ_RECV_IM_TEMP_QUN_IM == im_type) { bytes += qq_get32(&(id), data + bytes); } @@ -384,7 +384,7 @@ * buf.getInt(); */ - if(msg_type != QQ_MSG_UNKNOWN_QUN_IM) + if(im_type != QQ_RECV_IM_UNKNOWN_QUN_IM) skip_len = 10; else skip_len = 0; diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/group_im.h --- a/libpurple/protocols/qq/group_im.h Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/group_im.h Wed Oct 22 14:49:38 2008 +0000 @@ -36,7 +36,7 @@ void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc); -void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 msg_type); +void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type); void qq_process_room_msg_apply_join(guint8 *data, gint len, guint32 id, PurpleConnection *gc); diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/group_info.c --- a/libpurple/protocols/qq/group_info.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/group_info.c Wed Oct 22 14:49:38 2008 +0000 @@ -157,7 +157,7 @@ qd = (qq_data *) gc->proto_data; /* qq_show_packet("Room Info", data, data_len); */ - + bytes = 0; bytes += qq_get32(&id, data + bytes); g_return_if_fail(id > 0); @@ -191,16 +191,15 @@ purple_debug_info("QQ", "type=%u creatorid=%u category=%u maxmembers=%u\n", group->type8, group->creator_uid, group->category, max_members); - if (qd->client_version >= 2007) { - /* skip 7 bytes unknow in qq2007 0x(00 00 01 00 00 00 fc)*/ - bytes += 7; - } + /* skip 7 bytes unknow in qq2007 0x(00 00 01 00 00 00 fc)*/ + bytes += 7; + /* qq_show_packet("Room Info", data + bytes, data_len - bytes); */ /* strlen + */ - bytes += qq_get_vstr(&(group->title_utf8), QQ_CHARSET_DEFAULT, data + bytes); + bytes += convert_as_pascal_string(data + bytes, &(group->title_utf8), QQ_CHARSET_DEFAULT); bytes += qq_get16(&unknown, data + bytes); /* 0x0000 */ - bytes += qq_get_vstr(¬ice, QQ_CHARSET_DEFAULT, data + bytes); - bytes += qq_get_vstr(&(group->desc_utf8), QQ_CHARSET_DEFAULT, data + bytes); + bytes += convert_as_pascal_string(data + bytes, ¬ice, QQ_CHARSET_DEFAULT); + bytes += convert_as_pascal_string(data + bytes, &(group->desc_utf8), QQ_CHARSET_DEFAULT); purple_debug_info("QQ", "room [%s] notice [%s] desc [%s] unknow 0x%04X\n", group->title_utf8, notice, group->desc_utf8, unknown); @@ -315,7 +314,9 @@ g_return_if_fail(data != NULL && len > 0); - /* qq_show_packet("qq_process_room_cmd_get_buddies", data, len); */ +#if 0 + qq_show_packet("qq_process_room_cmd_get_buddies", data, len); +#endif bytes = 0; bytes += qq_get32(&id, data + bytes); @@ -336,7 +337,7 @@ bytes += qq_get16(&(member->face), data + bytes); bytes += qq_get8(&(member->age), data + bytes); bytes += qq_get8(&(member->gender), data + bytes); - bytes += qq_get_vstr(&nick, QQ_CHARSET_DEFAULT, data + bytes); + bytes += convert_as_pascal_string(data + bytes, &nick, QQ_CHARSET_DEFAULT); bytes += qq_get16(&unknown, data + bytes); bytes += qq_get8(&(member->ext_flag), data + bytes); bytes += qq_get8(&(member->comm_flag), data + bytes); diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/group_search.c --- a/libpurple/protocols/qq/group_search.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/group_search.c Wed Oct 22 14:49:38 2008 +0000 @@ -110,10 +110,10 @@ bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get32(&(group.category), data + bytes); - bytes += qq_get_vstr(&(group.title_utf8), QQ_CHARSET_DEFAULT, data + bytes); + bytes += convert_as_pascal_string(data + bytes, &(group.title_utf8), QQ_CHARSET_DEFAULT); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get8(&(group.auth_type), data + bytes); - bytes += qq_get_vstr(&(group.desc_utf8), QQ_CHARSET_DEFAULT, data + bytes); + bytes += convert_as_pascal_string(data + bytes, &(group.desc_utf8), QQ_CHARSET_DEFAULT); /* end of one qq_group */ if(bytes != len) { purple_debug_error("QQ", diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/im.c --- a/libpurple/protocols/qq/im.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/im.c Wed Oct 22 14:49:38 2008 +0000 @@ -35,6 +35,7 @@ #include "buddy_list.h" #include "buddy_opt.h" #include "char_conv.h" +#include "group_im.h" #include "qq_define.h" #include "im.h" #include "packet_parse.h" @@ -42,6 +43,7 @@ #include "send_file.h" #include "utils.h" +#define QQ_SEND_IM_REPLY_OK 0x00 #define DEFAULT_FONT_NAME_LEN 4 enum @@ -62,15 +64,52 @@ QQ_NORMAL_IM_FILE_EX_NOTIFY_IP = 0x87 }; -typedef struct _qq_im_header qq_im_header; -typedef struct _qq_recv_extended_im_text qq_recv_extended_im_text; +enum { + QQ_RECV_SYS_IM_KICK_OUT = 0x01 +}; -struct _qq_im_header { +typedef struct _qq_recv_im_header qq_recv_im_header; +typedef struct _qq_recv_normal_im_text qq_recv_normal_im_text; +typedef struct _qq_recv_normal_im_common qq_recv_normal_im_common; +typedef struct _qq_recv_normal_im_unprocessed qq_recv_normal_im_unprocessed; + +struct _qq_recv_normal_im_common { /* this is the common part of normal_text */ - guint16 version_from; - guint32 uid_from; - guint32 uid_to; + guint16 sender_ver; + guint32 sender_uid; + guint32 receiver_uid; guint8 session_md5[QQ_KEY_LENGTH]; + guint16 normal_im_type; +}; + +struct _qq_recv_normal_im_text { + qq_recv_normal_im_common *common; + /* now comes the part for text only */ + guint16 msg_seq; + guint32 send_time; + guint16 sender_icon; + guint8 unknown2[3]; + guint8 is_there_font_attr; + guint8 unknown3[4]; + guint8 msg_type; + gchar *msg; /* no fixed length, ends with 0x00 */ + guint8 *font_attr; + gint font_attr_len; +}; + +struct _qq_recv_normal_im_unprocessed { + qq_recv_normal_im_common *common; + /* now comes the part of unprocessed */ + guint8 *unknown; /* no fixed length */ + gint length; +}; + +struct _qq_recv_im_header { + guint32 sender_uid; + guint32 receiver_uid; + guint32 server_im_seq; + struct in_addr sender_ip; + guint16 sender_port; guint16 im_type; }; @@ -143,22 +182,118 @@ return (guint8 *) send_im_tail; } +static const gchar *qq_get_recv_im_type_str(gint type) +{ + switch (type) { + case QQ_RECV_IM_TO_BUDDY: + return "QQ_RECV_IM_TO_BUDDY"; + case QQ_RECV_IM_TO_UNKNOWN: + return "QQ_RECV_IM_TO_UNKNOWN"; + case QQ_RECV_IM_UNKNOWN_QUN_IM: + return "QQ_RECV_IM_UNKNOWN_QUN_IM"; + case QQ_RECV_IM_ADD_TO_QUN: + return "QQ_RECV_IM_ADD_TO_QUN"; + case QQ_RECV_IM_DEL_FROM_QUN: + return "QQ_RECV_IM_DEL_FROM_QUN"; + case QQ_RECV_IM_APPLY_ADD_TO_QUN: + return "QQ_RECV_IM_APPLY_ADD_TO_QUN"; + case QQ_RECV_IM_CREATE_QUN: + return "QQ_RECV_IM_CREATE_QUN"; + case QQ_RECV_IM_SYS_NOTIFICATION: + return "QQ_RECV_IM_SYS_NOTIFICATION"; + case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN: + return "QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN"; + case QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN: + return "QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN"; + case QQ_RECV_IM_TEMP_QUN_IM: + return "QQ_RECV_IM_TEMP_QUN_IM"; + case QQ_RECV_IM_QUN_IM: + return "QQ_RECV_IM_QUN_IM"; + case QQ_RECV_IM_NEWS: + return "QQ_RECV_IM_NEWS"; + case QQ_RECV_IM_FROM_BUDDY_2006: + return "QQ_RECV_IM_FROM_BUDDY_2006"; + case QQ_RECV_IM_FROM_UNKNOWN_2006: + return "QQ_RECV_IM_FROM_UNKNOWN_2006"; + default: + return "QQ_RECV_IM_UNKNOWN"; + } +} + /* read the common parts of the normal_im, * returns the bytes read if succeed, or -1 if there is any error */ -static gint get_im_header(qq_im_header *im_header, guint8 *data, gint len) +static gint normal_im_common_read(guint8 *data, gint len, qq_recv_normal_im_common *common) { gint bytes; - g_return_val_if_fail(data != NULL && len > 0, -1); + g_return_val_if_fail(data != NULL && len != 0 && common != NULL, -1); bytes = 0; - bytes += qq_get16(&(im_header->version_from), data + bytes); - bytes += qq_get32(&(im_header->uid_from), data + bytes); - bytes += qq_get32(&(im_header->uid_to), data + bytes); - bytes += qq_getdata(im_header->session_md5, QQ_KEY_LENGTH, data + bytes); - bytes += qq_get16(&(im_header->im_type), data + bytes); + /* now push data into common header */ + bytes += qq_get16(&(common->sender_ver), data + bytes); + bytes += qq_get32(&(common->sender_uid), data + bytes); + bytes += qq_get32(&(common->receiver_uid), data + bytes); + bytes += qq_getdata(common->session_md5, QQ_KEY_LENGTH, data + bytes); + bytes += qq_get16(&(common->normal_im_type), data + bytes); + + if (bytes != 28) { /* read common place fail */ + purple_debug_error("QQ", "Expect 28 bytes, read %d bytes\n", bytes); + return -1; + } + return bytes; } +static void process_recv_news(guint8 *data, gint data_len, PurpleConnection *gc) +{ + qq_data *qd = (qq_data *) gc->proto_data; + gint bytes; + guint8 *temp; + guint8 temp_len; + gchar *title, *brief, *url; + gchar *title_utf8; + gchar *content, *content_utf8; + + g_return_if_fail(data != NULL && data_len != 0); + +#if 0 + qq_show_packet("Rcv news", data, data_len); +#endif + + temp = g_newa(guint8, data_len); + bytes = 4; /* ignore unknown 4 bytes */ + + bytes += qq_get8(&temp_len, data + bytes); + g_return_if_fail(bytes + temp_len <= data_len); + bytes += qq_getdata(temp, temp_len, data+bytes); + title = g_strndup((gchar *)temp, temp_len); + + bytes += qq_get8(&temp_len, data + bytes); + g_return_if_fail(bytes + temp_len <= data_len); + bytes += qq_getdata(temp, temp_len, data+bytes); + brief = g_strndup((gchar *)temp, temp_len); + + bytes += qq_get8(&temp_len, data + bytes); + g_return_if_fail(bytes + temp_len <= data_len); + bytes += qq_getdata(temp, temp_len, data+bytes); + url = g_strndup((gchar *)temp, temp_len); + + title_utf8 = qq_to_utf8(title, QQ_CHARSET_DEFAULT); + content = g_strdup_printf(_("Server News:\n%s\n%s\n%s"), title, brief, url); + content_utf8 = qq_to_utf8(content, QQ_CHARSET_DEFAULT); + + if (qd->is_show_news) { + qq_got_attention(gc, content_utf8); + } else { + purple_debug_info("QQ", "QQ Server news:\n%s\n%s", title_utf8, content_utf8); + } + g_free(title); + g_free(title_utf8); + g_free(brief); + g_free(url); + g_free(content); + g_free(content_utf8); +} + void qq_got_attention(PurpleConnection *gc, const gchar *msg) { qq_data *qd; @@ -181,316 +316,215 @@ } /* process received normal text IM */ -static void process_im_text(PurpleConnection *gc, guint8 *data, gint len, qq_im_header *im_header) -{ - guint16 purple_msg_type; - gchar *name; - gchar *msg_with_purple_smiley; - gchar *msg_utf8_encoded; - qq_data *qd; - gint bytes = 0; - PurpleBuddy *b; - qq_buddy *qq_b; - - struct { - /* now comes the part for text only */ - guint16 msg_seq; - guint32 send_time; - guint16 sender_icon; - guint8 unknown2[3]; - guint8 is_there_font_attr; - guint8 unknown3[4]; - guint8 msg_type; - gchar *msg; /* no fixed length, ends with 0x00 */ - guint8 *font_attr; - gint font_attr_len; - } im_text; - - g_return_if_fail (data != NULL && len > 0); - g_return_if_fail(im_header != NULL); - - qd = (qq_data *) gc->proto_data; - memset(&im_text, 0, sizeof(im_text)); - - /* push data into im_text */ - bytes += qq_get16(&(im_text.msg_seq), data + bytes); - bytes += qq_get32(&(im_text.send_time), data + bytes); - bytes += qq_get16(&(im_text.sender_icon), data + bytes); - bytes += qq_getdata((guint8 *) & (im_text.unknown2), 3, data + bytes); - bytes += qq_get8(&(im_text.is_there_font_attr), data + bytes); - /** - * from lumaqq for unknown3 - * totalFragments = buf.get() & 255; - * fragmentSequence = buf.get() & 255; - * messageId = buf.getChar(); - */ - bytes += qq_getdata((guint8 *) & (im_text.unknown3), 4, data + bytes); - bytes += qq_get8(&(im_text.msg_type), data + bytes); - - /* we need to check if this is auto-reply - * QQ2003iii build 0304, returns the msg without font_attr - * even the is_there_font_attr shows 0x01, and msg does not ends with 0x00 */ - if (im_text.msg_type == QQ_IM_AUTO_REPLY) { - im_text.is_there_font_attr = 0x00; /* indeed there is no this flag */ - im_text.msg = g_strndup((gchar *)(data + bytes), len - bytes); - } else { /* it is normal mesasge */ - if (im_text.is_there_font_attr) { - im_text.msg = g_strdup((gchar *)(data + bytes)); - bytes += strlen(im_text.msg) + 1; /* length decided by strlen! will it cause a crash? */ - im_text.font_attr_len = len - bytes; - im_text.font_attr = g_memdup(data + bytes, im_text.font_attr_len); - } else /* not im_text.is_there_font_attr */ - im_text.msg = g_strndup((gchar *)(data + bytes), len - bytes); - } /* if im_text.msg_type */ - - name = uid_to_purple_name(im_header->uid_from); - b = purple_find_buddy(gc->account, name); - if (b == NULL) { - qq_create_buddy(gc, im_header->uid_from, FALSE, TRUE); - b = purple_find_buddy(gc->account, name); - } - qq_b = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; - if (qq_b != NULL) { - qq_b->client_tag = im_header->version_from; - } - - purple_msg_type = (im_text.msg_type == QQ_IM_AUTO_REPLY) ? PURPLE_MESSAGE_AUTO_RESP : 0; - - msg_with_purple_smiley = qq_smiley_to_purple(im_text.msg); - msg_utf8_encoded = im_text.is_there_font_attr ? - qq_encode_to_purple(im_text.font_attr, - im_text.font_attr_len, - msg_with_purple_smiley, qd->client_version) - : qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT); - - /* send encoded to purple, note that we use im_text.send_time, - * not the time we receive the message - * as it may have been delayed when I am not online. */ - serv_got_im(gc, name, msg_utf8_encoded, purple_msg_type, (time_t) im_text.send_time); - - g_free(msg_utf8_encoded); - g_free(msg_with_purple_smiley); - g_free(name); - g_free(im_text.msg); - if (im_text.font_attr) g_free(im_text.font_attr); -} - -/* process received extended (2007) text IM */ -static void process_extend_im_text( - PurpleConnection *gc, guint8 *data, gint len, qq_im_header *im_header) +static void process_recv_normal_im_text(guint8 *data, gint len, qq_recv_normal_im_common *common, PurpleConnection *gc) { guint16 purple_msg_type; gchar *name; gchar *msg_with_purple_smiley; gchar *msg_utf8_encoded; qq_data *qd; - gint bytes, text_len; + qq_recv_normal_im_text *im_text; + gint bytes = 0; + PurpleBuddy *b; + qq_buddy *qq_b; + + g_return_if_fail(common != NULL); + qd = (qq_data *) gc->proto_data; - struct { - /* now comes the part for text only */ - guint16 sessionId; - guint32 send_time; - guint16 senderHead; - guint32 flag; - guint8 unknown2[8]; - guint8 fragmentCount; - guint8 fragmentIndex; - guint16 messageId; - guint8 replyType; - gchar *msg; /* no fixed length, ends with 0x00 */ - guint8 fromMobileQQ; - - guint8 is_there_font_attr; - guint8 *font_attr; - gint8 font_attr_len; - } im_text; + /* now it is QQ_NORMAL_IM_TEXT */ + /* + if (*cursor >= (data + len - 1)) { + purple_debug_warning("QQ", "Received normal IM text is empty\n"); + return; + } else + */ + im_text = g_newa(qq_recv_normal_im_text, 1); - g_return_if_fail (data != NULL && len > 0); - g_return_if_fail(im_header != NULL); - - qd = (qq_data *) gc->proto_data; - memset(&im_text, 0, sizeof(im_text)); + im_text->common = common; /* push data into im_text */ - bytes = 0; - bytes += qq_get16(&(im_text.sessionId), data + bytes); - bytes += qq_get32(&(im_text.send_time), data + bytes); - bytes += qq_get16(&(im_text.senderHead), data + bytes); - bytes += qq_get32(&(im_text.flag), data + bytes); - - bytes += qq_getdata(im_text.unknown2, 8, data + bytes); - bytes += qq_get8(&(im_text.fragmentCount), data + bytes); - bytes += qq_get8(&(im_text.fragmentIndex), data + bytes); - - bytes += qq_get16(&(im_text.messageId), data + bytes); - bytes += qq_get8(&(im_text.replyType), data + bytes); - - im_text.font_attr_len = data[len-1] & 0xff; - - text_len = len - bytes - im_text.font_attr_len; - im_text.msg = g_strndup((gchar *)(data + bytes), text_len); - bytes += text_len; - if(im_text.font_attr_len >= 0) - im_text.font_attr = g_memdup(data + bytes, im_text.font_attr_len); - else - { - purple_debug_error("QQ", "Failed to get IM's font attribute len %d\n", - im_text.font_attr_len); - return; + bytes += qq_get16(&(im_text->msg_seq), data + bytes); + bytes += qq_get32(&(im_text->send_time), data + bytes); + bytes += qq_get16(&(im_text->sender_icon), data + bytes); + bytes += qq_getdata((guint8 *) & (im_text->unknown2), 3, data + bytes); + bytes += qq_get8(&(im_text->is_there_font_attr), data + bytes); + /** + * from lumaqq for unknown3 + * totalFragments = buf.get() & 255; + * fragmentSequence = buf.get() & 255; + * messageId = buf.getChar(); + */ + bytes += qq_getdata((guint8 *) & (im_text->unknown3), 4, data + bytes); + bytes += qq_get8(&(im_text->msg_type), data + bytes); + + /* we need to check if this is auto-reply + * QQ2003iii build 0304, returns the msg without font_attr + * even the is_there_font_attr shows 0x01, and msg does not ends with 0x00 */ + if (im_text->msg_type == QQ_IM_AUTO_REPLY) { + im_text->is_there_font_attr = 0x00; /* indeed there is no this flag */ + im_text->msg = g_strndup((gchar *)(data + bytes), len - bytes); + } else { /* it is normal mesasge */ + if (im_text->is_there_font_attr) { + im_text->msg = g_strdup((gchar *)(data + bytes)); + bytes += strlen(im_text->msg) + 1; /* length decided by strlen! will it cause a crash? */ + im_text->font_attr_len = len - bytes; + im_text->font_attr = g_memdup(data + bytes, im_text->font_attr_len); + } else /* not im_text->is_there_font_attr */ + im_text->msg = g_strndup((gchar *)(data + bytes), len - bytes); + } /* if im_text->msg_type */ + + name = uid_to_purple_name(common->sender_uid); + b = purple_find_buddy(gc->account, name); + if (b == NULL) { + qq_create_buddy(gc, common->sender_uid, FALSE, TRUE); + b = purple_find_buddy(gc->account, name); + } + qq_b = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; + if (qq_b != NULL) { + qq_b->client_tag = common->sender_ver; } - if(im_text.fragmentCount == 0) - im_text.fragmentCount = 1; - - // Filter tail space - if(im_text.fragmentIndex == im_text.fragmentCount -1) - { - gint real_len = text_len; - while(real_len > 0 && im_text.msg[real_len - 1] == 0x20) - real_len --; - - text_len = real_len; - // Null string instaed of space - im_text.msg[text_len] = 0; - } - - name = uid_to_purple_name(im_header->uid_from); - if (purple_find_buddy(gc->account, name) == NULL) - qq_create_buddy(gc, im_header->uid_from, FALSE, TRUE); + purple_msg_type = (im_text->msg_type == QQ_IM_AUTO_REPLY) ? PURPLE_MESSAGE_AUTO_RESP : 0; - purple_msg_type = 0; - - msg_with_purple_smiley = qq_smiley_to_purple(im_text.msg); - msg_utf8_encoded = im_text.font_attr ? - qq_encode_to_purple(im_text.font_attr, - im_text.font_attr_len, - msg_with_purple_smiley, qd->client_version) + msg_with_purple_smiley = qq_smiley_to_purple(im_text->msg); + msg_utf8_encoded = im_text->is_there_font_attr ? + qq_encode_to_purple(im_text->font_attr, + im_text->font_attr_len, + msg_with_purple_smiley, qd->client_version) : qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT); - /* send encoded to purple, note that we use im_text.send_time, + /* send encoded to purple, note that we use im_text->send_time, * not the time we receive the message * as it may have been delayed when I am not online. */ - serv_got_im(gc, name, msg_utf8_encoded, purple_msg_type, (time_t) im_text.send_time); + serv_got_im(gc, name, msg_utf8_encoded, purple_msg_type, (time_t) im_text->send_time); g_free(msg_utf8_encoded); g_free(msg_with_purple_smiley); g_free(name); - g_free(im_text.msg); - if (im_text.font_attr) g_free(im_text.font_attr); + g_free(im_text->msg); + if (im_text->is_there_font_attr) + g_free(im_text->font_attr); } /* it is a normal IM, maybe text or video request */ -void qq_process_im(PurpleConnection *gc, guint8 *data, gint len) +static void process_recv_normal_im(guint8 *data, gint len, PurpleConnection *gc) { gint bytes = 0; - qq_im_header im_header; + qq_recv_normal_im_common *common; + qq_recv_normal_im_unprocessed *im_unprocessed; - g_return_if_fail (data != NULL && len > 0); + g_return_if_fail (data != NULL && len != 0); - bytes = get_im_header(&im_header, data, len); + common = g_newa (qq_recv_normal_im_common, 1); + + bytes = normal_im_common_read(data, len, common); if (bytes < 0) { - purple_debug_error("QQ", "Fail read im header, len %d\n", len); - qq_show_packet ("IM Header", data, len); + purple_debug_error("QQ", "Fail read the common part of normal IM\n"); return; } - purple_debug_info("QQ", - "Got IM to %d, type: %02X from: %d ver: %s (%04X)\n", - im_header.uid_to, im_header.im_type, im_header.uid_from, - qq_get_ver_desc(im_header.version_from), im_header.version_from); - switch (im_header.im_type) { + switch (common->normal_im_type) { case QQ_NORMAL_IM_TEXT: + purple_debug_info("QQ", + "Normal IM, text type:\n [%d] => [%d], src: %s (%04X)\n", + common->sender_uid, common->receiver_uid, + qq_get_ver_desc (common->sender_ver), common->sender_ver); if (bytes >= len - 1) { purple_debug_warning("QQ", "Received normal IM text is empty\n"); return; } - process_im_text(gc, data + bytes, len - bytes, &im_header); + process_recv_normal_im_text(data + bytes, len - bytes, common, gc); break; case QQ_NORMAL_IM_FILE_REJECT_UDP: - qq_process_recv_file_reject(data + bytes, len - bytes, im_header.uid_from, gc); + qq_process_recv_file_reject(data + bytes, len - bytes, common->sender_uid, gc); break; case QQ_NORMAL_IM_FILE_APPROVE_UDP: - qq_process_recv_file_accept(data + bytes, len - bytes, im_header.uid_from, gc); + qq_process_recv_file_accept(data + bytes, len - bytes, common->sender_uid, gc); break; case QQ_NORMAL_IM_FILE_REQUEST_UDP: - qq_process_recv_file_request(data + bytes, len - bytes, im_header.uid_from, gc); + qq_process_recv_file_request(data + bytes, len - bytes, common->sender_uid, gc); break; case QQ_NORMAL_IM_FILE_CANCEL: - qq_process_recv_file_cancel(data + bytes, len - bytes, im_header.uid_from, gc); + qq_process_recv_file_cancel(data + bytes, len - bytes, common->sender_uid, gc); break; case QQ_NORMAL_IM_FILE_NOTIFY: - qq_process_recv_file_notify(data + bytes, len - bytes, im_header.uid_from, gc); + qq_process_recv_file_notify(data + bytes, len - bytes, common->sender_uid, gc); break; case QQ_NORMAL_IM_FILE_REQUEST_TCP: /* Check ReceivedFileIM::parseContents in eva*/ /* some client use this function for detect invisable buddy*/ + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_REQUEST_TCP\n"); + qq_show_packet ("Not support", data, len); + break; case QQ_NORMAL_IM_FILE_APPROVE_TCP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_APPROVE_TCP\n"); + qq_show_packet ("Not support", data, len); + break; case QQ_NORMAL_IM_FILE_REJECT_TCP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_REJECT_TCP\n"); + qq_show_packet ("Not support", data, len); + break; case QQ_NORMAL_IM_FILE_PASV: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_PASV\n"); + qq_show_packet ("Not support", data, len); + break; case QQ_NORMAL_IM_FILE_EX_REQUEST_UDP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_REQUEST_TCP\n"); + qq_show_packet ("QQ", data, len); + break; case QQ_NORMAL_IM_FILE_EX_REQUEST_ACCEPT: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_EX_REQUEST_ACCEPT\n"); + qq_show_packet ("QQ", data, len); + break; case QQ_NORMAL_IM_FILE_EX_REQUEST_CANCEL: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_EX_REQUEST_CANCEL\n"); + qq_show_packet ("Not support", data, len); + break; case QQ_NORMAL_IM_FILE_EX_NOTIFY_IP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_EX_NOTIFY_IP\n"); qq_show_packet ("Not support", data, len); break; default: + im_unprocessed = g_newa (qq_recv_normal_im_unprocessed, 1); + im_unprocessed->common = common; + im_unprocessed->unknown = data + bytes; + im_unprocessed->length = len - bytes; /* a simple process here, maybe more later */ - qq_show_packet ("Unknow", data + bytes, len - bytes); + purple_debug_warning("QQ", + "Normal IM, unprocessed type [0x%04x], len %d\n", + common->normal_im_type, im_unprocessed->length); + qq_show_packet ("QQ", im_unprocessed->unknown, im_unprocessed->length); return; } } -/* it is a extended IM, maybe text or video request */ -void qq_process_extend_im(PurpleConnection *gc, guint8 *data, gint len) +/* process im from system administrator */ +static void process_recv_sys_im(guint8 *data, gint data_len, PurpleConnection *gc) { - gint bytes; - qq_im_header im_header; - - g_return_if_fail (data != NULL && len > 0); + gint len; + guint8 reply; + gchar **segments, *msg_utf8; - bytes = get_im_header(&im_header, data, len); - if (bytes < 0) { - purple_debug_error("QQ", "Fail read im header, len %d\n", len); - qq_show_packet ("IM Header", data, len); - return; - } - purple_debug_info("QQ", - "Got Extend IM to %d, type: %02X from: %d ver: %s (%04X)\n", - im_header.uid_to, im_header.im_type, im_header.uid_from, - qq_get_ver_desc(im_header.version_from), im_header.version_from); + g_return_if_fail(data != NULL && data_len != 0); - switch (im_header.im_type) { - case QQ_NORMAL_IM_TEXT: - process_extend_im_text(gc, data + bytes, len - bytes, &im_header); - break; - case QQ_NORMAL_IM_FILE_REJECT_UDP: - qq_process_recv_file_reject (data + bytes, len - bytes, im_header.uid_from, gc); - break; - case QQ_NORMAL_IM_FILE_APPROVE_UDP: - qq_process_recv_file_accept (data + bytes, len - bytes, im_header.uid_from, gc); - break; - case QQ_NORMAL_IM_FILE_REQUEST_UDP: - qq_process_recv_file_request (data + bytes, len - bytes, im_header.uid_from, gc); - break; - case QQ_NORMAL_IM_FILE_CANCEL: - qq_process_recv_file_cancel (data + bytes, len - bytes, im_header.uid_from, gc); - break; - case QQ_NORMAL_IM_FILE_NOTIFY: - qq_process_recv_file_notify (data + bytes, len - bytes, im_header.uid_from, gc); - break; - default: - /* a simple process here, maybe more later */ - qq_show_packet ("Unknow", data + bytes, len - bytes); - break; - } + len = data_len; + + if (NULL == (segments = split_data(data, len, "\x2f", 2))) + return; + + reply = strtol(segments[0], NULL, 10); + if (reply == QQ_RECV_SYS_IM_KICK_OUT) + purple_debug_warning("QQ", "We are kicked out by QQ server\n"); + msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT); + purple_notify_warning(gc, NULL, _("System Message"), msg_utf8); } -/* send an IM to uid_to */ -void qq_request_send_im(PurpleConnection *gc, guint32 uid_to, gchar *msg, gint type) +/* send an IM to to_uid */ +void qq_send_packet_im(PurpleConnection *gc, guint32 to_uid, gchar *msg, gint type) { qq_data *qd; guint8 *raw_data, *send_im_tail; - guint16 im_type; + guint16 normal_im_type; gint msg_len, raw_len, font_name_len, tail_len, bytes; time_t now; gchar *msg_filtered; @@ -500,7 +534,7 @@ const gchar *start, *end, *last; qd = (qq_data *) gc->proto_data; - im_type = QQ_NORMAL_IM_TEXT; + normal_im_type = QQ_NORMAL_IM_TEXT; last = msg; while (purple_markup_find_tag("font", last, &start, &end, &attribs)) { @@ -557,17 +591,17 @@ /* 000-003: receiver uid */ bytes += qq_put32(raw_data + bytes, qd->uid); /* 004-007: sender uid */ - bytes += qq_put32(raw_data + bytes, uid_to); + bytes += qq_put32(raw_data + bytes, to_uid); /* 008-009: sender client version */ bytes += qq_put16(raw_data + bytes, qd->client_tag); /* 010-013: receiver uid */ bytes += qq_put32(raw_data + bytes, qd->uid); /* 014-017: sender uid */ - bytes += qq_put32(raw_data + bytes, uid_to); + bytes += qq_put32(raw_data + bytes, to_uid); /* 018-033: md5 of (uid+session_key) */ bytes += qq_putdata(raw_data + bytes, qd->session_md5, 16); /* 034-035: message type */ - bytes += qq_put16(raw_data + bytes, im_type); + bytes += qq_put16(raw_data + bytes, normal_im_type); /* 036-037: sequence number */ bytes += qq_put16(raw_data + bytes, qd->send_seq); /* 038-041: send time */ @@ -606,5 +640,127 @@ g_free(msg_filtered); } +/* parse the reply to send_im */ +void qq_process_send_im_reply(guint8 *data, gint data_len, PurpleConnection *gc) +{ + qq_data *qd; + g_return_if_fail(data != NULL && data_len != 0); + qd = gc->proto_data; + + if (data[0] != QQ_SEND_IM_REPLY_OK) { + purple_debug_warning("QQ", "Send IM fail\n"); + purple_notify_error(gc, _("Error"), _("Failed to send IM."), NULL); + } else { + purple_debug_info("QQ", "IM ACK OK\n"); + } +} + +/* I receive a message, mainly it is text msg, + * but we need to proess other types (group etc) */ +void qq_process_recv_im(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc) +{ + qq_data *qd; + gint bytes; + qq_recv_im_header *im_header; + + g_return_if_fail(data != NULL && data_len != 0); + + qd = (qq_data *) gc->proto_data; + + if (data_len < 16) { /* we need to ack with the first 16 bytes */ + purple_debug_error("QQ", "MSG is too short\n"); + return; + } else { + /* when we receive a message, + * we send an ACK which is the first 16 bytes of incoming packet */ + qq_send_server_reply(gc, QQ_CMD_RECV_IM, seq, data, 16); + } + + /* check len first */ + if (data_len < 20) { /* length of im_header */ + purple_debug_error("QQ", "Invald MSG header, len %d < 20\n", data_len); + return; + } + + bytes = 0; + im_header = g_newa(qq_recv_im_header, 1); + bytes += qq_get32(&(im_header->sender_uid), data + bytes); + bytes += qq_get32(&(im_header->receiver_uid), data + bytes); + bytes += qq_get32(&(im_header->server_im_seq), data + bytes); + /* if the message is delivered via server, it is server IP/port */ + bytes += qq_getIP(&(im_header->sender_ip), data + bytes); + bytes += qq_get16(&(im_header->sender_port), data + bytes); + bytes += qq_get16(&(im_header->im_type), data + bytes); + /* im_header prepared */ + + if (im_header->receiver_uid != qd->uid) { /* should not happen */ + purple_debug_error("QQ", "MSG to [%d], NOT me\n", im_header->receiver_uid); + return; + } + + /* check bytes */ + if (bytes >= data_len - 1) { + purple_debug_warning("QQ", "Empty MSG\n"); + return; + } + + switch (im_header->im_type) { + case QQ_RECV_IM_NEWS: + process_recv_news(data + bytes, data_len - bytes, gc); + break; + case QQ_RECV_IM_FROM_BUDDY_2006: + case QQ_RECV_IM_FROM_UNKNOWN_2006: + case QQ_RECV_IM_TO_UNKNOWN: + case QQ_RECV_IM_TO_BUDDY: + purple_debug_info("QQ", "MSG from buddy [%d]\n", im_header->sender_uid); + process_recv_normal_im(data + bytes, data_len - bytes, gc); + break; + case QQ_RECV_IM_UNKNOWN_QUN_IM: + case QQ_RECV_IM_TEMP_QUN_IM: + case QQ_RECV_IM_QUN_IM: + purple_debug_info("QQ", "MSG from room [%d]\n", im_header->sender_uid); + /* sender_uid is in fact id */ + qq_process_room_msg_normal(data + bytes, data_len - bytes, im_header->sender_uid, gc, im_header->im_type); + break; + case QQ_RECV_IM_ADD_TO_QUN: + purple_debug_info("QQ", "Notice from [%d], Added\n", im_header->sender_uid); + /* sender_uid is group id + * we need this to create a dummy group and add to blist */ + qq_process_room_msg_been_added(data + bytes, data_len - bytes, im_header->sender_uid, gc); + break; + case QQ_RECV_IM_DEL_FROM_QUN: + purple_debug_info("QQ", "Notice from room [%d], Removed\n", im_header->sender_uid); + /* sender_uid is group id */ + qq_process_room_msg_been_removed(data + bytes, data_len - bytes, im_header->sender_uid, gc); + break; + case QQ_RECV_IM_APPLY_ADD_TO_QUN: + purple_debug_info("QQ", "Notice from room [%d], Joined\n", im_header->sender_uid); + /* sender_uid is group id */ + qq_process_room_msg_apply_join(data + bytes, data_len - bytes, im_header->sender_uid, gc); + break; + case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN: + purple_debug_info("QQ", "Notice from room [%d], Confirm add in\n", + im_header->sender_uid); + /* sender_uid is group id */ + qq_process_room_msg_been_approved(data + bytes, data_len - bytes, im_header->sender_uid, gc); + break; + case QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN: + purple_debug_info("QQ", "Notice from room [%d], Refuse add in\n", + im_header->sender_uid); + /* sender_uid is group id */ + qq_process_room_msg_been_rejected(data + bytes, data_len - bytes, im_header->sender_uid, gc); + break; + case QQ_RECV_IM_SYS_NOTIFICATION: + purple_debug_info("QQ", "Admin notice from [%d]\n", im_header->sender_uid); + process_recv_sys_im(data + bytes, data_len - bytes, gc); + break; + default: + purple_debug_warning("QQ", "MSG from [%d], unknown type %s [0x%02x]\n", + im_header->sender_uid, qq_get_recv_im_type_str(im_header->im_type), + im_header->im_type); + qq_show_packet("Unknown MSG type", data, data_len); + } +} + diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/im.h --- a/libpurple/protocols/qq/im.h Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/im.h Wed Oct 22 14:49:38 2008 +0000 @@ -39,22 +39,21 @@ }; enum { - QQ_MSG_TO_BUDDY = 0x0009, - QQ_MSG_TO_UNKNOWN = 0x000a, - QQ_MSG_NEWS = 0x0018, - QQ_MSG_UNKNOWN_QUN_IM = 0x0020, - QQ_MSG_ADD_TO_QUN = 0x0021, - QQ_MSG_DEL_FROM_QUN = 0x0022, - QQ_MSG_APPLY_ADD_TO_QUN = 0x0023, - QQ_MSG_APPROVE_APPLY_ADD_TO_QUN = 0x0024, - QQ_MSG_REJCT_APPLY_ADD_TO_QUN = 0x0025, - QQ_MSG_CREATE_QUN = 0x0026, - QQ_MSG_TEMP_QUN_IM = 0x002A, - QQ_MSG_QUN_IM = 0x002B, - QQ_MSG_SYS_30 = 0x0030, - QQ_MSG_SYS_4C = 0x004C, - QQ_MSG_EXTEND = 0x0084, - QQ_MSG_EXTEND_85 = 0x0085, + QQ_RECV_IM_TO_BUDDY = 0x0009, + QQ_RECV_IM_TO_UNKNOWN = 0x000a, + QQ_RECV_IM_NEWS = 0x0018, + QQ_RECV_IM_UNKNOWN_QUN_IM = 0x0020, + QQ_RECV_IM_ADD_TO_QUN = 0x0021, + QQ_RECV_IM_DEL_FROM_QUN = 0x0022, + QQ_RECV_IM_APPLY_ADD_TO_QUN = 0x0023, + QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN = 0x0024, + QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN = 0x0025, + QQ_RECV_IM_CREATE_QUN = 0x0026, + QQ_RECV_IM_TEMP_QUN_IM = 0x002A, + QQ_RECV_IM_QUN_IM = 0x002B, + QQ_RECV_IM_SYS_NOTIFICATION = 0x0030, + QQ_RECV_IM_FROM_BUDDY_2006 = 0x0084, + QQ_RECV_IM_FROM_UNKNOWN_2006 = 0x0085, }; void qq_got_attention(PurpleConnection *gc, const gchar *msg); @@ -64,8 +63,8 @@ const gchar *font_name, gboolean is_bold, gboolean is_italic, gboolean is_underline, gint len); -void qq_request_send_im(PurpleConnection *gc, guint32 uid_to, gchar *msg, gint type); +void qq_send_packet_im(PurpleConnection *gc, guint32 to_uid, gchar *msg, gint type); +void qq_process_recv_im(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc); +void qq_process_send_im_reply(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_process_im(PurpleConnection *gc, guint8 *data, gint len); -void qq_process_extend_im(PurpleConnection *gc, guint8 *data, gint len); #endif diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/packet_parse.c --- a/libpurple/protocols/qq/packet_parse.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/packet_parse.c Wed Oct 22 14:49:38 2008 +0000 @@ -151,7 +151,10 @@ * return the number of bytes packed, otherwise return -1 */ gint qq_put32(guint8 *buf, guint32 dw) { - guint32 dw_porter; + guint32 dw_dest; + memcpy(&dw_dest, buf, sizeof(dw_dest)); + + guint32 dw_porter; dw_porter = g_htonl(dw); #ifdef PARSER_DEBUG purple_debug_info("QQ", "[DBG][put32] buf %p\n", (void *)buf); diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/qq.c --- a/libpurple/protocols/qq/qq.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/qq.c Wed Oct 22 14:49:38 2008 +0000 @@ -435,7 +435,7 @@ /* send an instant msg to a buddy */ static gint qq_send_im(PurpleConnection *gc, const gchar *who, const gchar *message, PurpleMessageFlags flags) { - gint type, uid_to; + gint type, to_uid; gchar *msg, *msg_with_qq_smiley; qq_data *qd; @@ -446,15 +446,15 @@ g_return_val_if_fail(strlen(message) <= QQ_MSG_IM_MAX, -E2BIG); type = (flags == PURPLE_MESSAGE_AUTO_RESP ? QQ_IM_AUTO_REPLY : QQ_IM_TEXT); - uid_to = purple_name_to_uid(who); + to_uid = purple_name_to_uid(who); /* if msg is to myself, bypass the network */ - if (uid_to == qd->uid) { + if (to_uid == qd->uid) { serv_got_im(gc, who, message, flags, time(NULL)); } else { msg = utf8_to_qq(message, QQ_CHARSET_DEFAULT); msg_with_qq_smiley = purple_smiley_to_qq(msg); - qq_request_send_im(gc, uid_to, msg_with_qq_smiley, type); + qq_send_packet_im(gc, to_uid, msg_with_qq_smiley, type); g_free(msg); g_free(msg_with_qq_smiley); } diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/qq_base.c --- a/libpurple/protocols/qq/qq_base.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.c Wed Oct 22 14:49:38 2008 +0000 @@ -66,7 +66,7 @@ struct tm *tm_local; qd = (qq_data *) gc->proto_data; - /* qq_show_packet("Login reply", data, len); */ + qq_show_packet("Login reply", data, len); if (len < 139) { purple_connection_error_reason(gc, @@ -665,7 +665,7 @@ qd->redirect_len = data_len; qd->redirect = g_realloc(qd->redirect, qd->redirect_len); qq_getdata(qd->redirect, qd->redirect_len, data); - /* qq_show_packet("Redirect to", qd->redirect, qd->redirect_len); */ + qq_show_packet("Redirect to", qd->redirect, qd->redirect_len); qq_getIP(&qd->redirect_ip, data + 11); purple_debug_info("QQ", "Get server %s\n", inet_ntoa(qd->redirect_ip)); @@ -912,7 +912,7 @@ bytes += qq_get16(&(qd->ld.token_ex_len), data + bytes); qd->ld.token_ex = g_realloc(qd->ld.token_ex, qd->ld.token_ex_len); bytes += qq_getdata(qd->ld.token_ex, qd->ld.token_ex_len, data + bytes); - /* qq_show_packet("Get token ex", qd->ld.token_ex, qd->ld.token_ex_len); */ + qq_show_packet("Get token ex", qd->ld.token_ex, qd->ld.token_ex_len); if(reply != 1) { @@ -932,7 +932,7 @@ bytes += qq_get16(&qd->captcha.token_len, data + bytes); qd->captcha.token = g_realloc(qd->captcha.token, qd->captcha.token_len); bytes += qq_getdata(qd->captcha.token, qd->captcha.token_len, data + bytes); - /* qq_show_packet("Get captcha token", qd->captcha.token, qd->captcha.token_len); */ + qq_show_packet("Get captcha token", qd->captcha.token, qd->captcha.token_len); purple_debug_info("QQ", "Request next captcha %d, new %d, total %d\n", qd->captcha.next_index, captcha_len, qd->captcha.data_len); @@ -1038,7 +1038,7 @@ bytes += qq_put8(raw_data + bytes, qd->ld.pwd_md5[1]); bytes += qq_put8(raw_data + bytes, qd->ld.pwd_md5[2]); - /* qq_show_packet("Check password", raw_data, bytes); */ + qq_show_packet("Check password", raw_data, bytes); /* Encrypted by random key*/ encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key); @@ -1068,7 +1068,7 @@ g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR); qd = (qq_data *) gc->proto_data; - /* qq_show_packet("Check password reply", data, data_len); */ + qq_show_packet("Check password reply", data, data_len); bytes = 0; bytes += qq_get16(&unknow_token_len, data + bytes); /* maybe total length */ @@ -1086,11 +1086,10 @@ if (qd->ld.login_token != NULL) g_free(qd->ld.login_token); qd->ld.login_token = g_new0(guint8, qd->ld.login_token_len); bytes += qq_getdata(qd->ld.login_token, qd->ld.login_token_len, data + bytes); - /* qq_show_packet("Get login token", qd->ld.login_token, qd->ld.login_token_len); */ - + qq_show_packet("Get login token", qd->ld.login_token, qd->ld.login_token_len); /* get login_key */ bytes += qq_getdata(qd->ld.login_key, sizeof(qd->ld.login_key), data + bytes); - /* qq_show_packet("Get login key", qd->ld.login_key, sizeof(qd->ld.login_key)); */ + qq_show_packet("Get login key", qd->ld.login_key, sizeof(qd->ld.login_key)); return QQ_LOGIN_REPLY_OK; } @@ -1203,7 +1202,7 @@ memset(raw_data + bytes, 0, 10); bytes += 10; /* redirect data, 15 bytes */ - /* qq_show_packet("Redirect", qd->redirect, qd->redirect_len); */ + qq_show_packet("Redirect", qd->redirect, qd->redirect_len); bytes += qq_putdata(raw_data + bytes, qd->redirect, qd->redirect_len); /* unknow fill */ bytes += qq_putdata(raw_data + bytes, login_2_16, sizeof(login_2_16)); @@ -1215,7 +1214,7 @@ memset(raw_data + bytes, 0, 332 - sizeof(login_3_83)); bytes += 332 - sizeof(login_3_83); - /* qq_show_packet("Login", raw_data, bytes); */ + qq_show_packet("Login", raw_data, bytes); encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.login_key); @@ -1243,24 +1242,27 @@ gchar *msg_utf8; g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR); + purple_debug_info("QQ", "FN_base, GO\n"); qd = (qq_data *) gc->proto_data; bytes = 0; bytes += qq_get8(&ret, data + bytes); if (ret != 0) { + purple_debug_info("QQ", "FN_base, RET!=0\n"); msg = g_strndup((gchar *)data + bytes, data_len - bytes); msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); + purple_debug_info("QQ", "FN_base, SW RET now\n"); switch (ret) { case 0x05: + purple_debug_info("QQ", "FN_base, RET:0x%02x\n", ret); error = g_strdup_printf( - _("Server is busy now (0x%02X), Please try later\n%s"), - ret, msg_utf8); + _("Server is busy now, Please try later\n%s"), + msg_utf8); break; case 0x0A: /* 0a 2d 9a 4b 9a 01 01 00 00 00 05 00 00 00 00 79 0e 5f fd */ - /* Missing get server before login*/ default: error = g_strdup_printf( _("Unknow reply code when login (0x%02X):\n%s"), @@ -1410,7 +1412,7 @@ memset(raw_data + bytes, 0, 249); bytes += 249; - /* qq_show_packet("Login request", raw_data, bytes); */ + qq_show_packet("Login request", raw_data, bytes); encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.login_key); buf = g_newa(guint8, MAX_PACKET_SIZE); @@ -1448,8 +1450,8 @@ switch (ret) { case 0x05: error = g_strdup_printf( - _("Server is busy now (0x%02X), Please try later\n%s"), - ret, msg_utf8); + _("Server is busy now, Please try later\n%s"), + msg_utf8); break; default: error = g_strdup_printf( diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/qq_process.c --- a/libpurple/protocols/qq/qq_process.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.c Wed Oct 22 14:49:38 2008 +0000 @@ -58,7 +58,7 @@ }; /* default process, decrypt and dump */ -static void process_unknow_cmd(PurpleConnection *gc,const gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq) +static void process_cmd_unknow(PurpleConnection *gc,const gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq) { qq_data *qd; gchar *msg_utf8 = NULL; @@ -81,285 +81,8 @@ } } -/* parse the reply to send_im */ -static void do_im_ack(guint8 *data, gint data_len, PurpleConnection *gc) -{ - qq_data *qd; - - g_return_if_fail(data != NULL && data_len != 0); - - qd = gc->proto_data; - - if (data[0] != 0) { - purple_debug_warning("QQ", "Failed sent IM\n"); - purple_notify_error(gc, _("Error"), _("Failed to send IM."), NULL); - return; - } - - purple_debug_info("QQ", "OK sent IM\n"); -} - -static void do_server_news(guint8 *data, gint data_len, PurpleConnection *gc) -{ - qq_data *qd = (qq_data *) gc->proto_data; - gint bytes; - guint8 *temp; - guint8 temp_len; - gchar *title, *brief, *url; - gchar *title_utf8; - gchar *content, *content_utf8; - - g_return_if_fail(data != NULL && data_len != 0); - - /* qq_show_packet("Rcv news", data, data_len); */ - - temp = g_newa(guint8, data_len); - bytes = 4; /* ignore unknown 4 bytes */ - - bytes += qq_get8(&temp_len, data + bytes); - g_return_if_fail(bytes + temp_len <= data_len); - bytes += qq_getdata(temp, temp_len, data+bytes); - title = g_strndup((gchar *)temp, temp_len); - - bytes += qq_get8(&temp_len, data + bytes); - g_return_if_fail(bytes + temp_len <= data_len); - bytes += qq_getdata(temp, temp_len, data+bytes); - brief = g_strndup((gchar *)temp, temp_len); - - bytes += qq_get8(&temp_len, data + bytes); - g_return_if_fail(bytes + temp_len <= data_len); - bytes += qq_getdata(temp, temp_len, data+bytes); - url = g_strndup((gchar *)temp, temp_len); - - title_utf8 = qq_to_utf8(title, QQ_CHARSET_DEFAULT); - content = g_strdup_printf(_("Server News:\n%s\n%s\n%s"), title, brief, url); - content_utf8 = qq_to_utf8(content, QQ_CHARSET_DEFAULT); - - if (qd->is_show_news) { - qq_got_attention(gc, content_utf8); - } else { - purple_debug_info("QQ", "QQ Server news:\n%s\n%s", title_utf8, content_utf8); - } - g_free(title); - g_free(title_utf8); - g_free(brief); - g_free(url); - g_free(content); - g_free(content_utf8); -} - -static void do_msg_sys_30(PurpleConnection *gc, guint8 *data, gint data_len) -{ - gint len; - guint8 reply; - gchar **segments, *msg_utf8; - - g_return_if_fail(data != NULL && data_len != 0); - - len = data_len; - - if (NULL == (segments = split_data(data, len, "\x2f", 2))) - return; - - reply = strtol(segments[0], NULL, 10); - if (reply == 1) - purple_debug_warning("QQ", "We are kicked out by QQ server\n"); - - msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT); - qq_got_attention(gc, msg_utf8); -} - -static void do_msg_sys_4c(PurpleConnection *gc, guint8 *data, gint data_len) -{ - gint bytes; - gint msg_len; - GString *content; - gchar *msg = NULL; - - g_return_if_fail(data != NULL && data_len > 0); - - bytes = 6; /* skip 0x(06 00 01 1e 01 1c)*/ - - content = g_string_new(""); - while (bytes < data_len) { - msg_len = qq_get_vstr(&msg, QQ_CHARSET_DEFAULT, data + bytes); - g_string_append(content, msg); - g_string_append(content, "\n"); - g_free(msg); - - if (msg_len <= 1) { - break; - } - bytes += msg_len; - } - if (bytes != data_len) { - purple_debug_warning("QQ", "Failed to read QQ_MSG_SYS_4C\n"); - qq_show_packet("do_msg_sys_4c", data, data_len); - } - qq_got_attention(gc, content->str); - g_string_free(content, FALSE); -} - -static const gchar *get_im_type_desc(gint type) -{ - switch (type) { - case QQ_MSG_TO_BUDDY: - return "QQ_MSG_TO_BUDDY"; - case QQ_MSG_TO_UNKNOWN: - return "QQ_MSG_TO_UNKNOWN"; - case QQ_MSG_UNKNOWN_QUN_IM: - return "QQ_MSG_UNKNOWN_QUN_IM"; - case QQ_MSG_ADD_TO_QUN: - return "QQ_MSG_ADD_TO_QUN"; - case QQ_MSG_DEL_FROM_QUN: - return "QQ_MSG_DEL_FROM_QUN"; - case QQ_MSG_APPLY_ADD_TO_QUN: - return "QQ_MSG_APPLY_ADD_TO_QUN"; - case QQ_MSG_CREATE_QUN: - return "QQ_MSG_CREATE_QUN"; - case QQ_MSG_SYS_30: - return "QQ_MSG_SYS_30"; - case QQ_MSG_SYS_4C: - return "QQ_MSG_SYS_4C"; - case QQ_MSG_APPROVE_APPLY_ADD_TO_QUN: - return "QQ_MSG_APPROVE_APPLY_ADD_TO_QUN"; - case QQ_MSG_REJCT_APPLY_ADD_TO_QUN: - return "QQ_MSG_REJCT_APPLY_ADD_TO_QUN"; - case QQ_MSG_TEMP_QUN_IM: - return "QQ_MSG_TEMP_QUN_IM"; - case QQ_MSG_QUN_IM: - return "QQ_MSG_QUN_IM"; - case QQ_MSG_NEWS: - return "QQ_MSG_NEWS"; - case QQ_MSG_EXTEND: - return "QQ_MSG_EXTEND"; - case QQ_MSG_EXTEND_85: - return "QQ_MSG_EXTEND_85"; - default: - return "QQ_MSG_UNKNOWN"; - } -} - -/* I receive a message, mainly it is text msg, - * but we need to proess other types (group etc) */ -static void process_private_msg(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc) -{ - qq_data *qd; - gint bytes; - - struct { - guint32 uid_from; - guint32 uid_to; - guint32 seq; - struct in_addr ip_from; - guint16 port_from; - guint16 msg_type; - } header; - - g_return_if_fail(data != NULL && data_len != 0); - - qd = (qq_data *) gc->proto_data; - - if (data_len < 16) { /* we need to ack with the first 16 bytes */ - purple_debug_error("QQ", "MSG is too short\n"); - return; - } else { - /* when we receive a message, - * we send an ACK which is the first 16 bytes of incoming packet */ - qq_send_server_reply(gc, QQ_CMD_RECV_IM, seq, data, 16); - } - - /* check len first */ - if (data_len < 20) { /* length of im_header */ - purple_debug_error("QQ", "Invald MSG header, len %d < 20\n", data_len); - return; - } - - bytes = 0; - bytes += qq_get32(&(header.uid_from), data + bytes); - bytes += qq_get32(&(header.uid_to), data + bytes); - bytes += qq_get32(&(header.seq), data + bytes); - /* if the message is delivered via server, it is server IP/port */ - bytes += qq_getIP(&(header.ip_from), data + bytes); - bytes += qq_get16(&(header.port_from), data + bytes); - bytes += qq_get16(&(header.msg_type), data + bytes); - /* im_header prepared */ - - if (header.uid_to != qd->uid) { /* should not happen */ - purple_debug_error("QQ", "MSG to [%d], NOT me\n", header.uid_to); - return; - } - - /* check bytes */ - if (bytes >= data_len - 1) { - purple_debug_warning("QQ", "Empty MSG\n"); - return; - } - - switch (header.msg_type) { - case QQ_MSG_NEWS: - do_server_news(data + bytes, data_len - bytes, gc); - break; - case QQ_MSG_EXTEND: - case QQ_MSG_EXTEND_85: - purple_debug_info("QQ", "MSG from buddy [%d]\n", header.uid_from); - qq_process_extend_im(gc, data + bytes, data_len - bytes); - break; - case QQ_MSG_TO_UNKNOWN: - case QQ_MSG_TO_BUDDY: - purple_debug_info("QQ", "MSG from buddy [%d]\n", header.uid_from); - qq_process_im(gc, data + bytes, data_len - bytes); - break; - case QQ_MSG_UNKNOWN_QUN_IM: - case QQ_MSG_TEMP_QUN_IM: - case QQ_MSG_QUN_IM: - purple_debug_info("QQ", "MSG from room [%d]\n", header.uid_from); - qq_process_room_msg_normal(data + bytes, data_len - bytes, header.uid_from, gc, header.msg_type); - break; - case QQ_MSG_ADD_TO_QUN: - purple_debug_info("QQ", "Notice from [%d], Added\n", header.uid_from); - /* uid_from is group id - * we need this to create a dummy group and add to blist */ - qq_process_room_msg_been_added(data + bytes, data_len - bytes, header.uid_from, gc); - break; - case QQ_MSG_DEL_FROM_QUN: - purple_debug_info("QQ", "Notice from room [%d], Removed\n", header.uid_from); - /* uid_from is group id */ - qq_process_room_msg_been_removed(data + bytes, data_len - bytes, header.uid_from, gc); - break; - case QQ_MSG_APPLY_ADD_TO_QUN: - purple_debug_info("QQ", "Notice from room [%d], Joined\n", header.uid_from); - /* uid_from is group id */ - qq_process_room_msg_apply_join(data + bytes, data_len - bytes, header.uid_from, gc); - break; - case QQ_MSG_APPROVE_APPLY_ADD_TO_QUN: - purple_debug_info("QQ", "Notice from room [%d], Confirm add in\n", - header.uid_from); - /* uid_from is group id */ - qq_process_room_msg_been_approved(data + bytes, data_len - bytes, header.uid_from, gc); - break; - case QQ_MSG_REJCT_APPLY_ADD_TO_QUN: - purple_debug_info("QQ", "Notice from room [%d], Refuse add in\n", - header.uid_from); - /* uid_from is group id */ - qq_process_room_msg_been_rejected(data + bytes, data_len - bytes, header.uid_from, gc); - break; - case QQ_MSG_SYS_30: - do_msg_sys_30(gc, data + bytes, data_len - bytes); - break; - case QQ_MSG_SYS_4C: - do_msg_sys_4c(gc, data + bytes, data_len - bytes); - break; - default: - purple_debug_warning("QQ", "MSG from [%d], unknown type %s [0x%04X]\n", - header.uid_from, get_im_type_desc(header.msg_type), header.msg_type); - qq_show_packet("Unknown MSG type", data, data_len); - break; - } -} - /* Send ACK if the sys message needs an ACK */ -static void request_server_ack(PurpleConnection *gc, guint8 code, guint32 from, guint16 seq) +static void ack_server_msg(PurpleConnection *gc, guint8 code, guint32 from, guint16 seq) { qq_data *qd; guint8 bar, *ack; @@ -389,7 +112,7 @@ "Fail creating sys msg ACK, expect %d bytes, build %d bytes\n", ack_len, bytes); } -static void do_server_notice(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) +static void process_server_notice(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) { qq_data *qd = (qq_data *) gc->proto_data; gchar *title, *content; @@ -425,7 +148,7 @@ to = segments[2]; msg = segments[3]; - request_server_ack(gc, code[0], strtol(from, NULL, 10), seq); + ack_server_msg(gc, code[0], strtol(from, NULL, 10), seq); if (strtol(to, NULL, 10) != qd->uid) { /* not to me */ purple_debug_error("QQ", "Recv sys msg to [%s], not me!, discard\n", to); @@ -450,7 +173,7 @@ qq_process_buddy_from_server(gc, funct, from, to, msg_utf8); break; case QQ_SERVER_NOTICE: - do_server_notice(gc, from, to, msg_utf8); + process_server_notice(gc, from, to, msg_utf8); break; case QQ_SERVER_NEW_CLIENT: purple_debug_warning("QQ", "QQ Server has newer client version\n"); @@ -493,7 +216,7 @@ /* now process the packet */ switch (cmd) { case QQ_CMD_RECV_IM: - process_private_msg(data, data_len, seq, gc); + qq_process_recv_im(data, data_len, seq, gc); break; case QQ_CMD_RECV_MSG_SYS: process_server_msg(data, data_len, seq, gc); @@ -502,7 +225,7 @@ qq_process_buddy_change_status(data, data_len, gc); break; default: - process_unknow_cmd(gc, _("Unknow SERVER CMD"), data, data_len, cmd, seq); + process_cmd_unknow(gc, _("Unknow SERVER CMD"), data, data_len, cmd, seq); break; } } @@ -898,16 +621,25 @@ case QQ_CMD_LOGIN: default: if (qd->client_version >= 2007) { + purple_debug_warning("QQ", "Decrypt login packet by pwd_twice_md5\n"); data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.pwd_twice_md5); + if (data_len >= 0) { - purple_debug_warning("QQ", "Decrypt login packet by pwd_twice_md5\n"); - } else { + purple_debug_warning("QQ", "Dpwd_twice_md5 *OK*\n"); + } + else { + purple_debug_warning("QQ", "Dpwd_twice_md5 *FAILED*, try login_key, last data_len=%d\n", data_len); data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.login_key); + if (data_len >= 0) { - purple_debug_warning("QQ", "Decrypt login packet by login_key\n"); + purple_debug_warning("QQ", "Dlogin_key *OK*\n"); + } + else { + purple_debug_warning("QQ", "Dlogin_key *FAILED*\n"); } } - } else { + } + else { /* May use password_twice_md5 in the past version like QQ2005 */ data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.random_key); if (data_len >= 0) { @@ -933,6 +665,7 @@ return QQ_LOGIN_REPLY_ERR; } + purple_debug_warning("QQ", "we are processing: 0x%02x\n", cmd); switch (cmd) { case QQ_CMD_GET_SERVER: ret_8 = qq_process_get_server(gc, data, data_len); @@ -958,7 +691,7 @@ case QQ_CMD_CHECK_PWD: ret_8 = qq_process_check_pwd(gc, data, data_len); if (ret_8 != QQ_LOGIN_REPLY_OK) { - return ret_8; + return ret_8; } if (qd->client_version == 2008) { qq_request_login_2008(gc); @@ -975,7 +708,7 @@ ret_8 = qq_process_login(gc, data, data_len); } if (ret_8 != QQ_LOGIN_REPLY_OK) { - return ret_8; + return ret_8; } purple_connection_update_progress(gc, _("Logined"), QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS); @@ -992,7 +725,8 @@ qq_update_all(gc, 0); break; default: - process_unknow_cmd(gc, _("Unknow LOGIN CMD"), data, data_len, cmd, seq); + purple_debug_warning("QQ", "UNKNOWN LOGIN CMD: %d\n", cmd); + process_cmd_unknow(gc, _("Unknow LOGIN CMD"), data, data_len, cmd, seq); return QQ_LOGIN_REPLY_ERR; } return QQ_LOGIN_REPLY_OK; @@ -1056,7 +790,7 @@ qq_process_change_status_reply(data, data_len, gc); break; case QQ_CMD_SEND_IM: - do_im_ack(data, data_len, gc); + qq_process_send_im_reply(data, data_len, gc); break; case QQ_CMD_KEEP_ALIVE: if (qd->client_version >= 2008) { @@ -1099,7 +833,7 @@ purple_debug_info("QQ", "All buddies and groups received\n"); break; default: - process_unknow_cmd(gc, _("Unknow CLIENT CMD"), data, data_len, cmd, seq); + process_cmd_unknow(gc, _("Unknow CLIENT CMD"), data, data_len, cmd, seq); is_unknow = TRUE; break; } diff -r a95c7e71064c -r ec3f7d3e0445 libpurple/protocols/qq/utils.c --- a/libpurple/protocols/qq/utils.c Wed Oct 22 14:48:46 2008 +0000 +++ b/libpurple/protocols/qq/utils.c Wed Oct 22 14:49:38 2008 +0000 @@ -104,7 +104,7 @@ { guint8 *input; gchar **segments; - gint count, j; + gint i, j; g_return_val_if_fail(data != NULL && len != 0 && delimit != 0, NULL); @@ -118,18 +118,22 @@ if (expected_fields <= 0) return segments; - for (count = 0; segments[count] != NULL; count++) {; + for (i = 0; segments[i] != NULL; i++) {; } - if (count < expected_fields) { /* not enough fields */ - purple_debug_error("QQ", "Less fields %d then %d\n", count, expected_fields); + if (i < expected_fields) { /* not enough fields */ + purple_debug_error("QQ", "Invalid data, expect %d fields, found only %d, discard\n", + expected_fields, i); + g_strfreev(segments); return NULL; - } else if (count > expected_fields) { /* more fields, OK */ - purple_debug_warning("QQ", "More fields %d than %d\n", count, expected_fields); + } else if (i > expected_fields) { /* more fields, OK */ + purple_debug_warning("QQ", "Dangerous data, expect %d fields, found %d, return all\n", + expected_fields, i); /* free up those not used */ - for (j = expected_fields; j < count; j++) { + for (j = expected_fields; j < i; j++) { purple_debug_warning("QQ", "field[%d] is %s\n", j, segments[j]); g_free(segments[j]); } + segments[expected_fields] = NULL; } @@ -193,7 +197,7 @@ g_return_val_if_fail(start != NULL, NULL); end = strchr(start, ')'); g_return_val_if_fail(end != NULL && (end - start) > 1, NULL); - + ret = g_strndup(start + 1, end - start - 1); return ret;