Exemplo n.º 1
0
static void do_server_notice(PurpleConnection *gc, gchar *from, gchar *to,
	guint8 *data, gint data_len)
{
	qq_data *qd = (qq_data *) gc->proto_data;
	gchar *msg, *msg_utf8;
	gchar *title, *content;

	g_return_if_fail(from != NULL && to != NULL && data_len > 0);

	msg = g_strndup((gchar *)data, data_len);
	msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
	g_free(msg);
	if (msg_utf8 == NULL) {
		purple_debug_error("QQ", "Recv NULL sys msg from %s to %s, discard\n",
			from, to);
		return;
	}

	title = g_strdup_printf(_("From %s:"), from);
	content = g_strdup_printf(_("Server notice From %s: \n%s"), from, msg_utf8);

	if (qd->is_show_notice) {
		qq_got_message(gc, content);
	} else {
		purple_debug_info("QQ", "QQ Server notice from %s:\n%s\n", from, msg_utf8);
	}
	g_free(msg_utf8);
	g_free(title);
	g_free(content);
}
Exemplo n.º 2
0
/* someone wants to add you to his buddy list */
static void server_buddy_add_request(PurpleConnection *gc, gchar *from, gchar *to,
		guint8 *data, gint data_len)
{
	guint32 uid;
	gchar *msg, *reason;

	g_return_if_fail(from != NULL && to != NULL);
	uid = strtoul(from, NULL, 10);
	g_return_if_fail(uid != 0);

	if (purple_prefs_get_bool("/plugins/prpl/qq/auto_get_authorize_info")) {
		qq_request_buddy_info(gc, uid, 0, QQ_BUDDY_INFO_DISPLAY);
	}

	if (data_len <= 0) {
		reason = g_strdup( _("No reason given") );
	} else {
		msg = g_strndup((gchar *)data, data_len);
		reason = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
		if (reason == NULL)	reason = g_strdup( _("Unknown reason") );
		g_free(msg);
	}

	buddy_add_input(gc, uid, reason);
	g_free(reason);
}
Exemplo n.º 3
0
static void do_got_sms(PurpleConnection *gc, guint8 *data, gint data_len)
{
	gint bytes;
	gchar *mobile = NULL;
	gchar *msg = NULL;
	gchar *msg_utf8 = NULL;
	gchar *msg_formated;

	g_return_if_fail(data != NULL && data_len > 26);

	qq_show_packet("Rcv sms", data, data_len);

	bytes = 0;
	bytes += 1;	/* skip 0x00 */
	mobile = g_strndup((gchar *)data + bytes, 20);
	bytes += 20;
	bytes += 5; /* skip 0x(49 11 98 d5 03)*/
	if (bytes < data_len) {
		msg = g_strndup((gchar *)data + bytes, data_len - bytes);
		msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
		g_free(msg);
	} else {
		msg_utf8 = g_strdup("");
	}

	msg_formated = g_strdup_printf(_("%s:%s"), mobile, msg_utf8);

	qq_got_message(gc, msg_formated);

	g_free(msg_formated);
	g_free(msg_utf8);
	g_free(mobile);
}
Exemplo n.º 4
0
/* you are rejected by the person */
static void server_buddy_rejected_me(PurpleConnection *gc, gchar *from, gchar *to,
		guint8 *data, gint data_len)
{
	guint32 uid;
	PurpleBuddy *buddy;
	gchar *msg, *msg_utf8;
	gint bytes;
	gchar **segments;
	gchar *primary, *secondary;
	qq_buddy_data *bd;

	g_return_if_fail(from != NULL && to != NULL);

	qq_show_packet("server_buddy_rejected_me", data, data_len);

	if (data_len <= 0) {
		msg = g_strdup( _("No reason given") );
	} else {
		segments = g_strsplit((gchar *)data, "\x1f", 1);
		if (segments != NULL && segments[0] != NULL) {
			msg = g_strdup(segments[0]);
			g_strfreev(segments);
			bytes = strlen(msg) + 1;
			if (bytes < data_len) {
				server_buddy_check_code(gc, from, data + bytes, data_len - bytes);
			}
		} else {
			msg = g_strdup( _("No reason given") );
		}
	}
	msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
	if (msg_utf8 == NULL) {
		msg_utf8 = g_strdup( _("Unknown reason") );
	}
	g_free(msg);

	primary = g_strdup_printf(_("Rejected by %s"), from);
	secondary = g_strdup_printf(_("Message: %s"), msg_utf8);

	purple_notify_info(gc, _("QQ Buddy"), primary, secondary);

	g_free(msg_utf8);
	g_free(primary);
	g_free(secondary);

	uid = strtoul(from, NULL, 10);
	g_return_if_fail(uid != 0);

	buddy = qq_buddy_find(gc, uid);
	if (buddy != NULL && (bd = purple_buddy_get_protocol_data(buddy)) != NULL) {
		/* Not authorized now, free buddy data */
		qq_buddy_data_free(bd);
		purple_buddy_set_protocol_data(buddy, NULL);
	}
}
Exemplo n.º 5
0
/* after getting info or modify myself, refresh the buddy list accordingly */
static void update_buddy_info(PurpleConnection *gc, gchar **segments)
{
	PurpleBuddy *buddy;
	qq_data *qd;
	qq_buddy_data *bd;
	guint32 uid;
	gchar *who;
	gchar *alias_utf8;
	PurpleAccount *account = purple_connection_get_account(gc);

	qd = (qq_data *) gc->proto_data;

	uid = strtoul(segments[QQ_INFO_UID], NULL, 10);
	who = uid_to_purple_name(uid);

	qq_filter_str(segments[QQ_INFO_NICK]);
	alias_utf8 = qq_to_utf8(segments[QQ_INFO_NICK], QQ_CHARSET_DEFAULT);
	if (uid == qd->uid) {	/* it is me */
		purple_debug_info("QQ", "Got my info\n");
		qd->my_icon = strtol(segments[QQ_INFO_FACE], NULL, 10);
		if (alias_utf8 != NULL) {
			purple_account_set_alias(account, alias_utf8);
		}
		/* add me to buddy list */
		buddy = qq_buddy_find_or_new(gc, uid);
	} else {
		buddy = purple_find_buddy(gc->account, who);
	}

	if (buddy == NULL || buddy->proto_data == NULL) {
		g_free(who);
		g_free(alias_utf8);
		return;
	}

	/* update buddy list (including myself, if myself is the buddy) */
	bd = (qq_buddy_data *)buddy->proto_data;

	bd->age = strtol(segments[QQ_INFO_AGE], NULL, 10);
	bd->gender = strtol(segments[QQ_INFO_GENDER], NULL, 10);
	bd->face = strtol(segments[QQ_INFO_FACE], NULL, 10);
	if (alias_utf8 != NULL) {
		if (bd->nickname) g_free(bd->nickname);
		bd->nickname = g_strdup(alias_utf8);
	}
	bd->last_update = time(NULL);

	purple_blist_server_alias_buddy(buddy, bd->nickname);

	/* convert face num from packet (0-299) to local face (1-100) */
	qq_update_buddy_icon(gc->account, who, bd->face);

	g_free(who);
	g_free(alias_utf8);
}
Exemplo n.º 6
0
static void field_request_new(PurpleRequestFieldGroup *group, gint index, gchar **segments)
{
	PurpleRequestField *field;
	gchar *utf8_value;
	int choice_num;
	int i;

	g_return_if_fail(index >=0 && segments[index] != NULL && index < QQ_INFO_LAST);

	switch (field_infos[index].type) {
		case QQ_FIELD_STRING:
		case QQ_FIELD_MULTI:
			utf8_value = qq_to_utf8(segments[index], QQ_CHARSET_DEFAULT);
			if (field_infos[index].type == QQ_FIELD_STRING) {
				field = purple_request_field_string_new(
						field_infos[index].id, field_infos[index].text, utf8_value, FALSE);
			} else {
				field = purple_request_field_string_new(
						field_infos[index].id, field_infos[index].text, utf8_value, TRUE);
			}
			purple_request_field_group_add_field(group, field);
			g_free(utf8_value);
			break;
		case QQ_FIELD_BOOL:
			field = purple_request_field_bool_new(
					field_infos[index].id, field_infos[index].text,
					strtol(segments[index], NULL, 10) ? TRUE : FALSE);
			purple_request_field_group_add_field(group, field);
			break;
		case QQ_FIELD_CHOICE:
			choice_num = strtol(segments[index], NULL, 10);
			if (choice_num < 0 || choice_num >= field_infos[index].choice_size)	choice_num = 0;

			if (index == QQ_INFO_GENDER && strlen(segments[index]) != 0) {
				for (i = 0; i < QQ_GENDER_SIZE; i++) {
					if (strcmp(segments[index], genders_zh[i]) == 0) {
						choice_num = i;
					}
				}
			}
			field = purple_request_field_choice_new(
					field_infos[index].id, field_infos[index].text, choice_num);
			for (i = 0; i < field_infos[index].choice_size; i++) {
				purple_request_field_choice_add(field, field_infos[index].choice[i]);
			}
			purple_request_field_group_add_field(group, field);
			break;
		case QQ_FIELD_LABEL:
		default:
			field = purple_request_field_label_new(field_infos[index].id, segments[index]);
			purple_request_field_group_add_field(group, field);
			break;
	}
}
Exemplo n.º 7
0
/* process login reply which says wrong password */
static gint _qq_process_login_wrong_pwd(PurpleConnection *gc, guint8 *data, gint len)
{
	gchar *server_reply, *server_reply_utf8;
	server_reply = g_new0(gchar, len);
	g_memmove(server_reply, data + 1, len - 1);
	server_reply_utf8 = qq_to_utf8(server_reply, QQ_CHARSET_DEFAULT);
	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Wrong password, server msg in UTF8: %s\n", server_reply_utf8);
	g_free(server_reply);
	g_free(server_reply_utf8);

	return QQ_LOGIN_REPLY_PWD_ERROR;
}
Exemplo n.º 8
0
static void process_level_2007(PurpleConnection *gc, guint8 *data, gint data_len)
{
	gint bytes;
	guint32 uid, onlineTime;
	guint16 level, timeRemainder;
	qq_buddy_data *bd;
	guint16 str_len;
	gchar *str;
	gchar *str_utf8;

	bytes = 0;
	bytes += qq_get32(&uid, data + bytes);
	bytes += qq_get32(&onlineTime, data + bytes);
	bytes += qq_get16(&level, data + bytes);
	bytes += qq_get16(&timeRemainder, data + bytes);
	purple_debug_info("QQ", "level: %d, uid %u, tmOnline: %d, tmRemainder: %d\n",
			level, uid, onlineTime, timeRemainder);

	bd = qq_buddy_data_find(gc, uid);
	if (bd == NULL) {
		purple_debug_error("QQ", "Got levels of %u not in my buddy list\n", uid);
		return;
	}

	bd->onlineTime = onlineTime;
	bd->level = level;
	bd->timeRemainder = timeRemainder;

	/* extend bytes in qq2007*/
	bytes += 4;	/* skip 8 bytes */
	/* qq_show_packet("Buddies level", data + bytes, data_len - bytes); */

	do {
		bytes += qq_get16(&str_len, data + bytes);
		if (str_len <= 0 || bytes + str_len > data_len) {
			purple_debug_error("QQ",
					"Wrong format of Get levels. Truncate %d bytes.\n", data_len - bytes);
			break;
		}
		str = g_strndup((gchar *)data + bytes, str_len);
		bytes += str_len;
		str_utf8 = qq_to_utf8(str, QQ_CHARSET_DEFAULT);
		purple_debug_info("QQ", "%s\n", str_utf8);
		g_free(str_utf8);
		g_free(str);
	} while (bytes < data_len);
}
Exemplo n.º 9
0
static void info_display_only(PurpleConnection *gc, gchar **segments)
{
	PurpleNotifyUserInfo *user_info;
	gchar *utf8_value;
	int index;
	int choice_num;

	user_info = purple_notify_user_info_new();

	for (index = 1; segments[index] != NULL && index < QQ_INFO_LAST; index++) {
		if (field_infos[index].iclass == QQ_FIELD_UNUSED) {
			continue;
		}
		switch (field_infos[index].type) {
			case QQ_FIELD_BOOL:
				purple_notify_user_info_add_pair(user_info, field_infos[index].text,
					strtol(segments[index], NULL, 10) ? _("True") : _("False"));
				break;
			case QQ_FIELD_CHOICE:
				choice_num = strtol(segments[index], NULL, 10);
				if (choice_num < 0 || choice_num >= field_infos[index].choice_size) {
					choice_num = 0;
				}

				purple_notify_user_info_add_pair(user_info, field_infos[index].text, field_infos[index].choice[choice_num]);
				break;
			case QQ_FIELD_LABEL:
			case QQ_FIELD_STRING:
			case QQ_FIELD_MULTI:
			default:
				if (strlen(segments[index]) != 0) {
					utf8_value = qq_to_utf8(segments[index], QQ_CHARSET_DEFAULT);
					purple_notify_user_info_add_pair(user_info, field_infos[index].text, utf8_value);
					g_free(utf8_value);
				}
				break;
		}
	}

	purple_notify_userinfo(gc, segments[0], user_info, NULL, NULL);

	purple_notify_user_info_destroy(user_info);
	g_strfreev(segments);
}
Exemplo n.º 10
0
static void process_room_cmd_notify(PurpleConnection *gc,
	guint8 room_cmd, guint8 room_id, guint8 reply, guint8 *data, gint data_len)
{
	gchar *prim;
	gchar *msg, *msg_utf8;
	g_return_if_fail(data != NULL && data_len > 0);

	msg = g_strndup((gchar *) data, data_len);	/* it will append 0x00 */
	msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
	g_free(msg);

	prim = g_strdup_printf(_("Error reply of %s(0x%02X)\nRoom %u, reply 0x%02X"),
		qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, reply);

	purple_notify_error(gc, _("QQ Qun Command"), prim, msg_utf8);

	g_free(prim);
	g_free(msg_utf8);
}
Exemplo n.º 11
0
static void info_debug(gchar **segments)
{
#if 0
	int index;
	gchar *utf8_str;
	for (index = 0; segments[index] != NULL && index < QQ_INFO_LAST; index++) {
		if (field_infos[index].type == QQ_FIELD_STRING
				|| field_infos[index].type == QQ_FIELD_LABEL
				|| field_infos[index].type == QQ_FIELD_MULTI
				|| index == QQ_INFO_GENDER)  {
			utf8_str = qq_to_utf8(segments[index], QQ_CHARSET_DEFAULT);
			purple_debug_info("QQ_BUDDY_INFO", "%s: %s\n", field_infos[index].text, utf8_str);
			g_free(utf8_str);
			continue;
		}
		purple_debug_info("QQ_BUDDY_INFO", "%s: %s\n", field_infos[index].text, segments[index]);
	}
#endif
}
Exemplo n.º 12
0
/*  process reply to add_buddy_auth request */
void qq_process_add_buddy_auth(guint8 *data, gint data_len, PurpleConnection *gc)
{
	qq_data *qd;
	gchar **segments, *msg_utf8;

	g_return_if_fail(data != NULL && data_len != 0);

	qd = (qq_data *) gc->proto_data;

	if (data[0] == '0') {
		purple_debug_info("QQ", "Reply OK for sending authorize\n");
		return;
	}

	if (NULL == (segments = split_data(data, data_len, "\x1f", 2))) {
		purple_notify_error(gc, _("QQ Buddy"), _("Failed sending authorize"), NULL);
		return;
	}
	msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT);
	purple_notify_error(gc, _("QQ Buddy"), _("Failed sending authorize"), msg_utf8);
	g_free(msg_utf8);
}
Exemplo n.º 13
0
/* recv an IM from a group chat */
void qq_process_room_im(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 msg_type)
{
	qq_data *qd;
	gchar *msg_smiley, *msg_fmt, *msg_utf8;
	gint bytes, tail_len;
	struct {
		guint32 ext_id;
		guint8 type8;
		guint32 member_uid;
		guint16 unknown;
		guint16 msg_seq;
		time_t send_time;
		guint32 version;
		guint16 msg_len;
		gchar *msg;
	} im_text;
	guint32 temp_id;
	guint16 content_type;
	guint8 frag_count, frag_index;
	guint16 msg_id;
	qq_im_format *fmt = NULL;

	/* at least include im_text.msg_len */
	g_return_if_fail(data != NULL && data_len > 23);
	qd = (qq_data *) gc->proto_data;

	/* qq_show_packet("ROOM_IM", data, data_len); */
	memset(&im_text, 0, sizeof(im_text));
	bytes = 0;
	bytes += qq_get32(&(im_text.ext_id), data + bytes);
	bytes += qq_get8(&(im_text.type8), data + bytes);

	if(QQ_MSG_TEMP_QUN_IM == msg_type) {
		bytes += qq_get32(&temp_id, data + bytes);
	}

	bytes += qq_get32(&(im_text.member_uid), bytes + data);
	bytes += qq_get16(&im_text.unknown, data + bytes);	/* 0x0001? */
	bytes += qq_get16(&(im_text.msg_seq), data + bytes);
	bytes += qq_getime(&im_text.send_time, data + bytes);
	bytes += qq_get32(&im_text.version, data + bytes);
	bytes += qq_get16(&(im_text.msg_len), data + bytes);
	purple_debug_info("QQ", "Room IM, ext id %u, seq %u, version 0x%04X, len %u\n",
		im_text.ext_id, im_text.msg_seq, im_text.version, im_text.msg_len);

	if (im_text.msg_len != data_len - bytes) {
		purple_debug_warning("QQ", "Room IM length %d should be %d\n",
			im_text.msg_len, data_len - bytes);
		im_text.msg_len = data_len - bytes;
	}

	g_return_if_fail(im_text.msg_len > 0 && bytes + im_text.msg_len <= data_len);
	if(msg_type != QQ_MSG_QUN_IM_UNKNOWN) {
		g_return_if_fail(im_text.msg_len >= 10);

		bytes += qq_get16(&content_type, data + bytes);
		bytes += qq_get8(&frag_count, data + bytes);
		bytes += qq_get8(&frag_index, data + bytes);
		bytes += qq_get16(&msg_id, data + bytes);
		bytes += 4;	/* skip 0x(00 00 00 00) */
		purple_debug_info("QQ", "Room IM, content %d, frag %d-%d, msg id %u\n",
			content_type, frag_count, frag_index, msg_id);
		im_text.msg_len -= 10;
	}
	g_return_if_fail(im_text.msg_len > 0);

	/* qq_show_packet("Message", data + bytes, data_len - bytes); */
	if (frag_count <= 1 || frag_count == frag_index + 1) {
		fmt = qq_im_fmt_new();
		tail_len = qq_get_im_tail(fmt, data + bytes, data_len - bytes);
		im_text.msg = g_strndup((gchar *)(data + bytes), data_len - tail_len);
	} else {
		im_text.msg = g_strndup((gchar *)(data + bytes), data_len - bytes);
	}

	/* group im_group has no flag to indicate whether it has font_attr or not */
	msg_smiley = qq_emoticon_to_purple(im_text.msg);
	if (fmt != NULL) {
		msg_fmt = qq_im_fmt_to_purple(fmt, msg_smiley);
		msg_utf8 =  qq_to_utf8(msg_fmt, QQ_CHARSET_DEFAULT);
		g_free(msg_fmt);
		qq_im_fmt_free(fmt);
	} else {
		msg_utf8 =  qq_to_utf8(msg_smiley, QQ_CHARSET_DEFAULT);
	}
	g_free(msg_smiley);

	purple_debug_info("QQ", "Room (%u) IM from %u: %s\n",
			im_text.ext_id, im_text.member_uid, msg_utf8);
 	qq_room_got_chat_in(gc, id, im_text.member_uid, msg_utf8, im_text.send_time);

	g_free(msg_utf8);
	g_free(im_text.msg);
}
Exemplo n.º 14
0
/* process received extended (2007) text IM */
static void process_extend_im_text(PurpleConnection *gc, guint8 *data, gint len, qq_im_header *im_header)
{
	qq_data *qd;
	guint16 purple_msg_type;
	gchar *who;
	gchar *msg_smiley, *msg_fmt, *msg_utf8;
	PurpleBuddy *buddy;
	qq_buddy_data *bd;
	gint bytes, tail_len;
	qq_im_format *fmt = NULL;

	struct {
		/* now comes the part for text only */
		guint16 msg_seq;
		guint32 send_time;
		guint16 sender_icon;
		guint32 has_font_attr;
		guint8 unknown1[8];
		guint8 fragment_count;
		guint8 fragment_index;
		guint8 msg_id;
		guint8 unknown2;
		guint8 msg_type;
		gchar *msg;		/* no fixed length, ends with 0x00 */
		guint8 fromMobileQQ;
	} im_text;

	g_return_if_fail (data != NULL && len > 0);
	g_return_if_fail(im_header != NULL);

	qd = (qq_data *) gc->proto_data;
	memset(&im_text, 0, sizeof(im_text));

	/* qq_show_packet("Extend IM text", data, len); */
	bytes = 0;
	bytes += qq_get16(&(im_text.msg_seq), data + bytes);
	bytes += qq_get32(&(im_text.send_time), data + bytes);
	bytes += qq_get16(&(im_text.sender_icon), data + bytes);
	bytes += qq_get32(&(im_text.has_font_attr), data + bytes);
	bytes += qq_getdata(im_text.unknown1, sizeof(im_text.unknown1), data + bytes);
	bytes += qq_get8(&(im_text.fragment_count), data + bytes);
	bytes += qq_get8(&(im_text.fragment_index), data + bytes);
	bytes += qq_get8(&(im_text.msg_id), data + bytes);
	bytes += 1; 	/* skip 0x00 */
	bytes += qq_get8(&(im_text.msg_type), data + bytes);
	purple_debug_info("QQ", "IM Seq %u, id %04X, fragment %d-%d, type %d, %s\n",
			im_text.msg_seq, im_text.msg_id,
			im_text.fragment_count, im_text.fragment_index,
			im_text.msg_type,
			im_text.has_font_attr ? "exist font atrr" : "");

	if (im_text.has_font_attr) {
		fmt = qq_im_fmt_new();
		tail_len = qq_get_im_tail(fmt, data + bytes, len - bytes);
		im_text.msg = g_strndup((gchar *)(data + bytes), len - tail_len);
	} else	{
		im_text.msg = g_strndup((gchar *)(data + bytes), len - bytes);
	}
	/* qq_show_packet("IM text", (guint8 *)im_text.msg , strlen(im_text.msg)); */

	if(im_text.fragment_count == 0) 	im_text.fragment_count = 1;

	who = uid_to_purple_name(im_header->uid_from);
	buddy = purple_find_buddy(gc->account, who);
	if (buddy == NULL) {
		/* create no-auth buddy */
		buddy = qq_buddy_new(gc, im_header->uid_from);
	}
	bd = (buddy == NULL) ? NULL : purple_buddy_get_protocol_data(buddy);
	if (bd != NULL) {
		bd->client_tag = im_header->version_from;
		bd->face = im_text.sender_icon;
		qq_update_buddy_icon(gc->account, who, bd->face);
	}

	purple_msg_type = 0;

	msg_smiley = qq_emoticon_to_purple(im_text.msg);
	if (fmt != NULL) {
		msg_fmt = qq_im_fmt_to_purple(fmt, msg_smiley);
		msg_utf8 =  qq_to_utf8(msg_fmt, QQ_CHARSET_DEFAULT);
		g_free(msg_fmt);
		qq_im_fmt_free(fmt);
	} else {
		msg_utf8 =  qq_to_utf8(msg_smiley, QQ_CHARSET_DEFAULT);
	}
	g_free(msg_smiley);

	/* send encoded to purple, note that we use im_text.send_time,
	 * not the time we receive the message
	 * as it may have been delayed when I am not online. */
	serv_got_im(gc, who, msg_utf8, purple_msg_type, (time_t) im_text.send_time);

	g_free(msg_utf8);
	g_free(who);
	g_free(im_text.msg);
}
Exemplo n.º 15
0
/* 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);
}