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