diff options
Diffstat (limited to 'libpurple/protocols/qq/group_internal.c')
-rw-r--r-- | libpurple/protocols/qq/group_internal.c | 519 |
1 files changed, 348 insertions, 171 deletions
diff --git a/libpurple/protocols/qq/group_internal.c b/libpurple/protocols/qq/group_internal.c index 1853fd2999..002e19b875 100644 --- a/libpurple/protocols/qq/group_internal.c +++ b/libpurple/protocols/qq/group_internal.c @@ -27,219 +27,396 @@ #include "debug.h" #include "buddy_opt.h" -#include "group_free.h" #include "group_internal.h" #include "utils.h" -static gchar *get_role_desc(qq_group *group) +static qq_room_data *room_data_new(guint32 id, guint32 ext_id, gchar *title) { - const char *role_desc; - g_return_val_if_fail(group != NULL, g_strdup("")); + qq_room_data *rmd; - switch (group->my_role) { - case QQ_ROOM_ROLE_NO: - role_desc = _("I am not a member"); - break; - case QQ_ROOM_ROLE_YES: - role_desc = _("I am a member"); - break; - case QQ_ROOM_ROLE_REQUESTING: - role_desc = _("I am requesting"); - break; - case QQ_ROOM_ROLE_ADMIN: - role_desc = _("I am the admin"); - break; - default: - role_desc = _("Unknown status"); + purple_debug_info("QQ", "Created room data: %s, ext id %d, id %d\n", + title, ext_id, id); + rmd = g_new0(qq_room_data, 1); + rmd->my_role = QQ_ROOM_ROLE_NO; + rmd->id = id; + rmd->ext_id = ext_id; + rmd->type8 = 0x01; /* assume permanent Qun */ + rmd->creator_uid = 10000; /* assume by QQ admin */ + rmd->category = 0x01; + rmd->auth_type = 0x02; /* assume need auth */ + rmd->title_utf8 = g_strdup(title == NULL ? "" : title); + rmd->desc_utf8 = g_strdup(""); + rmd->notice_utf8 = g_strdup(""); + rmd->members = NULL; + rmd->is_got_buddies = FALSE; + return rmd; +} + +/* create a qq_room_data from hashtable */ +static qq_room_data *room_data_new_by_hashtable(PurpleConnection *gc, GHashTable *data) +{ + qq_room_data *rmd; + guint32 id, ext_id; + gchar *value; + + value = g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID); + id = value ? strtol(value, NULL, 10) : 0; + value= g_hash_table_lookup(data, QQ_ROOM_KEY_EXTERNAL_ID); + ext_id = value ? strtol(value, NULL, 10) : 0; + value = g_strdup(g_hash_table_lookup(data, QQ_ROOM_KEY_TITLE_UTF8)); + + rmd = room_data_new(id, ext_id, value); + rmd->my_role = QQ_ROOM_ROLE_YES; + return rmd; +} + +/* gracefully free all members in a room */ +static void room_buddies_free(qq_room_data *rmd) +{ + gint i; + GList *list; + qq_buddy_data *bd; + + g_return_if_fail(rmd != NULL); + i = 0; + while (NULL != (list = rmd->members)) { + bd = (qq_buddy_data *) list->data; + i++; + rmd->members = g_list_remove(rmd->members, bd); + qq_buddy_data_free(bd); } - return g_strdup(role_desc); + rmd->members = NULL; } -static void add_room_to_blist(PurpleConnection *gc, qq_group *group) +/* gracefully free the memory for one qq_room_data */ +static void room_data_free(qq_room_data *rmd) +{ + g_return_if_fail(rmd != NULL); + room_buddies_free(rmd); + g_free(rmd->title_utf8); + g_free(rmd->desc_utf8); + g_free(rmd->notice_utf8); + g_free(rmd); +} + +void qq_room_update_chat_info(PurpleChat *chat, qq_room_data *rmd) +{ + if (rmd->title_utf8 != NULL && strlen(rmd->title_utf8) > 0) { + purple_blist_alias_chat(chat, rmd->title_utf8); + } + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_INTERNAL_ID), + g_strdup_printf("%d", rmd->id)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_EXTERNAL_ID), + g_strdup_printf("%d", rmd->ext_id)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(rmd->title_utf8)); +} + +static PurpleChat *chat_new(PurpleConnection *gc, qq_room_data *rmd) { GHashTable *components; PurpleGroup *g; PurpleChat *chat; - components = qq_group_to_hashtable(group); - chat = purple_chat_new(purple_connection_get_account(gc), group->title_utf8, components); - g = qq_get_purple_group(PURPLE_GROUP_QQ_QUN); + + purple_debug_info("QQ", "Add new chat: id %d, ext id %d, title %s\n", + rmd->id, rmd->ext_id, rmd->title_utf8); + + components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_insert(components, + g_strdup(QQ_ROOM_KEY_INTERNAL_ID), g_strdup_printf("%d", rmd->id)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_EXTERNAL_ID), + g_strdup_printf("%d", rmd->ext_id)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(rmd->title_utf8)); + + chat = purple_chat_new(purple_connection_get_account(gc), rmd->title_utf8, components); + g = qq_group_find_or_new(PURPLE_GROUP_QQ_QUN); purple_blist_add_chat(chat, g, NULL); - purple_debug_info("QQ", "You have added group \"%s\" to blist locally\n", group->title_utf8); + + return chat; } -/* Create a dummy qq_group, which includes only internal_id, ext_id, - * and potentially title_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(PurpleConnection *gc, - guint32 internal_id, guint32 ext_id, gchar *title_utf8) +PurpleChat *qq_room_find_or_new(PurpleConnection *gc, guint32 id, guint32 ext_id) { - qq_group *group; - qq_data *qd; + qq_data *qd; + qq_room_data *rmd; + PurpleChat *chat; + gchar *num_str; - g_return_val_if_fail(internal_id > 0, NULL); - qd = (qq_data *) gc->proto_data; + g_return_val_if_fail (gc != NULL && gc->proto_data != NULL, NULL); + qd = (qq_data *) gc->proto_data; + + g_return_val_if_fail(id != 0 && ext_id != 0, NULL); + + purple_debug_info("QQ", "Find or add new room: id %d, ext id %d\n", id, ext_id); + + rmd = qq_room_data_find(gc, id); + if (rmd == NULL) { + rmd = room_data_new(id, ext_id, NULL); + g_return_val_if_fail(rmd != NULL, NULL); + rmd->my_role = QQ_ROOM_ROLE_YES; + qd->groups = g_list_append(qd->groups, rmd); + } + + num_str = g_strdup_printf("%d", ext_id); + chat = purple_blist_find_chat(purple_connection_get_account(gc), num_str); + g_free(num_str); + if (chat) { + return chat; + } + + return chat_new(gc, rmd); +} + +void qq_room_remove(PurpleConnection *gc, guint32 id) +{ + qq_data *qd; + PurpleChat *chat; + qq_room_data *rmd; + gchar *num_str; + guint32 ext_id; - group = g_new0(qq_group, 1); - group->my_role = QQ_ROOM_ROLE_NO; - group->my_role_desc = get_role_desc(group); - group->id = internal_id; - group->ext_id = ext_id; - group->type8 = 0x01; /* assume permanent Qun */ - group->creator_uid = 10000; /* assume by QQ admin */ - group->category = 0x01; - group->auth_type = 0x02; /* assume need auth */ - group->title_utf8 = g_strdup(title_utf8 == NULL ? "" : title_utf8); - group->desc_utf8 = g_strdup(""); - group->notice_utf8 = g_strdup(""); - group->members = NULL; + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + purple_debug_info("QQ", "Find and remove room data, id %d", id); + rmd = qq_room_data_find(gc, id); + g_return_if_fail (rmd != NULL); + + ext_id = rmd->ext_id; + qd->groups = g_list_remove(qd->groups, rmd); + room_data_free(rmd); + + purple_debug_info("QQ", "Find and remove chat, ext_id %d", ext_id); + num_str = g_strdup_printf("%d", ext_id); + chat = purple_blist_find_chat(purple_connection_get_account(gc), num_str); + g_free(num_str); - qd->groups = g_list_append(qd->groups, group); - add_room_to_blist(gc, group); + g_return_if_fail (chat != NULL); - return group; + purple_blist_remove_chat(chat); } -void qq_group_delete_internal_record(qq_data *qd, guint32 id) +/* find a qq_buddy_data by uid, called by im.c */ +qq_buddy_data *qq_room_buddy_find(qq_room_data *rmd, guint32 uid) { - qq_group *group; - GList *list; + GList *list; + qq_buddy_data *bd; + g_return_val_if_fail(rmd != NULL && uid > 0, NULL); - list = qd->groups; - while (list != NULL) { - group = (qq_group *) qd->groups->data; - if (id == group->id) { - qd->groups = g_list_remove(qd->groups, group); - qq_group_free(group); - break; - } else { - list = list->next; - } - } + list = rmd->members; + while (list != NULL) { + bd = (qq_buddy_data *) list->data; + if (bd->uid == uid) + return bd; + else + list = list->next; + } + + return NULL; } -/* convert a qq_group to hash-table, which could be component of PurpleChat */ -GHashTable *qq_group_to_hashtable(qq_group *group) +/* remove a qq_buddy_data by uid, called by qq_group_opt.c */ +void qq_room_buddy_remove(qq_room_data *rmd, guint32 uid) { - 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_ROOM_KEY_ROLE), g_strdup_printf("%d", group->my_role)); - group->my_role_desc = get_role_desc(group); + GList *list; + qq_buddy_data *bd; + g_return_if_fail(rmd != NULL && uid > 0); - g_hash_table_insert(components, - g_strdup(QQ_ROOM_KEY_INTERNAL_ID), g_strdup_printf("%d", group->id)); - g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_EXTERNAL_ID), - g_strdup_printf("%d", group->ext_id)); - g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_TYPE), g_strdup_printf("%d", group->type8)); - g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); - g_hash_table_insert(components, - g_strdup(QQ_ROOM_KEY_CATEGORY), g_strdup_printf("%d", group->category)); - g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); - g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_ROLE_DESC), g_strdup(group->my_role_desc)); - g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(group->title_utf8)); - g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_DESC_UTF8), g_strdup(group->desc_utf8)); - return components; + list = rmd->members; + while (list != NULL) { + bd = (qq_buddy_data *) list->data; + if (bd->uid == uid) { + rmd->members = g_list_remove(rmd->members, bd); + return; + } else { + list = list->next; + } + } +} + +qq_buddy_data *qq_room_buddy_find_or_new(PurpleConnection *gc, qq_room_data *rmd, guint32 member_uid) +{ + qq_buddy_data *member, *bd; + PurpleBuddy *buddy; + g_return_val_if_fail(rmd != NULL && member_uid > 0, NULL); + + member = qq_room_buddy_find(rmd, member_uid); + if (member == NULL) { /* first appear during my session */ + member = g_new0(qq_buddy_data, 1); + member->uid = member_uid; + buddy = purple_find_buddy(purple_connection_get_account(gc), uid_to_purple_name(member_uid)); + if (buddy != NULL) { + bd = (qq_buddy_data *) buddy->proto_data; + if (bd != NULL && bd->nickname != NULL) + member->nickname = g_strdup(bd->nickname); + else if (buddy->alias != NULL) + member->nickname = g_strdup(buddy->alias); + } + rmd->members = g_list_append(rmd->members, member); + } + + return member; } -/* create a qq_group from hashtable */ -qq_group *qq_room_create_by_hashtable(PurpleConnection *gc, GHashTable *data) +qq_room_data *qq_room_data_find(PurpleConnection *gc, guint32 room_id) { + GList *list; + qq_room_data *rmd; qq_data *qd; - qq_group *group; - g_return_val_if_fail(data != NULL, NULL); qd = (qq_data *) gc->proto_data; - group = g_new0(qq_group, 1); - group->my_role = - qq_string_to_dec_value - (NULL == - g_hash_table_lookup(data, - QQ_ROOM_KEY_ROLE) ? - g_strdup_printf("%d", QQ_ROOM_ROLE_NO) : - g_hash_table_lookup(data, QQ_ROOM_KEY_ROLE)); - group->id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID)); - group->ext_id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_EXTERNAL_ID)); - group->type8 = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_TYPE)); - group->creator_uid = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_CREATOR_UID)); - group->category = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_CATEGORY)); - group->auth_type = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_AUTH_TYPE)); - group->title_utf8 = g_strdup(g_hash_table_lookup(data, QQ_ROOM_KEY_TITLE_UTF8)); - group->desc_utf8 = g_strdup(g_hash_table_lookup(data, QQ_ROOM_KEY_DESC_UTF8)); - group->my_role_desc = get_role_desc(group); - group->is_got_info = FALSE; - - qd->groups = g_list_append(qd->groups, group); - return group; -} - -/* refresh group local subscription */ -void qq_group_refresh(PurpleConnection *gc, qq_group *group) + if (qd->groups == NULL || room_id <= 0) + return 0; + + list = qd->groups; + while (list != NULL) { + rmd = (qq_room_data *) list->data; + if (rmd->id == room_id) { + return rmd; + } + list = list->next; + } + + return NULL; +} + +guint32 qq_room_get_next(PurpleConnection *gc, guint32 room_id) { + GList *list; + qq_room_data *rmd; + qq_data *qd; + gboolean is_find = FALSE; + + qd = (qq_data *) gc->proto_data; + + if (qd->groups == NULL) { + return 0; + } + + if (room_id <= 0) { + rmd = (qq_room_data *) qd->groups->data; + return rmd->id; + } + + list = qd->groups; + while (list != NULL) { + rmd = (qq_room_data *) list->data; + list = list->next; + if (rmd->id == room_id) { + is_find = TRUE; + break; + } + } + + g_return_val_if_fail(is_find, 0); + if (list == NULL) return 0; /* be the end */ + rmd = (qq_room_data *) list->data; + g_return_val_if_fail(rmd != NULL, 0); + return rmd->id; +} + +guint32 qq_room_get_next_conv(PurpleConnection *gc, guint32 room_id) +{ + GList *list; + qq_room_data *rmd; + qq_data *qd; + gboolean is_find; + + qd = (qq_data *) gc->proto_data; + + list = qd->groups; + if (room_id > 0) { + /* search next room */ + is_find = FALSE; + while (list != NULL) { + rmd = (qq_room_data *) list->data; + list = list->next; + if (rmd->id == room_id) { + is_find = TRUE; + break; + } + } + g_return_val_if_fail(is_find, 0); + } + + while (list != NULL) { + rmd = (qq_room_data *) list->data; + g_return_val_if_fail(rmd != NULL, 0); + + if (rmd->my_role == QQ_ROOM_ROLE_YES || rmd->my_role == QQ_ROOM_ROLE_ADMIN) { + if (NULL != purple_find_conversation_with_account( + PURPLE_CONV_TYPE_CHAT,rmd->title_utf8, purple_connection_get_account(gc))) { + /* In convseration*/ + return rmd->id; + } + } + list = list->next; + } + + return 0; +} + +/* this should be called upon signin, even when we did not open group chat window */ +void qq_room_data_initial(PurpleConnection *gc) +{ + PurpleAccount *account; PurpleChat *chat; - GHashTable *components; - gchar *ext_id; - g_return_if_fail(group != NULL); - - ext_id = g_strdup_printf("%d", group->ext_id); - chat = purple_blist_find_chat(purple_connection_get_account(gc), ext_id); - g_free(ext_id); - if (chat == NULL && group->my_role != QQ_ROOM_ROLE_NO) { - add_room_to_blist(gc, group); + PurpleGroup *purple_group; + PurpleBlistNode *node; + qq_data *qd; + qq_room_data *rmd; + gint count; + + account = purple_connection_get_account(gc); + qd = (qq_data *) gc->proto_data; + + purple_debug_info("QQ", "Initial QQ Qun configurations\n"); + purple_group = purple_find_group(PURPLE_GROUP_QQ_QUN); + if (purple_group == NULL) { + purple_debug_info("QQ", "We have no QQ Qun\n"); return; } - if (chat == NULL) { - return; + count = 0; + for (node = ((PurpleBlistNode *) purple_group)->child; node != NULL; node = node->next) { + if ( !PURPLE_BLIST_NODE_IS_CHAT(node)) { + continue; + } + /* got one */ + chat = (PurpleChat *) node; + if (account != chat->account) /* not qq account*/ + continue; + + rmd = room_data_new_by_hashtable(gc, chat->components); + qd->groups = g_list_append(qd->groups, rmd); + count++; } - components = purple_chat_get_components(chat); + purple_debug_info("QQ", "Load %d QQ Qun configurations\n", count); +} - /* we have a local record, update its info */ - /* if there is title_utf8, we update the group name */ - if (group->title_utf8 != NULL && strlen(group->title_utf8) > 0) - purple_blist_alias_chat(chat, group->title_utf8); - g_hash_table_replace(components, - g_strdup(QQ_ROOM_KEY_ROLE), g_strdup_printf("%d", group->my_role)); - group->my_role_desc = get_role_desc(group); - g_hash_table_replace(components, - g_strdup(QQ_ROOM_KEY_ROLE_DESC), g_strdup(group->my_role_desc)); - g_hash_table_replace(components, - g_strdup(QQ_ROOM_KEY_INTERNAL_ID), - g_strdup_printf("%d", group->id)); - g_hash_table_replace(components, - g_strdup(QQ_ROOM_KEY_EXTERNAL_ID), - g_strdup_printf("%d", group->ext_id)); - g_hash_table_replace(components, - g_strdup(QQ_ROOM_KEY_TYPE), g_strdup_printf("%d", group->type8)); - g_hash_table_replace(components, - g_strdup(QQ_ROOM_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); - g_hash_table_replace(components, - g_strdup(QQ_ROOM_KEY_CATEGORY), - g_strdup_printf("%d", group->category)); - g_hash_table_replace(components, - g_strdup(QQ_ROOM_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); - g_hash_table_replace(components, - g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(group->title_utf8)); - g_hash_table_replace(components, - g_strdup(QQ_ROOM_KEY_DESC_UTF8), g_strdup(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)); +void qq_room_data_free_all(PurpleConnection *gc) +{ + qq_data *qd; + qq_room_data *rmd; + gint count; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + count = 0; + while (qd->groups != NULL) { + rmd = (qq_room_data *) qd->groups->data; + qd->groups = g_list_remove(qd->groups, rmd); + room_data_free(rmd); + count++; + } + + if (count > 0) { + purple_debug_info("QQ", "%d rooms are freed\n", count); + } } |