# HG changeset patch # User SHiNE CsyFeK # Date 1221447663 0 # Node ID 23cec4360d4ae237505a502fdceea701d72a2347 # Parent 967344bc404d3440c471565e64cafa8e501c9fc3 applied changes from 8cebefbc6cd5d84acb69c74e69e8821f11dd225d through 92d52eef2994d2697999177804e3665989cfa352 Reapplied 92d52eef2994d2697999177804e3665989cfa352 at the right time. 2008.09.02 - ccpaging * Bugfix: can not send message to the QUN blocked adding * Tickets: Fixes #6957 Fixes #6990 2008.09.02 - ccpaging * Use new tactics of information update: 1. send next package till the previous package received 2. fix duplicated get_room_info and get_room_buddies command committer: Daniel Atallah diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/buddy_info.c --- a/libpurple/protocols/qq/buddy_info.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.c Mon Sep 15 03:01:03 2008 +0000 @@ -284,7 +284,7 @@ qd = (qq_data *) gc->proto_data; g_snprintf(uid_str, sizeof(uid_str), "%d", uid); - qq_send_cmd(gc, QQ_CMD_GET_USER_INFO, (guint8 *) uid_str, strlen(uid_str)); + qq_send_cmd(gc, QQ_CMD_GET_BUDDY_INFO, (guint8 *) uid_str, strlen(uid_str)); query = g_new0(qq_info_query, 1); query->uid = uid; @@ -303,7 +303,7 @@ qd = (qq_data *) gc->proto_data; g_snprintf(raw_data, sizeof(raw_data), "%d", uid); - qq_send_cmd_mess(gc, QQ_CMD_GET_USER_INFO, (guint8 *) raw_data, strlen(raw_data), + qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDY_INFO, (guint8 *) raw_data, strlen(raw_data), update_class, ship32); } @@ -690,9 +690,9 @@ mid->info->qq_show = g_strdup(info->qq_show); mid->info->unknown6 = g_strdup(info->unknown6); - purple_request_fields(gc, _("Modify my information"), - _("Modify my information"), NULL, fields, - _("Update my information"), G_CALLBACK(modify_info_ok_cb), + purple_request_fields(gc, _("Modify information"), + _("Modify information"), NULL, fields, + _("Update information"), G_CALLBACK(modify_info_ok_cb), _("Cancel"), G_CALLBACK(modify_info_cancel_cb), purple_connection_get_account(gc), NULL, NULL, mid); @@ -759,8 +759,8 @@ const gchar *buddy_icon_dir = qq_buddy_icon_dir(); gint prefix_len = strlen(QQ_ICON_PREFIX); gint suffix_len = strlen(QQ_ICON_SUFFIX); - gint dir_len = strlen(buddy_icon_dir); - gchar *errmsg = g_strdup_printf(_("Setting custom faces is not currently supported. Please choose an image from %s."), buddy_icon_dir); + gint dir_len = buddy_icon_dir ? strlen(buddy_icon_dir) : 0; + gchar *errmsg = g_strdup_printf(_("Setting custom faces is not currently supported. Please choose an image from %s."), buddy_icon_dir ? buddy_icon_dir : "(null)"); gboolean icon_global = purple_account_get_bool(gc->account, "use-global-buddyicon", TRUE); if (!icon_path) @@ -769,7 +769,7 @@ icon_len = strlen(icon_path) - dir_len - 1 - prefix_len - suffix_len; /* make sure we're using an appropriate icon */ - if (!(g_ascii_strncasecmp(icon_path, buddy_icon_dir, dir_len) == 0 + if (buddy_icon_dir && !(g_ascii_strncasecmp(icon_path, buddy_icon_dir, dir_len) == 0 && icon_path[dir_len] == G_DIR_SEPARATOR && g_ascii_strncasecmp(icon_path + dir_len + 1, QQ_ICON_PREFIX, prefix_len) == 0 && g_ascii_strncasecmp(icon_path + dir_len + 1 + prefix_len + icon_len, QQ_ICON_SUFFIX, suffix_len) == 0 @@ -811,8 +811,8 @@ if ((buddy = purple_find_buddy(account, name))) old_icon_num = purple_buddy_icons_get_checksum_for_user(buddy); - if (old_icon_num == NULL || - strcmp(icon_num_str, old_icon_num)) + if ((old_icon_num == NULL || + strcmp(icon_num_str, old_icon_num)) && (qq_buddy_icon_dir() != NULL)) { gchar *icon_path; @@ -862,7 +862,7 @@ } /* process reply to get_info packet */ -void qq_process_get_info_reply(guint8 *data, gint data_len, PurpleConnection *gc) +void qq_process_get_buddy_info(guint8 *data, gint data_len, PurpleConnection *gc) { gchar **segments; qq_info_query *query; @@ -932,7 +932,7 @@ } } -void qq_send_packet_get_level(PurpleConnection *gc, guint32 uid) +void qq_request_get_level(PurpleConnection *gc, guint32 uid) { qq_data *qd = (qq_data *) gc->proto_data; guint8 buf[16] = {0}; @@ -945,7 +945,7 @@ qq_send_cmd(gc, QQ_CMD_GET_LEVEL, buf, bytes); } -void qq_request_get_buddies_levels(PurpleConnection *gc, gint update_class) +void qq_request_get_buddies_level(PurpleConnection *gc, gint update_class) { guint8 *buf; guint16 size; diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/buddy_info.h --- a/libpurple/protocols/qq/buddy_info.h Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.h Mon Sep 15 03:01:03 2008 +0000 @@ -80,9 +80,9 @@ void qq_set_buddy_icon_for_user(PurpleAccount *account, const gchar *who, const gchar *icon_num, const gchar *iconfile); void qq_prepare_modify_info(PurpleConnection *gc); void qq_process_modify_info_reply(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_process_get_info_reply(guint8 *data, gint data_len, PurpleConnection *gc); +void qq_process_get_buddy_info(guint8 *data, gint data_len, PurpleConnection *gc); void qq_info_query_free(qq_data *qd); -void qq_send_packet_get_level(PurpleConnection *gc, guint32 uid); -void qq_request_get_buddies_levels(PurpleConnection *gc, gint update_class); +void qq_request_get_level(PurpleConnection *gc, guint32 uid); +void qq_request_get_buddies_level(PurpleConnection *gc, gint update_class); void qq_process_get_level_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); #endif diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/buddy_list.c --- a/libpurple/protocols/qq/buddy_list.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Mon Sep 15 03:01:03 2008 +0000 @@ -569,7 +569,7 @@ q_bud->status =bs.status; if (q_bud->status == QQ_BUDDY_ONLINE_NORMAL) { - qq_send_packet_get_level(gc, q_bud->uid); + qq_request_get_level(gc, q_bud->uid); } qq_update_buddy_contact(gc, q_bud); } diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/group_im.c --- a/libpurple/protocols/qq/group_im.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/group_im.c Mon Sep 15 03:01:03 2008 +0000 @@ -120,7 +120,7 @@ bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); - msg = g_strdup_printf(_("%d requested to join Qun %d"), user_uid, ext_id); + msg = g_strdup_printf(_("%d request to join Qun %d"), user_uid, ext_id); reason = g_strdup_printf(_("Message: %s"), reason_utf8); g = g_new0(group_member_opt, 1); @@ -171,7 +171,7 @@ bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf - (_("Your request to join Qun %d has been rejected by admin %d"), ext_id, admin_uid); + (_("Failed to join Qun %d, operated by admin %d"), ext_id, admin_uid); reason = g_strdup_printf(_("Message: %s"), reason_utf8); purple_notify_warning(gc, _("QQ Qun Operation"), msg, reason); @@ -209,7 +209,7 @@ bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf - (_("Your request to join Qun %d has been approved by admin %d"), ext_id, admin_uid); + (_("Successed to join Qun %d, operated by admin %d"), ext_id, admin_uid); purple_notify_warning(gc, _("QQ Qun Operation"), msg, NULL); @@ -284,7 +284,7 @@ group = qq_group_create_internal_record(gc, id, ext_id, NULL); group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); - qq_room_update(gc, 0, group->id); + qq_update_room(gc, 0, group->id); /* the return of this cmd will automatically update the group in blist */ } @@ -380,7 +380,8 @@ conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->title_utf8, purple_connection_get_account(gc)); if (conv == NULL && purple_prefs_get_bool("/plugins/prpl/qq/prompt_group_msg_on_recv")) { /* New conv should open, get group info*/ - qq_room_update(gc, 0, group->id); + /* qq_update_room(gc, 0, group->id); */ + qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_ONLINES, group->id); serv_got_joined_chat(gc, qd->channel++, group->title_utf8); conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->title_utf8, purple_connection_get_account(gc)); diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/group_info.c --- a/libpurple/protocols/qq/group_info.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/group_info.c Mon Sep 15 03:01:03 2008 +0000 @@ -154,12 +154,12 @@ /* strlen + */ bytes += convert_as_pascal_string(data + bytes, &(group->title_utf8), QQ_CHARSET_DEFAULT); - purple_debug_info("QQ", "group \"%s\"\n", group->title_utf8); bytes += qq_get16(&unknown, data + bytes); /* 0x0000 */ bytes += convert_as_pascal_string(data + bytes, ¬ice, QQ_CHARSET_DEFAULT); - purple_debug_info("QQ", "notice \"%s\"\n", notice); bytes += convert_as_pascal_string(data + bytes, &(group->desc_utf8), QQ_CHARSET_DEFAULT); - purple_debug_info("QQ", "group_desc \"%s\"\n", group->desc_utf8); + + purple_debug_info("QQ", "room [%s] notice [%s] desc [%s] unknow 0x%04X\n", + group->title_utf8, notice, group->desc_utf8, unknown); num = 0; /* now comes the member list separated by 0x00 */ diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/group_join.c --- a/libpurple/protocols/qq/group_join.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/group_join.c Mon Sep 15 03:01:03 2008 +0000 @@ -65,7 +65,7 @@ } /* send packet to join a group without auth */ -void qq_send_cmd_group_join_group(PurpleConnection *gc, qq_group *group) +void qq_request_room_join(PurpleConnection *gc, qq_group *group) { g_return_if_fail(group != NULL); @@ -79,8 +79,12 @@ case QQ_ROOM_AUTH_TYPE_NEED_AUTH: break; case QQ_ROOM_AUTH_TYPE_NO_ADD: - purple_notify_warning(gc, NULL, _("The Qun does not allow others to join"), NULL); - return; + if (group->my_role == QQ_ROOM_ROLE_NO + && group->my_role == QQ_ROOM_ROLE_REQUESTING) { + purple_notify_warning(gc, NULL, _("The Qun does not allow others to join"), NULL); + return; + } + break; default: purple_debug_error("QQ", "Unknown room auth type: %d\n", group->auth_type); break; @@ -245,7 +249,8 @@ qq_group_refresh(gc, group); /* this must be shown before getting online members */ qq_group_conv_show_window(gc, group); - qq_room_update(gc, 0, group->id); + /* qq_update_room(gc, 0, group->id); */ + qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_ONLINES, group->id); break; case QQ_ROOM_JOIN_NEED_AUTH: purple_debug_info("QQ", @@ -285,7 +290,7 @@ group = qq_room_search_ext_id(gc, ext_id); if (group) { - qq_send_cmd_group_join_group(gc, group); + qq_request_room_join(gc, group); } else { qq_set_pending_id(&qd->joining_groups, ext_id, TRUE); qq_send_cmd_group_search_group(gc, ext_id); diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/group_join.h --- a/libpurple/protocols/qq/group_join.h Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/group_join.h Mon Sep 15 03:01:03 2008 +0000 @@ -43,7 +43,7 @@ void qq_send_cmd_group_auth(PurpleConnection *gc, qq_group *group, guint8 opt, guint32 uid, const gchar *reason_utf8); void qq_group_join(PurpleConnection *gc, GHashTable *data); -void qq_send_cmd_group_join_group(PurpleConnection *gc, qq_group *group); +void qq_request_room_join(PurpleConnection *gc, qq_group *group); void qq_group_exit(PurpleConnection *gc, GHashTable *data); void qq_process_group_cmd_exit_group(guint8 *data, gint len, PurpleConnection *gc); void qq_process_group_cmd_join_group_auth(guint8 *data, gint len, PurpleConnection *gc); diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/group_opt.c --- a/libpurple/protocols/qq/group_opt.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/group_opt.c Mon Sep 15 03:01:03 2008 +0000 @@ -359,7 +359,7 @@ qq_group_refresh(gc, group); qq_send_room_cmd_only(gc, QQ_ROOM_CMD_ACTIVATE, id); - qq_room_update(gc, 0, group->id); + qq_update_room(gc, 0, group->id); purple_debug_info("QQ", "Succeed in create Qun, external ID %d\n", group->ext_id); diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/group_search.c --- a/libpurple/protocols/qq/group_search.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/group_search.c Mon Sep 15 03:01:03 2008 +0000 @@ -116,7 +116,7 @@ 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", + purple_debug_error("QQ", "group_cmd_search_group: Dangerous error! maybe protocol changed, notify developers!"); } @@ -124,9 +124,9 @@ if (pending_id != NULL) { qq_set_pending_id(&qd->joining_groups, group.ext_id, FALSE); if (qq_room_search_id(gc, group.id) == NULL) - qq_group_create_internal_record(gc, + qq_group_create_internal_record(gc, group.id, group.ext_id, group.title_utf8); - qq_send_cmd_group_join_group(gc, &group); + qq_request_room_join(gc, &group); } else { _qq_setup_roomlist(qd, &group); } diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/header_info.c --- a/libpurple/protocols/qq/header_info.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/header_info.c Mon Sep 15 03:01:03 2008 +0000 @@ -138,8 +138,8 @@ return "QQ_CMD_UPDATE_INFO"; case QQ_CMD_SEARCH_USER: return "QQ_CMD_SEARCH_USER"; - case QQ_CMD_GET_USER_INFO: - return "QQ_CMD_GET_USER_INFO"; + case QQ_CMD_GET_BUDDY_INFO: + return "QQ_CMD_GET_BUDDY_INFO"; case QQ_CMD_ADD_BUDDY_WO_AUTH: return "QQ_CMD_ADD_BUDDY_WO_AUTH"; case QQ_CMD_DEL_BUDDY: diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/header_info.h --- a/libpurple/protocols/qq/header_info.h Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/header_info.h Mon Sep 15 03:01:03 2008 +0000 @@ -43,7 +43,7 @@ QQ_CMD_KEEP_ALIVE = 0x0002, /* get onlines from tencent */ QQ_CMD_UPDATE_INFO = 0x0004, /* update information */ QQ_CMD_SEARCH_USER = 0x0005, /* search for user */ - QQ_CMD_GET_USER_INFO = 0x0006, /* get user information */ + QQ_CMD_GET_BUDDY_INFO = 0x0006, /* get user information */ QQ_CMD_ADD_BUDDY_WO_AUTH = 0x0009, /* add buddy without auth */ QQ_CMD_DEL_BUDDY = 0x000a, /* delete a buddy */ QQ_CMD_BUDDY_AUTH = 0x000b, /* buddy authentication */ diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/im.c --- a/libpurple/protocols/qq/im.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/im.c Mon Sep 15 03:01:03 2008 +0000 @@ -259,7 +259,7 @@ #endif temp = g_newa(guint8, data_len); - bytes = 4; // ignore unknown 4 bytes + bytes = 4; /* ignore unknown 4 bytes */ bytes += qq_get8(&temp_len, data + bytes); g_return_if_fail(bytes + temp_len <= data_len); diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/qq.c --- a/libpurple/protocols/qq/qq.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/qq.c Mon Sep 15 03:01:03 2008 +0000 @@ -97,10 +97,7 @@ gpi = purple_proxy_get_setup(account); - qd->use_tcp = TRUE; - if (purple_proxy_info_get_type(gpi) == PURPLE_PROXY_UDP) { - qd->use_tcp = FALSE; - } + qd->use_tcp = purple_account_get_bool(account, "use_tcp", TRUE); user_server = purple_account_get_string(account, "server", NULL); purple_debug_info("QQ", "Select server '%s'\n", user_server); @@ -468,7 +465,7 @@ return; } - qq_send_packet_get_level(gc, uid); + qq_request_get_level(gc, uid); qq_send_packet_get_info(gc, uid, TRUE); } @@ -845,14 +842,10 @@ entry = entry->next; } - /* - option = purple_account_option_string_new(_("Server"), "server", NULL); + option = purple_account_option_list_new(_("Server"), "server", kvlist); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_int_new(_("Port"), "port", 0); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - */ - option = purple_account_option_list_new(_("Server"), "server", kvlist); + option = purple_account_option_bool_new(_("Connect by TCP"), "use_tcp", TRUE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_bool_new(_("Show server notice"), "show_notice", TRUE); diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/qq.h --- a/libpurple/protocols/qq/qq.h Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/qq.h Mon Sep 15 03:01:03 2008 +0000 @@ -48,7 +48,7 @@ struct _qq_interval { gint resend; gint keep_alive; - gint update; + gint update; }; struct _qq_buddy { @@ -91,11 +91,15 @@ GSList *openconns; gboolean use_tcp; /* network in tcp or udp */ PurpleProxyConnectData *conn_data; +#ifndef purple_proxy_connect_udp + PurpleDnsQueryData *udp_query_data; /* udp related */ + gint udp_can_write_handler; /* socket can_write handle, use in udp connecting and tcp send out */ +#endif gint fd; /* socket file handler */ GList *servers; gchar *curr_server; /* point to servers->data, do not free*/ - + struct in_addr redirect_ip; guint16 redirect_port; guint check_watcher; @@ -105,7 +109,7 @@ qq_interval itv_config; qq_interval itv_count; guint network_watcher; - + GList *transactions; /* check ack packet and resend */ guint32 uid; /* QQ number */ @@ -119,7 +123,6 @@ guint16 send_seq; /* send sequence number */ guint8 login_mode; /* online of invisible */ gboolean is_login; /* used by qq-add_buddy */ - gboolean is_finish_update; PurpleXfer *xfer; /* file transfer handler */ diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/qq_network.c --- a/libpurple/protocols/qq/qq_network.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/qq_network.c Mon Sep 15 03:01:03 2008 +0000 @@ -234,8 +234,6 @@ qq_data *qd; gint bytes, bytes_not_read; - gboolean prev_update_status; - guint8 header_tag; guint16 source_tag; guint16 cmd; @@ -256,8 +254,8 @@ bytes += packet_get_header(&header_tag, &source_tag, &cmd, &seq, buf + bytes); #if 1 - purple_debug_info("QQ", "==> [%05d] 0x%04X %s, source tag 0x%04X len %d\n", - seq, cmd, qq_get_cmd_desc(cmd), source_tag, buf_len); + purple_debug_info("QQ", "==> [%05d] %s 0x%04X, source tag 0x%04X len %d\n", + seq, qq_get_cmd_desc(cmd), cmd, source_tag, buf_len); #endif /* this is the length of all the encrypted data (also remove tail tag) */ bytes_not_read = buf_len - bytes - 1; @@ -267,9 +265,11 @@ trans = qq_trans_find_rcved(gc, cmd, seq); if (trans == NULL) { /* new server command */ - qq_trans_add_server_cmd(gc, cmd, seq, buf + bytes, bytes_not_read); - if ( qd->is_finish_update ) { - qq_proc_cmd_server(gc, cmd, seq, buf + bytes, bytes_not_read); + if ( !qd->is_login ) { + qq_trans_add_remain(gc, cmd, seq, buf + bytes, bytes_not_read); + } else { + qq_trans_add_server_cmd(gc, cmd, seq, buf + bytes, bytes_not_read); + qq_proc_server_cmd(gc, cmd, seq, buf + bytes, bytes_not_read); } return TRUE; } @@ -279,17 +279,9 @@ return TRUE; } - if (qq_trans_is_server(trans)) { - if ( qd->is_finish_update ) { - qq_proc_cmd_server(gc, cmd, seq, buf + bytes, bytes_not_read); - } - return TRUE; - } - update_class = qq_trans_get_class(trans); ship32 = qq_trans_get_ship(trans); - prev_update_status = qd->is_finish_update; switch (cmd) { case QQ_CMD_TOKEN: if (qq_process_token_reply(gc, buf + bytes, bytes_not_read) == QQ_TOKEN_REPLY_OK) { @@ -297,7 +289,7 @@ } break; case QQ_CMD_LOGIN: - qq_proc_cmd_login(gc, buf + bytes, bytes_not_read); + qq_proc_login_cmd(gc, buf + bytes, bytes_not_read); /* check is redirect or not, and do it now */ if (qd->redirect_ip.s_addr != 0) { if (qd->check_watcher > 0) { @@ -316,18 +308,13 @@ purple_debug_info("QQ", "%s (0x%02X) for room %d, len %d\n", qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, buf_len); #endif - qq_proc_room_cmd_reply(gc, seq, room_cmd, room_id, buf + bytes, bytes_not_read, update_class, ship32); + qq_proc_room_cmd(gc, seq, room_cmd, room_id, buf + bytes, bytes_not_read, update_class, ship32); break; default: - qq_proc_cmd_reply(gc, cmd, seq, buf + bytes, bytes_not_read, update_class, ship32); + qq_proc_client_cmd(gc, cmd, seq, buf + bytes, bytes_not_read, update_class, ship32); break; } - if (prev_update_status != qd->is_finish_update && qd->is_finish_update == TRUE) { - /* is_login, but we have packets before login */ - qq_trans_process_before_login(gc); - return TRUE; - } return TRUE; } @@ -684,7 +671,6 @@ qd->send_seq = rand() & 0xffff; qd->is_login = FALSE; - qd->is_finish_update = FALSE; qd->channel = 1; qd->uid = strtol(purple_account_get_username(purple_connection_get_account(gc)), NULL, 10); @@ -753,6 +739,140 @@ do_request_token( gc ); } +#ifndef purple_proxy_connect_udp +static void udp_can_write(gpointer data, gint source, PurpleInputCondition cond) +{ + PurpleConnection *gc; + qq_data *qd; + socklen_t len; + int error=0, ret; + + gc = (PurpleConnection *) data; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + + qd = (qq_data *) gc->proto_data; + + + purple_debug_info("proxy", "Connected.\n"); + + /* + * getsockopt after a non-blocking connect returns -1 if something is + * really messed up (bad descriptor, usually). Otherwise, it returns 0 and + * error holds what connect would have returned if it blocked until now. + * Thus, error == 0 is success, error == EINPROGRESS means "try again", + * and anything else is a real error. + * + * (error == EINPROGRESS can happen after a select because the kernel can + * be overly optimistic sometimes. select is just a hint that you might be + * able to do something.) + */ + len = sizeof(error); + ret = getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len); + if (ret == 0 && error == EINPROGRESS) + return; /* we'll be called again later */ + + purple_input_remove(qd->udp_can_write_handler); + qd->udp_can_write_handler = 0; + if (ret < 0 || error != 0) { + if(ret != 0) + error = errno; + + close(source); + + purple_debug_error("proxy", "getsockopt SO_ERROR check: %s\n", g_strerror(error)); + + connect_cb(gc, -1, _("Unable to connect")); + return; + } + + connect_cb(gc, source, NULL); +} + +static void udp_host_resolved(GSList *hosts, gpointer data, const char *error_message) { + PurpleConnection *gc; + qq_data *qd; + struct sockaddr server_addr; + int addr_size; + gint fd = -1; + int flags; + + gc = (PurpleConnection *) data; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + + qd = (qq_data *) gc->proto_data; + + /* udp_query_data must be set as NULL. + * Otherwise purple_dnsquery_destroy in qq_disconnect cause glib double free error */ + qd->udp_query_data = NULL; + + if (!hosts || !hosts->data) { + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Couldn't resolve host")); + return; + } + + addr_size = GPOINTER_TO_INT(hosts->data); + hosts = g_slist_remove(hosts, hosts->data); + memcpy(&server_addr, hosts->data, addr_size); + g_free(hosts->data); + + hosts = g_slist_remove(hosts, hosts->data); + while(hosts) { + hosts = g_slist_remove(hosts, hosts->data); + g_free(hosts->data); + hosts = g_slist_remove(hosts, hosts->data); + } + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + purple_debug_error("QQ", + "Unable to create socket: %s\n", g_strerror(errno)); + return; + } + + /* we use non-blocking mode to speed up connection */ + flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + + /* From Unix-socket-FAQ: http://www.faqs.org/faqs/unix-faq/socket/ + * + * If a UDP socket is unconnected, which is the normal state after a + * bind() call, then send() or write() are not allowed, since no + * destination is available; only sendto() can be used to send data. + * + * Calling connect() on the socket simply records the specified address + * and port number as being the desired communications partner. That + * means that send() or write() are now allowed; they use the destination + * address and port given on the connect call as the destination of packets. + */ + if (connect(fd, &server_addr, addr_size) >= 0) { + purple_debug_info("QQ", "Connected.\n"); + flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + connect_cb(gc, fd, NULL); + return; + } + + /* [EINPROGRESS] + * The socket is marked as non-blocking and the connection cannot be + * completed immediately. It is possible to select for completion by + * selecting the socket for writing. + * [EINTR] + * A signal interrupted the call. + * The connection is established asynchronously. + */ + if ((errno == EINPROGRESS) || (errno == EINTR)) { + purple_debug_warning( "QQ", "Connect in asynchronous mode.\n"); + qd->udp_can_write_handler = purple_input_add(fd, PURPLE_INPUT_WRITE, udp_can_write, gc); + return; + } + + purple_debug_error("QQ", "Connection failed: %s\n", g_strerror(errno)); + close(fd); +} +#endif + gboolean connect_to_server(PurpleConnection *gc, gchar *server, gint port) { PurpleAccount *account ; @@ -779,11 +899,37 @@ purple_proxy_connect_cancel(qd->conn_data); qd->conn_data = NULL; } - qd->conn_data = purple_proxy_connect(gc, account, server, port, connect_cb, gc); + +#ifdef purple_proxy_connect_udp + if (qd->use_tcp) { + qd->conn_data = purple_proxy_connect(gc, account, server, port, connect_cb, gc); + } else { + qd->conn_data = purple_proxy_connect_udp(gc, account, server, port, connect_cb, gc); + } if ( qd->conn_data == NULL ) { purple_debug_error("QQ", _("Couldn't create socket")); return FALSE; } +#else + /* QQ connection via UDP/TCP. + * Now use Purple proxy function to provide TCP proxy support, + * and qq_udp_proxy.c to add UDP proxy support (thanks henry) */ + if(qd->use_tcp) { + qd->conn_data = purple_proxy_connect(gc, account, server, port, connect_cb, gc); + if ( qd->conn_data == NULL ) { + purple_debug_error("QQ", "Unable to connect."); + return FALSE; + } + return TRUE; + } + + purple_debug_info("QQ", "UDP Connect to %s:%d\n", server, port); + qd->udp_query_data = purple_dnsquery_a(server, port, udp_host_resolved, gc); + if ( qd->udp_query_data == NULL ) { + purple_debug_error("QQ", "Could not resolve hostname"); + return FALSE; + } +#endif return TRUE; } @@ -815,6 +961,17 @@ purple_proxy_connect_cancel(qd->conn_data); qd->conn_data = NULL; } +#ifndef purple_proxy_connect_udp + if (qd->udp_can_write_handler) { + purple_input_remove(qd->udp_can_write_handler); + qd->udp_can_write_handler = 0; + } + if (qd->udp_query_data != NULL) { + purple_debug_info("QQ", "destroy udp_query_data\n"); + purple_dnsquery_destroy(qd->udp_query_data); + qd->udp_query_data = NULL; + } +#endif connection_free_all(qd); qd->fd = -1; diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/qq_process.c --- a/libpurple/protocols/qq/qq_process.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.c Mon Sep 15 03:01:03 2008 +0000 @@ -60,7 +60,7 @@ }; /* default process, decrypt and dump */ -static void process_cmd_unknow(PurpleConnection *gc,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; @@ -77,13 +77,13 @@ seq, qq_get_cmd_desc(cmd)); msg_utf8 = try_dump_as_gbk(data, data_len); - if (msg_utf8) { - purple_notify_info(gc, NULL, msg_utf8, NULL); + if (msg_utf8 != NULL) { + purple_notify_info(gc, title, msg_utf8, NULL); g_free(msg_utf8); } } -void qq_proc_cmd_server(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) +void qq_proc_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) { qq_data *qd; @@ -122,7 +122,7 @@ qq_process_buddy_change_status(data, data_len, gc); break; default: - process_cmd_unknow(gc, "Unknow SERVER CMD", data, data_len, cmd, seq); + process_cmd_unknow(gc, _("Unknow SERVER CMD"), data, data_len, cmd, seq); break; } } @@ -145,7 +145,7 @@ g_free(msg_utf8); } -void qq_room_update(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +void qq_update_room(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) { qq_data *qd; qq_group *group; @@ -198,8 +198,7 @@ next_group = qq_room_get_next(gc, room_id); if (next_group == NULL && room_id <= 0) { - purple_debug_info("QQ", "No room, nothing update\n"); - qd->is_finish_update = TRUE; + purple_debug_info("QQ", "No room. Finished update\n"); return; } if (next_group == NULL ) { @@ -226,7 +225,7 @@ if (!is_new_turn) { qq_request_room_get_buddies(gc, next_group, QQ_CMD_CLASS_UPDATE_ALL); } else { - qd->is_finish_update = TRUE; + purple_debug_info("QQ", "Finished update\n"); } break; default: @@ -245,7 +244,7 @@ case 0: qq_request_buddy_info(gc, qd->uid, QQ_CMD_CLASS_UPDATE_ALL, QQ_BUDDY_INFO_UPDATE_ONLY); break; - case QQ_CMD_GET_USER_INFO: + case QQ_CMD_GET_BUDDY_INFO: qq_request_change_status(gc, QQ_CMD_CLASS_UPDATE_ALL); break; case QQ_CMD_CHANGE_STATUS: @@ -255,7 +254,7 @@ qq_request_get_buddies_and_rooms(gc, 0, QQ_CMD_CLASS_UPDATE_ALL); break; case QQ_CMD_GET_BUDDIES_AND_ROOMS: - qq_request_get_buddies_levels(gc, QQ_CMD_CLASS_UPDATE_ALL); + qq_request_get_buddies_level(gc, QQ_CMD_CLASS_UPDATE_ALL); break; case QQ_CMD_GET_LEVEL: qq_request_get_buddies_online(gc, 0, QQ_CMD_CLASS_UPDATE_ALL); @@ -279,11 +278,11 @@ next_group = qq_room_get_next_conv(gc, room_id); if (next_group == NULL && room_id <= 0) { - purple_debug_info("QQ", "No room, no update online buddies\n"); + purple_debug_info("QQ", "No room in conversation, no update online buddies\n"); return; } if (next_group == NULL ) { - purple_debug_info("QQ", "finished update online buddies\n"); + purple_debug_info("QQ", "finished update rooms' online buddies\n"); return; } @@ -316,7 +315,7 @@ } } -void qq_proc_room_cmd_reply(PurpleConnection *gc, guint16 seq, +void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32) { @@ -445,6 +444,9 @@ reply_cmd, qq_get_room_cmd_desc(reply_cmd)); } + if (update_class == QQ_CMD_CLASS_NONE) + return; + purple_debug_info("QQ", "Update class %d\n", update_class); if (update_class == QQ_CMD_CLASS_UPDATE_ALL) { update_all_rooms(gc, room_cmd, room_id); @@ -455,11 +457,11 @@ return; } if (update_class == QQ_CMD_CLASS_UPDATE_ROOM) { - qq_room_update(gc, room_cmd, room_id); + qq_update_room(gc, room_cmd, room_id); } } -void qq_proc_cmd_login(PurpleConnection *gc, guint8 *rcved, gint rcved_len) +void qq_proc_login_cmd(PurpleConnection *gc, guint8 *rcved, gint rcved_len) { qq_data *qd; guint8 *data; @@ -503,11 +505,14 @@ /* Now goes on updating my icon/nickname, not showing info_window */ qd->modifying_face = FALSE; + /* is_login, but we have packets before login */ + qq_trans_process_remained(gc); + qq_update_all(gc, 0); return; } -void qq_proc_cmd_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, +void qq_proc_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32) { qq_data *qd; @@ -559,8 +564,8 @@ case QQ_CMD_BUDDY_AUTH: qq_process_add_buddy_auth_reply(data, data_len, gc); break; - case QQ_CMD_GET_USER_INFO: - qq_process_get_info_reply(data, data_len, gc); + case QQ_CMD_GET_BUDDY_INFO: + qq_process_get_buddy_info(data, data_len, gc); break; case QQ_CMD_CHANGE_STATUS: qq_process_change_status_reply(data, data_len, gc); @@ -603,7 +608,7 @@ purple_debug_info("QQ", "All buddies and groups received\n"); break; default: - process_cmd_unknow(gc, "Unknow reply CMD", data, data_len, cmd, seq); + process_cmd_unknow(gc, _("Unknow reply CMD"), data, data_len, cmd, seq); is_unknow = TRUE; break; } diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/qq_process.h --- a/libpurple/protocols/qq/qq_process.h Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.h Mon Sep 15 03:01:03 2008 +0000 @@ -37,17 +37,17 @@ QQ_CMD_CLASS_UPDATE_ROOM, }; -void qq_proc_cmd_login(PurpleConnection *gc, guint8 *rcved, gint rcved_len); -void qq_proc_cmd_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, +void qq_proc_login_cmd(PurpleConnection *gc, guint8 *rcved, gint rcved_len); +void qq_proc_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32); -void qq_proc_room_cmd_reply(PurpleConnection *gc, guint16 seq, +void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32); -void qq_proc_cmd_server(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len); +void qq_proc_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len); void qq_update_all(PurpleConnection *gc, guint16 cmd); void qq_update_online(PurpleConnection *gc, guint16 cmd); -void qq_room_update(PurpleConnection *gc, guint8 room_cmd, guint32 room_id); +void qq_update_room(PurpleConnection *gc, guint8 room_cmd, guint32 room_id); #endif diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/qq_trans.c --- a/libpurple/protocols/qq/qq_trans.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/qq_trans.c Mon Sep 15 03:01:03 2008 +0000 @@ -40,7 +40,7 @@ enum { QQ_TRANS_IS_SERVER = 0x01, /* Is server command or client command */ QQ_TRANS_IS_IMPORT = 0x02, /* Only notice if not get reply; or resend, disconn if reties get 0*/ - QQ_TRANS_BEFORE_LOGIN = 0x04, /* server command before login*/ + QQ_TRANS_REMAINED = 0x04, /* server command before login*/ }; struct _qq_transaction { @@ -225,16 +225,13 @@ qd->transactions = g_list_append(qd->transactions, trans); } -void qq_trans_add_server_cmd(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *data, gint data_len) +void qq_trans_add_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len) { qq_data *qd = (qq_data *)gc->proto_data; qq_transaction *trans = trans_create(gc, qd->fd, cmd, seq, data, data_len, QQ_CMD_CLASS_NONE, 0); trans->flag = QQ_TRANS_IS_SERVER; - if ( !qd->is_login ) { - trans->flag |= QQ_TRANS_BEFORE_LOGIN; - } trans->send_retries = 0; trans->rcved_times = 1; #if 0 @@ -244,7 +241,24 @@ qd->transactions = g_list_append(qd->transactions, trans); } -void qq_trans_process_before_login(PurpleConnection *gc) +void qq_trans_add_remain(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len) +{ + qq_data *qd = (qq_data *)gc->proto_data; + qq_transaction *trans = trans_create(gc, qd->fd, cmd, seq, data, data_len, QQ_CMD_CLASS_NONE, 0); + + trans->flag = QQ_TRANS_IS_SERVER; + trans->flag |= QQ_TRANS_REMAINED; + trans->send_retries = 0; + trans->rcved_times = 1; +#if 1 + purple_debug_info("QQ_TRANS", "Add server cmd and remained, seq %d, data %p, len %d\n", + trans->seq, trans->data, trans->data_len); +#endif + qd->transactions = g_list_append(qd->transactions, trans); +} + +void qq_trans_process_remained(PurpleConnection *gc) { qq_data *qd = (qq_data *)gc->proto_data; GList *curr; @@ -263,17 +277,18 @@ if ( !(trans->flag & QQ_TRANS_IS_SERVER) ) { continue; } - if ( !(trans->flag & QQ_TRANS_BEFORE_LOGIN) ) { + if ( !(trans->flag & QQ_TRANS_REMAINED) ) { continue; } - /* set QQ_TRANS_BEFORE_LOGIN off */ - trans->flag &= ~QQ_TRANS_BEFORE_LOGIN; + /* set QQ_TRANS_REMAINED off */ + trans->flag &= ~QQ_TRANS_REMAINED; +#if 1 purple_debug_info("QQ_TRANS", - "Process server cmd before login, seq %d, data %p, len %d, send_retries %d\n", + "Process server cmd remained, seq %d, data %p, len %d, send_retries %d\n", trans->seq, trans->data, trans->data_len, trans->send_retries); - - qq_proc_cmd_reply(gc, trans->seq, trans->cmd, trans->data, trans->data_len, trans->update_class, trans->ship32); +#endif + qq_proc_server_cmd(gc, trans->cmd, trans->seq, trans->data, trans->data_len); } /* purple_debug_info("QQ_TRANS", "Scan finished\n"); */ @@ -295,7 +310,7 @@ trans = (qq_transaction *) (curr->data); /* purple_debug_info("QQ_TRANS", "Scan [%d]\n", trans->seq); */ - if (trans->flag & QQ_TRANS_BEFORE_LOGIN) { + if (trans->flag & QQ_TRANS_REMAINED) { /* keep server cmd before login*/ continue; } diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/qq_trans.h --- a/libpurple/protocols/qq/qq_trans.h Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/qq_trans.h Mon Sep 15 03:01:03 2008 +0000 @@ -46,8 +46,10 @@ void qq_trans_add_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len); +void qq_trans_add_remain(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len); -void qq_trans_process_before_login(PurpleConnection *gc); +void qq_trans_process_remained(PurpleConnection *gc); gboolean qq_trans_scan(PurpleConnection *gc); void qq_trans_remove_all(PurpleConnection *gc); diff -r 967344bc404d -r 23cec4360d4a libpurple/protocols/qq/sys_msg.c --- a/libpurple/protocols/qq/sys_msg.c Mon Sep 15 02:59:23 2008 +0000 +++ b/libpurple/protocols/qq/sys_msg.c Mon Sep 15 03:01:03 2008 +0000 @@ -84,7 +84,7 @@ nombre = uid_to_purple_name(uid); purple_request_action - (gc, NULL, _("Do you want to approve the request?"), "", + (gc, NULL, _("Do you approve the requestion?"), "", PURPLE_DEFAULT_ACTION_NONE, purple_connection_get_account(gc), nombre, NULL, g, 2, @@ -108,7 +108,7 @@ qq_send_packet_get_info(gc, uid, TRUE); /* we want to see window */ nombre = uid_to_purple_name(uid); purple_request_action - (gc, NULL, _("Do you want to add this buddy?"), "", + (gc, NULL, _("Do you add the buddy?"), "", PURPLE_DEFAULT_ACTION_NONE, purple_connection_get_account(gc), nombre, NULL, g, 2,