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; }
/* this buddy needs authentication, text conversion is done at lowest level */ static void request_add_buddy_auth(PurpleConnection *gc, guint32 uid, const gchar response, const gchar *text) { guint8 raw_data[MAX_PACKET_SIZE - 16]; gint bytes; gchar *msg, uid_str[11]; guint8 bar; g_return_if_fail(uid != 0); g_snprintf(uid_str, sizeof(uid_str), "%u", uid); bar = 0x1f; bytes = 0; bytes += qq_putdata(raw_data + bytes, (guint8 *) uid_str, strlen(uid_str)); bytes += qq_put8(raw_data + bytes, bar); bytes += qq_put8(raw_data + bytes, response); if (text != NULL) { msg = utf8_to_qq(text, QQ_CHARSET_DEFAULT); bytes += qq_put8(raw_data + bytes, bar); bytes += qq_putdata(raw_data + bytes, (guint8 *) msg, strlen(msg)); g_free(msg); } qq_send_cmd(gc, QQ_CMD_ADD_BUDDY_AUTH, raw_data, bytes); }
static void request_room_send_im_ex(PurpleConnection *gc, guint32 room_id, qq_im_format *fmt, gchar *msg, guint16 msg_id, guint8 frag_count, guint8 frag_index) { guint8 raw_data[MAX_PACKET_SIZE - 16]; gint bytes; g_return_if_fail(room_id != 0 && msg != NULL); bytes = 0; bytes += qq_put16(raw_data + bytes, 0); /* packet len */ /* type 0x0001, text only; 0x0002, with custom emoticon */ bytes += qq_put16(raw_data + bytes, 0x0001); bytes += qq_put8(raw_data + bytes, frag_count); bytes += qq_put8(raw_data + bytes, frag_index); bytes += qq_put16(raw_data + bytes, msg_id); bytes += qq_put32(raw_data + bytes, 0); /* unknow 4 bytes */ bytes += qq_putdata(raw_data + bytes, (guint8 *)msg, strlen(msg)); if (frag_count == frag_index + 1) { bytes += qq_put8(raw_data + bytes, 0x20); /* add extra SPACE */ bytes += qq_put_im_tail(raw_data + bytes, fmt); } /* reset first two bytes as length */ qq_put16(raw_data, bytes - 2); /*qq_show_packet("QQ_ROOM_CMD_SEND_IM_EX", raw_data, bytes); */ qq_send_room_cmd(gc, QQ_ROOM_CMD_SEND_IM_EX, room_id, raw_data, bytes); }
static void request_change_memo(PurpleConnection *gc, guint32 bd_uid, gchar **segments) { gint bytes; /* Attention, length of each segment must be guint8(0~255), * so length of memo string is limited. * convert it to guint8 first before putting data */ guint seg_len; gint index; guint8 raw_data[MAX_PACKET_SIZE - 16] = {0}; purple_debug_info( "QQ", "request_change_memo\n" ); g_return_if_fail(NULL != gc && NULL != segments); bytes = 0; bytes += qq_put8(raw_data+bytes, QQ_BUDDY_MEMO_MODIFY); bytes += qq_put8(raw_data+bytes, 0x00); bytes += qq_put32(raw_data+bytes, (guint32)bd_uid); bytes += qq_put8(raw_data+bytes, 0x00); for (index = 0; index < QQ_MEMO_SIZE; index++) { seg_len = strlen(segments[index]); seg_len = seg_len & 0xff; bytes += qq_put8(raw_data+bytes, (guint8)seg_len); bytes += qq_putdata(raw_data+bytes, (const guint8 *)segments[index], (guint8)seg_len); } /* debug */ /* qq_show_packet("MEMO MODIFY", raw_data, bytes); */ qq_send_cmd(gc, QQ_CMD_BUDDY_MEMO, raw_data, bytes); }
static gint _qq_send_file(PurpleConnection *gc, guint8 *data, gint len, guint16 packet_type, guint32 to_uid) { guint8 *raw_data; gint bytes = 0; guint32 file_key; qq_data *qd; qd = (qq_data *) gc->proto_data; raw_data = g_newa(guint8, MAX_PACKET_SIZE); file_key = _gen_file_key(); bytes += qq_put8(raw_data + bytes, packet_type); bytes += qq_put16(raw_data + bytes, qd->client_tag); bytes += qq_put8(raw_data + bytes, file_key & 0xff); bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(qd->uid, file_key)); bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(to_uid, file_key)); bytes += qq_putdata(raw_data + bytes, data, len); if (bytes == len + 12) { _qq_xfer_write(raw_data, bytes, qd->xfer); } else purple_debug_info("QQ", "send_file: want %d but got %d\n", len + 12, bytes); return bytes; }
void qq_request_get_level_2007(PurpleConnection *gc, guint32 uid) { guint8 buf[16] = {0}; gint bytes = 0; bytes += qq_put8(buf + bytes, 0x08); bytes += qq_put32(buf + bytes, uid); bytes += qq_put8(buf + bytes, 0x00); qq_send_cmd(gc, QQ_CMD_GET_LEVEL, buf, bytes); }
void qq_request_get_level(PurpleConnection *gc, guint32 uid) { qq_data *qd = (qq_data *) gc->proto_data; guint8 buf[16] = {0}; gint bytes = 0; if (qd->client_version >= 2007) { bytes += qq_put8(buf + bytes, 0x02); } else { bytes += qq_put8(buf + bytes, 0x00); } bytes += qq_put32(buf + bytes, uid); qq_send_cmd(gc, QQ_CMD_GET_LEVEL, buf, bytes); }
/* send an IM to uid_to */ static void request_send_im(PurpleConnection *gc, guint32 uid_to, gint type, qq_im_format *fmt, gchar *msg, guint8 id, guint8 frag_count, guint8 frag_index) { qq_data *qd; guint8 raw_data[MAX_PACKET_SIZE - 16]; guint16 im_type; gint bytes; time_t now; qd = (qq_data *) gc->proto_data; im_type = QQ_NORMAL_IM_TEXT; /* purple_debug_info("QQ", "Send IM %d-%d\n", frag_count, frag_index); */ bytes = 0; /* 000-003: receiver uid */ bytes += qq_put32(raw_data + bytes, qd->uid); /* 004-007: sender uid */ bytes += qq_put32(raw_data + bytes, uid_to); /* 008-009: sender client version */ bytes += qq_put16(raw_data + bytes, qd->client_tag); /* 010-013: receiver uid */ bytes += qq_put32(raw_data + bytes, qd->uid); /* 014-017: sender uid */ bytes += qq_put32(raw_data + bytes, uid_to); /* 018-033: md5 of (uid+session_key) */ bytes += qq_putdata(raw_data + bytes, qd->session_md5, 16); /* 034-035: message type */ bytes += qq_put16(raw_data + bytes, QQ_NORMAL_IM_TEXT); /* 036-037: sequence number */ bytes += qq_put16(raw_data + bytes, qd->send_seq); /* 038-041: send time */ now = time(NULL); bytes += qq_put32(raw_data + bytes, (guint32) now); /* 042-043: sender icon */ bytes += qq_put16(raw_data + bytes, qd->my_icon); /* 044-046: always 0x00 */ bytes += qq_put16(raw_data + bytes, 0x0000); bytes += qq_put8(raw_data + bytes, 0x00); /* 047-047: always use font attr */ bytes += qq_put8(raw_data + bytes, 0x01); /* 048-051: always 0x00 */ /* Fixme: frag_count, frag_index not working now */ bytes += qq_put8(raw_data + bytes, frag_count); bytes += qq_put8(raw_data + bytes, frag_index); bytes += qq_put8(raw_data + bytes, id); bytes += qq_put8(raw_data + bytes, 0); /* 052-052: text message type (normal/auto-reply) */ bytes += qq_put8(raw_data + bytes, type); /* 053- : msg ends with 0x00 */ bytes += qq_putdata(raw_data + bytes, (guint8 *)msg, strlen(msg)); if (frag_count == frag_index + 1) { bytes += qq_put8(raw_data + bytes, 0x20); /* add extra SPACE */ } bytes += qq_put_im_tail(raw_data + bytes, fmt); /* qq_show_packet("QQ_CMD_SEND_IM", raw_data, bytes); */ qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); }
void qq_request_get_buddies_level(PurpleConnection *gc, guint32 update_class) { qq_data *qd = (qq_data *) gc->proto_data; PurpleBuddy *buddy; qq_buddy_data *bd; guint8 *buf; GSList *buddies, *it; gint bytes; /* server only reply levels for online buddies */ buf = g_newa(guint8, MAX_PACKET_SIZE); bytes = 0; bytes += qq_put8(buf + bytes, 0x00); buddies = purple_find_buddies(purple_connection_get_account(gc), NULL); for (it = buddies; it; it = it->next) { buddy = it->data; if (buddy == NULL) continue; if (buddy->proto_data == NULL) continue; bd = (qq_buddy_data *)buddy->proto_data; if (bd->uid == 0) continue; /* keep me as end of packet*/ if (bd->uid == qd->uid) continue; bytes += qq_put32(buf + bytes, bd->uid); } bytes += qq_put32(buf + bytes, qd->uid); qq_send_cmd_mess(gc, QQ_CMD_GET_LEVEL, buf, bytes, update_class, 0); }
static void request_buddy_check_code(PurpleConnection *gc, gchar *from, guint8 *code, gint code_len) { guint8 *raw_data; gint bytes; guint32 uid; g_return_if_fail(code != NULL && code_len > 0 && from != NULL); uid = strtoul(from, NULL, 10); raw_data = g_newa(guint8, code_len + 16); bytes = 0; bytes += qq_put8(raw_data + bytes, 0x03); bytes += qq_put8(raw_data + bytes, 0x01); bytes += qq_put32(raw_data + bytes, uid); bytes += qq_put16(raw_data + bytes, code_len); bytes += qq_putdata(raw_data + bytes, code, code_len); qq_send_cmd(gc, QQ_CMD_BUDDY_CHECK_CODE, raw_data, bytes); }
gint qq_put_im_tail(guint8 *buf, qq_im_format *fmt) { gint bytes; g_return_val_if_fail(buf != NULL && fmt != NULL, 0); bytes = 0; bytes += qq_put8(buf + bytes, 0); bytes += qq_put8(buf + bytes, fmt->attr); bytes += qq_putdata(buf + bytes, fmt->rgb, sizeof(fmt->rgb)); bytes += qq_put8(buf + bytes, 0); bytes += qq_put16(buf + bytes, fmt->charset); if (fmt->font != NULL && fmt->font_len > 0) { bytes += qq_putdata(buf + bytes, (guint8 *)fmt->font, fmt->font_len); } else { purple_debug_warning("QQ", "Font name is empty\n"); } bytes += qq_put8(buf + bytes, bytes + 1); /* qq_show_packet("IM tail", buf, bytes); */ return bytes; }
static gint send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, guint8 *data, gint data_len, UPDCLS update_class, guint32 ship32) { qq_data *qd; guint8 *buf; gint buf_len; guint8 *encrypted; gint encrypted_len; gint bytes_sent; guint16 seq; g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); qd = (qq_data *) gc->proto_data; buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); /* encap room_cmd and room id to buf*/ buf_len = 0; buf_len += qq_put8(buf + buf_len, room_cmd); if (room_id != 0) { /* id 0 is for QQ Demo Group, now they are closed*/ buf_len += qq_put32(buf + buf_len, room_id); } if (data != NULL && data_len > 0) { buf_len += qq_putdata(buf + buf_len, data, data_len); } qd->send_seq++; seq = qd->send_seq; /* Encrypt to encrypted with session_key */ /* at most 17 bytes more */ encrypted = g_newa(guint8, buf_len + 17); encrypted_len = qq_encrypt(encrypted, buf, buf_len, qd->session_key); if (encrypted_len < 16) { purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] %s (0x%02X)\n", encrypted_len, seq, qq_get_room_cmd_desc(room_cmd), room_cmd); return -1; } bytes_sent = packet_send_out(gc, QQ_CMD_ROOM, seq, encrypted, encrypted_len); #if 1 /* qq_show_packet("send_room_cmd", buf, buf_len); */ purple_debug_info("QQ", "<== [%05d] %s (0x%02X) to room %d, datalen %d\n", seq, qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, buf_len); #endif qq_trans_add_room_cmd(gc, seq, room_cmd, room_id, encrypted, encrypted_len, update_class, ship32); return bytes_sent; }
void qq_request_question(PurpleConnection *gc, guint8 cmd, guint32 uid, const gchar *question_utf8, const gchar *answer_utf8) { guint8 raw_data[MAX_PACKET_SIZE - 16]; gint bytes; g_return_if_fail(uid > 0); bytes = 0; bytes += qq_put8(raw_data + bytes, cmd); if (cmd == QQ_QUESTION_GET) { bytes += qq_put8(raw_data + bytes, 0); qq_send_cmd_mess(gc, QQ_CMD_BUDDY_QUESTION, raw_data, bytes, 0, uid); return; } if (cmd == QQ_QUESTION_SET) { bytes += qq_put_vstr(raw_data + bytes, question_utf8, QQ_CHARSET_DEFAULT); bytes += qq_put_vstr(raw_data + bytes, answer_utf8, QQ_CHARSET_DEFAULT); bytes += qq_put8(raw_data + bytes, 0); qq_send_cmd_mess(gc, QQ_CMD_BUDDY_QUESTION, raw_data, bytes, 0, uid); return; } /* Unknow 2 bytes, 0x(00 01) */ bytes += qq_put8(raw_data + bytes, 0x00); bytes += qq_put8(raw_data + bytes, 0x01); g_return_if_fail(uid != 0); bytes += qq_put32(raw_data + bytes, uid); if (cmd == QQ_QUESTION_REQUEST) { qq_send_cmd_mess(gc, QQ_CMD_BUDDY_QUESTION, raw_data, bytes, 0, uid); return; } bytes += qq_put_vstr(raw_data + bytes, answer_utf8, QQ_CHARSET_DEFAULT); bytes += qq_put8(raw_data + bytes, 0); qq_send_cmd_mess(gc, QQ_CMD_BUDDY_QUESTION, raw_data, bytes, 0, uid); return; }
static void request_add_buddy_auth_ex(PurpleConnection *gc, guint32 uid, const gchar *text, guint8 *auth, guint8 auth_len) { guint8 raw_data[MAX_PACKET_SIZE - 16]; gint bytes = 0; g_return_if_fail(uid != 0); bytes = 0; bytes += qq_put8(raw_data + bytes, 0x02); bytes += qq_put32(raw_data + bytes, uid); bytes += qq_put16(raw_data + bytes, 0); bytes += qq_put8(raw_data + bytes, 0); if (auth == NULL || auth_len <= 0) { bytes += qq_put8(raw_data + bytes, 0); } else { bytes += qq_put8(raw_data + bytes, auth_len); bytes += qq_putdata(raw_data + bytes, auth, auth_len); } bytes += qq_put8(raw_data + bytes, 1); /* ALLOW ADD ME FLAG */ bytes += qq_put8(raw_data + bytes, 0); /* group number? */ bytes += qq_put_vstr(raw_data + bytes, text, QQ_CHARSET_DEFAULT); qq_send_cmd(gc, QQ_CMD_ADD_BUDDY_AUTH_EX, raw_data, bytes); }
void qq_request_auth_code(PurpleConnection *gc, guint8 cmd, guint16 sub_cmd, guint32 uid) { guint8 raw_data[16]; gint bytes; g_return_if_fail(uid > 0); bytes = 0; bytes += qq_put8(raw_data + bytes, cmd); bytes += qq_put16(raw_data + bytes, sub_cmd); bytes += qq_put32(raw_data + bytes, uid); qq_send_cmd_mess(gc, QQ_CMD_AUTH_CODE, raw_data, bytes, 0, uid); }
void qq_request_search_uid(PurpleConnection *gc, qq_buddy_opt_req *opt_req) { guint8 raw_data[8]; gint bytes; g_return_if_fail(opt_req && opt_req->uid > 0); bytes = 0; bytes += qq_put8(raw_data + bytes, 0x03); bytes += qq_put32(raw_data + bytes, opt_req->uid); qq_send_cmd_mess(gc, QQ_CMD_SEARCH_UID, raw_data, bytes, 0, (guintptr)opt_req); }
static void request_add_buddy_by_question(PurpleConnection *gc, guint32 uid, guint8 *code, guint16 code_len) { guint8 raw_data[MAX_PACKET_SIZE - 16]; gint bytes = 0; g_return_if_fail(uid != 0 && code_len > 0); bytes = 0; bytes += qq_put8(raw_data + bytes, 0x10); bytes += qq_put32(raw_data + bytes, uid); bytes += qq_put16(raw_data + bytes, 0); bytes += qq_put8(raw_data + bytes, 0); bytes += qq_put8(raw_data + bytes, 0); /* no auth code */ bytes += qq_put16(raw_data + bytes, code_len); bytes += qq_putdata(raw_data + bytes, code, code_len); bytes += qq_put8(raw_data + bytes, 1); /* ALLOW ADD ME FLAG */ bytes += qq_put8(raw_data + bytes, 0); /* group number? */ qq_send_cmd(gc, QQ_CMD_ADD_BUDDY_AUTH_EX, raw_data, bytes); }
/* send packet to search for qq_group */ void qq_request_room_search(PurpleConnection *gc, guint32 ext_id, int action) { guint8 raw_data[16] = {0}; gint bytes = 0; guint8 type; purple_debug_info("QQ", "Search QQ Qun %u\n", ext_id); type = (ext_id == 0x00000000) ? QQ_ROOM_SEARCH_TYPE_DEMO : QQ_ROOM_SEARCH_TYPE_BY_ID; bytes = 0; bytes += qq_put8(raw_data + bytes, type); bytes += qq_put32(raw_data + bytes, ext_id); qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_SEARCH, 0, raw_data, bytes, 0, action); }
/* send packet to modify personal information */ static void request_change_info(PurpleConnection *gc, gchar **segments) { gint bytes = 0; guint8 raw_data[MAX_PACKET_SIZE - 128] = {0}; guint8 bar; gchar *join; g_return_if_fail(segments != NULL); bar = 0x1f; bytes += qq_put8(raw_data + bytes, bar); bytes += qq_put8(raw_data + bytes, bar); /* important! skip the first uid entry */ join = g_strjoinv("\x1f", segments + 1); bytes += qq_putdata(raw_data + bytes, (guint8 *)join, strlen(join)); g_free(join); bytes += qq_put8(raw_data + bytes, bar); /* qq_show_packet("request_modify_info", raw_data, bytes); */ qq_send_cmd(gc, QQ_CMD_UPDATE_INFO, raw_data, bytes); }
void qq_request_auth_token( PurpleConnection *gc, guint8 cmd, guint16 sub_cmd, guint32 dataptr2ship, qq_buddy_opt_req *opt_req ) { guint8 raw_data[128]; gint bytes; g_return_if_fail(opt_req && opt_req->uid > 0); bytes = 0; bytes += qq_put8(raw_data + bytes, cmd); bytes += qq_put16(raw_data + bytes, sub_cmd); bytes += qq_put32(raw_data + bytes, opt_req->uid); if (opt_req->captcha_input && opt_req->session) { bytes += qq_put_vstr(raw_data+bytes, opt_req->captcha_input, sizeof(guint16), NULL); bytes += qq_put16(raw_data+bytes, opt_req->session_len); bytes += qq_putdata(raw_data+bytes, opt_req->session, opt_req->session_len); } qq_send_cmd_mess(gc, QQ_CMD_AUTH_TOKEN, raw_data, bytes, dataptr2ship, (guintptr)opt_req); }
/* request buddy memo */ void qq_request_buddy_memo(PurpleConnection *gc, guint32 bd_uid, guint32 update_class, guint32 action) { guint8 raw_data[16] = {0}; gint bytes; purple_debug_info("QQ", "qq_request_buddy_memo, buddy uid=%u, update_class=%u\n", bd_uid, update_class); g_return_if_fail(NULL != gc); /* '0' is ok g_return_if_fail(uid != 0); */ bytes = 0; bytes += qq_put8(raw_data+bytes, QQ_BUDDY_MEMO_GET); bytes += qq_put32(raw_data+bytes, bd_uid); /* qq_show_packet("MEMO REQUEST", raw_data, bytes); */ qq_send_cmd_mess(gc, QQ_CMD_BUDDY_MEMO, (guint8*)raw_data, bytes, update_class, action); }
void qq_send_cmd_group_auth(PurpleConnection *gc, qq_room_data *rmd, guint8 opt, guint32 uid, const gchar *reason_utf8) { guint8 raw_data[MAX_PACKET_SIZE - 16]; gint bytes; g_return_if_fail(rmd != NULL); if (opt == QQ_ROOM_AUTH_REQUEST_APPLY) { rmd->my_role = QQ_ROOM_ROLE_REQUESTING; uid = 0; } bytes = 0; bytes += qq_put8(raw_data + bytes, opt); bytes += qq_put32(raw_data + bytes, uid); bytes += qq_put_vstr(raw_data + bytes, reason_utf8, QQ_CHARSET_DEFAULT); qq_send_room_cmd(gc, QQ_ROOM_CMD_AUTH, rmd->id, raw_data, bytes); }
static void request_remove_buddy_ex(PurpleConnection *gc, guint32 uid, guint8 *auth, guint8 auth_len) { gint bytes; guint8 *raw_data; gchar uid_str[16]; g_return_if_fail(uid != 0); g_return_if_fail(auth != NULL && auth_len > 0); raw_data = g_newa(guint8, auth_len + sizeof(uid_str) ); bytes = 0; bytes += qq_put8(raw_data + bytes, auth_len); bytes += qq_putdata(raw_data + bytes, auth, auth_len); g_snprintf(uid_str, sizeof(uid_str), "%u", uid); bytes += qq_putdata(raw_data + bytes, (guint8 *)uid_str, strlen(uid_str)); qq_send_cmd_mess(gc, QQ_CMD_REMOVE_BUDDY, raw_data, bytes, 0, uid); }
/* send packet to remove a buddy from my buddy list */ static void qq_request_remove_buddy(PurpleConnection *gc, qq_buddy_opt_req *opt_req) { gint bytes; guint8 *raw_data; gchar * uid_str; g_return_if_fail(opt_req && opt_req->uid != 0); g_return_if_fail(opt_req->auth != NULL && opt_req->auth_len > 0); raw_data = g_newa(guint8, opt_req->auth_len + sizeof(uid_str)); bytes = 0; bytes += qq_put8(raw_data + bytes, opt_req->auth_len); bytes += qq_putdata(raw_data + bytes, opt_req->auth, opt_req->auth_len); uid_str = uid_to_purple_name(opt_req->uid); bytes += qq_putdata(raw_data + bytes, (guint8 *)uid_str, strlen(uid_str)); g_free(uid_str); qq_send_cmd_mess(gc, QQ_CMD_REMOVE_BUDDY, raw_data, bytes, 0, opt_req->uid); buddy_opt_req_free(opt_req); }
/* send a file to udp channel with QQ_FILE_DATA_PACKET_TAG */ static void _qq_send_file_data_packet(PurpleConnection *gc, guint16 packet_type, guint8 sub_type, guint32 fragment_index, guint16 seq, guint8 *data, gint len) { guint8 *raw_data, filename_md5[QQ_KEY_LENGTH], file_md5[QQ_KEY_LENGTH]; gint bytes; guint32 fragment_size = 1000; const char *filename; gint filename_len, filesize; qq_data *qd; ft_info *info; qd = (qq_data *) gc->proto_data; info = (ft_info *) qd->xfer->data; filename = purple_xfer_get_filename(qd->xfer); filesize = purple_xfer_get_size(qd->xfer); raw_data = g_newa(guint8, MAX_PACKET_SIZE); bytes = 0; bytes += qq_put8(raw_data + bytes, 0x00); bytes += qq_put16(raw_data + bytes, packet_type); switch (packet_type) { case QQ_FILE_BASIC_INFO: case QQ_FILE_DATA_INFO: case QQ_FILE_EOF: bytes += qq_put16(raw_data + bytes, 0x0000); bytes += qq_put8(raw_data + bytes, 0x00); break; case QQ_FILE_CMD_FILE_OP: switch(sub_type) { case QQ_FILE_BASIC_INFO: filename_len = strlen(filename); qq_get_md5(filename_md5, sizeof(filename_md5), (guint8 *)filename, filename_len); _fill_file_md5(purple_xfer_get_local_filename(qd->xfer), purple_xfer_get_size(qd->xfer), file_md5); info->fragment_num = (filesize - 1) / QQ_FILE_FRAGMENT_MAXLEN + 1; info->fragment_len = QQ_FILE_FRAGMENT_MAXLEN; purple_debug_info("QQ", "start transfering data, %d fragments with %d length each\n", info->fragment_num, info->fragment_len); /* Unknown */ bytes += qq_put16(raw_data + bytes, 0x0000); /* Sub-operation type */ bytes += qq_put8(raw_data + bytes, sub_type); /* Length of file */ bytes += qq_put32(raw_data + bytes, filesize); /* Number of fragments */ bytes += qq_put32(raw_data + bytes, info->fragment_num); /* Length of a single fragment */ bytes += qq_put32(raw_data + bytes, info->fragment_len); bytes += qq_putdata(raw_data + bytes, file_md5, 16); bytes += qq_putdata(raw_data + bytes, filename_md5, 16); /* Length of filename */ bytes += qq_put16(raw_data + bytes, filename_len); /* 8 unknown bytes */ bytes += qq_put32(raw_data + bytes, 0x00000000); bytes += qq_put32(raw_data + bytes, 0x00000000); /* filename */ bytes += qq_putdata(raw_data + bytes, (guint8 *) filename, filename_len); break; case QQ_FILE_DATA_INFO: purple_debug_info("QQ", "sending %dth fragment with length %d, offset %d\n", fragment_index, len, (fragment_index-1)*fragment_size); /* bytes += qq_put16(raw_data + bytes, ++(qd->send_seq)); */ bytes += qq_put16(raw_data + bytes, info->send_seq); bytes += qq_put8(raw_data + bytes, sub_type); /* bytes += qq_put32(raw_data + bytes, fragment_index); */ bytes += qq_put32(raw_data + bytes, fragment_index - 1); bytes += qq_put32(raw_data + bytes, (fragment_index - 1) * fragment_size); bytes += qq_put16(raw_data + bytes, len); bytes += qq_putdata(raw_data + bytes, data, len); break; case QQ_FILE_EOF: purple_debug_info("QQ", "end of sending data\n"); /* bytes += qq_put16(raw_data + bytes, info->fragment_num + 1); */ bytes += qq_put16(raw_data + bytes, info->fragment_num); bytes += qq_put8(raw_data + bytes, sub_type); /* purple_xfer_set_completed(qd->xfer, TRUE); */ } break; case QQ_FILE_CMD_FILE_OP_ACK: switch (sub_type) { case QQ_FILE_BASIC_INFO: bytes += qq_put16(raw_data + bytes, 0x0000); bytes += qq_put8(raw_data + bytes, sub_type); bytes += qq_put32(raw_data + bytes, 0x00000000); break; case QQ_FILE_DATA_INFO: bytes += qq_put16(raw_data + bytes, seq); bytes += qq_put8(raw_data + bytes, sub_type); bytes += qq_put32(raw_data + bytes, fragment_index); break; case QQ_FILE_EOF: bytes += qq_put16(raw_data + bytes, filesize / QQ_FILE_FRAGMENT_MAXLEN + 2); bytes += qq_put8(raw_data + bytes, sub_type); break; } } purple_debug_info("QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); _qq_send_file(gc, raw_data, bytes, QQ_FILE_DATA_PACKET_TAG, info->to_uid); }
/* 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); }
void qq_request_add_buddy_post(PurpleConnection *gc, qq_buddy_opt_req *opt_req, const gchar *text) { static guint8 fill1[] = { 0x00, 0x0A, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static guint8 fill2[] = { 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; guint8 raw_data[256]; gint bytes = 0; guint8 cmd; g_return_if_fail(opt_req && opt_req->uid!= 0); switch (opt_req->auth_type) { case 0x01: //auth cmd = 0x02; break; case 0x02: //question cmd = 0x10; break; case 0x00: //no_auth case 0x03: //approve and add case 0x04: //approve case 0x05: //reject cmd = opt_req->auth_type; break; } bytes = 0; bytes += qq_put8(raw_data + bytes, cmd); bytes += qq_put32(raw_data + bytes, opt_req->uid); if (cmd == 0x03 || cmd == 0x04 || cmd == 0x05) { bytes += qq_put16(raw_data + bytes, 0); } else { if (opt_req->no_auth && opt_req->no_auth_len > 0) { bytes += qq_put16(raw_data + bytes, opt_req->no_auth_len); bytes += qq_putdata(raw_data + bytes, opt_req->no_auth, opt_req->no_auth_len); } else bytes += qq_put16(raw_data + bytes, 0); if (opt_req->auth == NULL || opt_req->auth_len <= 0) { bytes += qq_put16(raw_data + bytes, 0); } else { bytes += qq_put16(raw_data + bytes, opt_req->auth_len); bytes += qq_putdata(raw_data + bytes, opt_req->auth, opt_req->auth_len); } bytes += qq_put8(raw_data + bytes, 1); /* ALLOW ADD ME FLAG */ } bytes += qq_put8(raw_data + bytes, opt_req->group_id); /* group number */ if (text) { bytes += qq_put8(raw_data + bytes, strlen(text)); bytes += qq_putdata(raw_data + bytes, (guint8 *)text, strlen(text)); } if (cmd == 0x03 || cmd == 0x04 || cmd == 0x05) bytes += qq_putdata(raw_data + bytes, fill2, sizeof(fill2)); else bytes += qq_putdata(raw_data + bytes, fill1, sizeof(fill1)); qq_send_cmd_mess(gc, QQ_CMD_ADD_BUDDY_POST, raw_data, bytes, 0, opt_req->auth_type); buddy_opt_req_free(opt_req); }