예제 #1
0
파일: im.c 프로젝트: Mons/libpurple-mini
/* it is a normal IM, maybe text or video request */
void qq_process_im(PurpleConnection *gc, guint8 *data, gint len)
{
	gint bytes = 0;
	qq_im_header im_header;

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

	bytes = get_im_header(&im_header, data, len);
	if (bytes < 0) {
		purple_debug_error("QQ", "Fail read im header, len %d\n", len);
		qq_show_packet ("IM Header", data, len);
		return;
	}
	purple_debug_info("QQ",
			"Got IM to %u, type: %02X from: %u ver: %s (%04X)\n",
			im_header.uid_to, im_header.im_type, im_header.uid_from,
			qq_get_ver_desc(im_header.version_from), im_header.version_from);

	switch (im_header.im_type) {
		case QQ_NORMAL_IM_TEXT:
			if (bytes >= len - 1) {
				purple_debug_warning("QQ", "Received normal IM text is empty\n");
				return;
			}
			process_im_text(gc, data + bytes, len - bytes, &im_header);
			break;
		case QQ_NORMAL_IM_FILE_REJECT_UDP:
			qq_process_recv_file_reject(data + bytes, len - bytes, im_header.uid_from, gc);
			break;
		case QQ_NORMAL_IM_FILE_APPROVE_UDP:
			qq_process_recv_file_accept(data + bytes, len - bytes, im_header.uid_from, gc);
			break;
		case QQ_NORMAL_IM_FILE_REQUEST_UDP:
			qq_process_recv_file_request(data + bytes, len - bytes, im_header.uid_from, gc);
			break;
		case QQ_NORMAL_IM_FILE_CANCEL:
			qq_process_recv_file_cancel(data + bytes, len - bytes, im_header.uid_from, gc);
			break;
		case QQ_NORMAL_IM_FILE_NOTIFY:
			qq_process_recv_file_notify(data + bytes, len - bytes, im_header.uid_from, gc);
			break;
		case QQ_NORMAL_IM_FILE_REQUEST_TCP:
			/* Check ReceivedFileIM::parseContents in eva*/
			/* some client use this function for detect invisable buddy*/
		case QQ_NORMAL_IM_FILE_APPROVE_TCP:
		case QQ_NORMAL_IM_FILE_REJECT_TCP:
		case QQ_NORMAL_IM_FILE_PASV:
		case QQ_NORMAL_IM_FILE_EX_REQUEST_UDP:
		case QQ_NORMAL_IM_FILE_EX_REQUEST_ACCEPT:
		case QQ_NORMAL_IM_FILE_EX_REQUEST_CANCEL:
		case QQ_NORMAL_IM_FILE_EX_NOTIFY_IP:
			qq_show_packet ("Not support", data, len);
			break;
		default:
			/* a simple process here, maybe more later */
			qq_show_packet ("Unknow", data + bytes, len - bytes);
			return;
	}
}
예제 #2
0
static gint server_buddy_check_code(PurpleConnection *gc,
		gchar *from, guint8 *data, gint data_len)
{
	gint bytes;
	guint16 code_len;
	guint8 *code;

	g_return_val_if_fail(data != NULL && data_len > 0, 0);

	bytes = 0;
	bytes += qq_get16(&code_len, data + bytes);
	if (code_len <= 0) {
		purple_debug_info("QQ", "Server msg for buddy has no code\n");
		return bytes;
	}
	if (bytes + code_len < data_len) {
		purple_debug_error("QQ", "Code len error in server msg for buddy\n");
		qq_show_packet("server_buddy_check_code", data, data_len);
		code_len = data_len - bytes;
	}
	code = g_newa(guint8, code_len);
	bytes += qq_getdata(code, code_len, data + bytes);

	request_buddy_check_code(gc, from, code, code_len);
	return bytes;
}
예제 #3
0
파일: buddy_opt.c 프로젝트: bf4/pidgin-mac
void qq_process_add_buddy_no_auth(PurpleConnection *gc,
		guint8 *data, gint data_len, guint32 uid)
{
	qq_data *qd;
	gchar **segments;
	gchar *dest_uid, *reply;
	PurpleBuddy *buddy;

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

	qd = (qq_data *) gc->proto_data;

	purple_debug_info("QQ", "Process buddy add for id [%u]\n", uid);
	qq_show_packet("buddy_add_no_auth", data, data_len);

	if (NULL == (segments = split_data(data, data_len, "\x1f", 2)))
		return;

	dest_uid = segments[0];
	reply = segments[1];
	if (strtoul(dest_uid, NULL, 10) != qd->uid) {	/* should not happen */
		purple_debug_error("QQ", "Add buddy reply is to [%s], not me!", dest_uid);
		g_strfreev(segments);
		return;
	}

	if (strtol(reply, NULL, 10) == 0) {
		/* add OK */
		qq_buddy_find_or_new(gc, uid);

		qq_request_buddy_info(gc, uid, 0, 0);
		if (qd->client_version >= 2007) {
			qq_request_get_level_2007(gc, uid);
		} else {
			qq_request_get_level(gc, uid);
		}
		qq_request_get_buddies_online(gc, 0, 0);

		purple_debug_info("QQ", "Successed adding into %u's buddy list", uid);
		g_strfreev(segments);
		return;
	}

	/* need auth */
	purple_debug_warning("QQ", "Failed adding buddy, need authorize\n");

	buddy = qq_buddy_find(gc, uid);
	if (buddy == NULL) {
		buddy = qq_buddy_new(gc, uid);
	}
	if (buddy != NULL && buddy->proto_data != NULL) {
		/* Not authorized now, free buddy data */
		qq_buddy_data_free(buddy->proto_data);
		buddy->proto_data = NULL;
	}

	add_buddy_authorize_input(gc, uid, NULL, 0);
	g_strfreev(segments);
}
예제 #4
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);
}
예제 #5
0
static gint packet_encap(qq_data *qd, guint8 *buf, gint maxlen, guint16 cmd, guint16 seq,
	guint8 *data, gint data_len)
{
	gint bytes = 0;
	g_return_val_if_fail(qd != NULL && buf != NULL && maxlen > 0, -1);
	g_return_val_if_fail(data != NULL && data_len > 0, -1);

	/* QQ TCP packet has two bytes in the begining defines packet length
	 * so leave room here to store packet size */
	if (qd->use_tcp) {
		bytes += qq_put16(buf + bytes, 0x0000);
	}
	/* now comes the normal QQ packet as UDP */
	bytes += qq_put8(buf + bytes, QQ_PACKET_TAG);
	bytes += qq_put16(buf + bytes, qd->client_tag);
	bytes += qq_put16(buf + bytes, cmd);
	bytes += qq_put16(buf + bytes, seq);
	bytes += qq_put32(buf + bytes, qd->uid);
	if(qd->client_version == 2010)
	{
		bytes += qq_putdata(buf + bytes, qd->vd.sig1, VD_SIG1_LEN);
	}
	bytes += qq_putdata(buf + bytes, data, data_len);
	bytes += qq_put8(buf + bytes, QQ_PACKET_TAIL);

	/* set TCP packet length at begin of the packet */
	if (qd->use_tcp) {
		qq_put16(buf, bytes);
	}
#if 1
	qq_show_packet("packet_encap", buf, bytes);
#endif
	return bytes;
}
예제 #6
0
void qq_process_buddy_check_code(PurpleConnection *gc, guint8 *data, gint data_len)
{
	qq_data *qd;
	gint bytes;
	guint8 cmd;
	guint8 reply;
	guint32 uid;
	guint16 flag1, flag2;

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

	qd = (qq_data *) gc->proto_data;

	qq_show_packet("buddy_check_code", data, data_len);

	bytes = 0;
	bytes += qq_get8(&cmd, data + bytes);		/* 0x03 */
	bytes += qq_get8(&reply, data + bytes);

	if (reply == 0) {
		purple_debug_info("QQ", "Failed checking code\n");
		return;
	}

	bytes += qq_get32(&uid, data + bytes);
	g_return_if_fail(uid != 0);
	bytes += qq_get16(&flag1, data + bytes);
	bytes += qq_get16(&flag2, data + bytes);
	purple_debug_info("QQ", "Check code reply Ok, uid %u, flag 0x%04X-0x%04X\n",
			uid, flag1, flag2);
	return;
}
예제 #7
0
void qq_process_add_buddy_touch( PurpleConnection *gc, guint8 *data, gint data_len, qq_buddy_opt_req *opt_req )
{
	qq_data *qd;
	gint bytes;
	guint32 dest_uid;
	guint8 reply;

	g_return_if_fail(data != NULL && data_len >= 5);
	g_return_if_fail(opt_req && opt_req->uid != 0);

	qd = (qq_data *) gc->proto_data;

	purple_debug_info("QQ", "Process buddy add no auth for id [%u]\n", opt_req->uid);
	qq_show_packet("buddy_add_no_auth_ex", data, data_len);

	bytes = 0;
	bytes += qq_get32(&dest_uid, data + bytes);
	bytes += qq_get8(&reply, data + bytes);

	g_return_if_fail(dest_uid == opt_req->uid);

	if (reply == 0x99) {
		purple_debug_info("QQ", "Successfully added buddy %u\n", opt_req->uid);
		qq_buddy_find_or_new(gc, opt_req->uid, opt_req->group_id);
		qq_request_get_buddy_info(gc, opt_req->uid, 0, 0);
		qq_request_get_level(gc, opt_req->uid);
		qq_request_get_buddies_online(gc, 0, 0);
		return;
	}

	if (reply != 0) {
		purple_debug_info("QQ", "Failed adding buddy %u, Unknown reply 0x%02X\n",
			opt_req->uid, reply);
	}

	/* need auth */
	g_return_if_fail(data_len > bytes);
	bytes += qq_get8(&opt_req->auth_type, data + bytes);
	purple_debug_warning("QQ", "Adding buddy needs authorize 0x%02X\n", opt_req->auth_type);

	switch (opt_req->auth_type) {
		case 0x00:	/* no authorize */
		case 0x01:	/* authorize */
			qq_request_auth_token(gc, QQ_AUTH_INFO_BUDDY, QQ_AUTH_INFO_ADD_BUDDY, 0, opt_req);
			break;
		case 0x02:	/* disable */
			break;
		case 0x03:	/* answer question */
			qq_request_question(gc, QQ_QUESTION_REQUEST, opt_req->uid, NULL, NULL);
			break;
		case 0x04: /* deny! */
			break;
		default:
			g_return_if_reached();
			break;
	}
	return;
}
예제 #8
0
/* from QQ2010 on, extra info should be taken out */
static gint packet_get_header_ex(UID *uid, guint8 *header_ex_fixed, guint8 *buf)
{
	gint bytes = 0;
	bytes += qq_get32(uid, buf + bytes);
	bytes += qq_getdata(header_ex_fixed, 3, buf + bytes);
	qq_show_packet("packet_get_header_ex", header_ex_fixed, 3);
	purple_debug_info("QQ", "packet_get_header_ex - UID:%u\n", *uid);
	return bytes;
}
예제 #9
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);
	}
}
예제 #10
0
static void server_buddy_adding_ex(PurpleConnection *gc, gchar *from, gchar *to,
		guint8 *data, gint data_len)
{
	gint bytes;
	guint8 allow_reverse;

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

	qq_show_packet("server_buddy_adding_ex", data, data_len);

	bytes = 0;
	bytes += qq_get8(&allow_reverse, data + bytes);	/* allow_reverse = 0x01, allowed */
	server_buddy_check_code(gc, from, data + bytes, data_len - bytes);
}
예제 #11
0
/* default process, decrypt and dump */
static void process_unknown_cmd(PurpleConnection *gc,const gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq)
{
	gchar *msg;

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

	qq_show_packet(title, data, data_len);

	qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ",
			data, data_len,
			">>> [%d] %s -> [default] decrypt and dump",
			seq, qq_get_cmd_desc(cmd));

	msg = g_strdup_printf("Unknown command 0x%02X, %s", cmd, qq_get_cmd_desc(cmd));
	//purple_notify_info(gc, _("QQ Error"), title, msg);
	g_free(msg);
}
예제 #12
0
void qq_proc_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len)
{
	qq_data *qd;

	guint8 *data;
	gint data_len;

	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 server cmd by session key, [%05d], 0x%04X %s, len %d\n",
			seq, cmd, qq_get_cmd_desc(cmd), rcved_len);
		qq_show_packet("Can not decrypted", rcved, rcved_len);
		return;
	}

	if (data_len <= 0) {
		purple_debug_warning("QQ",
			"Server cmd decrypted is empty, [%05d], 0x%04X %s, len %d\n",
			seq, cmd, qq_get_cmd_desc(cmd), rcved_len);
		return;
	}

	/* now process the packet */
	switch (cmd) {
		case QQ_CMD_RECV_IM_CE:
		case QQ_CMD_RECV_IM:
			process_private_msg(data, data_len, cmd, seq, gc);
			break;
		case QQ_CMD_RECV_MSG_SYS:
			process_server_msg(gc, data, data_len, seq);
			break;
		case QQ_CMD_BUDDY_CHANGE_STATUS:
			qq_process_buddy_change_status(data, data_len, gc);
			break;
		default:
			process_unknown_cmd(gc, _("Unknown SERVER CMD"), data, data_len, cmd, seq);
			break;
	}
}
예제 #13
0
static void server_buddy_added(PurpleConnection *gc, gchar *from, gchar *to,
		guint8 *data, gint data_len)
{
	guint32 uid;

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

	qq_show_packet("server_buddy_added", data, data_len);

	purple_debug_info("QQ", "Buddy %s added \n", from);

	//server_buddy_check_code(gc, from, data + bytes, data_len - bytes);

	uid = purple_name_to_uid(from);
	qq_buddy_find_or_new(gc, uid, 0xFF);
	qq_request_get_buddy_info(gc, uid, 0, 0);
	qq_request_get_buddies_online(gc, 0, 0);
	qq_request_get_level(gc, uid);
}
예제 #14
0
static void server_buddy_added_ex(PurpleConnection *gc, gchar *from, gchar *to,
		guint8 *data, gint data_len)
{
	gint bytes;
	guint8 allow_reverse;
	gchar *msg;

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

	qq_show_packet("server_buddy_added_ex", data, data_len);

	bytes = 0;
	bytes += qq_get_vstr(&msg, QQ_CHARSET_DEFAULT, data+bytes);	/* always empty msg */
	purple_debug_info("QQ", "Buddy added msg: %s\n", msg);
	bytes += qq_get8(&allow_reverse, data + bytes);	/* allow_reverse = 0x01, allowed */
	server_buddy_check_code(gc, from, data + bytes, data_len - bytes);

	g_free(msg);
}
예제 #15
0
파일: char_conv.c 프로젝트: bf4/pidgin-mac
/* Warning: do not return NULL */
static gchar *do_convert(const gchar *str, gssize len, const gchar *to_charset, const gchar *from_charset)
{
	GError *error = NULL;
	gchar *ret;
	gsize byte_read, byte_write;

	g_return_val_if_fail(str != NULL && to_charset != NULL && from_charset != NULL, g_strdup(QQ_NULL_MSG));

	ret = g_convert(str, len, to_charset, from_charset, &byte_read, &byte_write, &error);

	if (error == NULL) {
		return ret;	/* convert is OK */
	}

	/* convert error */
	purple_debug_error("QQ_CONVERT", "%s\n", error->message);
	qq_show_packet("Dump failed text", (guint8 *) str, (len == -1) ? strlen(str) : len);

	g_error_free(error);
	return g_strdup(QQ_NULL_MSG);
}
예제 #16
0
void qq_process_auth_code(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid)
{
	qq_data *qd;
	gint bytes;
	guint8 cmd, reply;
	guint16 sub_cmd;
	guint8 *code = NULL;
	guint16 code_len = 0;

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

	qd = (qq_data *) gc->proto_data;

	qq_show_packet("qq_process_auth_code", data, data_len);
	bytes = 0;
	bytes += qq_get8(&cmd, data + bytes);
	bytes += qq_get16(&sub_cmd, data + bytes);
	bytes += qq_get8(&reply, data + bytes);
	g_return_if_fail(bytes + 2 <= data_len);

	bytes += qq_get16(&code_len, data + bytes);
	g_return_if_fail(code_len > 0);
	g_return_if_fail(bytes + code_len <= data_len);
	code = g_newa(guint8, code_len);
	bytes += qq_getdata(code, code_len, data + bytes);

	if (cmd == QQ_AUTH_INFO_BUDDY && sub_cmd == QQ_AUTH_INFO_REMOVE_BUDDY) {
		request_remove_buddy_ex(gc, uid, code, code_len);
		return;
	}
	if (cmd == QQ_AUTH_INFO_BUDDY && sub_cmd == QQ_AUTH_INFO_ADD_BUDDY) {
		add_buddy_authorize_input(gc, uid, code, code_len);
		return;
	}
	purple_debug_info("QQ", "Got auth info cmd 0x%x, sub 0x%x, reply 0x%x\n",
			cmd, sub_cmd, reply);
}
예제 #17
0
guint8 qq_proc_login_cmds(PurpleConnection *gc,  guint16 cmd, guint16 seq,
		guint8 *rcved, gint rcved_len, guint32 update_class, guintptr ship_value)
{
	qq_data *qd;
	guint8 *data = NULL;
	gint data_len = 0;
	guint ret_8 = QQ_LOGIN_REPLY_ERR;

	g_return_val_if_fail (gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR);
	qd = (qq_data *) gc->proto_data;

	g_return_val_if_fail(rcved_len > 0, QQ_LOGIN_REPLY_ERR);
	data = g_newa(guint8, rcved_len);

	switch (cmd) {
		case QQ_CMD_TOUCH_SERVER:
		case QQ_CMD_CAPTCHA:
			data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.random_key);
			break;
		case QQ_CMD_AUTH:
			data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.random_key);
			if (data_len >= 0) {
				purple_debug_warning("QQ", "Decrypt login packet by random_key, %d bytes\n", data_len);
			} else {
				data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.keys[4]);
				if (data_len >= 0) {
					purple_debug_warning("QQ", "Decrypt login packet by auth_key1, %d bytes\n", data_len);
				}
			}
			break;
		case QQ_CMD_VERIFY_DE:
			data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.keys[0]);
			break;
		case QQ_CMD_VERIFY_E5:
			data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.keys[1]);
			break;
		case QQ_CMD_VERIFY_E3:
			data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.keys[3]);
			break;
		case QQ_CMD_LOGIN:
			data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.keys[2]);
			if (data_len >= 0) {
				purple_debug_info("QQ", "Decrypt login packet by Key0_VerifyE5\n");
			} else {
				/* network condition may has changed. please sign in again. */
				data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.keys[0]);	
				if (data_len >= 0) {
					purple_debug_info("QQ", "Decrypt login packet rarely by Key2_Auth\n");
				}
			}
			break;
		case QQ_CMD_LOGIN_E9:
		case QQ_CMD_LOGIN_EA:
		case QQ_CMD_LOGIN_GETLIST:
		case QQ_CMD_LOGIN_ED:
		case QQ_CMD_LOGIN_EC:
		default:
			data_len = qq_decrypt(data, rcved, rcved_len, qd->session_key);
			break;
	}

	if (data_len < 0) {
		purple_debug_warning("QQ",
				"Can not decrypt login cmd, [%05d], 0x%04X %s, len %d\n",
				seq, cmd, qq_get_cmd_desc(cmd), rcved_len);
		qq_show_packet("Can not decrypted", rcved, rcved_len);
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
				_("Unable to decrypt login reply"));
		return QQ_LOGIN_REPLY_ERR;
	}

	switch (cmd) {
		case QQ_CMD_TOUCH_SERVER:
			ret_8 = qq_process_touch_server(gc, data, data_len);
			if ( ret_8 == QQ_LOGIN_REPLY_OK) {
				qq_request_captcha(gc);
			} else if ( ret_8 == QQ_TOUCH_REPLY_REDIRECT) {
				return QQ_TOUCH_REPLY_REDIRECT;
			}
			break;
		case QQ_CMD_CAPTCHA:
			ret_8 = qq_process_captcha(gc, data, data_len);
			if (ret_8 == QQ_LOGIN_REPLY_OK) {
				qq_request_auth(gc);
			} else if (ret_8 == QQ_LOGIN_REPLY_NEXT_CAPTCHA) {
				qq_request_captcha_next(gc);
			} else if (ret_8 == QQ_LOGIN_REPLY_CAPTCHA_DLG) {
				qq_captcha_input_dialog(gc, &(qd->captcha));
				g_free(qd->captcha.token);
				g_free(qd->captcha.data);
				memset(&qd->captcha, 0, sizeof(qd->captcha));
			}
			break;
		case QQ_CMD_AUTH:
			ret_8 = qq_process_auth(gc, data, data_len);
			if (ret_8 == QQ_LOGIN_REPLY_DE)
			{
				qq_request_verify_DE(gc);
			} else if (ret_8 == QQ_LOGIN_REPLY_OK) {
				qq_request_verify_E5(gc);
			} else	return ret_8;
			break;
		case QQ_CMD_VERIFY_DE:
			ret_8 = qq_process_verify_DE(gc, data, data_len);
			if (ret_8 != QQ_LOGIN_REPLY_OK) {
				return ret_8;
			}
			qq_request_verify_E5(gc);
			break;
		case QQ_CMD_VERIFY_E5:
			ret_8 = qq_process_verify_E5(gc, data, data_len);
			if (ret_8 != QQ_LOGIN_REPLY_OK) {
				return ret_8;
			}
			qq_request_verify_E3(gc);
			break;
		case QQ_CMD_VERIFY_E3:
			ret_8 = qq_process_verify_E3(gc, data, data_len);
			if (ret_8 != QQ_LOGIN_REPLY_OK) {
				return ret_8;
			}
			qq_request_login(gc);
			break;
		case QQ_CMD_LOGIN:
			ret_8 = qq_process_login(gc, data, data_len);
			if ( ret_8 == QQ_TOUCH_REPLY_REDIRECT) {
           		qq_request_touch_server(gc);
				return QQ_LOGIN_REPLY_OK;
           	}
			if (ret_8 == QQ_LOGIN_REPLY_OK) {
				qq_request_login_E9(gc);
			} else {
				return ret_8;
			}

			break;
		case QQ_CMD_LOGIN_E9:
			qq_request_login_EA(gc);
			break;
		case QQ_CMD_LOGIN_EA:
			qq_request_login_getlist(gc, 0x0001);
			break;
		case QQ_CMD_LOGIN_GETLIST:
			ret_8 = qq_process_login_getlist(gc, data, data_len);
			if (ret_8 == QQ_LOGIN_REPLY_OK)
			{
				qq_request_login_ED(gc);
			}
			break;
		case QQ_CMD_LOGIN_EC:
			break;
		case QQ_CMD_LOGIN_ED:
			qq_request_login_EC(gc);

			purple_connection_update_progress(gc, _("Logging in"), QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS);
			purple_debug_info("QQ", "Login replies OK; everything is fine\n");
			purple_connection_set_state(gc, PURPLE_CONNECTED);
			qd->is_login = TRUE;	/* must be defined after sev_finish_login */

			/* is_login, but we have packets before login */
			qq_trans_process_remained(gc);

			qq_update_all(gc, 0);
			break;
		default:
			process_unknown_cmd(gc, _("Unknown LOGIN CMD"), data, data_len, cmd, seq);
			return QQ_LOGIN_REPLY_ERR;
	}
	return QQ_LOGIN_REPLY_OK;
}
예제 #18
0
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);
	}
}
예제 #19
0
static void process_server_msg(PurpleConnection *gc, guint8 *data, gint data_len, guint16 seq)
{
	qq_data *qd;
	guint8 *data_str, i = 0;
	gchar **segments, **seg;
	gchar *funct_str, *from, *to;
	gint bytes, funct;

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

	qd = (qq_data *) gc->proto_data;

	data_str = g_newa(guint8, data_len + 1);
	g_memmove(data_str, data, data_len);
	data_str[data_len] = 0x00;

	segments = g_strsplit((gchar *) data_str, "\x1f", 0);
	g_return_if_fail(segments != NULL);
	for (seg = segments; *seg != NULL; seg++)
		i++;
	if (i < 3) {
		purple_debug_warning("QQ", "Server message segments is less than 3\n");
		g_strfreev(segments);
		return;
	}

	bytes = 0;
	funct_str = segments[0];
	bytes += strlen(funct_str) + 1;
	from = segments[1];
	bytes += strlen(from) + 1;
	to = segments[2];
	bytes += strlen(to) + 1;

	/* qq_show_packet("Server MSG", data, data_len); */
	if (strtoul(to, NULL, 10) != qd->uid) {	/* not to me */
		purple_debug_error("QQ", "Recv sys msg to [%s], not me!, discard\n", to);
		g_strfreev(segments);
		return;
	}

	funct = strtol(funct_str, NULL, 10);
	switch (funct) {
		case QQ_SERVER_BUDDY_ADDED_DEPRECATED:
		case QQ_SERVER_BUDDY_ADDED_ME:
		case QQ_SERVER_BUDDY_ADD_REQUEST_DEPRECATED:
		case QQ_SERVER_BUDDY_REJECTED_ME:
		case QQ_SERVER_BUDDY_ADD_REQUEST:
		case QQ_SERVER_BUDDY_ADDING_EX:
		case QQ_SERVER_BUDDY_ADDED_ANSWER:
		case QQ_SERVER_BUDDY_ADDED:
			qq_process_buddy_from_server(gc,  funct, from, to, data + bytes, data_len - bytes);
			break;
		case QQ_SERVER_NOTICE:
			do_server_notice(gc, from, to, data + bytes, data_len - bytes);
			break;
		case QQ_SERVER_NEW_CLIENT:
			purple_debug_warning("QQ", "QQ Server has newer client version\n");
			break;
		default:
			qq_show_packet("Unknown sys msg", data, data_len);
			purple_debug_warning("QQ", "Recv unknown sys msg code: %s\n", funct_str);
			break;
	}
	g_strfreev(segments);
}
예제 #20
0
/* I receive a message, mainly it is text msg,
 * but we need to process other types (group etc) */
