comparison libpurple/protocols/qq/qq_process.c @ 24143:c2253c485728

2008.10.04 - ccpaging <ccpagint(at)gmail.com> * Update protocol for 2007 * Code cleanup
author SHiNE CsyFeK <csyfek@gmail.com>
date Wed, 22 Oct 2008 14:47:39 +0000
parents df699d739b8f
children a95c7e71064c
comparison
equal deleted inserted replaced
24142:df699d739b8f 24143:c2253c485728
56 QQ_ROOM_CMD_REPLY_SEARCH_ERROR = 0x02, 56 QQ_ROOM_CMD_REPLY_SEARCH_ERROR = 0x02,
57 QQ_ROOM_CMD_REPLY_NOT_MEMBER = 0x0a 57 QQ_ROOM_CMD_REPLY_NOT_MEMBER = 0x0a
58 }; 58 };
59 59
60 /* default process, decrypt and dump */ 60 /* default process, decrypt and dump */
61 static void process_cmd_unknow(PurpleConnection *gc,const gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq) 61 static void process_unknow_cmd(PurpleConnection *gc,const gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq)
62 { 62 {
63 qq_data *qd; 63 qq_data *qd;
64 gchar *msg_utf8 = NULL; 64 gchar *msg_utf8 = NULL;
65 65
66 g_return_if_fail(data != NULL && data_len != 0); 66 g_return_if_fail(data != NULL && data_len != 0);
79 purple_notify_info(gc, _("QQ Error"), title, msg_utf8); 79 purple_notify_info(gc, _("QQ Error"), title, msg_utf8);
80 g_free(msg_utf8); 80 g_free(msg_utf8);
81 } 81 }
82 } 82 }
83 83
84 /* parse the reply to send_im */
85 static void do_im_ack(guint8 *data, gint data_len, PurpleConnection *gc)
86 {
87 qq_data *qd;
88
89 g_return_if_fail(data != NULL && data_len != 0);
90
91 qd = gc->proto_data;
92
93 if (data[0] != 0) {
94 purple_debug_warning("QQ", "Failed sent IM\n");
95 purple_notify_error(gc, _("Error"), _("Failed to send IM."), NULL);
96 return;
97 }
98
99 purple_debug_info("QQ", "OK sent IM\n");
100 }
101
102 static void do_server_news(guint8 *data, gint data_len, PurpleConnection *gc)
103 {
104 qq_data *qd = (qq_data *) gc->proto_data;
105 gint bytes;
106 guint8 *temp;
107 guint8 temp_len;
108 gchar *title, *brief, *url;
109 gchar *title_utf8;
110 gchar *content, *content_utf8;
111
112 g_return_if_fail(data != NULL && data_len != 0);
113
114 /* qq_show_packet("Rcv news", data, data_len); */
115
116 temp = g_newa(guint8, data_len);
117 bytes = 4; /* ignore unknown 4 bytes */
118
119 bytes += qq_get8(&temp_len, data + bytes);
120 g_return_if_fail(bytes + temp_len <= data_len);
121 bytes += qq_getdata(temp, temp_len, data+bytes);
122 title = g_strndup((gchar *)temp, temp_len);
123
124 bytes += qq_get8(&temp_len, data + bytes);
125 g_return_if_fail(bytes + temp_len <= data_len);
126 bytes += qq_getdata(temp, temp_len, data+bytes);
127 brief = g_strndup((gchar *)temp, temp_len);
128
129 bytes += qq_get8(&temp_len, data + bytes);
130 g_return_if_fail(bytes + temp_len <= data_len);
131 bytes += qq_getdata(temp, temp_len, data+bytes);
132 url = g_strndup((gchar *)temp, temp_len);
133
134 title_utf8 = qq_to_utf8(title, QQ_CHARSET_DEFAULT);
135 content = g_strdup_printf(_("Server News:\n%s\n%s\n%s"), title, brief, url);
136 content_utf8 = qq_to_utf8(content, QQ_CHARSET_DEFAULT);
137
138 if (qd->is_show_news) {
139 qq_got_attention(gc, content_utf8);
140 } else {
141 purple_debug_info("QQ", "QQ Server news:\n%s\n%s", title_utf8, content_utf8);
142 }
143 g_free(title);
144 g_free(title_utf8);
145 g_free(brief);
146 g_free(url);
147 g_free(content);
148 g_free(content_utf8);
149 }
150
151 /* process im from system administrator */
152 static void do_server_im(guint8 *data, gint data_len, PurpleConnection *gc)
153 {
154 gint len;
155 guint8 reply;
156 gchar **segments, *msg_utf8;
157
158 g_return_if_fail(data != NULL && data_len != 0);
159
160 len = data_len;
161
162 if (NULL == (segments = split_data(data, len, "\x2f", 2)))
163 return;
164
165 reply = strtol(segments[0], NULL, 10);
166 if (reply == 1)
167 purple_debug_warning("QQ", "We are kicked out by QQ server\n");
168
169 msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT);
170 purple_notify_warning(gc, NULL, _("System Message"), msg_utf8);
171 }
172
173 static const gchar *get_im_type_desc(gint type)
174 {
175 switch (type) {
176 case QQ_RECV_IM_TO_BUDDY:
177 return "QQ_RECV_IM_TO_BUDDY";
178 case QQ_RECV_IM_TO_UNKNOWN:
179 return "QQ_RECV_IM_TO_UNKNOWN";
180 case QQ_RECV_IM_UNKNOWN_QUN_IM:
181 return "QQ_RECV_IM_UNKNOWN_QUN_IM";
182 case QQ_RECV_IM_ADD_TO_QUN:
183 return "QQ_RECV_IM_ADD_TO_QUN";
184 case QQ_RECV_IM_DEL_FROM_QUN:
185 return "QQ_RECV_IM_DEL_FROM_QUN";
186 case QQ_RECV_IM_APPLY_ADD_TO_QUN:
187 return "QQ_RECV_IM_APPLY_ADD_TO_QUN";
188 case QQ_RECV_IM_CREATE_QUN:
189 return "QQ_RECV_IM_CREATE_QUN";
190 case QQ_RECV_IM_SYS_NOTIFICATION:
191 return "QQ_RECV_IM_SYS_NOTIFICATION";
192 case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN:
193 return "QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN";
194 case QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN:
195 return "QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN";
196 case QQ_RECV_IM_TEMP_QUN_IM:
197 return "QQ_RECV_IM_TEMP_QUN_IM";
198 case QQ_RECV_IM_QUN_IM:
199 return "QQ_RECV_IM_QUN_IM";
200 case QQ_RECV_IM_NEWS:
201 return "QQ_RECV_IM_NEWS";
202 case QQ_RECV_IM_EXTEND:
203 return "QQ_RECV_IM_EXTEND";
204 case QQ_RECV_IM_EXTEND_85:
205 return "QQ_RECV_IM_EXTEND_85";
206 default:
207 return "QQ_RECV_IM_UNKNOWN";
208 }
209 }
210
211 /* I receive a message, mainly it is text msg,
212 * but we need to proess other types (group etc) */
213 static void process_private_msg(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc)
214 {
215 qq_data *qd;
216 gint bytes;
217
218 struct {
219 guint32 uid_from;
220 guint32 uid_to;
221 guint32 seq;
222 struct in_addr ip_from;
223 guint16 port_from;
224 guint16 im_type;
225 } header;
226
227 g_return_if_fail(data != NULL && data_len != 0);
228
229 qd = (qq_data *) gc->proto_data;
230
231 if (data_len < 16) { /* we need to ack with the first 16 bytes */
232 purple_debug_error("QQ", "MSG is too short\n");
233 return;
234 } else {
235 /* when we receive a message,
236 * we send an ACK which is the first 16 bytes of incoming packet */
237 qq_send_server_reply(gc, QQ_CMD_RECV_IM, seq, data, 16);
238 }
239
240 /* check len first */
241 if (data_len < 20) { /* length of im_header */
242 purple_debug_error("QQ", "Invald MSG header, len %d < 20\n", data_len);
243 return;
244 }
245
246 bytes = 0;
247 bytes += qq_get32(&(header.uid_from), data + bytes);
248 bytes += qq_get32(&(header.uid_to), data + bytes);
249 bytes += qq_get32(&(header.seq), data + bytes);
250 /* if the message is delivered via server, it is server IP/port */
251 bytes += qq_getIP(&(header.ip_from), data + bytes);
252 bytes += qq_get16(&(header.port_from), data + bytes);
253 bytes += qq_get16(&(header.im_type), data + bytes);
254 /* im_header prepared */
255
256 if (header.uid_to != qd->uid) { /* should not happen */
257 purple_debug_error("QQ", "MSG to [%d], NOT me\n", header.uid_to);
258 return;
259 }
260
261 /* check bytes */
262 if (bytes >= data_len - 1) {
263 purple_debug_warning("QQ", "Empty MSG\n");
264 return;
265 }
266
267 switch (header.im_type) {
268 case QQ_RECV_IM_NEWS:
269 do_server_news(data + bytes, data_len - bytes, gc);
270 break;
271 case QQ_RECV_IM_EXTEND:
272 case QQ_RECV_IM_EXTEND_85:
273 purple_debug_info("QQ", "MSG from buddy [%d]\n", header.uid_from);
274 qq_process_extend_im(gc, data + bytes, data_len - bytes);
275 break;
276 case QQ_RECV_IM_TO_UNKNOWN:
277 case QQ_RECV_IM_TO_BUDDY:
278 purple_debug_info("QQ", "MSG from buddy [%d]\n", header.uid_from);
279 qq_process_im(gc, data + bytes, data_len - bytes);
280 break;
281 case QQ_RECV_IM_UNKNOWN_QUN_IM:
282 case QQ_RECV_IM_TEMP_QUN_IM:
283 case QQ_RECV_IM_QUN_IM:
284 purple_debug_info("QQ", "MSG from room [%d]\n", header.uid_from);
285 /* uid_from is in fact id */
286 qq_process_room_msg_normal(data + bytes, data_len - bytes, header.uid_from, gc, header.im_type);
287 break;
288 case QQ_RECV_IM_ADD_TO_QUN:
289 purple_debug_info("QQ", "Notice from [%d], Added\n", header.uid_from);
290 /* uid_from is group id
291 * we need this to create a dummy group and add to blist */
292 qq_process_room_msg_been_added(data + bytes, data_len - bytes, header.uid_from, gc);
293 break;
294 case QQ_RECV_IM_DEL_FROM_QUN:
295 purple_debug_info("QQ", "Notice from room [%d], Removed\n", header.uid_from);
296 /* uid_from is group id */
297 qq_process_room_msg_been_removed(data + bytes, data_len - bytes, header.uid_from, gc);
298 break;
299 case QQ_RECV_IM_APPLY_ADD_TO_QUN:
300 purple_debug_info("QQ", "Notice from room [%d], Joined\n", header.uid_from);
301 /* uid_from is group id */
302 qq_process_room_msg_apply_join(data + bytes, data_len - bytes, header.uid_from, gc);
303 break;
304 case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN:
305 purple_debug_info("QQ", "Notice from room [%d], Confirm add in\n",
306 header.uid_from);
307 /* uid_from is group id */
308 qq_process_room_msg_been_approved(data + bytes, data_len - bytes, header.uid_from, gc);
309 break;
310 case QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN:
311 purple_debug_info("QQ", "Notice from room [%d], Refuse add in\n",
312 header.uid_from);
313 /* uid_from is group id */
314 qq_process_room_msg_been_rejected(data + bytes, data_len - bytes, header.uid_from, gc);
315 break;
316 case QQ_RECV_IM_SYS_NOTIFICATION:
317 purple_debug_info("QQ", "Admin notice from [%d]\n", header.uid_from);
318 do_server_im(data + bytes, data_len - bytes, gc);
319 break;
320 default:
321 purple_debug_warning("QQ", "MSG from [%d], unknown type %s [0x%02x]\n",
322 header.uid_from, get_im_type_desc(header.im_type),
323 header.im_type);
324 qq_show_packet("Unknown MSG type", data, data_len);
325 break;
326 }
327 }
328
84 /* Send ACK if the sys message needs an ACK */ 329 /* Send ACK if the sys message needs an ACK */
85 static void ack_server_msg(PurpleConnection *gc, guint8 code, guint32 from, guint16 seq) 330 static void request_server_ack(PurpleConnection *gc, guint8 code, guint32 from, guint16 seq)
86 { 331 {
87 qq_data *qd; 332 qq_data *qd;
88 guint8 bar, *ack; 333 guint8 bar, *ack;
89 gchar *str; 334 gchar *str;
90 gint ack_len, bytes; 335 gint ack_len, bytes;
110 else 355 else
111 purple_debug_error("QQ", 356 purple_debug_error("QQ",
112 "Fail creating sys msg ACK, expect %d bytes, build %d bytes\n", ack_len, bytes); 357 "Fail creating sys msg ACK, expect %d bytes, build %d bytes\n", ack_len, bytes);
113 } 358 }
114 359
115 static void process_server_notice(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) 360 static void do_server_notice(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8)
116 { 361 {
117 qq_data *qd = (qq_data *) gc->proto_data; 362 qq_data *qd = (qq_data *) gc->proto_data;
118 gchar *title, *content; 363 gchar *title, *content;
119 364
120 g_return_if_fail(from != NULL && to != NULL); 365 g_return_if_fail(from != NULL && to != NULL);
146 code = segments[0]; 391 code = segments[0];
147 from = segments[1]; 392 from = segments[1];
148 to = segments[2]; 393 to = segments[2];
149 msg = segments[3]; 394 msg = segments[3];
150 395
151 ack_server_msg(gc, code[0], strtol(from, NULL, 10), seq); 396 request_server_ack(gc, code[0], strtol(from, NULL, 10), seq);
152 397
153 if (strtol(to, NULL, 10) != qd->uid) { /* not to me */ 398 if (strtol(to, NULL, 10) != qd->uid) { /* not to me */
154 purple_debug_error("QQ", "Recv sys msg to [%s], not me!, discard\n", to); 399 purple_debug_error("QQ", "Recv sys msg to [%s], not me!, discard\n", to);
155 g_strfreev(segments); 400 g_strfreev(segments);
156 return; 401 return;
171 case QQ_SERVER_BUDDY_ADDED_ME: 416 case QQ_SERVER_BUDDY_ADDED_ME:
172 case QQ_SERVER_BUDDY_REJECTED_ME: 417 case QQ_SERVER_BUDDY_REJECTED_ME:
173 qq_process_buddy_from_server(gc, funct, from, to, msg_utf8); 418 qq_process_buddy_from_server(gc, funct, from, to, msg_utf8);
174 break; 419 break;
175 case QQ_SERVER_NOTICE: 420 case QQ_SERVER_NOTICE:
176 process_server_notice(gc, from, to, msg_utf8); 421 do_server_notice(gc, from, to, msg_utf8);
177 break; 422 break;
178 case QQ_SERVER_NEW_CLIENT: 423 case QQ_SERVER_NEW_CLIENT:
179 purple_debug_warning("QQ", "QQ Server has newer client version\n"); 424 purple_debug_warning("QQ", "QQ Server has newer client version\n");
180 break; 425 break;
181 default: 426 default:
214 } 459 }
215 460
216 /* now process the packet */ 461 /* now process the packet */
217 switch (cmd) { 462 switch (cmd) {
218 case QQ_CMD_RECV_IM: 463 case QQ_CMD_RECV_IM:
219 qq_process_recv_im(data, data_len, seq, gc); 464 process_private_msg(data, data_len, seq, gc);
220 break; 465 break;
221 case QQ_CMD_RECV_MSG_SYS: 466 case QQ_CMD_RECV_MSG_SYS:
222 process_server_msg(data, data_len, seq, gc); 467 process_server_msg(data, data_len, seq, gc);
223 break; 468 break;
224 case QQ_CMD_BUDDY_CHANGE_STATUS: 469 case QQ_CMD_BUDDY_CHANGE_STATUS:
225 qq_process_buddy_change_status(data, data_len, gc); 470 qq_process_buddy_change_status(data, data_len, gc);
226 break; 471 break;
227 default: 472 default:
228 process_cmd_unknow(gc, _("Unknow SERVER CMD"), data, data_len, cmd, seq); 473 process_unknow_cmd(gc, _("Unknow SERVER CMD"), data, data_len, cmd, seq);
229 break; 474 break;
230 } 475 }
231 } 476 }
232 477
233 static void process_room_cmd_notify(PurpleConnection *gc, 478 static void process_room_cmd_notify(PurpleConnection *gc,
679 } 924 }
680 break; 925 break;
681 case QQ_CMD_CHECK_PWD: 926 case QQ_CMD_CHECK_PWD:
682 ret_8 = qq_process_check_pwd(gc, data, data_len); 927 ret_8 = qq_process_check_pwd(gc, data, data_len);
683 if (ret_8 != QQ_LOGIN_REPLY_OK) { 928 if (ret_8 != QQ_LOGIN_REPLY_OK) {
684 return ret_8; 929 return ret_8;
685 } 930 }
686 if (qd->client_version == 2008) { 931 if (qd->client_version == 2008) {
687 qq_request_login_2008(gc); 932 qq_request_login_2008(gc);
688 } else { 933 } else {
689 qq_request_login_2007(gc); 934 qq_request_login_2007(gc);
696 ret_8 = qq_process_login_2007(gc, data, data_len); 941 ret_8 = qq_process_login_2007(gc, data, data_len);
697 } else { 942 } else {
698 ret_8 = qq_process_login(gc, data, data_len); 943 ret_8 = qq_process_login(gc, data, data_len);
699 } 944 }
700 if (ret_8 != QQ_LOGIN_REPLY_OK) { 945 if (ret_8 != QQ_LOGIN_REPLY_OK) {
701 return ret_8; 946 return ret_8;
702 } 947 }
703 948
704 purple_connection_update_progress(gc, _("Logined"), QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS); 949 purple_connection_update_progress(gc, _("Logined"), QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS);
705 purple_debug_info("QQ", "Login repliess OK; everything is fine\n"); 950 purple_debug_info("QQ", "Login repliess OK; everything is fine\n");
706 purple_connection_set_state(gc, PURPLE_CONNECTED); 951 purple_connection_set_state(gc, PURPLE_CONNECTED);
713 qq_trans_process_remained(gc); 958 qq_trans_process_remained(gc);
714 959
715 qq_update_all(gc, 0); 960 qq_update_all(gc, 0);
716 break; 961 break;
717 default: 962 default:
718 process_cmd_unknow(gc, _("Unknow LOGIN CMD"), data, data_len, cmd, seq); 963 process_unknow_cmd(gc, _("Unknow LOGIN CMD"), data, data_len, cmd, seq);
719 return QQ_LOGIN_REPLY_ERR; 964 return QQ_LOGIN_REPLY_ERR;
720 } 965 }
721 return QQ_LOGIN_REPLY_OK; 966 return QQ_LOGIN_REPLY_OK;
722 } 967 }
723 968
777 break; 1022 break;
778 case QQ_CMD_CHANGE_STATUS: 1023 case QQ_CMD_CHANGE_STATUS:
779 qq_process_change_status_reply(data, data_len, gc); 1024 qq_process_change_status_reply(data, data_len, gc);
780 break; 1025 break;
781 case QQ_CMD_SEND_IM: 1026 case QQ_CMD_SEND_IM:
782 qq_process_send_im_reply(data, data_len, gc); 1027 do_im_ack(data, data_len, gc);
783 break; 1028 break;
784 case QQ_CMD_KEEP_ALIVE: 1029 case QQ_CMD_KEEP_ALIVE:
785 if (qd->client_version >= 2008) { 1030 if (qd->client_version >= 2008) {
786 qq_process_keep_alive_2008(data, data_len, gc); 1031 qq_process_keep_alive_2008(data, data_len, gc);
787 } else if (qd->client_version >= 2007) { 1032 } else if (qd->client_version >= 2007) {
820 return; 1065 return;
821 } 1066 }
822 purple_debug_info("QQ", "All buddies and groups received\n"); 1067 purple_debug_info("QQ", "All buddies and groups received\n");
823 break; 1068 break;
824 default: 1069 default:
825 process_cmd_unknow(gc, _("Unknow CLIENT CMD"), data, data_len, cmd, seq); 1070 process_unknow_cmd(gc, _("Unknow CLIENT CMD"), data, data_len, cmd, seq);
826 is_unknow = TRUE; 1071 is_unknow = TRUE;
827 break; 1072 break;
828 } 1073 }
829 if (is_unknow) 1074 if (is_unknow)
830 return; 1075 return;