static void do_server_news(PurpleConnection *gc, guint8 *data, gint data_len) { qq_data *qd = (qq_data *) gc->proto_data; gint bytes; gchar *title, *brief, *url; gchar *content; g_return_if_fail(data != NULL && data_len != 0); /* qq_show_packet("Rcv news", data, data_len); */ bytes = 4; /* skip unknown 4 bytes */ bytes += qq_get_vstr(&title, QQ_CHARSET_DEFAULT, sizeof(guint8), data + bytes); bytes += qq_get_vstr(&brief, QQ_CHARSET_DEFAULT, sizeof(guint8), data + bytes); bytes += qq_get_vstr(&url, QQ_CHARSET_DEFAULT, sizeof(guint8), data + bytes); content = g_strdup_printf(_("Server News:\n%s\n%s\n%s"), title, brief, url); if (qd->is_show_news) { qq_got_message(gc, content); } else { purple_debug_info("QQ", "QQ Server news:\n%s\n", content); } g_free(title); g_free(brief); g_free(url); g_free(content); }
static void server_buddy_add_request_ex(PurpleConnection *gc, gchar *from, gchar *to, guint8 *data, gint data_len) { gint bytes; guint32 uid; gchar *msg; guint8 allow_reverse; g_return_if_fail(from != NULL && to != NULL); g_return_if_fail(data != NULL && data_len >= 3); uid = strtoul(from, NULL, 10); g_return_if_fail(uid != 0); /* qq_show_packet("server_buddy_add_request_ex", data, data_len); */ bytes = 0; bytes += qq_get_vstr(&msg, QQ_CHARSET_DEFAULT, data+bytes); bytes += qq_get8(&allow_reverse, data + bytes); /* allow_reverse = 0x01, allowed */ server_buddy_check_code(gc, from, data + bytes, data_len - bytes); if (strlen(msg) <= 0) { g_free(msg); msg = g_strdup( _("No reason given") ); } buddy_add_input(gc, uid, msg); g_free(msg); }
void qq_process_search_uid( PurpleConnection *gc, guint8 *data, gint data_len, qq_buddy_opt_req *opt_req ) { gint bytes; guint32 uid; guint8 status; gchar * name; guint16 icon; g_return_if_fail(data != NULL && data_len != 0); g_return_if_fail(opt_req && opt_req->uid != 0); //qq_show_packet("qq_process_search_uid", data, data_len); bytes = 7; bytes += qq_get32(&uid, data + bytes); g_return_if_fail(uid == opt_req->uid); bytes ++; bytes += qq_get8(&status, data + bytes); bytes += 4; bytes += qq_get_vstr(&name, NULL, sizeof(guint8), data + bytes); bytes += qq_get16(&icon, data + bytes); bytes += 13; bytes += qq_get16(&opt_req->no_auth_len, data + bytes); if (opt_req->no_auth) { opt_req->no_auth = g_new0(guint8, opt_req->no_auth_len); bytes += qq_getdata(opt_req->no_auth, opt_req->no_auth_len, data + bytes); } qq_request_add_buddy_post(gc, opt_req, NULL); }
/* process group cmd reply "search group" */ void qq_process_room_search(PurpleConnection *gc, guint8 *data, gint len, guint32 ship32) { qq_data *qd; qq_room_data rmd; PurpleChat *chat; gint bytes; guint8 search_type; guint16 unknown; g_return_if_fail(data != NULL && len > 0); qd = (qq_data *) gc->proto_data; bytes = 0; bytes += qq_get8(&search_type, data + bytes); /* now it starts with group_info_entry */ bytes += qq_get32(&(rmd.id), data + bytes); bytes += qq_get32(&(rmd.ext_id), data + bytes); bytes += qq_get8(&(rmd.type8), data + bytes); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get32(&(rmd.creator_uid), data + bytes); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get32(&(rmd.category), data + bytes); bytes += qq_get_vstr(&(rmd.title_utf8), QQ_CHARSET_DEFAULT, data + bytes); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get8(&(rmd.auth_type), data + bytes); bytes += qq_get_vstr(&(rmd.desc_utf8), QQ_CHARSET_DEFAULT, data + bytes); /* end of one qq_group */ if(bytes != len) { purple_debug_error("QQ", "group_cmd_search_group: Dangerous error! maybe protocol changed, notify developers!"); } if (ship32 == QQ_ROOM_SEARCH_FOR_JOIN) { chat = qq_room_find_or_new(gc, rmd.id, rmd.ext_id); g_return_if_fail(chat != NULL); qq_room_update_chat_info(chat, &rmd); qq_request_room_join(gc, &rmd); } else { add_to_roomlist(qd, &rmd); } }
void qq_process_auth_token( PurpleConnection *gc, guint8 *data, gint data_len, guint32 dataptr, qq_buddy_opt_req *opt_req ) { 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(opt_req && opt_req->uid != 0); //qq_show_packet("qq_process_auth_token", data, data_len); bytes = 0; bytes += qq_get8(&cmd, data + bytes); bytes += qq_get16(&sub_cmd, data + bytes); bytes += qq_get8(&reply, data + bytes); /* if reply == 0x01, we need request captcha */ if (reply) { /* if this is end, means you have submitted the wrong captcha */ if (bytes>=data_len) { qq_request_auth_token(gc, QQ_AUTH_INFO_BUDDY, QQ_AUTH_INFO_ADD_BUDDY, 0, opt_req); return; } bytes += qq_get_vstr(&code, NULL, sizeof(guint16), data + bytes); purple_util_fetch_url_request( (gchar *)code, TRUE, NULL, TRUE, NULL, TRUE, auth_token_captcha_input_cb, opt_req); return; } bytes += qq_get16(&opt_req->auth_len, data + bytes); g_return_if_fail(opt_req->auth_len > 0); g_return_if_fail(bytes + opt_req->auth_len <= data_len); opt_req->auth = g_new0(guint8, opt_req->auth_len); bytes += qq_getdata(opt_req->auth, opt_req->auth_len, data + bytes); if (cmd == QQ_AUTH_INFO_BUDDY && sub_cmd == QQ_AUTH_INFO_REMOVE_BUDDY) { qq_request_remove_buddy(gc, opt_req); return; } if (sub_cmd == QQ_AUTH_INFO_ADD_BUDDY) { if (opt_req->auth_type == 0x01) add_buddy_authorize_input(gc, opt_req); else if (opt_req->auth_type == 0x00) qq_request_search_uid(gc, opt_req); return; } if (cmd == QQ_AUTH_INFO_BUDDY && sub_cmd == QQ_AUTH_INFO_UPDATE_BUDDY_INFO) { request_change_info(gc, (guint8 *)dataptr, 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); }
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); }
static void do_msg_sys(PurpleConnection *gc, guint8 *data, gint data_len) { guint8 reply; gchar *msg, *msg_esc; qq_data * qd; g_return_if_fail(gc != NULL && gc->proto_data != NULL && data != NULL && data_len != 0); qd = (qq_data *)gc->proto_data; qq_get8(&reply, data+4); qq_get_vstr(&msg, NULL, sizeof(guint8), data+5); if (reply == 0x01) { purple_debug_error("QQ", "We are kicked out by QQ server\n"); msg_esc = purple_markup_escape_text(msg, -1); purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, msg_esc); g_free(msg); g_free(msg_esc); return; } qq_got_message(gc, msg); }
/* process reply to get_memo packet */ void qq_process_get_buddy_memo(PurpleConnection *gc, guint8* data, gint data_len, guint32 update_class, guint32 action) { gchar **segments; gint bytes; gint index; guint8 rcv_cmd; guint32 rcv_uid; guint8 unk1_8; guint8 is_success; g_return_if_fail(NULL != gc && NULL != data && 0 != data_len); /* qq_show_packet("MEMO REACH", data, data_len); */ purple_debug_info("QQ", "action=0x%02X\n", action); bytes = 0; /* TX looks a bit clever than before... :) */ bytes += qq_get8(&rcv_cmd, data+bytes); purple_debug_info("QQ", "rcv_cmd=0x%02X\n", rcv_cmd); /* it's possible that packet contains no buddy uid and no memo!!! * go to next step according to previous action sent */ if (1 == data_len) { /* only one byte */ purple_debug_info("QQ", "memo packet contains no buddy uid and memo...\n"); if (QQ_BUDDY_MEMO_MODIFY == action) { qq_create_buddy_memo(gc, (guint32)update_class, QQ_BUDDY_MEMO_MODIFY); return; } return; } switch (rcv_cmd) { case QQ_BUDDY_MEMO_MODIFY: case QQ_BUDDY_MEMO_REMOVE: bytes += qq_get8(&is_success, data+bytes); if (QQ_BUDDY_MEMO_REQUEST_SUCCESS == is_success) { purple_notify_message(gc, PURPLE_NOTIFY_MSG_INFO, _("Memo Modify"), _("Server says:"), _("Your request was accepted."), NULL, NULL); purple_debug_info("QQ", "memo change succeessfully!\n"); } else { purple_notify_message(gc, PURPLE_NOTIFY_MSG_INFO, _("Memo Modify"), _("Server says:"), _("Your request was rejected."), NULL, NULL); purple_debug_info("QQ", "memo change failed\n"); } break; case QQ_BUDDY_MEMO_GET: bytes += qq_get32(&rcv_uid, data+bytes); purple_debug_info("QQ", "rcv_uid=%u\n", rcv_uid); bytes += qq_get8(&unk1_8, data+bytes); purple_debug_info("QQ", "unk1_8=0x%02X\n", unk1_8); segments = g_new0(gchar*, QQ_MEMO_SIZE); for (index = 0; index < QQ_MEMO_SIZE; index++) { /* get utf8 string */ bytes += qq_get_vstr(&segments[index], QQ_CHARSET_DEFAULT, data+bytes); /* purple_debug_info("QQ", "bytes:%d, seg:%s\n", bytes, segments[index]); */ } /* common action, update buddy memo */ update_buddy_memo(gc, rcv_uid, segments[QQ_MEMO_ALIAS]); /* memo is thing that we regard our buddy as, so we need one more buddy_uid */ memo_modify_dialogue(gc, rcv_uid, segments, action); break; default: purple_debug_info("QQ", "received an UNKNOWN memo cmd!!!\n"); break; } }
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(); }
/* process the reply to get_members_info packet */ void qq_process_room_cmd_get_members_info( guint8 *data, gint len, guint32 index, PurpleConnection *gc ) { gint bytes; gint num; guint32 id, member_uid; guint16 unknown; qq_room_data *rmd; qq_buddy_data *bd; gchar *nick; g_return_if_fail(data != NULL && len > 0); /* qq_show_packet("qq_process_room_cmd_get_members_info", data, len); */ bytes = 0; bytes += qq_get32(&id, data + bytes); g_return_if_fail(id > 0); rmd = qq_room_data_find(gc, id); g_return_if_fail(rmd != NULL); num = 0; while (bytes < len) { bytes += qq_get32(&member_uid, data + bytes); g_return_if_fail(member_uid > 0); bd = qq_room_buddy_find_or_new(gc, rmd, member_uid); g_return_if_fail(bd != NULL); num++; bytes += qq_get16(&(bd->face), data + bytes); bytes += qq_get8(&(bd->age), data + bytes); bytes += qq_get8(&(bd->gender), data + bytes); /* only here use old charset GB18030 */ bytes += qq_get_vstr(&nick, QQ_CHARSET_DEFAULT, sizeof(guint8), data + bytes); bytes += qq_get16(&unknown, data + bytes); bytes += qq_get8(&(bd->ext_flag), data + bytes); bytes += qq_get8(&(bd->comm_flag), data + bytes); qq_filter_str(nick); bd->nickname = g_strdup(nick); g_free(nick); #if 0 purple_debug_info("QQ", "member [%d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", member_uid, bd->ext_flag, bd->comm_flag, bd->nickname); #endif bd->last_update = time(NULL); } if (bytes > len) { purple_debug_error("QQ", "group_cmd_get_members_info: Dangerous error! maybe protocol changed, notify developers!"); } purple_debug_info("QQ", "Group \"%s\" got %d member info\n", rmd->name, num); if (index) { qq_request_room_get_members_info(gc, id, 0, index); return; } rmd->has_got_members_info = TRUE; qq_room_conv_set_onlines(gc, rmd); }
void qq_process_room_cmd_get_info(guint8 *data, gint data_len, guint32 action, PurpleConnection *gc) { qq_data *qd; qq_room_data *rmd; qq_buddy_data *bd; PurpleChat *chat; PurpleConversation *conv; guint8 organization, role; guint16 max_members; guint32 resend_flag, member_uid, id, qun_id, last_uid; gint bytes; guint num=0; guint8 has_more=0; gchar *topic; g_return_if_fail(data != NULL && data_len > 0); qd = (qq_data *) gc->proto_data; /* qq_show_packet("Room Info", data, data_len); */ bytes = 0; bytes += qq_get32(&id, data + bytes); g_return_if_fail(id > 0); bytes += qq_get32(&qun_id, data + bytes); g_return_if_fail(qun_id > 0); chat = qq_room_find_or_new(gc, id, qun_id); g_return_if_fail(chat != NULL); rmd = qq_room_data_find(gc, id); g_return_if_fail(rmd != NULL); bytes += qq_get32(&resend_flag, data + bytes); //first 00 00 00 03, then 00 00 00 02 if (resend_flag == 0x00000003) { bytes += qq_get8(&(rmd->type8), data + bytes); bytes += 4; //maybe vip sign bytes += qq_get32(&(rmd->creator_uid), data + bytes); if (rmd->creator_uid == qd->uid) rmd->my_role = QQ_ROOM_ROLE_ADMIN; bytes += qq_get8(&(rmd->auth_type), data + bytes); bytes += 4 ; /* oldCategory */ bytes += 2; // 00 00 bytes += qq_get32(&(rmd->category), data + bytes); bytes += qq_get16(&max_members, data + bytes); bytes += 1; bytes += 8; purple_debug_info("QQ", "type: %u creator: %u category: %u max_members: %u\n", rmd->type8, rmd->creator_uid, rmd->category, max_members); bytes += qq_get_vstr(&(rmd->name), NULL, sizeof(guint8), data + bytes); bytes += 2; /* 0x0000 */ bytes += qq_get_vstr(&(rmd->bulletin), NULL, sizeof(guint8), data + bytes); bytes += qq_get_vstr(&(rmd->intro), NULL, sizeof(guint8), data + bytes); bytes += qq_get_vstr(&(rmd->token), NULL, sizeof(guint16), data + bytes); purple_debug_info("QQ", "room [%s] bulletin [%s] intro [%s] \n", rmd->name, rmd->bulletin, rmd->intro); bytes += 2; //Unknown bytes += qq_get32(&last_uid, data + bytes); /* last_uid of this recv, request more with it */ bytes += qq_get8(&has_more, data + bytes); /* if there are more, request again */ /* now comes the member list separated by 0x00 */ } else { /* resend_flag 00 00 00 02 is special, start with random one only 5 bytes */ bytes += qq_get32(&member_uid, data + bytes); num++; bytes += qq_get8(&organization, data + bytes); bd = qq_room_buddy_find_or_new(gc, rmd, member_uid); } while (bytes < data_len) { bytes += qq_get32(&member_uid, data + bytes); num++; bytes += qq_get8(&organization, data + bytes); bytes += qq_get8(&role, data + bytes); #if 0 if(organization != 0 || role != 0) { purple_debug_info("QQ", "%u, organization=%d, role=%d\n", member_uid, organization, role); } #endif bd = qq_room_buddy_find_or_new(gc, rmd, member_uid); if (bd != NULL) bd->role = role; } purple_debug_info("QQ", "Qun \"%s\" has received %d members\n", rmd->name, num); if (has_more) { qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, id, NULL, 0, 0, last_uid); } else { qq_room_update_chat_info(chat, rmd); if (action == QQ_ROOM_INFO_DISPLAY) { room_info_display(gc, rmd); } conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, rmd->name, purple_connection_get_account(gc)); if(NULL == conv) { purple_debug_warning("QQ", "Conversation \"%s\" is not opened\n", rmd->name); return; } topic = g_strdup_printf("%u %s", rmd->qun_id, rmd->bulletin); purple_debug_info("QQ", "Set chat topic to %s\n", topic); purple_conv_chat_set_topic(PURPLE_CONV_CHAT(conv), NULL, topic); g_free(topic); } }