/* Process the reply to group_auth subcmd */ void qq_process_group_cmd_join_group_auth(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; guint32 id; qq_room_data *rmd; gchar *msg; g_return_if_fail(data != NULL && len > 0); if (len < 4) { purple_debug_error("QQ", "Invalid join room reply, expect %d bytes, read %d bytes\n", 4, len); return; } bytes = 0; bytes += qq_get32(&id, data + bytes); g_return_if_fail(id > 0); rmd = qq_room_data_find(gc, id); if (rmd != NULL) { msg = g_strdup_printf(_("Successfully joined Qun %s (%u)"), rmd->title_utf8, rmd->ext_id); qq_got_message(gc, msg); g_free(msg); } else { qq_got_message(gc, _("Successfully joined Qun")); } }
void qq_room_remove(PurpleConnection *gc, guint32 id) { qq_data *qd; PurpleChat *chat; qq_room_data *rmd; gchar *num_str; guint32 qun_id; 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 %u\n", id); rmd = qq_room_data_find(gc, id); g_return_if_fail (rmd != NULL); qun_id = rmd->qun_id; qd->rooms = g_slist_remove(qd->rooms, rmd); room_data_free(rmd); purple_debug_info("QQ", "Find and remove chat, qun_id %u\n", qun_id); num_str = g_strdup_printf("%u", qun_id); chat = purple_blist_find_chat(purple_connection_get_account(gc), num_str); g_free(num_str); g_return_if_fail (chat != NULL); purple_blist_remove_chat(chat); }
void qq_process_room_cmd_get_qun_list( guint8 *data, gint data_len, PurpleConnection *gc ) { qq_data *qd; qq_room_data *rmd; guint32 id, qun_id; gint bytes; guint8 num; guint8 i; g_return_if_fail(data != NULL && data_len > 0); qd = (qq_data *) gc->proto_data; /* qq_show_packet("Room List", data, data_len); */ bytes = 0; bytes += qq_get8(&num, data); for (i=0; i<num; ++i) { bytes += qq_get32(&id, data+bytes); bytes += qq_get32(&qun_id, data+bytes); bytes ++; rmd = qq_room_data_find(gc, id); g_return_if_fail(rmd != NULL); rmd->qun_id = qun_id; rmd->my_role = QQ_ROOM_ROLE_YES; purple_debug_info("QQ", "Qun added id: %u qun_id: %u\n", rmd->id, rmd->qun_id); } }
PurpleChat *qq_room_find_or_new(PurpleConnection *gc, guint32 id, guint32 qun_id) { qq_data *qd; qq_room_data *rmd; PurpleChat *chat; gchar *num_str; 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 && qun_id != 0, NULL); purple_debug_info("QQ", "Find or add new room: id %u, qun id %u\n", id, qun_id); rmd = qq_room_data_find(gc, id); if (rmd == NULL) { rmd = room_data_new(id, qun_id, NULL); g_return_val_if_fail(rmd != NULL, NULL); rmd->my_role = QQ_ROOM_ROLE_YES; qd->rooms = g_slist_append(qd->rooms, rmd); } num_str = g_strdup_printf("%u", qun_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); }
/* process group cmd reply "join group" */ void qq_process_group_cmd_join_group(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; guint32 id; qq_room_data *rmd; gchar *msg; g_return_if_fail(data != NULL && len > 0); if (len < 4) { purple_debug_error("QQ", "Invalid join room reply, expect %d bytes, read %d bytes\n", 5, len); return; } bytes = 0; bytes += qq_get32(&id, data + bytes); /* join group OK */ rmd = qq_room_data_find(gc, id); /* need to check if group is NULL or not. */ g_return_if_fail(rmd != NULL); purple_debug_info("QQ", "Succeeded in joining group \"%s\"\n", rmd->name); rmd->my_role = QQ_ROOM_ROLE_YES; qq_room_conv_open(gc, rmd); /* switch (reply) { case QQ_ROOM_JOIN_OK: purple_debug_info("QQ", "Succeeded in joining group \"%s\"\n", rmd->name); rmd->my_role = QQ_ROOM_ROLE_YES; qq_room_conv_open(gc, rmd); break; case QQ_ROOM_JOIN_NEED_AUTH: purple_debug_info("QQ", "Failed to join room qun id %u %s, needs authentication\n", rmd->qun_id, rmd->name); rmd->my_role = QQ_ROOM_ROLE_NO; do_room_join_request(gc, rmd); break; case QQ_ROOM_JOIN_DENIED: msg = g_strdup_printf(_("Qun %u denied from joining"), rmd->qun_id); purple_notify_info(gc, _("QQ Qun Operation"), _("Failed:"), msg); g_free(msg); break; default: purple_debug_info("QQ", "Failed to join room qun id %u %s, unknown reply: 0x%02x\n", rmd->qun_id, rmd->name, reply); purple_notify_info(gc, _("QQ Qun Operation"), _("Failed:"), _("Join Qun, Unknown Reply")); } */ }
/* send packet to get info for each group member */ gint qq_request_room_get_members_info( PurpleConnection *gc, guint32 room_id, guint32 update_class, guint32 index ) { guint8 *raw_data; gint bytes, num; GList *list; qq_room_data *rmd; qq_buddy_data *bd; guint32 i = 0; g_return_val_if_fail(room_id > 0, 0); rmd = qq_room_data_find(gc, room_id); g_return_val_if_fail(rmd != NULL, 0); for (num = 0, list = rmd->members; list != NULL; list = list->next) { bd = (qq_buddy_data *) list->data; if (check_update_interval(bd)) num++; } if (num <= 0) { purple_debug_info("QQ", "No group member info needs to be updated now.\n"); return 0; } raw_data = g_newa(guint8, 4 * num); bytes = 0; list = rmd->members; /* index shipped from last request send 30 uids one time */ while (list != NULL) { if (i>=index) { bd = (qq_buddy_data *) list->data; if (check_update_interval(bd)) bytes += qq_put32(raw_data + bytes, bd->uid); } i++; if (i==index+30) break; list = list->next; } /* if reach the end */ if (list == NULL) i=0; qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_MEMBERS_INFO, rmd->id, raw_data, bytes, update_class, i); return num; }
void qq_process_room_cmd_get_onlines(guint8 *data, gint len, PurpleConnection *gc) { guint32 room_id, member_uid; guint8 unknown; gint bytes, num; qq_room_data *rmd; qq_buddy_data *bd; g_return_if_fail(data != NULL && len > 0); if (len <= 3) { purple_debug_error("QQ", "Invalid group online member reply, discard it!\n"); return; } bytes = 0; bytes += qq_get32(&room_id, data + bytes); bytes += qq_get8(&unknown, data + bytes); /* 0x3c ?? */ g_return_if_fail(room_id > 0); rmd = qq_room_data_find(gc, room_id); if (rmd == NULL) { purple_debug_error("QQ", "Can not info of room id [%u]\n", room_id); return; } /* set all offline first, then update those online */ set_all_offline(rmd); num = 0; while (bytes < len) { bytes += qq_get32(&member_uid, data + bytes); num++; bd = qq_room_buddy_find_or_new(gc, rmd, member_uid); if (bd != NULL) bd->status = QQ_BUDDY_ONLINE_NORMAL; } if(bytes > len) { purple_debug_error("QQ", "group_cmd_get_online_members: Dangerous error! maybe protocol changed, notify developers!"); } purple_debug_info("QQ", "Group \"%s\" has %d online members\n", rmd->name, num); qq_room_conv_set_onlines(gc, rmd); }
static void group_join_cb(qq_room_req *add_req, const gchar *reason_utf8) { qq_room_data *rmd; g_return_if_fail(add_req != NULL); if (add_req->gc == NULL || add_req->id == 0) { g_free(add_req); return; } rmd = qq_room_data_find(add_req->gc, add_req->id); if (rmd == NULL) { purple_debug_error("QQ", "Can not find room data of %u\n", add_req->id); g_free(add_req); return; } qq_send_cmd_group_auth(add_req->gc, rmd, QQ_ROOM_AUTH_REQUEST_APPLY, 0, reason_utf8); g_free(add_req); }
void qq_room_got_chat_in(PurpleConnection *gc, guint32 room_id, guint32 uid_from, const gchar *msg, time_t in_time) { PurpleConversation *conv; qq_data *qd; qq_buddy_data *bd; qq_room_data *rmd; gchar *from; g_return_if_fail(gc != NULL && room_id != 0); g_return_if_fail(msg != NULL); qd = (qq_data *)gc->proto_data; conv = purple_find_chat(gc, room_id); rmd = qq_room_data_find(gc, room_id); g_return_if_fail(rmd != NULL); purple_debug_info("QQ", "is_show_chat:%d\n", qd->is_show_chat); if (NULL == conv && qd->is_show_chat) { conv = qq_room_conv_open(gc, rmd); } if (NULL == conv) { purple_debug_info("QQ", "Conversion of %u is not open, missing from %d:/n%s/v\n", room_id, uid_from, msg); return; } if (uid_from != 0) { bd = qq_room_buddy_find(rmd, uid_from); if (bd == NULL || bd->nickname == NULL) from = g_strdup_printf("%u", uid_from); else from = g_strdup(bd->nickname); } else { from = g_strdup(""); } serv_got_chat_in(gc, room_id, from, 0, msg, in_time); g_free(from); }
static void group_quit_cb(qq_room_req *add_req) { PurpleConnection *gc; guint32 id; qq_room_data *rmd; if (add_req->gc == NULL || add_req->id == 0) { g_free(add_req); return; } gc = add_req->gc; id = add_req->id; rmd = qq_room_data_find(gc, id); if (rmd == NULL) { g_free(add_req); return; } qq_send_room_cmd_only(gc, QQ_ROOM_CMD_QUIT, rmd->id); g_free(add_req); }
static void action_show_chat(PurpleBlistNode * node, gpointer flag) { PurpleChat *chat = (PurpleChat *)node; PurpleAccount *account = purple_chat_get_account(chat); PurpleConnection *gc = purple_account_get_connection(account); GHashTable *components = purple_chat_get_components(chat); gchar *num_str; guint32 room_id; qq_room_data *rmd; g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); g_return_if_fail(components != NULL); num_str = g_hash_table_lookup(components, QQ_ROOM_KEY_INTERNAL_ID); if (!num_str) { purple_debug_error("QQ", "Cannot find Room! Wait and Retry"); return; } room_id = strtoul(num_str, NULL, 10); g_return_if_fail(room_id != 0); rmd = qq_room_data_find(gc, room_id); g_return_if_fail(rmd != NULL); if (flag) { rmd->is_show_chat = TRUE; g_hash_table_replace(components, g_strdup(QQ_ROOM_KEY_ISSHOW), g_strdup_printf("%u", TRUE)); purple_notify_info(gc, _("QQ Chat Room"), _("Receive and Show QQ Chat Room Message"), num_str); } else { rmd->is_show_chat = FALSE; g_hash_table_replace(components, g_strdup(QQ_ROOM_KEY_ISSHOW), g_strdup_printf("%u", FALSE)); purple_notify_info(gc, _("QQ Chat Room"), _("QQ Chat Room Message Blocked"), num_str); } }
/* Attempt to join a group without auth */ void qq_group_join(PurpleConnection *gc, GHashTable *data) { gchar *ext_id_str; gchar *id_str; guint32 ext_id; guint32 id; qq_room_data *rmd; g_return_if_fail(data != NULL); ext_id_str = g_hash_table_lookup(data, QQ_ROOM_KEY_EXTERNAL_ID); id_str = g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID); purple_debug_info("QQ", "Join room %s, extend id %s\n", id_str, ext_id_str); if (id_str != NULL) { id = strtoul(id_str, NULL, 10); if (id != 0) { rmd = qq_room_data_find(gc, id); if (rmd) { qq_request_room_join(gc, rmd); return; } } } purple_debug_info("QQ", "Search and join extend id %s\n", ext_id_str); if (ext_id_str == NULL) { return; } ext_id = strtoul(ext_id_str, NULL, 10); if (ext_id == 0) { return; } qq_request_room_search(gc, ext_id, QQ_ROOM_SEARCH_FOR_JOIN); }
void qq_proc_room_cmds(PurpleConnection *gc, guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len, guint32 update_class, guintptr ship_value) { qq_data *qd; guint8 *data; gint data_len; qq_room_data *rmd; gint bytes; guint8 reply_cmd, reply; g_return_if_fail (gc != NULL && gc->proto_data != NULL); qd = (qq_data *) gc->proto_data; data = g_newa(guint8, rcved_len); data_len = qq_decrypt(data, rcved, rcved_len, qd->session_key); if (data_len < 0) { purple_debug_warning("QQ", "Can not decrypt room cmd by session key, [%05d], 0x%02X %s for %d, len %d\n", seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); qq_show_packet("Can not decrypted", rcved, rcved_len); return; } if (room_id <= 0) { purple_debug_warning("QQ", "room id is 0, [%05d], 0x%02X %s for %d, len %d\n", seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); /* Some room cmd has no room id, like QQ_ROOM_CMD_SEARCH */ } if (data_len <= 2) { purple_debug_warning("QQ", "Invaild len of room cmd decrypted, [%05d], 0x%02X %s for %d, len %d\n", seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); return; } bytes = 0; bytes += qq_get8(&reply_cmd, data + bytes); bytes += qq_get8(&reply, data + bytes); if (reply_cmd != room_cmd) { purple_debug_warning("QQ", "Missing room cmd in reply 0x%02X %s, [%05d], 0x%02X %s for %d, len %d\n", reply_cmd, qq_get_room_cmd_desc(reply_cmd), seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); } /* now process the packet */ if (reply != QQ_ROOM_CMD_REPLY_OK) { switch (reply) { /* this should be all errors */ case QQ_ROOM_CMD_REPLY_NOT_MEMBER: rmd = qq_room_data_find(gc, room_id); if (rmd == NULL) { purple_debug_warning("QQ", "Missing room id in [%05d], 0x%02X %s for %d, len %d\n", seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); } else { purple_debug_warning("QQ", "Not a member of room \"%s\"\n", rmd->name); rmd->my_role = QQ_ROOM_ROLE_NO; } break; case QQ_ROOM_CMD_REPLY_SEARCH_ERROR: if (qd->roomlist != NULL) { if (purple_roomlist_get_in_progress(qd->roomlist)) purple_roomlist_set_in_progress(qd->roomlist, FALSE); } default: process_room_cmd_notify(gc, reply_cmd, room_id, reply, data + bytes, data_len - bytes); } return; } /* seems ok so far, so we process the reply according to sub_cmd */ switch (reply_cmd) { case QQ_ROOM_CMD_GET_QUN_LIST: qq_process_room_cmd_get_qun_list(data + bytes, data_len - bytes, gc); break; case QQ_ROOM_CMD_GET_INFO: qq_process_room_cmd_get_info(data + bytes, data_len - bytes, ship_value, gc); break; case QQ_ROOM_CMD_CREATE: qq_group_process_create_group_reply(data + bytes, data_len - bytes, gc); break; case QQ_ROOM_CMD_CHANGE_INFO: qq_group_process_modify_info_reply(data + bytes, data_len - bytes, gc); break; case QQ_ROOM_CMD_MEMBER_OPT: qq_group_process_modify_members_reply(data + bytes, data_len - bytes, gc); break; case QQ_ROOM_CMD_ACTIVATE: qq_group_process_activate_group_reply(data + bytes, data_len - bytes, gc); break; case QQ_ROOM_CMD_SEARCH: qq_process_room_search(gc, data + bytes, data_len - bytes, ship_value); break; case QQ_ROOM_CMD_JOIN: qq_process_group_cmd_join_group(data + bytes, data_len - bytes, gc); break; case QQ_ROOM_CMD_AUTH: qq_process_group_cmd_join_group_auth(data + bytes, data_len - bytes, gc); break; case QQ_ROOM_CMD_QUIT: qq_process_group_cmd_exit_group(data + bytes, data_len - bytes, gc); break; case QQ_ROOM_CMD_SEND_IM: qq_process_room_send_im(gc, data + bytes, data_len - bytes); break; case QQ_ROOM_CMD_GET_ONLINES: qq_process_room_cmd_get_onlines(data + bytes, data_len - bytes, gc); break; case QQ_ROOM_CMD_GET_MEMBERS_INFO: qq_process_room_cmd_get_members_info(data + bytes, data_len - bytes, ship_value, gc); break; default: purple_debug_warning("QQ", "Unknown room cmd 0x%02X %s\n", reply_cmd, qq_get_room_cmd_desc(reply_cmd)); } if (update_class == QQ_CMD_CLASS_NONE) return; if (update_class == QQ_CMD_CLASS_UPDATE_ALL) { qq_update_all_rooms(gc, room_cmd, room_id); return; } if (update_class == QQ_CMD_CLASS_UPDATE_ONLINE) { update_all_rooms_online(gc, room_cmd, room_id); return; } if (update_class == QQ_CMD_CLASS_UPDATE_ROOM) { qq_update_room(gc, room_cmd, room_id); } }
/* process the reply to get_members_info packet */ void qq_process_room_cmd_get_members_info( guint8 *data, gint len, guint32 index, PurpleConnection *gc ) { gint bytes; gint num; guint32 id, member_uid; guint16 unknown; qq_room_data *rmd; qq_buddy_data *bd; gchar *nick; g_return_if_fail(data != NULL && len > 0); /* qq_show_packet("qq_process_room_cmd_get_members_info", data, len); */ bytes = 0; bytes += qq_get32(&id, data + bytes); g_return_if_fail(id > 0); rmd = qq_room_data_find(gc, id); g_return_if_fail(rmd != NULL); num = 0; while (bytes < len) { bytes += qq_get32(&member_uid, data + bytes); g_return_if_fail(member_uid > 0); bd = qq_room_buddy_find_or_new(gc, rmd, member_uid); g_return_if_fail(bd != NULL); num++; bytes += qq_get16(&(bd->face), data + bytes); bytes += qq_get8(&(bd->age), data + bytes); bytes += qq_get8(&(bd->gender), data + bytes); /* only here use old charset GB18030 */ bytes += qq_get_vstr(&nick, QQ_CHARSET_DEFAULT, sizeof(guint8), data + bytes); bytes += qq_get16(&unknown, data + bytes); bytes += qq_get8(&(bd->ext_flag), data + bytes); bytes += qq_get8(&(bd->comm_flag), data + bytes); qq_filter_str(nick); bd->nickname = g_strdup(nick); g_free(nick); #if 0 purple_debug_info("QQ", "member [%d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", member_uid, bd->ext_flag, bd->comm_flag, bd->nickname); #endif bd->last_update = time(NULL); } if (bytes > len) { purple_debug_error("QQ", "group_cmd_get_members_info: Dangerous error! maybe protocol changed, notify developers!"); } purple_debug_info("QQ", "Group \"%s\" got %d member info\n", rmd->name, num); if (index) { qq_request_room_get_members_info(gc, id, 0, index); return; } rmd->has_got_members_info = TRUE; qq_room_conv_set_onlines(gc, rmd); }
void qq_process_room_cmd_get_info(guint8 *data, gint data_len, guint32 action, PurpleConnection *gc) { qq_data *qd; qq_room_data *rmd; qq_buddy_data *bd; PurpleChat *chat; PurpleConversation *conv; guint8 organization, role; guint16 max_members; guint32 resend_flag, member_uid, id, qun_id, last_uid; gint bytes; guint num=0; guint8 has_more=0; gchar *topic; g_return_if_fail(data != NULL && data_len > 0); qd = (qq_data *) gc->proto_data; /* qq_show_packet("Room Info", data, data_len); */ bytes = 0; bytes += qq_get32(&id, data + bytes); g_return_if_fail(id > 0); bytes += qq_get32(&qun_id, data + bytes); g_return_if_fail(qun_id > 0); chat = qq_room_find_or_new(gc, id, qun_id); g_return_if_fail(chat != NULL); rmd = qq_room_data_find(gc, id); g_return_if_fail(rmd != NULL); bytes += qq_get32(&resend_flag, data + bytes); //first 00 00 00 03, then 00 00 00 02 if (resend_flag == 0x00000003) { bytes += qq_get8(&(rmd->type8), data + bytes); bytes += 4; //maybe vip sign bytes += qq_get32(&(rmd->creator_uid), data + bytes); if (rmd->creator_uid == qd->uid) rmd->my_role = QQ_ROOM_ROLE_ADMIN; bytes += qq_get8(&(rmd->auth_type), data + bytes); bytes += 4 ; /* oldCategory */ bytes += 2; // 00 00 bytes += qq_get32(&(rmd->category), data + bytes); bytes += qq_get16(&max_members, data + bytes); bytes += 1; bytes += 8; purple_debug_info("QQ", "type: %u creator: %u category: %u max_members: %u\n", rmd->type8, rmd->creator_uid, rmd->category, max_members); bytes += qq_get_vstr(&(rmd->name), NULL, sizeof(guint8), data + bytes); bytes += 2; /* 0x0000 */ bytes += qq_get_vstr(&(rmd->bulletin), NULL, sizeof(guint8), data + bytes); bytes += qq_get_vstr(&(rmd->intro), NULL, sizeof(guint8), data + bytes); bytes += qq_get_vstr(&(rmd->token), NULL, sizeof(guint16), data + bytes); purple_debug_info("QQ", "room [%s] bulletin [%s] intro [%s] \n", rmd->name, rmd->bulletin, rmd->intro); bytes += 2; //Unknown bytes += qq_get32(&last_uid, data + bytes); /* last_uid of this recv, request more with it */ bytes += qq_get8(&has_more, data + bytes); /* if there are more, request again */ /* now comes the member list separated by 0x00 */ } else { /* resend_flag 00 00 00 02 is special, start with random one only 5 bytes */ bytes += qq_get32(&member_uid, data + bytes); num++; bytes += qq_get8(&organization, data + bytes); bd = qq_room_buddy_find_or_new(gc, rmd, member_uid); } while (bytes < data_len) { bytes += qq_get32(&member_uid, data + bytes); num++; bytes += qq_get8(&organization, data + bytes); bytes += qq_get8(&role, data + bytes); #if 0 if(organization != 0 || role != 0) { purple_debug_info("QQ", "%u, organization=%d, role=%d\n", member_uid, organization, role); } #endif bd = qq_room_buddy_find_or_new(gc, rmd, member_uid); if (bd != NULL) bd->role = role; } purple_debug_info("QQ", "Qun \"%s\" has received %d members\n", rmd->name, num); if (has_more) { qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, id, NULL, 0, 0, last_uid); } else { qq_room_update_chat_info(chat, rmd); if (action == QQ_ROOM_INFO_DISPLAY) { room_info_display(gc, rmd); } conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, rmd->name, purple_connection_get_account(gc)); if(NULL == conv) { purple_debug_warning("QQ", "Conversation \"%s\" is not opened\n", rmd->name); return; } topic = g_strdup_printf("%u %s", rmd->qun_id, rmd->bulletin); purple_debug_info("QQ", "Set chat topic to %s\n", topic); purple_conv_chat_set_topic(PURPLE_CONV_CHAT(conv), NULL, topic); g_free(topic); } }