static void process_private_msg(guint8 *data, gint data_len, guint16 cmd, guint16 seq, PurpleConnection *gc)
{
	qq_data *qd;
	gint bytes;
	guint16 len;
	guint8 tmp8;
	struct {
		guint32 uid_from;
		guint32 uid_to;
		guint32 seq;
		struct in_addr ip_from;
		guint16 port_from;
		guint16 msg_type;
	} header;

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

	qd = (qq_data *) gc->proto_data;

	if (data_len < 16) {	/* we need to ack with the first 16 bytes */
		purple_debug_error("QQ", "MSG is too short\n");
		return;
	} else {
		/* when we receive a message,
		 * we send an ACK which is the first 16 bytes of incoming packet */
		qq_send_server_reply(gc, cmd, seq, data, 16);
	}

	/* check len first */
	if (data_len < 20) {	/* length of im_header */
		purple_debug_error("QQ", "Invald MSG header, len %d < 20\n", data_len);
		return;
	}

	bytes = 0;
	bytes += qq_get32(&(header.uid_from), data + bytes);
	bytes += qq_get32(&(header.uid_to), data + bytes);
	bytes += qq_get32(&(header.seq), data + bytes);
	/* if the message is delivered via server, it is server IP/port */
	bytes += qq_getIP(&(header.ip_from), data + bytes);
	bytes += qq_get16(&(header.port_from), data + bytes);
	bytes += qq_get16(&(header.msg_type), data + bytes);
	/* im_header prepared */

	if (header.uid_to != qd->uid) {	/* should not happen */
		purple_debug_error("QQ", "MSG to %u, NOT me\n", header.uid_to);
		return;
	}

	/* check bytes */
	if (bytes >= data_len - 1) {
		purple_debug_warning("QQ", "Empty MSG\n");
		return;
	}

	switch (header.msg_type) {
	case QQ_MSG_BUDDY_84:
	case QQ_MSG_BUDDY_85:
		purple_debug_info("QQ", "MSG from buddy [%d]\n", header.uid_from);
		qq_process_im(gc, data + bytes, data_len - bytes, header.msg_type);
		break;
	case QQ_MSG_TO_UNKNOWN:
	case QQ_MSG_BUDDY_09:		
	case QQ_MSG_BUDDY_A6:
	case QQ_MSG_BUDDY_A7:
	case QQ_MSG_BUDDY_78:
		purple_debug_info("QQ	", "MSG from buddy [%d]\n", header.uid_from);
		bytes += 1;
		qq_get8(&tmp8, data+bytes);
		while (tmp8 == 0)
		{
			bytes += 1;
			bytes += qq_get16(&len, data+bytes);
			bytes += len;
			qq_get8(&tmp8, data+bytes);
		}
		qq_process_im(gc, data + bytes, data_len - bytes, header.msg_type);
		break;
	case QQ_MSG_TYPING:
		qq_process_typing(gc, data+bytes, data_len-bytes, header.uid_from);
		break;
	case QQ_MSG_NEWS:
		do_server_news(gc, data + bytes, data_len - bytes);
		break;
	case QQ_MSG_SMS:
		do_got_sms(gc, data + bytes, data_len - bytes);
		break;
	case QQ_MSG_ROOM_IM_UNKNOWN:
	case QQ_MSG_TEMP_ROOM_IM:
	case QQ_MSG_ROOM_IM:
	case QQ_MSG_ROOM_IM_52:
		purple_debug_info("QQ", "MSG from room [%d]\n", header.uid_from);
		qq_process_room_im(data + bytes, data_len - bytes, header.uid_from, gc, header.msg_type);
		break;
	case QQ_MSG_ADD_TO_ROOM:
		purple_debug_info("QQ", "Notice from [%d], Added\n", header.uid_from);
		/* uid_from is group id
		* we need this to create a dummy group and add to blist */
		qq_process_room_buddy_joined(data + bytes, data_len - bytes, header.uid_from, gc);
		break;
	case QQ_MSG_DEL_FROM_ROOM:
		purple_debug_info("QQ", "Notice from room [%d], Removed\n", header.uid_from);
		/* uid_from is group id */
		qq_process_room_buddy_removed(data + bytes, data_len - bytes, header.uid_from, gc);
		break;
	case QQ_MSG_APPLY_ADD_TO_ROOM:
		purple_debug_info("QQ", "Notice from room [%d], Joined\n", header.uid_from);
		/* uid_from is group id */
		qq_process_room_buddy_request_join(data + bytes, data_len - bytes, header.uid_from, gc);
		break;
	case QQ_MSG_APPROVE_APPLY_ADD_TO_ROOM:
		purple_debug_info("QQ", "Notice from room [%d], Confirm add in\n",
			header.uid_from);
		/* uid_from is group id */
		qq_process_room_buddy_approved(data + bytes, data_len - bytes, header.uid_from, gc);
		break;
	case QQ_MSG_REJCT_APPLY_ADD_TO_ROOM:
		purple_debug_info("QQ", "Notice from room [%d], Refuse add in\n",
			header.uid_from);
		/* uid_from is group id */
		qq_process_room_buddy_rejected(data + bytes, data_len - bytes, header.uid_from, gc);
		break;
	case QQ_MSG_SYS:
		do_msg_sys(gc, data + bytes, data_len - bytes);
		break;
	default:
		purple_debug_warning("QQ", "MSG from %u, unknown type %s [0x%04X]\n",
			header.uid_from, get_im_type_desc(header.msg_type), header.msg_type);
		qq_show_packet("MSG header", data, bytes);
		if (data_len - bytes > 0) {
			qq_show_packet("MSG data", data + bytes, data_len - bytes);
		}
		break;
	}
}
예제 #21
0
static void tcp_pending(gpointer data, gint source, PurpleInputCondition cond)
{
	PurpleConnection *gc = (PurpleConnection *) data;
	qq_data *qd;
	qq_connection *conn;
	guint8 buf[1024];		/* set to 16 when test  tcp_rxqueue */
	gint buf_len;
	gint bytes;

	guint8 *pkt;
	guint16 pkt_len;

	gchar *error_msg;
	guint8 *jump;
	gint jump_len;

	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
	qd = (qq_data *) gc->proto_data;

	if(cond != PURPLE_INPUT_READ) {
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Socket error"));
		return;
	}

	conn = connection_find(qd, source);
	g_return_if_fail(conn != NULL);

	/* test code, not using tcp_rxqueue
	memset(pkt,0, sizeof(pkt));
	buf_len = read(qd->fd, pkt, sizeof(pkt));
	if (buf_len > 2) {
		packet_process(gc, pkt + 2, buf_len - 2);
	}
	return;
	*/

	buf_len = read(source, buf, sizeof(buf));
	if (buf_len < 0) {
		if (errno == EAGAIN)
			/* No worries */
			return;

		error_msg = g_strdup_printf(_("Lost connection with server: %s"), g_strerror(errno));
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				error_msg);
		g_free(error_msg);
		return;
	} else if (buf_len == 0) {
		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Server closed the connection"));
		return;
	}

	/* keep alive will be sent in 30 seconds since last_receive
	 *  QQ need a keep alive packet in every 60 seconds
	 gc->last_received = time(NULL);
	*/
