Mercurial > pidgin
changeset 14404:8ff8f1c897b5
[gaim-migrate @ 17112]
Fixed chat support.
committer: Tailor Script <tailor@pidgin.im>
line wrap: on
line diff
--- a/libgaim/protocols/qq/Makefile.am Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/Makefile.am Fri Sep 01 11:03:18 2006 +0000 @@ -22,15 +22,15 @@ crypt.c \ crypt.h \ group.c \ + group.h \ group_conv.c \ group_conv.h \ group_find.c \ group_find.h \ group_free.c \ group_free.h \ - group.h \ - group_hash.c \ - group_hash.h \ + group_internal.c \ + group_internal.h \ group_im.c \ group_im.h \ group_info.c \
--- a/libgaim/protocols/qq/Makefile.mingw Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/Makefile.mingw Fri Sep 01 11:03:18 2006 +0000 @@ -54,7 +54,7 @@ group_conv.c \ group_find.c \ group_free.c \ - group_hash.c \ + group_internal.c \ group_im.c \ group_info.c \ group_join.c \
--- a/libgaim/protocols/qq/buddy_list.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/buddy_list.c Fri Sep 01 11:03:18 2006 +0000 @@ -37,7 +37,7 @@ #include "qq.h" #include "group.h" #include "group_find.h" -#include "group_hash.h" +#include "group_internal.h" #include "group_info.h" #include "qq_proxy.h" @@ -222,7 +222,7 @@ } else { gaim_debug(GAIM_DEBUG_ERROR, "QQ", - "Got an online buddy %d, but not in my buddy list", fe->s->uid); + "Got an online buddy %d, but not in my buddy list\n", fe->s->uid); } g_free(fe->s->ip); @@ -231,11 +231,11 @@ if(cursor > (data + len)) { gaim_debug(GAIM_DEBUG_ERROR, "QQ", - "qq_process_get_buddies_online_reply: Dangerous error! maybe protocol changed, notify developers!"); + "qq_process_get_buddies_online_reply: Dangerous error! maybe protocol changed, notify developers!\n"); } if (position != QQ_FRIENDS_ONLINE_POSITION_END) { - gaim_debug(GAIM_DEBUG_INFO, "QQ", "Has more online buddies, position from %d", position); + gaim_debug(GAIM_DEBUG_INFO, "QQ", "Has more online buddies, position from %d\n", position); qq_send_packet_get_buddies_online(gc, position); } @@ -352,10 +352,6 @@ guint32 unknown, position; guint32 uid; guint8 type, groupid; - - qq_buddy *q_bud; - gchar *name; - GaimBuddy *b; qq_group *group; g_return_if_fail(gc != NULL && gc->proto_data != NULL); @@ -384,41 +380,28 @@ read_packet_dw(data, &cursor, len, &uid); /* 04: type 0x1:buddy 0x4:Qun */ read_packet_b(data, &cursor, len, &type); - /* 05: groupid*4 */ + /* 05: groupid*4 */ /* seems to always be 0 */ read_packet_b(data, &cursor, len, &groupid); - groupid >>= 2; /* these 2 bits might not be 0, faint! */ + /* + gaim_debug(GAIM_DEBUG_INFO, "QQ", "groupid: %i\n", groupid); + groupid >>= 2; + */ if (uid == 0 || (type != 0x1 && type != 0x4)) { - gaim_debug(GAIM_DEBUG_WARNING, "QQ", + gaim_debug(GAIM_DEBUG_INFO, "QQ", "Buddy entry, uid=%d, type=%d", uid, type); continue; } if(0x1 == type) { /* a buddy */ - name = uid_to_gaim_name(uid); - b = gaim_find_buddy(gc->account, name); - g_free(name); - - if (b == NULL) { - b = qq_add_buddy_by_recv_packet(gc, uid, TRUE, TRUE); - q_bud = b->proto_data; - } - else { - q_bud = NULL; - b->proto_data = q_bud; /* wrong !!!! */ - } - qd->buddies = g_list_append(qd->buddies, q_bud); - qq_update_buddy_contact(gc, q_bud); + /* don't do anything but count - buddies are handled by + * qq_send_packet_get_buddies_list */ ++i; } else { /* a group */ - group = qq_group_find_by_internal_group_id(gc, uid); + group = qq_group_find_by_id(gc, uid, QQ_INTERNAL_ID); if(group == NULL) { - /*XXX not working - group = qq_group_create_by_id(gc, uid, 0); + qq_set_pending_id(&qd->adding_groups_from_server, uid, TRUE); + group = g_newa(qq_group, 1); + group->internal_group_id = uid; qq_send_cmd_group_get_group_info(gc, group); - */ - gaim_debug(GAIM_DEBUG_ERROR, "QQ", - "Get a Qun with internal group %d\n", uid); - gaim_notify_info(gc, _("QQ Qun Operation"), - _("Find one Qun in the server list, but i don't know its external id, please re-rejoin it manually"), NULL); } else { group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; qq_group_refresh(gc, group);
--- a/libgaim/protocols/qq/group.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group.c Fri Sep 01 11:03:18 2006 +0000 @@ -26,7 +26,7 @@ #include "prpl.h" #include "request.h" -#include "group_hash.h" +#include "group_internal.h" #include "group_info.h" #include "group_search.h" #include "utils.h" @@ -43,6 +43,15 @@ qq_send_cmd_group_search_group(gc, external_group_id); } +static void _qq_group_search_cancel_callback(GaimConnection *gc, const gchar *input) +{ + qq_data *qd; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + + qd = (qq_data *) gc->proto_data; + gaim_roomlist_set_in_progress(qd->roomlist, FALSE); +} + /* This is needed for GaimChat node to be valid */ GList *qq_chat_info(GaimConnection *gc) { @@ -55,18 +64,20 @@ pce->label = _("ID: "); pce->identifier = QQ_GROUP_KEY_EXTERNAL_ID; m = g_list_append(m, pce); - - pce = g_new0(struct proto_chat_entry, 1); - pce->label = _("Admin: "); - pce->identifier = QQ_GROUP_KEY_CREATOR_UID; - m = g_list_append(m, pce); + + return m; +} - pce = g_new0(struct proto_chat_entry, 1); - pce->label = _("Status: "); - pce->identifier = QQ_GROUP_KEY_MEMBER_STATUS_DESC; - m = g_list_append(m, pce); +GHashTable *qq_chat_info_defaults(GaimConnection *gc, const gchar *chat_name) +{ + GHashTable *defaults; - return m; + defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); + + if (chat_name != NULL) + g_hash_table_insert(defaults, QQ_GROUP_KEY_EXTERNAL_ID, g_strdup(chat_name)); + + return defaults; } /* get a list of qq groups */ @@ -107,9 +118,11 @@ gaim_request_input(gc, _("QQ Qun"), _("Please input external group ID"), - _("You can only search for permanent QQ group\nInput 0 or leave it blank to search for demo groups"), - NULL, FALSE, FALSE, NULL, _("Search"), - G_CALLBACK(_qq_group_search_callback), _("Cancel"), NULL, gc); + _("You can only search for permanent QQ groups\n"), + NULL, FALSE, FALSE, NULL, + _("Search"), G_CALLBACK(_qq_group_search_callback), + _("Cancel"), G_CALLBACK(_qq_group_search_cancel_callback), + gc); return qd->roomlist; }
--- a/libgaim/protocols/qq/group.h Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group.h Fri Sep 01 11:03:18 2006 +0000 @@ -39,7 +39,7 @@ } qq_group_member_status; typedef struct _qq_group { - /* all these will be saved when exit GAIM */ + /* all these will be saved when we exit Gaim */ qq_group_member_status my_status; /* my status for this group */ gchar *my_status_desc; /* my status description */ guint32 internal_group_id; @@ -50,12 +50,13 @@ guint8 auth_type; gchar *group_name_utf8; gchar *group_desc_utf8; - /* all these will loaded from network only */ + /* all these will be loaded from the network */ gchar *notice_utf8; /* group notice by admin */ - GList *members; /* those evert appear in the group */ + GList *members; } qq_group; GList *qq_chat_info(GaimConnection *gc); +GHashTable *qq_chat_info_defaults(GaimConnection *gc, const gchar *chat_name); void qq_group_init(GaimConnection *gc);
--- a/libgaim/protocols/qq/group_conv.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_conv.c Fri Sep 01 11:03:18 2006 +0000 @@ -37,7 +37,8 @@ g_return_if_fail(gc != NULL && gc->proto_data != NULL && group != NULL); qd = (qq_data *) gc->proto_data; - conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT, group->group_name_utf8, gaim_connection_get_account(gc)); + conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT, + group->group_name_utf8, gaim_connection_get_account(gc)); if (conv == NULL) /* show only one window per group */ serv_got_joined_chat(gc, qd->channel++, group->group_name_utf8); } @@ -54,17 +55,19 @@ names = NULL; flags = NULL; - conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT, group->group_name_utf8, gaim_connection_get_account(gc)); + conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT, + group->group_name_utf8, gaim_connection_get_account(gc)); if (conv != NULL && group->members != NULL) { list = group->members; while (list != NULL) { member = (qq_buddy *) list->data; /* always put it even offline */ names = g_list_append(names, - (member->nickname != - NULL) ? - g_strdup(member->nickname) : uid_to_gaim_name(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->nickname != NULL && *(member->nickname) != '\0') ? + g_strdup_printf("%s (qq-%u)", member->nickname, member->uid) : + g_strdup_printf("(qq-%u)", member->uid)); flag = 0; /* TYPING to put online above OP and FOUNDER */ if (is_online(member->status)) flag |= (GAIM_CBFLAGS_TYPING | GAIM_CBFLAGS_VOICE);
--- a/libgaim/protocols/qq/group_find.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_find.c Fri Sep 01 11:03:18 2006 +0000 @@ -29,38 +29,6 @@ #include "qq.h" #include "utils.h" -/* find a chat member's valid gaim_name of its nickname and chat room channel */ -gchar *qq_group_find_member_by_channel_and_nickname(GaimConnection *gc, gint channel, const gchar *who) -{ - qq_group *group; - qq_buddy *member; - GList *list; - - g_return_val_if_fail(gc != NULL && who != NULL, NULL); - - /* TODO checkbox for this in UI */ - /* if it starts with QQ_NAME_PREFIX, we think it is valid name already - * otherwise we think it is nickname and try to find the matching gaim_name */ - /* - if (gaim_str_has_prefix(who, QQ_NAME_PREFIX) && gaim_name_to_uid(who) > 0) - return (gchar *) who; - */ - - group = qq_group_find_by_channel(gc, channel); - g_return_val_if_fail(group != NULL, NULL); - - list = group->members; - member = NULL; - while (list != NULL) { - member = (qq_buddy *) list->data; - if (member->nickname != NULL && !g_ascii_strcasecmp(member->nickname, who)) - break; - list = list->next; - } - - return (member == NULL) ? NULL : uid_to_gaim_name(member->uid); -} - /* find the internal_group_id by the reply packet sequence * return TRUE if we have a record of it, return FALSE if not */ gboolean qq_group_find_internal_group_id_by_seq(GaimConnection *gc, guint16 seq, guint32 *internal_group_id) @@ -69,7 +37,10 @@ qq_data *qd; group_packet *p; - g_return_val_if_fail(gc != NULL && gc->proto_data != NULL && internal_group_id != NULL, FALSE); + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE); + + if (internal_group_id == NULL) + return FALSE; qd = (qq_data *) gc->proto_data; list = qd->group_packets; @@ -87,7 +58,7 @@ return FALSE; } -/* find a qq_buddy by uid, called by qq_im.c */ +/* find a qq_buddy by uid, called by im.c */ qq_buddy *qq_group_find_member_by_uid(qq_group *group, guint32 uid) { GList *list; @@ -138,7 +109,7 @@ buddy = gaim_find_buddy(gaim_connection_get_account(gc), uid_to_gaim_name(member_uid)); if (buddy != NULL) { q_bud = (qq_buddy *) buddy->proto_data; - if (q_bud != NULL) + if (q_bud != NULL && q_bud->nickname != NULL) member->nickname = g_strdup(q_bud->nickname); else if (buddy->alias != NULL) member->nickname = g_strdup(buddy->alias); @@ -175,23 +146,24 @@ return group; } -/* find a qq_group by internal_group_id */ -qq_group *qq_group_find_by_internal_group_id(GaimConnection *gc, guint32 internal_group_id) +/* find a qq_group by its id, flag is QQ_INTERNAL_ID or QQ_EXTERNAL_ID */ +qq_group *qq_group_find_by_id(GaimConnection *gc, guint32 id, gboolean flag) { GList *list; qq_group *group; qq_data *qd; - g_return_val_if_fail(gc != NULL && gc->proto_data != NULL && internal_group_id > 0, NULL); + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL); + qd = (qq_data *) gc->proto_data; - qd = (qq_data *) gc->proto_data; - if (qd->groups == NULL) + if (qd->groups == NULL || id <= 0) return NULL; list = qd->groups; while (list != NULL) { group = (qq_group *) list->data; - if (group->internal_group_id == internal_group_id) + if (flag == QQ_INTERNAL_ID ? + (group->internal_group_id == id) : (group->external_group_id == id)) return group; list = list->next; }
--- a/libgaim/protocols/qq/group_find.h Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_find.h Fri Sep 01 11:03:18 2006 +0000 @@ -27,12 +27,14 @@ #include "connection.h" #include "group.h" -gchar *qq_group_find_member_by_channel_and_nickname(GaimConnection *gc, gint channel, const gchar *who); +#define QQ_INTERNAL_ID 0 +#define QQ_EXTERNAL_ID 1 + qq_buddy *qq_group_find_member_by_uid(qq_group *group, guint32 uid); void qq_group_remove_member_by_uid(qq_group *group, guint32 uid); qq_buddy *qq_group_find_or_add_member(GaimConnection *gc, qq_group *group, guint32 member_uid); gboolean qq_group_find_internal_group_id_by_seq(GaimConnection *gc, guint16 seq, guint32 *internal_group_id); qq_group *qq_group_find_by_channel(GaimConnection *gc, gint channel); -qq_group *qq_group_find_by_internal_group_id(GaimConnection *gc, guint32 internal_group_id); +qq_group *qq_group_find_by_id(GaimConnection *gc, guint32 id, gboolean flag); #endif
--- a/libgaim/protocols/qq/group_free.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_free.c Fri Sep 01 11:03:18 2006 +0000 @@ -23,12 +23,11 @@ #include "debug.h" #include "buddy_status.h" -#include "group.h" #include "group_free.h" #include "group_network.h" /* gracefully free all members in a group */ -static void _qq_group_free_member(qq_group *group) +static void qq_group_free_member(qq_group *group) { gint i; GList *list; @@ -48,10 +47,10 @@ } /* gracefully free the memory for one qq_group */ -static void _qq_group_free(qq_group *group) +void qq_group_free(qq_group *group) { g_return_if_fail(group != NULL); - _qq_group_free_member(group); + qq_group_free_member(group); g_free(group->group_name_utf8); g_free(group->group_desc_utf8); g_free(group); @@ -73,25 +72,6 @@ gaim_debug(GAIM_DEBUG_INFO, "QQ", "%d group packets are freed!\n", i); } -void qq_group_remove_by_internal_group_id(qq_data *qd, guint32 internal_group_id) -{ - qq_group *group; - GList *list; - g_return_if_fail(qd != NULL); - - list = qd->groups; - while (list != NULL) { - group = (qq_group *) qd->groups->data; - if (internal_group_id == group->internal_group_id) { - qd->groups = g_list_remove(qd->groups, group); - _qq_group_free(group); - break; - } else { - list = list->next; - } - } -} - void qq_group_free_all(qq_data *qd) { qq_group *group; @@ -103,7 +83,7 @@ i++; group = (qq_group *) qd->groups->data; qd->groups = g_list_remove(qd->groups, group); - _qq_group_free(group); + qq_group_free(group); } gaim_debug(GAIM_DEBUG_INFO, "QQ", "%d groups are freed\n", i);
--- a/libgaim/protocols/qq/group_free.h Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_free.h Fri Sep 01 11:03:18 2006 +0000 @@ -25,11 +25,11 @@ #include <glib.h> #include "qq.h" +#include "group.h" void qq_group_packets_free(qq_data *qd); +void qq_group_free(qq_group *group); void qq_group_free_all(qq_data *qd); -void qq_group_remove_by_internal_group_id(qq_data *qd, guint32 internal_group_id); - #endif
--- a/libgaim/protocols/qq/group_hash.c Fri Sep 01 10:05:30 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,195 +0,0 @@ -/** -* The QQ2003C protocol plugin - * - * for gaim - * - * Copyright (C) 2004 Puzzlebird - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "blist.h" -#include "debug.h" - -#include "buddy_opt.h" -#include "group_hash.h" -#include "group_misc.h" -#include "utils.h" - -static gchar *_qq_group_set_my_status_desc(qq_group *group) -{ - const char *status_desc; - g_return_val_if_fail(group != NULL, g_strdup("")); - - switch (group->my_status) { - case QQ_GROUP_MEMBER_STATUS_NOT_MEMBER: - status_desc = _("I am not member"); - break; - case QQ_GROUP_MEMBER_STATUS_IS_MEMBER: - status_desc = _("I am a member"); - break; - case QQ_GROUP_MEMBER_STATUS_APPLYING: - status_desc = _("I am applying to join"); - break; - case QQ_GROUP_MEMBER_STATUS_IS_ADMIN: - status_desc = _("I am the admin"); - break; - default: - status_desc = _("Unknown status"); - } - - return g_strdup(status_desc); -} - -static void _qq_group_add_to_blist(GaimConnection *gc, qq_group *group) -{ - GHashTable *components; - GaimGroup *g; - GaimChat *chat; - components = qq_group_to_hashtable(group); - chat = gaim_chat_new(gaim_connection_get_account(gc), group->group_name_utf8, components); - g = qq_get_gaim_group(GAIM_GROUP_QQ_QUN); - gaim_blist_add_chat(chat, g, NULL); - gaim_debug(GAIM_DEBUG_INFO, "QQ", "You have add group \"%s\" to blist locally\n", group->group_name_utf8); -} - -/* create a dummy qq_group, which includes only internal_id and external_id - * all other attributes should be set to empty. - * and we need to send a get_group_info to QQ server to update it right away */ -qq_group *qq_group_create_by_id(GaimConnection *gc, guint32 internal_id, guint32 external_id) -{ - qq_group *group; - qq_data *qd; - - g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL); - g_return_val_if_fail(internal_id > 0, NULL); - qd = (qq_data *) gc->proto_data; - - group = g_new0(qq_group, 1); - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; - group->my_status_desc = _qq_group_set_my_status_desc(group); - group->internal_group_id = internal_id; - group->external_group_id = external_id; - group->group_type = 0x01; /* assume permanent Qun */ - group->creator_uid = 10000; /* assume by QQ admin */ - group->group_category = 0x01; - group->auth_type = 0x02; /* assume need auth */ - group->group_name_utf8 = g_strdup(""); - group->group_desc_utf8 = g_strdup(""); - group->notice_utf8 = g_strdup(""); - group->members = NULL; - - qd->groups = g_list_append(qd->groups, group); - _qq_group_add_to_blist(gc, group); - - return group; -} - -/* convert a qq_group to hash-table, which could be component of GaimChat */ -GHashTable *qq_group_to_hashtable(qq_group *group) -{ - GHashTable *components; - components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_MEMBER_STATUS), g_strdup_printf("%d", group->my_status)); - group->my_status_desc = _qq_group_set_my_status_desc(group); - - g_hash_table_insert(components, - g_strdup(QQ_GROUP_KEY_INTERNAL_ID), g_strdup_printf("%d", group->internal_group_id)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_EXTERNAL_ID), - g_strdup_printf("%d", group->external_group_id)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_GROUP_TYPE), g_strdup_printf("%d", group->group_type)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); - g_hash_table_insert(components, - g_strdup(QQ_GROUP_KEY_GROUP_CATEGORY), g_strdup_printf("%d", group->group_category)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_MEMBER_STATUS_DESC), g_strdup(group->my_status_desc)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_GROUP_NAME_UTF8), g_strdup(group->group_name_utf8)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_GROUP_DESC_UTF8), g_strdup(group->group_desc_utf8)); - return components; -} - -/* create a qq_group from hashtable */ -qq_group *qq_group_from_hashtable(GaimConnection *gc, GHashTable *data) -{ - qq_data *qd; - qq_group *group; - - g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL); - g_return_val_if_fail(data != NULL, NULL); - qd = (qq_data *) gc->proto_data; - - group = g_new0(qq_group, 1); - group->my_status = - qq_string_to_dec_value - (NULL == - g_hash_table_lookup(data, - QQ_GROUP_KEY_MEMBER_STATUS) ? - g_strdup_printf("%d", - QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) : - g_hash_table_lookup(data, QQ_GROUP_KEY_MEMBER_STATUS)); - group->internal_group_id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_INTERNAL_ID)); - group->external_group_id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_EXTERNAL_ID)); - group->group_type = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_TYPE)); - group->creator_uid = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_CREATOR_UID)); - group->group_category = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_CATEGORY)); - group->auth_type = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_AUTH_TYPE)); - group->group_name_utf8 = g_strdup(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_NAME_UTF8)); - group->group_desc_utf8 = g_strdup(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_DESC_UTF8)); - group->my_status_desc = _qq_group_set_my_status_desc(group); - - qd->groups = g_list_append(qd->groups, group); - - return group; -} - -/* refresh group local subscription */ -void qq_group_refresh(GaimConnection *gc, qq_group *group) -{ - GaimChat *chat; - g_return_if_fail(gc != NULL && group != NULL); - - chat = gaim_blist_find_chat(gaim_connection_get_account(gc), g_strdup_printf("%d", group->external_group_id)); - if (chat == NULL && group->my_status != QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) { - _qq_group_add_to_blist(gc, group); - } else if (chat != NULL) { /* we have a local record, update its info */ - /* if there is group_name_utf8, we update the group name */ - if (group->group_name_utf8 != NULL && strlen(group->group_name_utf8) > 0) - gaim_blist_alias_chat(chat, group->group_name_utf8); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_MEMBER_STATUS), g_strdup_printf("%d", group->my_status)); - group->my_status_desc = _qq_group_set_my_status_desc(group); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_MEMBER_STATUS_DESC), g_strdup(group->my_status_desc)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_INTERNAL_ID), - g_strdup_printf("%d", group->internal_group_id)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_EXTERNAL_ID), - g_strdup_printf("%d", group->external_group_id)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_GROUP_TYPE), g_strdup_printf("%d", group->group_type)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_GROUP_CATEGORY), - g_strdup_printf("%d", group->group_category)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_GROUP_NAME_UTF8), g_strdup(group->group_name_utf8)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_GROUP_DESC_UTF8), g_strdup(group->group_desc_utf8)); - } -}
--- a/libgaim/protocols/qq/group_hash.h Fri Sep 01 10:05:30 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/** -* The QQ2003C protocol plugin - * - * for gaim - * - * Copyright (C) 2004 Puzzlebird - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _QQ_GROUP_HASH_H_ -#define _QQ_GROUP_HASH_H_ - -#include <glib.h> -#include "group.h" - -#define QQ_GROUP_KEY_MEMBER_STATUS "my_status_code" -#define QQ_GROUP_KEY_MEMBER_STATUS_DESC "my_status_desc" -#define QQ_GROUP_KEY_INTERNAL_ID "internal_group_id" -#define QQ_GROUP_KEY_EXTERNAL_ID "external_group_id" -#define QQ_GROUP_KEY_GROUP_TYPE "group_type" -#define QQ_GROUP_KEY_CREATOR_UID "creator_uid" -#define QQ_GROUP_KEY_GROUP_CATEGORY "group_category" -#define QQ_GROUP_KEY_AUTH_TYPE "auth_type" -#define QQ_GROUP_KEY_GROUP_NAME_UTF8 "group_name_utf8" -#define QQ_GROUP_KEY_GROUP_DESC_UTF8 "group_desc_utf8" - -qq_group *qq_group_create_by_id(GaimConnection *gc, guint32 internal_id, guint32 external_id); -GHashTable *qq_group_to_hashtable(qq_group *group); - -qq_group *qq_group_from_hashtable(GaimConnection *gc, GHashTable *data); -void qq_group_refresh(GaimConnection *gc, qq_group *group); - -#endif
--- a/libgaim/protocols/qq/group_im.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_im.c Fri Sep 01 11:03:18 2006 +0000 @@ -29,7 +29,7 @@ #include "char_conv.h" #include "group_find.h" -#include "group_hash.h" +#include "group_internal.h" #include "group_info.h" #include "group_im.h" #include "group_network.h" @@ -171,7 +171,7 @@ gaim_notify_warning(gc, _("QQ Qun Operation"), msg, reason); - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); if (group != NULL) { group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; qq_group_refresh(gc, group); @@ -211,7 +211,7 @@ gaim_notify_warning(gc, _("QQ Qun Operation"), msg, NULL); - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); if (group != NULL) { group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; qq_group_refresh(gc, group); @@ -246,7 +246,7 @@ msg = g_strdup_printf(_("You [%d] has exit group \"%d\""), uid, external_group_id); gaim_notify_info(gc, _("QQ Qun Operation"), msg, NULL); - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); if (group != NULL) { group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; qq_group_refresh(gc, group); @@ -278,14 +278,14 @@ g_return_if_fail(external_group_id > 0 && uid > 0); msg = g_strdup_printf(_("You [%d] has been added by group \"%d\""), uid, external_group_id); - gaim_notify_info(gc, _("QQ Qun Operation"), msg, _("OpenQ has added this group to your buddy list")); + gaim_notify_info(gc, _("QQ Qun Operation"), msg, _("This group has been added to your buddy list")); - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); if (group != NULL) { group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; qq_group_refresh(gc, group); } else { /* no such group, try to create a dummy first, and then update */ - group = qq_group_create_by_id(gc, internal_group_id, external_group_id); + group = qq_group_create_internal_record(gc, internal_group_id, external_group_id, NULL); group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; qq_group_refresh(gc, group); qq_send_cmd_group_get_group_info(gc, group); @@ -379,7 +379,7 @@ else msg_utf8_encoded = qq_to_utf8(msg_with_gaim_smiley, QQ_CHARSET_DEFAULT); - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT, group->group_name_utf8, gaim_connection_get_account(gc));
--- a/libgaim/protocols/qq/group_info.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_info.c Fri Sep 01 11:03:18 2006 +0000 @@ -26,7 +26,7 @@ #include "buddy_status.h" #include "char_conv.h" #include "group_find.h" -#include "group_hash.h" +#include "group_internal.h" #include "group_info.h" #include "buddy_status.h" #include "group_network.h" @@ -42,7 +42,7 @@ (time(NULL) - member->last_refresh) > QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL; } -/* this is done when we receive the reply to get_online_member sub_cmd +/* this is done when we receive the reply to get_online_members sub_cmd * all member are set offline, and then only those in reply packets are online */ static void _qq_group_set_members_all_offline(qq_group *group) { @@ -82,7 +82,7 @@ } /* send packet to get online group member, called by keep_alive */ -void qq_send_cmd_group_get_online_member(GaimConnection *gc, qq_group *group) +void qq_send_cmd_group_get_online_members(GaimConnection *gc, qq_group *group) { guint8 *raw_data, *cursor; gint bytes, data_len; @@ -111,8 +111,8 @@ qq_send_group_cmd(gc, group, raw_data, data_len); } -/* send packet to get group member info */ -void qq_send_cmd_group_get_member_info(GaimConnection *gc, qq_group *group) +/* send packet to get info for each group member */ +void qq_send_cmd_group_get_members_info(GaimConnection *gc, qq_group *group) { guint8 *raw_data, *cursor; gint bytes, data_len, i; @@ -160,9 +160,10 @@ qq_buddy *member; qq_data *qd; GaimConversation *gaim_conv; - guint8 orgnization, role; - guint16 unknown; - guint32 member_uid, internal_group_id; + guint8 organization, role; + guint16 unknown, max_members; + guint32 member_uid, internal_group_id, external_group_id; + GSList *pending_id; gint pascal_len, i; guint32 unknown4; guint8 unknown1; @@ -173,11 +174,18 @@ read_packet_dw(data, cursor, len, &(internal_group_id)); g_return_if_fail(internal_group_id > 0); + read_packet_dw(data, cursor, len, &(external_group_id)); + g_return_if_fail(internal_group_id > 0); - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + pending_id = qq_get_pending_id(qd->adding_groups_from_server, internal_group_id); + if (pending_id != NULL) { + qq_set_pending_id(&qd->adding_groups_from_server, internal_group_id, FALSE); + qq_group_create_internal_record(gc, internal_group_id, external_group_id, NULL); + } + + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); - read_packet_dw(data, cursor, len, &(group->external_group_id)); read_packet_b(data, cursor, len, &(group->group_type)); read_packet_dw(data, cursor, len, &unknown4); /* unknown 4 bytes */ read_packet_dw(data, cursor, len, &(group->creator_uid)); @@ -185,7 +193,7 @@ read_packet_dw(data, cursor, len, &unknown4); /* oldCategory */ read_packet_w(data, cursor, len, &unknown); read_packet_dw(data, cursor, len, &(group->group_category)); - read_packet_w(data, cursor, len, &(unknown)); /* 0x0000 */ + read_packet_w(data, cursor, len, &max_members); read_packet_b(data, cursor, len, &unknown1); read_packet_dw(data, cursor, len, &(unknown4)); /* versionID */ @@ -202,17 +210,18 @@ while (*cursor < data + len) { read_packet_dw(data, cursor, len, &member_uid); i++; - read_packet_b(data, cursor, len, &orgnization); + read_packet_b(data, cursor, len, &organization); read_packet_b(data, cursor, len, &role); - if(orgnization != 0 || role != 0) { - gaim_debug(GAIM_DEBUG_INFO, "QQ", "group member %d: orgnizatio=%d, role=%d\n", member_uid, orgnization, role); + if(organization != 0 || role != 0) { + gaim_debug(GAIM_DEBUG_INFO, "QQ", "group member %d: organization=%d, role=%d\n", member_uid, organization, role); } member = qq_group_find_or_add_member(gc, group, member_uid); - member->role = role; + if (member != NULL) + member->role = role; } if(*cursor > (data + len)) { - gaim_debug(GAIM_DEBUG_ERROR, "QQ", "group_cmd_get_group_info: Dangerous error! maybe protocal changed, notify me!"); + gaim_debug(GAIM_DEBUG_ERROR, "QQ", "group_cmd_get_group_info: Dangerous error! maybe protocol changed, notify me!"); } gaim_debug(GAIM_DEBUG_INFO, "QQ", "group \"%s\" has %d members\n", group->group_name_utf8, i); @@ -233,7 +242,7 @@ } } -void qq_process_group_cmd_get_online_member(guint8 *data, guint8 **cursor, gint len, GaimConnection *gc) +void qq_process_group_cmd_get_online_members(guint8 *data, guint8 **cursor, gint len, GaimConnection *gc) { guint32 internal_group_id, member_uid; guint8 unknown; @@ -254,7 +263,7 @@ bytes += read_packet_b(data, cursor, len, &unknown); /* 0x3c ?? */ g_return_if_fail(internal_group_id > 0); - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); if (group == NULL) { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "We have no group info for internal id [%d]\n", internal_group_id); @@ -272,14 +281,14 @@ } if(*cursor > (data + len)) { gaim_debug(GAIM_DEBUG_ERROR, "QQ", - "group_cmd_get_online_member: Dangerous error! maybe protocol changed, notify developers!"); + "group_cmd_get_online_members: Dangerous error! maybe protocol changed, notify developers!"); } gaim_debug(GAIM_DEBUG_INFO, "QQ", "Group \"%s\" has %d online members\n", group->group_name_utf8, i); } -/* process the reply to get_member_info packet */ -void qq_process_group_cmd_get_member_info(guint8 *data, guint8 **cursor, gint len, GaimConnection *gc) +/* process the reply to get_members_info packet */ +void qq_process_group_cmd_get_members_info(guint8 *data, guint8 **cursor, gint len, GaimConnection *gc) { guint32 internal_group_id, member_uid; guint16 unknown; @@ -292,10 +301,13 @@ read_packet_dw(data, cursor, len, &internal_group_id); g_return_if_fail(internal_group_id > 0); - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); i = 0; + /* TODO: Something is off. I get an entry with strange values + * (including a nick of "") buried in here. I need to find more + * groups to join before I can figure this out */ /* now starts the member info, as get buddy list reply */ while (*cursor < data + len) { read_packet_dw(data, cursor, len, &member_uid); @@ -317,7 +329,7 @@ } if(*cursor > (data + len)) { gaim_debug(GAIM_DEBUG_ERROR, "QQ", - "group_cmd_get_member_info: Dangerous error! maybe protocol changed, notify developers!"); + "group_cmd_get_members_info: Dangerous error! maybe protocol changed, notify developers!"); } gaim_debug(GAIM_DEBUG_INFO, "QQ", "Group \"%s\" obtained %d member info\n", group->group_name_utf8, i); }
--- a/libgaim/protocols/qq/group_info.h Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_info.h Fri Sep 01 11:03:18 2006 +0000 @@ -28,10 +28,10 @@ #include "group.h" void qq_send_cmd_group_get_group_info(GaimConnection *gc, qq_group *group); -void qq_send_cmd_group_get_online_member(GaimConnection *gc, qq_group *group); -void qq_send_cmd_group_get_member_info(GaimConnection *gc, qq_group *group); +void qq_send_cmd_group_get_online_members(GaimConnection *gc, qq_group *group); +void qq_send_cmd_group_get_members_info(GaimConnection *gc, qq_group *group); void qq_process_group_cmd_get_group_info(guint8 *data, guint8 **cursor, gint len, GaimConnection *gc); -void qq_process_group_cmd_get_online_member(guint8 *data, guint8 **cursor, gint len, GaimConnection *gc); -void qq_process_group_cmd_get_member_info(guint8 *data, guint8 **cursor, gint len, GaimConnection *gc); +void qq_process_group_cmd_get_online_members(guint8 *data, guint8 **cursor, gint len, GaimConnection *gc); +void qq_process_group_cmd_get_members_info(guint8 *data, guint8 **cursor, gint len, GaimConnection *gc); #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgaim/protocols/qq/group_internal.c Fri Sep 01 11:03:18 2006 +0000 @@ -0,0 +1,238 @@ +/** +* The QQ2003C protocol plugin + * + * for gaim + * + * Copyright (C) 2004 Puzzlebird + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "blist.h" +#include "debug.h" + +#include "buddy_opt.h" +#include "group_free.h" +#include "group_internal.h" +#include "group_misc.h" +#include "utils.h" + +static gchar *_qq_group_set_my_status_desc(qq_group *group) +{ + const char *status_desc; + g_return_val_if_fail(group != NULL, g_strdup("")); + + switch (group->my_status) { + case QQ_GROUP_MEMBER_STATUS_NOT_MEMBER: + status_desc = _("I am not member"); + break; + case QQ_GROUP_MEMBER_STATUS_IS_MEMBER: + status_desc = _("I am a member"); + break; + case QQ_GROUP_MEMBER_STATUS_APPLYING: + status_desc = _("I am applying to join"); + break; + case QQ_GROUP_MEMBER_STATUS_IS_ADMIN: + status_desc = _("I am the admin"); + break; + default: + status_desc = _("Unknown status"); + } + + return g_strdup(status_desc); +} + +static void _qq_group_add_to_blist(GaimConnection *gc, qq_group *group) +{ + GHashTable *components; + GaimGroup *g; + GaimChat *chat; + components = qq_group_to_hashtable(group); + chat = gaim_chat_new(gaim_connection_get_account(gc), group->group_name_utf8, components); + g = qq_get_gaim_group(GAIM_GROUP_QQ_QUN); + gaim_blist_add_chat(chat, g, NULL); + gaim_debug(GAIM_DEBUG_INFO, "QQ", "You have added group \"%s\" to blist locally\n", group->group_name_utf8); +} + +/* Create a dummy qq_group, which includes only internal_id, external_id, + * and potentially group_name_utf8, in case we need to call group_conv_show_window + * right after creation. All other attributes are set to empty. + * We need to send a get_group_info to the QQ server to update it right away */ +qq_group *qq_group_create_internal_record(GaimConnection *gc, + guint32 internal_id, guint32 external_id, gchar *group_name_utf8) +{ + qq_group *group; + qq_data *qd; + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL); + g_return_val_if_fail(internal_id > 0, NULL); + qd = (qq_data *) gc->proto_data; + + group = g_new0(qq_group, 1); + group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; + group->my_status_desc = _qq_group_set_my_status_desc(group); + group->internal_group_id = internal_id; + group->external_group_id = external_id; + group->group_type = 0x01; /* assume permanent Qun */ + group->creator_uid = 10000; /* assume by QQ admin */ + group->group_category = 0x01; + group->auth_type = 0x02; /* assume need auth */ + group->group_name_utf8 = g_strdup(group_name_utf8 == NULL ? "" : group_name_utf8); + group->group_desc_utf8 = g_strdup(""); + group->notice_utf8 = g_strdup(""); + group->members = NULL; + + qd->groups = g_list_append(qd->groups, group); + _qq_group_add_to_blist(gc, group); + + return group; +} + +void qq_group_delete_internal_record(qq_data *qd, guint32 internal_group_id) +{ + qq_group *group; + GList *list; + g_return_if_fail(qd != NULL); + + list = qd->groups; + while (list != NULL) { + group = (qq_group *) qd->groups->data; + if (internal_group_id == group->internal_group_id) { + qd->groups = g_list_remove(qd->groups, group); + qq_group_free(group); + break; + } else { + list = list->next; + } + } +} + +/* convert a qq_group to hash-table, which could be component of GaimChat */ +GHashTable *qq_group_to_hashtable(qq_group *group) +{ + GHashTable *components; + components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_MEMBER_STATUS), g_strdup_printf("%d", group->my_status)); + group->my_status_desc = _qq_group_set_my_status_desc(group); + + g_hash_table_insert(components, + g_strdup(QQ_GROUP_KEY_INTERNAL_ID), g_strdup_printf("%d", group->internal_group_id)); + g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_EXTERNAL_ID), + g_strdup_printf("%d", group->external_group_id)); + g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_GROUP_TYPE), g_strdup_printf("%d", group->group_type)); + g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); + g_hash_table_insert(components, + g_strdup(QQ_GROUP_KEY_GROUP_CATEGORY), g_strdup_printf("%d", group->group_category)); + g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); + g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_MEMBER_STATUS_DESC), g_strdup(group->my_status_desc)); + g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_GROUP_NAME_UTF8), g_strdup(group->group_name_utf8)); + g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_GROUP_DESC_UTF8), g_strdup(group->group_desc_utf8)); + return components; +} + +/* create a qq_group from hashtable */ +qq_group *qq_group_from_hashtable(GaimConnection *gc, GHashTable *data) +{ + qq_data *qd; + qq_group *group; + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL); + g_return_val_if_fail(data != NULL, NULL); + qd = (qq_data *) gc->proto_data; + + group = g_new0(qq_group, 1); + group->my_status = + qq_string_to_dec_value + (NULL == + g_hash_table_lookup(data, + QQ_GROUP_KEY_MEMBER_STATUS) ? + g_strdup_printf("%d", + QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) : + g_hash_table_lookup(data, QQ_GROUP_KEY_MEMBER_STATUS)); + group->internal_group_id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_INTERNAL_ID)); + group->external_group_id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_EXTERNAL_ID)); + group->group_type = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_TYPE)); + group->creator_uid = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_CREATOR_UID)); + group->group_category = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_CATEGORY)); + group->auth_type = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_AUTH_TYPE)); + group->group_name_utf8 = g_strdup(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_NAME_UTF8)); + group->group_desc_utf8 = g_strdup(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_DESC_UTF8)); + group->my_status_desc = _qq_group_set_my_status_desc(group); + + qd->groups = g_list_append(qd->groups, group); + + return group; +} + +/* refresh group local subscription */ +void qq_group_refresh(GaimConnection *gc, qq_group *group) +{ + GaimChat *chat; + gchar *external_group_id; + g_return_if_fail(gc != NULL && group != NULL); + + external_group_id = g_strdup_printf("%d", group->external_group_id); + chat = gaim_blist_find_chat(gaim_connection_get_account(gc), external_group_id); + g_free(external_group_id); + if (chat == NULL && group->my_status != QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) { + _qq_group_add_to_blist(gc, group); + } else if (chat != NULL) { /* we have a local record, update its info */ + /* if there is group_name_utf8, we update the group name */ + if (group->group_name_utf8 != NULL && strlen(group->group_name_utf8) > 0) + gaim_blist_alias_chat(chat, group->group_name_utf8); + g_hash_table_replace(chat->components, + g_strdup(QQ_GROUP_KEY_MEMBER_STATUS), g_strdup_printf("%d", group->my_status)); + group->my_status_desc = _qq_group_set_my_status_desc(group); + g_hash_table_replace(chat->components, + g_strdup(QQ_GROUP_KEY_MEMBER_STATUS_DESC), g_strdup(group->my_status_desc)); + g_hash_table_replace(chat->components, + g_strdup(QQ_GROUP_KEY_INTERNAL_ID), + g_strdup_printf("%d", group->internal_group_id)); + g_hash_table_replace(chat->components, + g_strdup(QQ_GROUP_KEY_EXTERNAL_ID), + g_strdup_printf("%d", group->external_group_id)); + g_hash_table_replace(chat->components, + g_strdup(QQ_GROUP_KEY_GROUP_TYPE), g_strdup_printf("%d", group->group_type)); + g_hash_table_replace(chat->components, + g_strdup(QQ_GROUP_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); + g_hash_table_replace(chat->components, + g_strdup(QQ_GROUP_KEY_GROUP_CATEGORY), + g_strdup_printf("%d", group->group_category)); + g_hash_table_replace(chat->components, + g_strdup(QQ_GROUP_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); + g_hash_table_replace(chat->components, + g_strdup(QQ_GROUP_KEY_GROUP_NAME_UTF8), g_strdup(group->group_name_utf8)); + g_hash_table_replace(chat->components, + g_strdup(QQ_GROUP_KEY_GROUP_DESC_UTF8), g_strdup(group->group_desc_utf8)); + } +} + +/* NOTE: If we knew how to convert between an external and internal group id, as the official + * client seems to, the following would be unnecessary. That would be ideal. */ + +/* Use list to specify if id's alternate id is pending discovery. */ +void qq_set_pending_id(GSList **list, guint32 id, gboolean pending) +{ + if (pending) + *list = g_slist_prepend(*list, GINT_TO_POINTER(id)); + else + *list = g_slist_remove(*list, GINT_TO_POINTER(id)); +} + +/* Return the location of id in list, or NULL if not found */ +GSList *qq_get_pending_id(GSList *list, guint32 id) +{ + return g_slist_find(list, GINT_TO_POINTER(id)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgaim/protocols/qq/group_internal.h Fri Sep 01 11:03:18 2006 +0000 @@ -0,0 +1,52 @@ +/** +* The QQ2003C protocol plugin + * + * for gaim + * + * Copyright (C) 2004 Puzzlebird + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _QQ_GROUP_HASH_H_ +#define _QQ_GROUP_HASH_H_ + +#include <glib.h> +#include "group.h" + +#define QQ_GROUP_KEY_MEMBER_STATUS "my_status_code" +#define QQ_GROUP_KEY_MEMBER_STATUS_DESC "my_status_desc" +#define QQ_GROUP_KEY_INTERNAL_ID "internal_group_id" +#define QQ_GROUP_KEY_EXTERNAL_ID "external_group_id" +#define QQ_GROUP_KEY_GROUP_TYPE "group_type" +#define QQ_GROUP_KEY_CREATOR_UID "creator_uid" +#define QQ_GROUP_KEY_GROUP_CATEGORY "group_category" +#define QQ_GROUP_KEY_AUTH_TYPE "auth_type" +#define QQ_GROUP_KEY_GROUP_NAME_UTF8 "group_name_utf8" +#define QQ_GROUP_KEY_GROUP_DESC_UTF8 "group_desc_utf8" + +qq_group *qq_group_create_internal_record(GaimConnection *gc, + guint32 internal_id, guint32 external_id, gchar *group_name_utf8); +void qq_group_delete_internal_record(qq_data *qd, guint32 internal_group_id); + +GHashTable *qq_group_to_hashtable(qq_group *group); +qq_group *qq_group_from_hashtable(GaimConnection *gc, GHashTable *data); + +void qq_group_refresh(GaimConnection *gc, qq_group *group); + +void qq_set_pending_id(GSList **list, guint32 id, gboolean pending); +GSList *qq_get_pending_id(GSList *list, guint32 id); + +#endif
--- a/libgaim/protocols/qq/group_join.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_join.c Fri Sep 01 11:03:18 2006 +0000 @@ -30,11 +30,12 @@ #include "group_conv.h" #include "group_find.h" #include "group_free.h" -#include "group_hash.h" +#include "group_internal.h" #include "group_info.h" #include "group_join.h" #include "group_opt.h" #include "group_network.h" +#include "group_search.h" enum { QQ_GROUP_JOIN_OK = 0x01, @@ -51,24 +52,37 @@ gc = g->gc; internal_group_id = g->uid; - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); qq_send_cmd_group_exit_group(gc, group); } /* send packet to join a group without auth */ -static void _qq_send_cmd_group_join_group(GaimConnection *gc, qq_group *group) +void qq_send_cmd_group_join_group(GaimConnection *gc, qq_group *group) { guint8 *raw_data, *cursor; gint bytes, data_len; g_return_if_fail(gc != NULL && group != NULL); + if (group->my_status == QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) { group->my_status = QQ_GROUP_MEMBER_STATUS_APPLYING; qq_group_refresh(gc, group); } + switch (group->auth_type) { + case QQ_GROUP_AUTH_TYPE_NO_AUTH: + case QQ_GROUP_AUTH_TYPE_NEED_AUTH: + break; + case QQ_GROUP_AUTH_TYPE_NO_ADD: + gaim_notify_warning(gc, NULL, _("This group does not allow others to join"), NULL); + return; + default: + gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Unknown group auth type: %d\n", group->auth_type); + break; + } + data_len = 5; raw_data = g_newa(guint8, data_len); cursor = raw_data; @@ -94,7 +108,7 @@ gc = g->gc; internal_group_id = g->uid; - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); if (group == NULL) { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Can not find qq_group by internal_id: %d\n", internal_group_id); return; @@ -163,15 +177,7 @@ qq_send_group_cmd(gc, group, raw_data, data_len); } -/* send packet to exit one group - * In fact, this will never be used for GAIM - * when we remove a GaimChat node, there is no user controlable callback - * so we only remove the GaimChat node, - * but we never use this cmd to update the server side - * anyway, it is function, as when we remove the GaimChat node, - * user has no way to start up the chat conversation window - * therefore even we are still in it, - * the group IM will not show up to bother us. (Limited by GAIM) */ +/* send a packet to exit a group */ void qq_send_cmd_group_exit_group(GaimConnection *gc, qq_group *group) { guint8 *raw_data, *cursor; @@ -212,16 +218,16 @@ bytes += read_packet_dw(data, cursor, len, &internal_group_id); if (bytes == expected_bytes) { - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); if (group != NULL) { chat = gaim_blist_find_chat (gaim_connection_get_account(gc), g_strdup_printf("%d", group->external_group_id)); if (chat != NULL) gaim_blist_remove_chat(chat); - qq_group_remove_by_internal_group_id(qd, internal_group_id); + qq_group_delete_internal_record(qd, internal_group_id); } - gaim_notify_info(gc, _("QQ Qun Operation"), _("You have successfully exit group"), NULL); + gaim_notify_info(gc, _("QQ Qun Operation"), _("You have successfully exited the group"), NULL); } else { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Invalid exit group reply, expect %d bytes, read %d bytes\n", expected_bytes, bytes); @@ -246,7 +252,8 @@ if (bytes == expected_bytes) gaim_notify_info - (gc, _("QQ Group Auth"), _("You authorization operation has been accepted by QQ server"), NULL); + (gc, _("QQ Group Auth"), + _("Your authorization operation has been accepted by the QQ server"), NULL); else gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Invalid join group reply, expect %d bytes, read %d bytes\n", expected_bytes, bytes); @@ -272,7 +279,7 @@ "Invalid join group reply, expect %d bytes, read %d bytes\n", expected_bytes, bytes); return; } else { /* join group OK */ - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); /* need to check if group is NULL or not. */ g_return_if_fail(group != NULL); switch (reply) { @@ -280,7 +287,7 @@ gaim_debug(GAIM_DEBUG_INFO, "QQ", "Succeed joining group \"%s\"\n", group->group_name_utf8); group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; qq_group_refresh(gc, group); - /* this must be show before getting online member */ + /* this must be shown before getting online members */ qq_group_conv_show_window(gc, group); qq_send_cmd_group_get_group_info(gc, group); break; @@ -300,38 +307,33 @@ } } -/* Apply to join one group without auth */ +/* Attempt to join a group without auth */ void qq_group_join(GaimConnection *gc, GHashTable *data) { - gchar *internal_group_id_ptr; - guint32 internal_group_id; + qq_data *qd; + gchar *external_group_id_ptr; + guint32 external_group_id; qq_group *group; - g_return_if_fail(gc != NULL && data != NULL); - - internal_group_id_ptr = g_hash_table_lookup(data, "internal_group_id"); - internal_group_id = strtol(internal_group_id_ptr, NULL, 10); - - g_return_if_fail(internal_group_id > 0); - - /* for those we have subscribed, they should have been put into - * qd->groups in qq_group_init subroutine */ - group = qq_group_find_by_internal_group_id(gc, internal_group_id); - if (group == NULL) - group = qq_group_from_hashtable(gc, data); + g_return_if_fail(gc != NULL && gc->proto_data != NULL && data != NULL); + qd = (qq_data *) gc->proto_data; - g_return_if_fail(group != NULL); + external_group_id_ptr = g_hash_table_lookup(data, QQ_GROUP_KEY_EXTERNAL_ID); + g_return_if_fail(external_group_id_ptr != NULL); + errno = 0; + external_group_id = strtol(external_group_id_ptr, NULL, 10); + if (errno != 0) { + gaim_notify_error(gc, _("Error"), + _("You inputted a group id outside the acceptable range"), NULL); + return; + } - switch (group->auth_type) { - case QQ_GROUP_AUTH_TYPE_NO_AUTH: - case QQ_GROUP_AUTH_TYPE_NEED_AUTH: - _qq_send_cmd_group_join_group(gc, group); - break; - case QQ_GROUP_AUTH_TYPE_NO_ADD: - gaim_notify_warning(gc, NULL, _("This group does not allow others to join"), NULL); - break; - default: - gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Unknown group auth type: %d\n", group->auth_type); + group = qq_group_find_by_id(gc, external_group_id, QQ_EXTERNAL_ID); + if (group) { + qq_send_cmd_group_join_group(gc, group); + } else { + qq_set_pending_id(&qd->joining_groups, external_group_id, TRUE); + qq_send_cmd_group_search_group(gc, external_group_id); } }
--- a/libgaim/protocols/qq/group_join.h Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_join.h Fri Sep 01 11:03:18 2006 +0000 @@ -41,6 +41,7 @@ void qq_send_cmd_group_auth(GaimConnection *gc, qq_group *group, guint8 opt, guint32 uid, const gchar *reason_utf8); void qq_group_join(GaimConnection *gc, GHashTable *data); +void qq_send_cmd_group_join_group(GaimConnection *gc, qq_group *group); void qq_group_exit(GaimConnection *gc, GHashTable *data); void qq_send_cmd_group_exit_group(GaimConnection *gc, qq_group *group); void qq_process_group_cmd_exit_group(guint8 *data, guint8 **cursor, gint len, GaimConnection *gc);
--- a/libgaim/protocols/qq/group_network.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_network.c Fri Sep 01 11:03:18 2006 +0000 @@ -27,7 +27,7 @@ #include "crypt.h" #include "group_conv.h" #include "group_find.h" -#include "group_hash.h" +#include "group_internal.h" #include "group_im.h" #include "group_info.h" #include "group_join.h" @@ -40,6 +40,7 @@ enum { QQ_GROUP_CMD_REPLY_OK = 0x00, + QQ_GROUP_CMD_REPLY_SEARCH_ERROR = 0x02, QQ_GROUP_CMD_REPLY_NOT_MEMBER = 0x0a }; @@ -154,11 +155,15 @@ bytes += read_packet_b(data, &cursor, len, &sub_cmd); bytes += read_packet_b(data, &cursor, len, &reply); - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); if (reply != QQ_GROUP_CMD_REPLY_OK) { gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Group cmd reply says cmd %s fails\n", qq_group_cmd_get_desc(sub_cmd)); + + if (group != NULL) + qq_set_pending_id(&qd->joining_groups, group->external_group_id, FALSE); + switch (reply) { /* this should be all errors */ case QQ_GROUP_CMD_REPLY_NOT_MEMBER: if (group != NULL) { @@ -169,19 +174,26 @@ qq_group_refresh(gc, group); } break; + case QQ_GROUP_CMD_REPLY_SEARCH_ERROR: + if (qd->roomlist != NULL) { + if (gaim_roomlist_get_in_progress(qd->roomlist)) + gaim_roomlist_set_in_progress(qd->roomlist, FALSE); + } + _qq_process_group_cmd_reply_error_default(reply, cursor, len - bytes, gc); + break; default: _qq_process_group_cmd_reply_error_default(reply, cursor, len - bytes, gc); } return; } - /* seems to ok so far, so we process the reply according to sub_cmd */ + /* seems ok so far, so we process the reply according to sub_cmd */ switch (sub_cmd) { case QQ_GROUP_CMD_GET_GROUP_INFO: qq_process_group_cmd_get_group_info(data, &cursor, len, gc); if (group != NULL) { - qq_send_cmd_group_get_member_info(gc, group); - qq_send_cmd_group_get_online_member(gc, group); + qq_send_cmd_group_get_members_info(gc, group); + qq_send_cmd_group_get_online_members(gc, group); } break; case QQ_GROUP_CMD_CREATE_GROUP: @@ -212,12 +224,12 @@ qq_process_group_cmd_im(data, &cursor, len, gc); break; case QQ_GROUP_CMD_GET_ONLINE_MEMBER: - qq_process_group_cmd_get_online_member(data, &cursor, len, gc); + qq_process_group_cmd_get_online_members(data, &cursor, len, gc); if (group != NULL) qq_group_conv_refresh_online_member(gc, group); break; case QQ_GROUP_CMD_GET_MEMBER_INFO: - qq_process_group_cmd_get_member_info(data, &cursor, len, gc); + qq_process_group_cmd_get_members_info(data, &cursor, len, gc); if (group != NULL) qq_group_conv_refresh_online_member(gc, group); break;
--- a/libgaim/protocols/qq/group_opt.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_opt.c Fri Sep 01 11:03:18 2006 +0000 @@ -26,9 +26,8 @@ #include "buddy_info.h" #include "char_conv.h" -/*#include "group_admindlg.h" */ #include "group_find.h" -#include "group_hash.h" +#include "group_internal.h" #include "group_info.h" #include "group_join.h" #include "group_network.h" @@ -108,7 +107,7 @@ { qq_group *group; g_return_if_fail(g != NULL && g->gc != NULL && g->internal_group_id > 0 && g->member > 0); - group = qq_group_find_by_internal_group_id(g->gc, g->internal_group_id); + group = qq_group_find_by_id(g->gc, g->internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); qq_send_cmd_group_auth(g->gc, group, QQ_GROUP_AUTH_REQUEST_REJECT, g->member, msg_utf8); g_free(g); @@ -148,7 +147,7 @@ { qq_group *group; g_return_if_fail(g != NULL && g->gc != NULL && g->internal_group_id > 0 && g->member > 0); - group = qq_group_find_by_internal_group_id(g->gc, g->internal_group_id); + group = qq_group_find_by_id(g->gc, g->internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); qq_send_cmd_group_auth(g->gc, group, QQ_GROUP_AUTH_REQUEST_APPROVE, g->member, ""); qq_group_find_or_add_member(g->gc, group, g->member); @@ -221,7 +220,7 @@ g_return_if_fail(internal_group_id > 0); /* we should have its info locally */ - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); gaim_debug(GAIM_DEBUG_INFO, "QQ", "Succeed in modify members for Qun %d\n", group->external_group_id); @@ -290,7 +289,7 @@ g_return_if_fail(internal_group_id > 0); /* we should have its info locally */ - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); gaim_debug(GAIM_DEBUG_INFO, "QQ", "Succeed in modify info for Qun %d\n", group->external_group_id); @@ -345,10 +344,10 @@ qq_group *group; g_return_if_fail(g != NULL && g->gc != NULL && g->uid > 0); - group = qq_group_find_by_internal_group_id(g->gc, g->uid); + group = qq_group_find_by_id(g->gc, g->uid, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); - /* XXX insert UI code here */ + /* TODO insert UI code here */ /* qq_group_detail_window_show(g->gc, group); */ g_free(g); } @@ -368,7 +367,7 @@ read_packet_dw(data, cursor, len, &external_group_id); g_return_if_fail(internal_group_id > 0 && external_group_id); - group = qq_group_create_by_id(gc, internal_group_id, external_group_id); + group = qq_group_create_internal_record(gc, internal_group_id, external_group_id, NULL); group->my_status = QQ_GROUP_MEMBER_STATUS_IS_ADMIN; group->creator_uid = qd->uid; qq_group_refresh(gc, group); @@ -427,7 +426,7 @@ g_return_if_fail(internal_group_id > 0); /* we should have its info locally */ - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); gaim_debug(GAIM_DEBUG_INFO, "QQ", "Succeed in activate Qun %d\n", group->external_group_id); @@ -445,7 +444,7 @@ internal_group_id = strtol(internal_group_id_ptr, NULL, 10); g_return_if_fail(internal_group_id > 0); - group = qq_group_find_by_internal_group_id(gc, internal_group_id); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); /* XXX insert UI code here */
--- a/libgaim/protocols/qq/group_search.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/group_search.c Fri Sep 01 11:03:18 2006 +0000 @@ -23,7 +23,10 @@ #include "debug.h" #include "char_conv.h" +#include "group_find.h" #include "group_free.h" +#include "group_internal.h" +#include "group_join.h" #include "group_network.h" #include "group_search.h" #include "utils.h" @@ -58,6 +61,37 @@ qq_send_group_cmd(gc, NULL, raw_data, data_len); } +static void _qq_setup_roomlist(qq_data *qd, qq_group *group) +{ + GaimRoomlistRoom *room; + gchar *field; + + room = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_ROOM, group->group_name_utf8, NULL); + field = g_strdup_printf("%d", group->external_group_id); + gaim_roomlist_room_add_field(qd->roomlist, room, field); + g_free(field); + field = g_strdup_printf("%d", group->creator_uid); + gaim_roomlist_room_add_field(qd->roomlist, room, field); + g_free(field); + gaim_roomlist_room_add_field(qd->roomlist, room, group->group_desc_utf8); + field = g_strdup_printf("%d", group->internal_group_id); + gaim_roomlist_room_add_field(qd->roomlist, room, field); + g_free(field); + field = g_strdup_printf("%d", group->group_type); + gaim_roomlist_room_add_field(qd->roomlist, room, field); + g_free(field); + field = g_strdup_printf("%d", group->auth_type); + gaim_roomlist_room_add_field(qd->roomlist, room, field); + g_free(field); + field = g_strdup_printf("%d", group->group_category); + gaim_roomlist_room_add_field(qd->roomlist, room, field); + g_free(field); + gaim_roomlist_room_add_field(qd->roomlist, room, group->group_name_utf8); + gaim_roomlist_room_add(qd->roomlist, room); + + gaim_roomlist_set_in_progress(qd->roomlist, FALSE); +} + /* process group cmd reply "search group" */ void qq_process_group_cmd_search_group(guint8 *data, guint8 **cursor, gint len, GaimConnection *gc) { @@ -65,56 +99,51 @@ guint16 unknown; gint bytes, pascal_len, i; qq_data *qd; - GaimRoomlistRoom *room; qq_group *group; + GSList *pending_id; g_return_if_fail(gc != NULL && gc->proto_data != NULL); g_return_if_fail(data != NULL && len > 0); qd = (qq_data *) gc->proto_data; - i = 0; read_packet_b(data, cursor, len, &search_type); group = g_newa(qq_group, 1); /* now it starts with group_info_entry */ - while (*cursor < (data + len)) { /* still have data to read */ - /* begin of one qq_group */ - bytes = 0; - i++; - bytes += read_packet_dw(data, cursor, len, &(group->internal_group_id)); - bytes += read_packet_dw(data, cursor, len, &(group->external_group_id)); - bytes += read_packet_b(data, cursor, len, &(group->group_type)); - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_dw(data, cursor, len, &(group->creator_uid)); - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_dw(data, cursor, len, &(group->group_category)); - pascal_len = convert_as_pascal_string(*cursor, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); - bytes += pascal_len; - *cursor += pascal_len; - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_b(data, cursor, len, &(group->auth_type)); - pascal_len = convert_as_pascal_string(*cursor, &(group->group_desc_utf8), QQ_CHARSET_DEFAULT); - bytes += pascal_len; - *cursor += pascal_len; - /* end of one qq_group */ - room = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_ROOM, group->group_name_utf8, NULL); - gaim_roomlist_room_add_field(qd->roomlist, room, g_strdup_printf("%d", group->external_group_id)); - gaim_roomlist_room_add_field(qd->roomlist, room, g_strdup_printf("%d", group->creator_uid)); - gaim_roomlist_room_add_field(qd->roomlist, room, group->group_desc_utf8); - gaim_roomlist_room_add_field(qd->roomlist, room, g_strdup_printf("%d", group->internal_group_id)); - gaim_roomlist_room_add_field(qd->roomlist, room, g_strdup_printf("%d", group->group_type)); - gaim_roomlist_room_add_field(qd->roomlist, room, g_strdup_printf("%d", group->auth_type)); - gaim_roomlist_room_add_field(qd->roomlist, room, g_strdup_printf("%d", group->group_category)); - gaim_roomlist_room_add_field(qd->roomlist, room, group->group_name_utf8); - gaim_roomlist_room_add(qd->roomlist, room); - } - if(*cursor > (data + len)) { + bytes = 0; + i++; + bytes += read_packet_dw(data, cursor, len, &(group->internal_group_id)); + bytes += read_packet_dw(data, cursor, len, &(group->external_group_id)); + bytes += read_packet_b(data, cursor, len, &(group->group_type)); + bytes += read_packet_w(data, cursor, len, &(unknown)); + bytes += read_packet_w(data, cursor, len, &(unknown)); + bytes += read_packet_dw(data, cursor, len, &(group->creator_uid)); + bytes += read_packet_w(data, cursor, len, &(unknown)); + bytes += read_packet_w(data, cursor, len, &(unknown)); + bytes += read_packet_w(data, cursor, len, &(unknown)); + bytes += read_packet_dw(data, cursor, len, &(group->group_category)); + pascal_len = convert_as_pascal_string(*cursor, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); + bytes += pascal_len; + *cursor += pascal_len; + bytes += read_packet_w(data, cursor, len, &(unknown)); + bytes += read_packet_b(data, cursor, len, &(group->auth_type)); + pascal_len = convert_as_pascal_string(*cursor, &(group->group_desc_utf8), QQ_CHARSET_DEFAULT); + bytes += pascal_len; + *cursor += pascal_len; + /* end of one qq_group */ + if(*cursor != (data + len)) { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "group_cmd_search_group: Dangerous error! maybe protocol changed, notify developers!"); } - gaim_roomlist_set_in_progress(qd->roomlist, FALSE); - gaim_debug(GAIM_DEBUG_INFO, "QQ", "Search group reply: %d groups\n", i); + + pending_id = qq_get_pending_id(qd->joining_groups, group->external_group_id); + if (pending_id != NULL) { + qq_set_pending_id(&qd->joining_groups, group->external_group_id, FALSE); + if (qq_group_find_by_id(gc, group->internal_group_id, QQ_INTERNAL_ID) == NULL) + qq_group_create_internal_record(gc, + group->internal_group_id, group->external_group_id, group->group_name_utf8); + qq_send_cmd_group_join_group(gc, group); + } else { + _qq_setup_roomlist(qd, group); + } }
--- a/libgaim/protocols/qq/login_logout.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/login_logout.c Fri Sep 01 11:03:18 2006 +0000 @@ -234,10 +234,10 @@ qq_send_packet_change_status(gc); - /* now refresh buddy list */ - /* changed by gfhuang, using With Qun version, error, not working still */ + /* refresh buddies */ qq_send_packet_get_buddies_list(gc, QQ_FRIENDS_LIST_POSITION_START); - /* qq_send_packet_get_all_list_with_group(gc, QQ_FRIENDS_LIST_POSITION_START); */ + /* refresh groups */ + qq_send_packet_get_all_list_with_group(gc, QQ_FRIENDS_LIST_POSITION_START); return QQ_LOGIN_REPLY_OK; }
--- a/libgaim/protocols/qq/qq.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/qq.c Fri Sep 01 11:03:18 2006 +0000 @@ -153,7 +153,7 @@ /* do not use g_return_val_if_fail, as it is not assertion */ if (b == NULL || b->proto_data == NULL) return "qq"; - + q_bud = (qq_buddy *) b->proto_data; filename = get_icon_name(q_bud->icon / 3 + 1); @@ -565,7 +565,6 @@ } */ -/* XXX re-enable this static void _qq_menu_unsubscribe_group(GaimBlistNode * node) { GaimChat *chat = (GaimChat *)node; @@ -578,7 +577,7 @@ qq_group_exit(gc, components); } -// XXX re-enable this +/* static void _qq_menu_manage_group(GaimBlistNode * node) { GaimChat *chat = (GaimChat *)node; @@ -860,7 +859,6 @@ } /* chat-related (QQ Qun) menu shown up with right-click */ -/* TODO re-enable this static GList *_qq_chat_menu(GaimBlistNode *node) { GList *m; @@ -870,14 +868,15 @@ act = gaim_menu_action_new(_("Exit this QQ Qun"), GAIM_CALLBACK(_qq_menu_unsubscribe_group), NULL, NULL); m = g_list_append(m, act); + /* TODO: enable this act = gaim_menu_action_new(_("Show Details"), GAIM_CALLBACK(_qq_menu_manage_group), NULL, NULL); m = g_list_append(m, act); + */ return m; } -*/ + /* buddy-related menu shown up with right-click */ -/* TODO re-enable this static GList *_qq_buddy_menu(GaimBlistNode * node) { GList *m; @@ -886,7 +885,9 @@ return _qq_chat_menu(node); m = NULL; -*/ + return m; +} + /* TODO : not working, temp commented out by gfhuang act = gaim_menu_action_new(_("Block this buddy"), GAIM_CALLBACK(_qq_menu_block_buddy), NULL, NULL); //add NULL by gfhuang @@ -918,7 +919,7 @@ if (group->my_status == QQ_GROUP_MEMBER_STATUS_IS_MEMBER || group->my_status == QQ_GROUP_MEMBER_STATUS_IS_ADMIN) /* no need to get info time and time again, online members enough */ - qq_send_cmd_group_get_online_member(gc, group); + qq_send_cmd_group_get_online_members(gc, group); list = list->next; } @@ -934,7 +935,7 @@ gchar *gaim_name; g_return_if_fail(gc != NULL && gc->proto_data != NULL && who != NULL); - gaim_name = qq_group_find_member_by_channel_and_nickname(gc, channel, who); + gaim_name = chat_name_to_gaim_name(who); if (gaim_name != NULL) _qq_get_info(gc, gaim_name); } @@ -944,7 +945,7 @@ static gchar *_qq_get_chat_buddy_real_name(GaimConnection *gc, gint channel, const gchar *who) { g_return_val_if_fail(gc != NULL && gc->proto_data != NULL && who != NULL, NULL); - return qq_group_find_member_by_channel_and_nickname(gc, channel, who); + return chat_name_to_gaim_name(who); } void qq_function_not_implemented(GaimConnection *gc) @@ -964,9 +965,9 @@ _qq_status_text, /* status_text */ _qq_tooltip_text, /* tooltip_text */ _qq_away_states, /* away_states */ - NULL, /* blist_node_menu */ - NULL, /* chat_info */ - NULL, /* chat_info_defaults */ + _qq_buddy_menu, /* blist_node_menu */ + qq_chat_info, /* chat_info */ + qq_chat_info_defaults, /* chat_info_defaults */ _qq_login, /* login */ _qq_close, /* close */ _qq_send_im, /* send_im */ @@ -1043,7 +1044,7 @@ NULL, /**< ui_info */ &prpl_info, /**< extra_info */ - NULL, /**< prefs_info */ + NULL, /**< prefs_info */ _qq_actions };
--- a/libgaim/protocols/qq/qq.h Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/qq.h Fri Sep 01 11:03:18 2006 +0000 @@ -95,9 +95,11 @@ GList *groups; GList *group_packets; + GSList *joining_groups; + GSList *adding_groups_from_server; /* internal ids of groups the server wants in my blist */ GList *buddies; GList *contact_info_window; - GList *qun_info_window; + GList *group_info_window; GList *sendqueue; GList *info_query; GList *add_buddy_request;
--- a/libgaim/protocols/qq/utils.c Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/utils.c Fri Sep 01 11:03:18 2006 +0000 @@ -164,13 +164,6 @@ return g_strdup_printf("qq_%d", set); } -/* convert a QQ UID to a unique name of Gaim - * the return needs to be freed */ -gchar *uid_to_gaim_name(guint32 uid) -{ - return g_strdup_printf(QQ_NAME_FORMAT, uid); -} - /* convert Gaim name to original QQ UID */ guint32 gaim_name_to_uid(const gchar *const name) { @@ -184,6 +177,27 @@ return ret; } +/* convert a QQ UID to a unique name of Gaim + * the return needs to be freed */ +gchar *uid_to_gaim_name(guint32 uid) +{ + return g_strdup_printf(QQ_NAME_FORMAT, uid); +} + +/* convert name displayed in a chat channel to original QQ UID */ +gchar *chat_name_to_gaim_name(const gchar *const name) +{ + const gchar *tmp; + gchar *ret; + + g_return_val_if_fail(name != NULL, NULL); + + tmp = (gchar *) gaim_strcasestr(name, "(qq-"); + ret = g_strndup(tmp + 4, strlen(name) - (tmp - name) - 4 - 1); + + return ret; +} + /* try to dump the data as GBK */ void try_dump_as_gbk(const guint8 *const data, gint len) {
--- a/libgaim/protocols/qq/utils.h Fri Sep 01 10:05:30 2006 +0000 +++ b/libgaim/protocols/qq/utils.h Fri Sep 01 11:03:18 2006 +0000 @@ -32,11 +32,13 @@ gchar **split_data(guint8 *data, gint len, const gchar *delimit, gint expected_fields); guint8 *_gen_session_md5(gint uid, guint8 *session_key); + gchar *gen_ip_str(guint8 *ip); guint8 *str_ip_gen(gchar *str); -gchar *uid_to_gaim_name(guint32 uid); guint32 gaim_name_to_uid(const gchar *name); +gchar *uid_to_gaim_name(guint32 uid); +gchar *chat_name_to_gaim_name(const gchar *const name); gchar *get_icon_name(gint set);