/* process the packet when removed from a group */ void qq_process_recv_group_im_been_removed (guint8 *data, guint8 **cursor, gint len, guint32 internal_group_id, GaimConnection *gc) { guint32 external_group_id, uid; guint8 group_type; gchar *msg; qq_group *group; g_return_if_fail(data != NULL && len > 0); if (*cursor >= (data + len - 1)) { gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Received group msg been_removed is empty\n"); return; } read_packet_dw(data, cursor, len, &external_group_id); read_packet_b(data, cursor, len, &group_type); read_packet_dw(data, cursor, len, &uid); g_return_if_fail(external_group_id > 0 && uid > 0); 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_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); } g_free(msg); }
/* receive an application to join the group */ void qq_process_recv_group_im_apply_join (guint8 *data, guint8 **cursor, gint len, guint32 internal_group_id, GaimConnection *gc) { guint32 external_group_id, user_uid; guint8 group_type; gchar *reason_utf8, *msg, *reason; group_member_opt *g; g_return_if_fail(internal_group_id > 0 && data != NULL && len > 0); if (*cursor >= (data + len - 1)) { gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Received group msg apply_join is empty\n"); return; } read_packet_dw(data, cursor, len, &external_group_id); read_packet_b(data, cursor, len, &group_type); read_packet_dw(data, cursor, len, &user_uid); g_return_if_fail(external_group_id > 0 && user_uid > 0); convert_as_pascal_string(*cursor, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf(_("User %d applied to join group %d"), user_uid, external_group_id); reason = g_strdup_printf(_("Reason: %s"), reason_utf8); g = g_new0(group_member_opt, 1); g->gc = gc; g->internal_group_id = internal_group_id; g->member = user_uid; gaim_request_action(gc, _("QQ Qun Operation"), msg, reason, 2, g, 3, _("Approve"), G_CALLBACK (qq_group_approve_application_with_struct), _("Reject"), G_CALLBACK (qq_group_reject_application_with_struct), _("Search"), G_CALLBACK(qq_group_search_application_with_struct)); g_free(reason); g_free(msg); g_free(reason_utf8); }
/* the request to join a group is rejected */ void qq_process_recv_group_im_been_rejected (guint8 *data, guint8 **cursor, gint len, guint32 internal_group_id, GaimConnection *gc) { guint32 external_group_id, admin_uid; guint8 group_type; gchar *reason_utf8, *msg, *reason; qq_group *group; g_return_if_fail(data != NULL && len > 0); if (*cursor >= (data + len - 1)) { gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Received group msg been_rejected is empty\n"); return; } read_packet_dw(data, cursor, len, &external_group_id); read_packet_b(data, cursor, len, &group_type); read_packet_dw(data, cursor, len, &admin_uid); g_return_if_fail(external_group_id > 0 && admin_uid > 0); convert_as_pascal_string(*cursor, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf (_("You request to join group %d has been rejected by admin %d"), external_group_id, admin_uid); reason = g_strdup_printf(_("Reason: %s"), reason_utf8); gaim_notify_warning(gc, _("QQ Qun Operation"), msg, reason); 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); } g_free(reason); g_free(msg); g_free(reason_utf8); }
/* process the packet when added to a group */ void qq_process_recv_group_im_been_added (guint8 *data, guint8 **cursor, gint len, guint32 internal_group_id, GaimConnection *gc) { guint32 external_group_id, uid; guint8 group_type; qq_group *group; gchar *msg; g_return_if_fail(data != NULL && len > 0); if (*cursor >= (data + len - 1)) { gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Received group msg been_added is empty\n"); return; } read_packet_dw(data, cursor, len, &external_group_id); read_packet_b(data, cursor, len, &group_type); read_packet_dw(data, cursor, len, &uid); 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, _("This group has been added to your buddy list")); 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_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); /* the return of this cmd will automatically update the group in blist */ } g_free(msg); }
/* process login reply packet which includes redirected new server address */ static gint _qq_process_login_redirect(PurpleConnection *gc, guint8 *data, gint len) { gint bytes, ret; guint8 *cursor; gchar *new_server_str; qq_data *qd; qq_login_reply_redirect_packet lrrp; qd = (qq_data *) gc->proto_data; cursor = data; bytes = 0; /* 000-000: reply code */ bytes += read_packet_b(data, &cursor, len, &lrrp.result); /* 001-004: login uid */ bytes += read_packet_dw(data, &cursor, len, &lrrp.uid); /* 005-008: redirected new server IP */ bytes += read_packet_data(data, &cursor, len, lrrp.new_server_ip, 4); /* 009-010: redirected new server port */ bytes += read_packet_w(data, &cursor, len, &lrrp.new_server_port); if (bytes != QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail parsing login redirect packet, expect %d bytes, read %d bytes\n", QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN, bytes); ret = QQ_LOGIN_REPLY_MISC_ERROR; } else { /* start new connection */ new_server_str = gen_ip_str(lrrp.new_server_ip); purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Redirected to new server: %s:%d\n", new_server_str, lrrp.new_server_port); qq_connect(gc->account, new_server_str, lrrp.new_server_port, qd->use_tcp, TRUE); g_free(new_server_str); ret = QQ_LOGIN_REPLY_REDIRECT; } return ret; }
void qq_process_get_all_list_with_group_reply(guint8 *buf, gint buf_len, GaimConnection *gc) { qq_data *qd; gint len, i, j; guint8 *data, *cursor; guint8 sub_cmd, reply_code; guint32 unknown, position; guint32 uid; guint8 type, groupid; qq_group *group; g_return_if_fail(buf != NULL && buf_len != 0); qd = (qq_data *) gc->proto_data; len = buf_len; data = g_newa(guint8, len); cursor = data; if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { read_packet_b(data, &cursor, len, &sub_cmd); g_return_if_fail(sub_cmd == 0x01); read_packet_b(data, &cursor, len, &reply_code); if(0 != reply_code) { gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Get all list with group reply, reply_code(%d) is not zero", reply_code); } read_packet_dw(data, &cursor, len, &unknown); read_packet_dw(data, &cursor, len, &position); /* the following data is all list in this packet */ i = 0; j = 0; while (cursor < (data + len)) { /* 00-03: uid */ read_packet_dw(data, &cursor, len, &uid); /* 04: type 0x1:buddy 0x4:Qun */ read_packet_b(data, &cursor, len, &type); /* 05: groupid*4 */ /* seems to always be 0 */ read_packet_b(data, &cursor, len, &groupid); /* gaim_debug(GAIM_DEBUG_INFO, "QQ", "groupid: %i\n", groupid); groupid >>= 2; */ if (uid == 0 || (type != 0x1 && type != 0x4)) { gaim_debug(GAIM_DEBUG_INFO, "QQ", "Buddy entry, uid=%d, type=%d", uid, type); continue; } if(0x1 == type) { /* a buddy */ /* 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_id(gc, uid, QQ_INTERNAL_ID); if(group == NULL) { 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); } else { group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; qq_group_refresh(gc, group); qq_send_cmd_group_get_group_info(gc, group); } ++j; } } if(cursor > (data + len)) { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "qq_process_get_all_list_with_group_reply: Dangerous error! maybe protocol changed, notify developers!"); } gaim_debug(GAIM_DEBUG_INFO, "QQ", "Get all list done, %d buddies and %d Quns\n", i, j); } else { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt all list with group"); } }
/* process reply for get_buddies_list */ void qq_process_get_buddies_list_reply(guint8 *buf, gint buf_len, GaimConnection *gc) { qq_data *qd; qq_buddy *q_bud; gint len, bytes, bytes_expected, i; guint16 position, unknown; guint8 *data, *cursor, pascal_len; gchar *name; GaimBuddy *b; g_return_if_fail(buf != NULL && buf_len != 0); qd = (qq_data *) gc->proto_data; len = buf_len; data = g_newa(guint8, len); cursor = data; if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { read_packet_w(data, &cursor, len, &position); /* the following data is buddy list in this packet */ i = 0; while (cursor < (data + len)) { q_bud = g_new0(qq_buddy, 1); bytes = 0; /* 000-003: uid */ bytes += read_packet_dw(data, &cursor, len, &q_bud->uid); /* 004-005: icon index (1-255) */ bytes += read_packet_w(data, &cursor, len, &q_bud->face); /* 006-006: age */ bytes += read_packet_b(data, &cursor, len, &q_bud->age); /* 007-007: gender */ bytes += read_packet_b(data, &cursor, len, &q_bud->gender); pascal_len = convert_as_pascal_string(cursor, &q_bud->nickname, QQ_CHARSET_DEFAULT); cursor += pascal_len; bytes += pascal_len; bytes += read_packet_w(data, &cursor, len, &unknown); /* flag1: (0-7) * bit1 => qq show * comm_flag: (0-7) * bit1 => member * bit4 => TCP mode * bit5 => open mobile QQ * bit6 => bind to mobile * bit7 => whether having a video */ bytes += read_packet_b(data, &cursor, len, &q_bud->flag1); bytes += read_packet_b(data, &cursor, len, &q_bud->comm_flag); bytes_expected = 12 + pascal_len; if (q_bud->uid == 0 || bytes != bytes_expected) { gaim_debug(GAIM_DEBUG_INFO, "QQ", "Buddy entry, expect %d bytes, read %d bytes\n", bytes_expected, bytes); g_free(q_bud->nickname); g_free(q_bud); continue; } else { i++; } if (QQ_DEBUG) { gaim_debug(GAIM_DEBUG_INFO, "QQ", "buddy [%09d]: flag1=0x%02x, comm_flag=0x%02x\n", q_bud->uid, q_bud->flag1, q_bud->comm_flag); } name = uid_to_gaim_name(q_bud->uid); b = gaim_find_buddy(gc->account, name); g_free(name); if (b == NULL) b = qq_add_buddy_by_recv_packet(gc, q_bud->uid, TRUE, FALSE); b->proto_data = q_bud; qd->buddies = g_list_append(qd->buddies, q_bud); qq_update_buddy_contact(gc, q_bud); } if(cursor > (data + len)) { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "qq_process_get_buddies_list_reply: Dangerous error! maybe protocol changed, notify developers!"); } if (position == QQ_FRIENDS_LIST_POSITION_END) { gaim_debug(GAIM_DEBUG_INFO, "QQ", "Get friends list done, %d buddies\n", i); qq_send_packet_get_buddies_online(gc, QQ_FRIENDS_ONLINE_POSITION_START); } else { qq_send_packet_get_buddies_list(gc, position); } } else { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt buddies list"); } }
/* process the reply packet for get_buddies_online packet */ void qq_process_get_buddies_online_reply(guint8 *buf, gint buf_len, GaimConnection *gc) { qq_data *qd; gint len, bytes; guint8 *data, *cursor, position; GaimBuddy *b; qq_buddy *q_bud; qq_friends_online_entry *fe; g_return_if_fail(buf != NULL && buf_len != 0); qd = (qq_data *) gc->proto_data; len = buf_len; data = g_newa(guint8, len); cursor = data; gaim_debug(GAIM_DEBUG_INFO, "QQ", "processing get_buddies_online_reply\n"); if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { _qq_show_packet("Get buddies online reply packet", data, len); read_packet_b(data, &cursor, len, &position); fe = g_newa(qq_friends_online_entry, 1); fe->s = g_newa(qq_buddy_status, 1); while (cursor < (data + len)) { /* based on one online buddy entry */ bytes = 0; /* 000-030 qq_buddy_status */ bytes += qq_buddy_status_read(data, &cursor, len, fe->s); /* 031-032: unknown4 */ bytes += read_packet_w(data, &cursor, len, &fe->unknown1); /* 033-033: flag1 */ bytes += read_packet_b(data, &cursor, len, &fe->flag1); /* 034-034: comm_flag */ bytes += read_packet_b(data, &cursor, len, &fe->comm_flag); /* 035-036: */ bytes += read_packet_w(data, &cursor, len, &fe->unknown2); /* 037-037: */ bytes += read_packet_b(data, &cursor, len, &fe->ending); /* 0x00 */ if (fe->s->uid == 0 || bytes != QQ_ONLINE_BUDDY_ENTRY_LEN) { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "uid=0 or entry complete len(%d) != %d", bytes, QQ_ONLINE_BUDDY_ENTRY_LEN); g_free(fe->s->ip); g_free(fe->s->unknown_key); continue; } /* check if it is a valid entry */ if (QQ_DEBUG) _qq_buddies_online_reply_dump_unclear(fe); /* update buddy information */ b = gaim_find_buddy(gaim_connection_get_account(gc), uid_to_gaim_name(fe->s->uid)); q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (q_bud != NULL) { /* we find one and update qq_buddy */ if(0 != fe->s->client_version) q_bud->client_version = fe->s->client_version; g_memmove(q_bud->ip, fe->s->ip, 4); q_bud->port = fe->s->port; q_bud->status = fe->s->status; q_bud->flag1 = fe->flag1; q_bud->comm_flag = fe->comm_flag; qq_update_buddy_contact(gc, q_bud); } else { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Got an online buddy %d, but not in my buddy list\n", fe->s->uid); } g_free(fe->s->ip); g_free(fe->s->unknown_key); } if(cursor > (data + len)) { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "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\n", position); qq_send_packet_get_buddies_online(gc, position); } else { qq_send_packet_get_buddies_levels(gc); qq_refresh_all_buddy_status(gc); } } else { gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt buddies online"); } }
/* process login reply which says OK */ static gint _qq_process_login_ok(PurpleConnection *gc, guint8 *data, gint len) { gint bytes; guint8 *cursor; qq_data *qd; qq_login_reply_ok_packet lrop; qd = (qq_data *) gc->proto_data; cursor = data; bytes = 0; /* 000-000: reply code */ bytes += read_packet_b(data, &cursor, len, &lrop.result); /* 001-016: session key */ lrop.session_key = g_memdup(cursor, QQ_KEY_LENGTH); cursor += QQ_KEY_LENGTH; bytes += QQ_KEY_LENGTH; purple_debug(PURPLE_DEBUG_INFO, "QQ", "Get session_key done\n"); /* 017-020: login uid */ bytes += read_packet_dw(data, &cursor, len, &lrop.uid); /* 021-024: server detected user public IP */ bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.client_ip, 4); /* 025-026: server detected user port */ bytes += read_packet_w(data, &cursor, len, &lrop.client_port); /* 027-030: server detected itself ip 127.0.0.1 ? */ bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.server_ip, 4); /* 031-032: server listening port */ bytes += read_packet_w(data, &cursor, len, &lrop.server_port); /* 033-036: login time for current session */ bytes += read_packet_time(data, &cursor, len, &lrop.login_time); /* 037-062: 26 bytes, unknown */ bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown1, 26); /* 063-066: unknown server1 ip address */ bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown_server1_ip, 4); /* 067-068: unknown server1 port */ bytes += read_packet_w(data, &cursor, len, &lrop.unknown_server1_port); /* 069-072: unknown server2 ip address */ bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown_server2_ip, 4); /* 073-074: unknown server2 port */ bytes += read_packet_w(data, &cursor, len, &lrop.unknown_server2_port); /* 075-076: 2 bytes unknown */ bytes += read_packet_w(data, &cursor, len, &lrop.unknown2); /* 077-078: 2 bytes unknown */ bytes += read_packet_w(data, &cursor, len, &lrop.unknown3); /* 079-110: 32 bytes unknown */ bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown4, 32); /* 111-122: 12 bytes unknown */ bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown5, 12); /* 123-126: login IP of last session */ bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.last_client_ip, 4); /* 127-130: login time of last session */ bytes += read_packet_time(data, &cursor, len, &lrop.last_login_time); /* 131-138: 8 bytes unknown */ bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown6, 8); if (bytes != QQ_LOGIN_REPLY_OK_PACKET_LEN) { /* fail parsing login info */ purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Fail parsing login info, expect %d bytes, read %d bytes\n", QQ_LOGIN_REPLY_OK_PACKET_LEN, bytes); } /* but we still go on as login OK */ qd->session_key = lrop.session_key; qd->session_md5 = _gen_session_md5(qd->uid, qd->session_key); qd->my_ip = gen_ip_str(lrop.client_ip); qd->my_port = lrop.client_port; qd->login_time = lrop.login_time; qd->last_login_time = lrop.last_login_time; qd->last_login_ip = gen_ip_str(lrop.last_client_ip); purple_connection_set_state(gc, PURPLE_CONNECTED); qd->logged_in = TRUE; /* must be defined after sev_finish_login */ /* now initiate QQ Qun, do it first as it may take longer to finish */ qq_group_init(gc); /* Now goes on updating my icon/nickname, not showing info_window */ qd->modifying_face = FALSE; qq_send_packet_get_info(gc, qd->uid, FALSE); /* grab my level */ qq_send_packet_get_level(gc, qd->uid); qq_send_packet_change_status(gc); /* refresh buddies */ qq_send_packet_get_buddies_list(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; }
/* recv an IM from a group chat */ void qq_process_recv_group_im(guint8 *data, guint8 **cursor, gint data_len, guint32 internal_group_id, GaimConnection *gc, guint16 im_type) { gchar *msg_with_gaim_smiley, *msg_utf8_encoded, *im_src_name, *hex_dump; guint16 unknown; guint32 unknown4; GaimConversation *conv; qq_data *qd; qq_buddy *member; qq_group *group; qq_recv_group_im *im_group; gint skip_len; g_return_if_fail(data != NULL && data_len > 0); qd = (qq_data *) gc->proto_data; hex_dump = hex_dump_to_str(*cursor, data_len - (*cursor - data)); gaim_debug(GAIM_DEBUG_INFO, "QQ", "group im hex dump\n%s\n", hex_dump); if (*cursor >= (data + data_len - 1)) { gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Received group im_group is empty\n"); return; } im_group = g_newa(qq_recv_group_im, 1); read_packet_dw(data, cursor, data_len, &(im_group->external_group_id)); read_packet_b(data, cursor, data_len, &(im_group->group_type)); if(QQ_RECV_IM_TEMP_QUN_IM == im_type) { read_packet_dw(data, cursor, data_len, &(internal_group_id)); } read_packet_dw(data, cursor, data_len, &(im_group->member_uid)); read_packet_w(data, cursor, data_len, &unknown); /* 0x0001? */ read_packet_w(data, cursor, data_len, &(im_group->msg_seq)); read_packet_dw(data, cursor, data_len, (guint32 *) & (im_group->send_time)); read_packet_dw(data, cursor, data_len, &unknown4); /* versionID */ /* * length includes font_attr * this msg_len includes msg and font_attr **** the format is **** * length of all * 1. unknown 10 bytes * 2. 0-ended string * 3. font_attr */ read_packet_w(data, cursor, data_len, &(im_group->msg_len)); g_return_if_fail(im_group->msg_len > 0); /* * 10 bytes from lumaqq * contentType = buf.getChar(); * totalFragments = buf.get() & 255; * fragmentSequence = buf.get() & 255; * messageId = buf.getChar(); * buf.getInt(); */ if(im_type != QQ_RECV_IM_UNKNOWN_QUN_IM) skip_len = 10; else skip_len = 0; *cursor += skip_len; im_group->msg = g_strdup((gchar *) *cursor); *cursor += strlen(im_group->msg) + 1; /* there might not be any font_attr, check it */ im_group->font_attr_len = im_group->msg_len - strlen(im_group->msg) - 1 - skip_len; if (im_group->font_attr_len > 0) im_group->font_attr = g_memdup(*cursor, im_group->font_attr_len); else im_group->font_attr = NULL; /* group im_group has no flag to indicate whether it has font_attr or not */ msg_with_gaim_smiley = qq_smiley_to_gaim(im_group->msg); if (im_group->font_attr_len > 0) msg_utf8_encoded = qq_encode_to_gaim(im_group->font_attr, im_group->font_attr_len, msg_with_gaim_smiley); else msg_utf8_encoded = qq_to_utf8(msg_with_gaim_smiley, QQ_CHARSET_DEFAULT); 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)); if (conv == NULL && gaim_prefs_get_bool("/plugins/prpl/qq/prompt_group_msg_on_recv")) { serv_got_joined_chat(gc, qd->channel++, group->group_name_utf8); conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT, group->group_name_utf8, gaim_connection_get_account(gc)); } if (conv != NULL) { member = qq_group_find_member_by_uid(group, im_group->member_uid); if (member == NULL || member->nickname == NULL) im_src_name = uid_to_gaim_name(im_group->member_uid); else im_src_name = g_strdup(member->nickname); serv_got_chat_in(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT (conv)), im_src_name, 0, msg_utf8_encoded, im_group->send_time); g_free(im_src_name); } g_free(hex_dump); g_free(msg_with_gaim_smiley); g_free(msg_utf8_encoded); g_free(im_group->msg); g_free(im_group->font_attr); }