#if 1
	purple_debug_info("TCP_PENDING", "Read %d bytes, tcp_rxlen is %d\n", buf_len, conn->tcp_rxlen);
#endif
	conn->tcp_rxqueue = g_realloc(conn->tcp_rxqueue, buf_len + conn->tcp_rxlen);
	memcpy(conn->tcp_rxqueue + conn->tcp_rxlen, buf, buf_len);
	conn->tcp_rxlen += buf_len;

	pkt = g_newa(guint8, MAX_PACKET_SIZE);
	while (PURPLE_CONNECTION_IS_VALID(gc)) {
		if (qd->openconns == NULL) {
			break;
		}
		if (conn->tcp_rxqueue == NULL) {
			conn->tcp_rxlen = 0;
			break;
		}
		if (conn->tcp_rxlen < QQ_TCP_HEADER_LENGTH) {
			break;
		}

		bytes = 0;
		bytes += qq_get16(&pkt_len, conn->tcp_rxqueue + bytes);
		if (conn->tcp_rxlen < pkt_len) {
			break;
		}

#if 1
		qq_show_packet("tcp_pending", conn->tcp_rxqueue, pkt_len);
#endif
		/* purple_debug_info("TCP_PENDING", "Packet len=%d, rxlen=%d\n", pkt_len, conn->tcp_rxlen); */
		if ( pkt_len < QQ_TCP_HEADER_LENGTH
		    || *(conn->tcp_rxqueue + bytes) != QQ_PACKET_TAG
			|| *(conn->tcp_rxqueue + pkt_len - 1) != QQ_PACKET_TAIL) {
			/* HEY! This isn't even a QQ. What are you trying to pull? */
			purple_debug_warning("TCP_PENDING", "Packet error, no header or tail tag\n");

			jump = memchr(conn->tcp_rxqueue + 1, QQ_PACKET_TAIL, conn->tcp_rxlen - 1);
			if ( !jump ) {
				purple_debug_warning("TCP_PENDING", "Failed to find next tail, clear receive buffer\n");
				g_free(conn->tcp_rxqueue);
				conn->tcp_rxqueue = NULL;
				conn->tcp_rxlen = 0;
				return;
			}

			/* jump and over QQ_PACKET_TAIL */
			jump_len = (jump - conn->tcp_rxqueue) + 1;
			purple_debug_warning("TCP_PENDING", "Find next tail at %d, jump %d\n", jump_len, jump_len + 1);
			g_memmove(conn->tcp_rxqueue, jump, conn->tcp_rxlen - jump_len);
			conn->tcp_rxlen -= jump_len;
			continue;
		}

		/* get packet */
		memset(pkt, 0, MAX_PACKET_SIZE);
		g_memmove(pkt, conn->tcp_rxqueue + bytes, pkt_len - bytes);

		/* jump to next packet */
		conn->tcp_rxlen -= pkt_len;
		if (conn->tcp_rxlen) {
			/* purple_debug_info("TCP_PENDING", "shrink tcp_rxqueue to %d\n", conn->tcp_rxlen);	*/
			jump = g_memdup(conn->tcp_rxqueue + pkt_len, conn->tcp_rxlen);
			g_free(conn->tcp_rxqueue);
			conn->tcp_rxqueue = jump;
		} else {
			/* purple_debug_info("TCP_PENDING", "free tcp_rxqueue\n"); */
			g_free(conn->tcp_rxqueue);
			conn->tcp_rxqueue = NULL;
		}

		/* packet_process may call disconnect and destory data like conn
		 * do not call packet_process before jump,
		 * break if packet_process return FALSE */
		if (packet_process(gc, pkt, pkt_len - bytes) == FALSE) {
			purple_debug_info("TCP_PENDING", "Connection has been destory\n");
			break;
		}
	}
}
예제 #22
0
void qq_proc_client_cmds(PurpleConnection *gc, guint16 cmd, guint16 seq,
		guint8 *rcved, gint rcved_len, guint32 update_class, guintptr ship_value)
{
	qq_data *qd;

	guint8 *data;
	gint data_len;

	guint8 ret_8 = 0;
	guint16 ret_16 = 0;
	guint32 ret_32 = 0;
	gboolean not_to_update = FALSE;

	g_return_if_fail(rcved_len > 0);

	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",
			"Reply can not be decrypted by session key, [%05d], 0x%04X %s, len %d\n",
			seq, cmd, qq_get_cmd_desc(cmd), rcved_len);
		qq_show_packet("Can not decrypted", rcved, rcved_len);
		return;
	}

	if (data_len <= 0) {
		purple_debug_warning("QQ",
			"Reply decrypted is empty, [%05d], 0x%04X %s, len %d\n",
			seq, cmd, qq_get_cmd_desc(cmd), rcved_len);
		return;
	}

	switch (cmd) {
		case QQ_CMD_UPDATE_INFO:
			qq_process_change_info(gc, data, data_len);
			break;
		case QQ_CMD_REMOVE_BUDDY:
			qq_process_remove_buddy(gc, data, data_len, ship_value);
			break;
		case QQ_CMD_REMOVE_ME:
			qq_process_buddy_remove_me(gc, data, data_len, ship_value);
			break;
		case QQ_CMD_GET_BUDDY_INFO:
			qq_process_get_buddy_info(data, data_len, ship_value, gc);
			break;
		case QQ_CMD_CHANGE_STATUS:
			qq_process_change_status(data, data_len, gc);
			break;
		case QQ_CMD_SEND_IM:
			do_im_ack(data, data_len, gc);
			break;
		case QQ_CMD_KEEP_ALIVE:
			if (qd->client_version >= 2010) {
				qq_process_keep_alive(data, data_len, gc);
			}
			break;
		case QQ_CMD_GET_BUDDIES_ONLINE:
			ret_8 = qq_process_get_buddies_online(data, data_len, gc);
			if (ret_8  > 0 && ret_8 < 0xff) {
				purple_debug_info("QQ", "Requesting for more online buddies\n");
				qq_request_get_buddies_online(gc, ret_8, update_class);
				return;
			}
			purple_debug_info("QQ", "All online buddies received\n");
			qq_update_buddies_status(gc);
			break;
		case QQ_CMD_GET_LEVEL:
			qq_process_get_level_reply(data, data_len, gc);
			if (ship_value)
			{
				purple_debug_info("QQ", "Requesting Buddy Level pos: %d\n", ship_value);
				qq_request_get_buddies_level(gc, 0, ship_value);
			}
			break;
		case QQ_CMD_GET_BUDDIES_SIGN:
			qq_process_get_buddies_sign(data, data_len, gc);
			if (ship_value)
			{
				purple_debug_info("QQ", "Requesting Buddy Signature pos: %d\n", ship_value);
				qq_request_get_buddies_sign(gc, 0, ship_value);
			}
			break;
		case QQ_CMD_GET_GROUP_LIST:
			ret_32 = qq_process_get_group_list(data, data_len, gc);
			/* if still have remained group name */
			if (ret_32)
			{
				purple_debug_info("QQ", "Requesting for Group pos: %d\n", ret_32);
				qq_request_get_group_list(gc, ret_32, 0);
				not_to_update = TRUE;		//not to update else when get_group not finished
			}
			break;
		case QQ_CMD_GET_BUDDIES_LIST:
			ret_16 = qq_process_get_buddies_list(data, data_len, gc);
			if (ret_16 > 0	&& ret_16 < 0xffff) {
				purple_debug_info("QQ", "Requesting for more buddies\n");
				qq_request_get_buddies_list(gc, ret_16, update_class);
				return;
			}
			purple_debug_info("QQ", "All buddies received. Requesting buddies' levels\n");
			break;
		case QQ_CMD_SEARCH_UID:
			qq_process_search_uid(gc, data, data_len, ship_value);
			break;
		case QQ_CMD_AUTH_TOKEN:
			qq_process_auth_token(gc, data, data_len, update_class, ship_value);
			break;
		case QQ_CMD_BUDDY_QUESTION:
			qq_process_question(gc, data, data_len, ship_value);
			break;
		case QQ_CMD_ADD_BUDDY_TOUCH:
			qq_process_add_buddy_touch(gc, data, data_len, ship_value);
			break;
		case QQ_CMD_ADD_BUDDY_POST:
			qq_process_add_buddy_post(gc, data, data_len, ship_value);
			break;
		/*case QQ_CMD_BUDDY_CHECK_CODE:
			qq_process_buddy_check_code(gc, data, data_len);
			break;*/
		case QQ_CMD_BUDDY_MEMO:
			purple_debug_info("QQ", "Receive memo from server!\n");
			qq_process_get_buddy_memo(gc, data, data_len, update_class, ship_value);
			break;
		default:
			process_unknown_cmd(gc, _("Unknown CLIENT CMD"), data, data_len, cmd, seq);
			not_to_update = TRUE;
			break;
	}
	if (not_to_update)
		return;

	if (update_class == QQ_CMD_CLASS_NONE)
		return;

	purple_debug_info("QQ", "Update class %d\n", update_class);
	if (update_class == QQ_CMD_CLASS_UPDATE_ALL) {
		qq_update_all(gc, cmd);
		return;
	}
	if (update_class == QQ_CMD_CLASS_UPDATE_ONLINE) {
		qq_update_online(gc, cmd);
		return;
	}
}
예제 #23
0
void qq_process_add_buddy_auth_ex(PurpleConnection *gc, guint8 *data, gint data_len, guint32 ship32)
{
	g_return_if_fail(data != NULL && data_len != 0);

	qq_show_packet("qq_process_question", data, data_len);
}
예제 #24
0
void qq_process_question(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid)
{
	qq_data *qd;
	gint bytes;
	guint8 cmd, reply;
	gchar *question, *answer;
	guint16 code_len;
	guint8 *code;

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

	qd = (qq_data *) gc->proto_data;

	qq_show_packet("qq_process_question", data, data_len);
	bytes = 0;
	bytes += qq_get8(&cmd, data + bytes);
	if (cmd == QQ_QUESTION_GET) {
		bytes += qq_get_vstr(&question, QQ_CHARSET_DEFAULT, data + bytes);
		bytes += qq_get_vstr(&answer, QQ_CHARSET_DEFAULT, data + bytes);
		purple_debug_info("QQ", "Get buddy adding Q&A:\n%s\n%s\n", question, answer);
		g_free(question);
		g_free(answer);
		return;
	}
	if (cmd == QQ_QUESTION_SET) {
		bytes += qq_get8(&reply, data + bytes);
		if (reply == 0) {
			purple_debug_info("QQ", "Successed setting Q&A\n");
		} else {
			purple_debug_warning("QQ", "Failed setting Q&A, reply %d\n", reply);
		}
		return;
	}

	g_return_if_fail(uid != 0);
	bytes += 2; /* skip 2 bytes, 0x(00 01)*/
	if (cmd == QQ_QUESTION_REQUEST) {
		bytes += qq_get8(&reply, data + bytes);
		if (reply == 0x01) {
			purple_debug_warning("QQ", "Failed getting question, reply %d\n", reply);
			return;
		}
		bytes += qq_get_vstr(&question, QQ_CHARSET_DEFAULT, data + bytes);
		purple_debug_info("QQ", "Get buddy question:\n%s\n", question);
		add_buddy_question_input(gc, uid, question);
		g_free(question);
		return;
	}

	if (cmd == QQ_QUESTION_ANSWER) {
		bytes += qq_get8(&reply, data + bytes);
		if (reply == 0x01) {
			purple_notify_error(gc, _("Add Buddy"), _("Invalid answer."), NULL);
			return;
		}
		bytes += qq_get16(&code_len, data + bytes);
		g_return_if_fail(code_len > 0);
		g_return_if_fail(bytes + code_len <= data_len);

		code = g_newa(guint8, code_len);
		bytes += qq_getdata(code, code_len, data + bytes);
		request_add_buddy_by_question(gc, uid, code, code_len);
		return;
	}

	g_return_if_reached();
}
예제 #25
0
파일: buddy_opt.c 프로젝트: bf4/pidgin-mac
void qq_process_add_buddy_no_auth_ex(PurpleConnection *gc,
		guint8 *data, gint data_len, guint32 uid)
{
	qq_data *qd;
	gint bytes;
	guint32 dest_uid;
	guint8 reply;
	guint8 auth_type;

	g_return_if_fail(data != NULL && data_len >= 5);
	g_return_if_fail(uid != 0);

	qd = (qq_data *) gc->proto_data;

	purple_debug_info("QQ", "Process buddy add no auth for id [%u]\n", uid);
	qq_show_packet("buddy_add_no_auth_ex", data, data_len);

	bytes = 0;
	bytes += qq_get32(&dest_uid, data + bytes);
	bytes += qq_get8(&reply, data + bytes);

	g_return_if_fail(dest_uid == uid);

	if (reply == 0x99) {
		purple_debug_info("QQ", "Successed adding buddy %u\n", uid);
		qq_buddy_find_or_new(gc, uid);

		qq_request_buddy_info(gc, uid, 0, 0);
		if (qd->client_version >= 2007) {
			qq_request_get_level_2007(gc, uid);
		} else {
			qq_request_get_level(gc, uid);
		}
		qq_request_get_buddies_online(gc, 0, 0);
		return;
	}

	if (reply != 0) {
		purple_debug_info("QQ", "Failed adding buddy %u, Unknow reply 0x%02X\n",
			uid, reply);
	}

	/* need auth */
	g_return_if_fail(data_len > bytes);
	bytes += qq_get8(&auth_type, data + bytes);
	purple_debug_warning("QQ", "Adding buddy needs authorize 0x%02X\n", auth_type);

	switch (auth_type) {
		case 0x00:	/* no authorize */
			break;
		case 0x01:	/* authorize */
			qq_request_auth_code(gc, QQ_AUTH_INFO_BUDDY, QQ_AUTH_INFO_ADD_BUDDY, uid);
			break;
		case 0x02:	/* disable */
			break;
		case 0x03:	/* answer question */
			qq_request_question(gc, QQ_QUESTION_REQUEST, uid, NULL, NULL);
			break;
		default:
			g_return_if_reached();
			break;
	}
	return;
}