Mercurial > pidgin
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; |