/* send IM to a group */ void qq_send_packet_group_im(GaimConnection *gc, qq_group *group, const gchar *msg) { gint data_len, bytes; guint8 *raw_data, *cursor, *send_im_tail; guint16 msg_len; gchar *msg_filtered; g_return_if_fail(group != NULL && msg != NULL); msg_filtered = gaim_markup_strip_html(msg); msg_len = strlen(msg_filtered); data_len = 7 + msg_len + QQ_SEND_IM_AFTER_MSG_LEN; raw_data = g_newa(guint8, data_len); cursor = raw_data; bytes = 0; bytes += create_packet_b(raw_data, &cursor, QQ_GROUP_CMD_SEND_MSG); bytes += create_packet_dw(raw_data, &cursor, group->internal_group_id); bytes += create_packet_w(raw_data, &cursor, msg_len + QQ_SEND_IM_AFTER_MSG_LEN); bytes += create_packet_data(raw_data, &cursor, (guint8 *) msg_filtered, msg_len); send_im_tail = qq_get_send_im_tail(NULL, NULL, NULL, FALSE, FALSE, FALSE, QQ_SEND_IM_AFTER_MSG_LEN); bytes += create_packet_data(raw_data, &cursor, send_im_tail, QQ_SEND_IM_AFTER_MSG_LEN); g_free(send_im_tail); g_free(msg_filtered); if (bytes == data_len) /* create OK */ qq_send_group_cmd(gc, group, raw_data, data_len); else gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Fail creating group_im packet, expect %d bytes, build %d bytes\n", data_len, bytes); }
/* get all list, buddies & Quns with groupsid support */ void qq_send_packet_get_all_list_with_group(GaimConnection *gc, guint32 position) { guint8 *raw_data, *cursor; gint data_len; data_len = 10; raw_data = g_newa(guint8, data_len); cursor = raw_data; /* 0x01 download, 0x02, upload */ create_packet_b(raw_data, &cursor, 0x01); /* unknown 0x02 */ create_packet_b(raw_data, &cursor, 0x02); /* unknown 00 00 00 00 */ create_packet_dw(raw_data, &cursor, 0x00000000); create_packet_dw(raw_data, &cursor, position); qq_send_cmd(gc, QQ_CMD_GET_ALL_LIST_WITH_GROUP, TRUE, 0, TRUE, raw_data, data_len); }
/* send login packet to QQ server */ static void qq_send_packet_login(PurpleConnection *gc, guint8 token_length, guint8 *token) { qq_data *qd; guint8 *buf, *cursor, *raw_data, *encrypted_data; guint16 seq_ret; gint encrypted_len, bytes; gint pos; qd = (qq_data *) gc->proto_data; buf = g_newa(guint8, MAX_PACKET_SIZE); raw_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH); encrypted_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */ qd->inikey = _gen_login_key(); /* now generate the encrypted data * 000-015 use pwkey as key to encrypt empty string */ qq_crypt(ENCRYPT, (guint8 *) "", 0, qd->pwkey, raw_data, &encrypted_len); /* 016-016 */ raw_data[16] = 0x00; /* 017-020, used to be IP, now zero */ *((guint32 *) (raw_data + 17)) = 0x00000000; /* 021-022, used to be port, now zero */ *((guint16 *) (raw_data + 21)) = 0x0000; /* 023-051, fixed value, unknown */ g_memmove(raw_data + 23, login_23_51, 29); /* 052-052, login mode */ raw_data[52] = qd->login_mode; /* 053-068, fixed value, maybe related to per machine */ g_memmove(raw_data + 53, login_53_68, 16); /* 069, login token length */ raw_data[69] = token_length; pos = 70; /* 070-093, login token, normally 24 bytes */ g_memmove(raw_data + pos, token, token_length); pos += token_length; /* 100 bytes unknown */ g_memmove(raw_data + pos, login_100_bytes, 100); pos += 100; /* all zero left */ memset(raw_data+pos, 0, QQ_LOGIN_DATA_LENGTH - pos); qq_crypt(ENCRYPT, raw_data, QQ_LOGIN_DATA_LENGTH, qd->inikey, encrypted_data, &encrypted_len); cursor = buf; bytes = 0; bytes += _create_packet_head_seq(buf, &cursor, gc, QQ_CMD_LOGIN, TRUE, &seq_ret); bytes += create_packet_dw(buf, &cursor, qd->uid); bytes += create_packet_data(buf, &cursor, qd->inikey, QQ_KEY_LENGTH); bytes += create_packet_data(buf, &cursor, encrypted_data, encrypted_len); bytes += create_packet_b(buf, &cursor, QQ_PACKET_TAIL); if (bytes == (cursor - buf)) /* packet creation OK */ _qq_send_packet(gc, buf, bytes, QQ_CMD_LOGIN); else purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail create login packet\n"); }
/* send keep-alive packet to QQ server (it is a heart-beat) */ void qq_send_packet_keep_alive(GaimConnection *gc) { qq_data *qd; guint8 *raw_data, *cursor; qd = (qq_data *) gc->proto_data; raw_data = g_newa(guint8, 4); cursor = raw_data; /* In fact, we can send whatever we like to server * with this command, server return the same result including * the amount of online QQ users, my ip and port */ create_packet_dw(raw_data, &cursor, qd->uid); qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, TRUE, 0, TRUE, raw_data, 4); }
/* request before login */ void qq_send_packet_request_login_token(PurpleConnection *gc) { qq_data *qd; guint8 *buf, *cursor; guint16 seq_ret; gint bytes; qd = (qq_data *) gc->proto_data; buf = g_newa(guint8, MAX_PACKET_SIZE); cursor = buf; bytes = 0; bytes += _create_packet_head_seq(buf, &cursor, gc, QQ_CMD_REQUEST_LOGIN_TOKEN, TRUE, &seq_ret); bytes += create_packet_dw(buf, &cursor, qd->uid); bytes += create_packet_b(buf, &cursor, 0); bytes += create_packet_b(buf, &cursor, QQ_PACKET_TAIL); if (bytes == (cursor - buf)) /* packet creation OK */ _qq_send_packet(gc, buf, bytes, QQ_CMD_REQUEST_LOGIN_TOKEN); else purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail create request login token packet\n"); }