コード例 #1
0
ファイル: keep_alive.c プロジェクト: VoxOx/VoxOx
/* parse the return of keep-alive packet, it includes some system information */
void qq_process_keep_alive_reply(guint8 *buf, gint buf_len, GaimConnection *gc) 
{
	qq_data *qd;
	gint len;
	gchar **segments;
	guint8 *data;

	g_return_if_fail(buf != NULL && buf_len != 0);

	qd = (qq_data *) gc->proto_data;
	len = buf_len;
	data = g_newa(guint8, len);

	if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
		/* the last one is 60, don't know what it is */
		if (NULL == (segments = split_data(data, len, "\x1f", 6)))
			return;
		/* segments[0] and segment[1] are all 0x30 ("0") */
		qd->all_online = strtol(segments[2], NULL, 10);
		if(0 == qd->all_online)
			gaim_connection_error(gc, _("Keep alive error, seems connection lost!"));
		g_free(qd->my_ip);
		qd->my_ip = g_strdup(segments[3]);
		qd->my_port = strtol(segments[4], NULL, 10);
		g_strfreev(segments);
	} else
		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt keep alive reply\n");

	/* we refresh buddies's online status periodically */
	/* qd->last_get_online is updated when setting get_buddies_online packet */
	if ((time(NULL) - qd->last_get_online) >= QQ_UPDATE_ONLINE_INTERVAL)
		qq_send_packet_get_buddies_online(gc, QQ_FRIENDS_ONLINE_POSITION_START);
}
コード例 #2
0
ファイル: file_trans.c プロジェクト: 1dot75cm/pidgin-libqq
/* send a file to udp channel with QQ_FILE_CONTROL_PACKET_TAG */
void qq_send_file_ctl_packet(PurpleConnection *gc, guint16 packet_type, guint32 to_uid, guint8 hellobyte)
{
	qq_data *qd;
	gint bytes, bytes_expected, encrypted_len;
	guint8 *raw_data, *encrypted;
	time_t now;
	ft_info *info;

	qd = (qq_data *) gc->proto_data;
	info = (ft_info *) qd->xfer->data;

	raw_data = g_newa (guint8, 61);
	bytes = 0;

	now = time(NULL);

	bytes += qq_putdata(raw_data + bytes, qd->session_md5, 16);
	bytes += qq_put16(raw_data + bytes, packet_type);
	switch (packet_type) {
		case QQ_FILE_CMD_SENDER_SAY_HELLO:
		case QQ_FILE_CMD_SENDER_SAY_HELLO_ACK:
		case QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK:
		case QQ_FILE_CMD_NOTIFY_IP_ACK:
		case QQ_FILE_CMD_RECEIVER_SAY_HELLO:
			bytes += qq_put16(raw_data + bytes, info->send_seq);
			break;
		default:
			bytes += qq_put16(raw_data + bytes, ++qd->send_seq);
	}
	bytes += qq_put32(raw_data + bytes, (guint32) now);
	bytes += qq_put8(raw_data + bytes, 0x00);
	bytes += qq_put8(raw_data + bytes, qd->my_icon);
	bytes += qq_put32(raw_data + bytes, 0x00000000);
	bytes += qq_put32(raw_data + bytes, 0x00000000);
	bytes += qq_put32(raw_data + bytes, 0x00000000);
	bytes += qq_put32(raw_data + bytes, 0x00000000);
	bytes += qq_put16(raw_data + bytes, 0x0000);
	bytes += qq_put8(raw_data + bytes, 0x00);
	/* 0x65: send a file, 0x6b: send a custom face */
	bytes += qq_put8(raw_data + bytes, QQ_FILE_TRANSFER_FILE); /* FIXME temp by gfhuang */
	switch (packet_type)
	{
		case QQ_FILE_CMD_SENDER_SAY_HELLO:
		case QQ_FILE_CMD_RECEIVER_SAY_HELLO:
		case QQ_FILE_CMD_SENDER_SAY_HELLO_ACK:
		case QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK:
			bytes += qq_put8(raw_data + bytes, 0x00);
			bytes += qq_put8(raw_data + bytes, hellobyte);
			bytes_expected = 48;
			break;
		case QQ_FILE_CMD_PING:
		case QQ_FILE_CMD_PONG:
		case QQ_FILE_CMD_NOTIFY_IP_ACK:
			bytes += qq_fill_conn_info(raw_data, info);
			bytes_expected = 61;
			break;
		default:
			purple_debug_info("QQ", "qq_send_file_ctl_packet: Unknown packet type[%d]\n",
					packet_type);
			bytes_expected = 0;
	}

	if (bytes != bytes_expected) {
		purple_debug_error("QQ", "qq_send_file_ctl_packet: Expected to get %d bytes, but get %d\n",
				bytes_expected, bytes);
		return;
	}

	qq_hex_dump(PURPLE_DEBUG_INFO, "QQ",
		raw_data, bytes,
		"sending packet[%s]:", qq_get_file_cmd_desc(packet_type));

	encrypted = g_newa(guint8, bytes + 17);
	encrypted_len = qq_encrypt(encrypted, raw_data, bytes, info->file_session_key);
	/*debug: try to decrypt it */

#if 0
	guint8 *buf;
	int buflen;
	hex_dump = hex_dump_to_str(encrypted, encrypted_len);
	purple_debug_info("QQ", "encrypted packet: \n%s\n", hex_dump);
	g_free(hex_dump);
	buf = g_newa(guint8, MAX_PACKET_SIZE);
	buflen = encrypted_len;
	if (qq_crypt(DECRYPT, encrypted, encrypted_len, info->file_session_key, buf, &buflen)) {
		purple_debug_info("QQ", "decrypt success\n");
	   if (buflen == bytes && memcmp(raw_data, buf, buflen) == 0)
			purple_debug_info("QQ", "checksum ok\n");

		hex_dump = hex_dump_to_str(buf, buflen);
		purple_debug_info("QQ", "decrypted packet: \n%s\n", hex_dump);
		g_free(hex_dump);
	 } else {
		purple_debug_info("QQ", "decrypt fail\n");
	}
#endif

	purple_debug_info("QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type));
	_qq_send_file(gc, encrypted, encrypted_len, QQ_FILE_CONTROL_PACKET_TAG, info->to_uid);
}
コード例 #3
0
ファイル: buddy_list.c プロジェクト: VoxOx/VoxOx
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");
	}
}
コード例 #4
0
ファイル: buddy_list.c プロジェクト: VoxOx/VoxOx
/* 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");
	}
}
コード例 #5
0
ファイル: buddy_list.c プロジェクト: VoxOx/VoxOx
/* 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");
	}
}
コード例 #6
0
ファイル: login_logout.c プロジェクト: arminius2/apolloim
/* process the login reply packet */
void qq_process_login_reply(guint8 *buf, gint buf_len, PurpleConnection *gc)
{
	gint len, ret, bytes;
	guint8 *data;
	qq_data *qd;
	gchar *hex_dump;

	g_return_if_fail(buf != NULL && buf_len != 0);

	qd = (qq_data *) gc->proto_data;
	len = buf_len;
	data = g_newa(guint8, len);

	if (qq_crypt(DECRYPT, buf, buf_len, qd->pwkey, data, &len)) {
		/* should be able to decrypt with pwkey */
		purple_debug(PURPLE_DEBUG_INFO, "QQ", "Decrypt login reply packet with pwkey, %d bytes\n", len);
		if (data[0] == QQ_LOGIN_REPLY_OK) {
			ret = _qq_process_login_ok(gc, data, len);
		} else {
			purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Unknown login reply code : %d\n", data[0]);
			ret = QQ_LOGIN_REPLY_MISC_ERROR;
		}
	} else {		/* decrypt with pwkey error */
		len = buf_len;	/* reset len, decrypt will fail if len is too short */
		if (qq_crypt(DECRYPT, buf, buf_len, qd->inikey, data, &len)) {
			/* decrypt ok with inipwd, it might be password error */
			purple_debug(PURPLE_DEBUG_WARNING, "QQ", 
					"Decrypt login reply packet with inikey, %d bytes\n", len);
			bytes = 0;
			switch (data[0]) {
			case QQ_LOGIN_REPLY_REDIRECT:
				ret = _qq_process_login_redirect(gc, data, len);
				break;
			case QQ_LOGIN_REPLY_PWD_ERROR:
				ret = _qq_process_login_wrong_pwd(gc, data, len);
				break;
			default:
				purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Unknown reply code: %d\n", data[0]);
				hex_dump = hex_dump_to_str(data, len);
		                purple_debug(PURPLE_DEBUG_WARNING, "QQ",
                		           ">>> %d bytes -> [default] decrypt and dump\n%s",
		                           buf_len, hex_dump);
				g_free(hex_dump);
                		try_dump_as_gbk(data, len);

				ret = QQ_LOGIN_REPLY_MISC_ERROR;
			}
		} else {	/* no idea how to decrypt */
			purple_debug(PURPLE_DEBUG_ERROR, "QQ", "No idea how to decrypt login reply\n");
			ret = QQ_LOGIN_REPLY_MISC_ERROR;
		}
	}

	switch (ret) {
	case QQ_LOGIN_REPLY_PWD_ERROR:
		gc->wants_to_die = TRUE;
		purple_connection_error(gc, _("Incorrect password."));
		break;
	case QQ_LOGIN_REPLY_MISC_ERROR:
		purple_connection_error(gc, _("Unable to login, check debug log"));
		break;
	case QQ_LOGIN_REPLY_OK:
		purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login replys OK, everything is fine\n");
		break;
	case QQ_LOGIN_REPLY_REDIRECT:
		/* the redirect has been done in _qq_process_login_reply */
		break;
	default:{;
		}
	}
}