Mercurial > pidgin.yaz
comparison libpurple/protocols/msn/msg.c @ 31292:47b6eda87723
propagate from branch 'im.pidgin.pidgin' (head 07d0765c444a097af45c2650f54323afb900a07b)
to branch 'im.pidgin.soc.2010.msn-tlc' (head f3998422a4724ab424e4e2328f58fc0504856557)
author | masca@cpw.pidgin.im |
---|---|
date | Mon, 19 Jul 2010 21:11:32 +0000 |
parents | 7edcf92b1537 |
children | 2d00d29a45fd |
comparison
equal
deleted
inserted
replaced
30698:e874875a74a7 | 31292:47b6eda87723 |
---|---|
19 * | 19 * |
20 * You should have received a copy of the GNU General Public License | 20 * You should have received a copy of the GNU General Public License |
21 * along with this program; if not, write to the Free Software | 21 * along with this program; if not, write to the Free Software |
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA | 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
23 */ | 23 */ |
24 | |
25 #include "internal.h" | |
26 #include "debug.h" | |
27 | |
24 #include "msn.h" | 28 #include "msn.h" |
25 #include "msg.h" | 29 #include "msg.h" |
26 #include "msnutils.h" | 30 #include "msnutils.h" |
31 #include "slpmsg.h" | |
32 #include "slpmsg_part.h" | |
27 | 33 |
28 MsnMessage * | 34 MsnMessage * |
29 msn_message_new(MsnMsgType type) | 35 msn_message_new(MsnMsgType type) |
30 { | 36 { |
31 MsnMessage *msg; | 37 MsnMessage *msg; |
34 msg->type = type; | 40 msg->type = type; |
35 | 41 |
36 if (purple_debug_is_verbose()) | 42 if (purple_debug_is_verbose()) |
37 purple_debug_info("msn", "message new (%p)(%d)\n", msg, type); | 43 purple_debug_info("msn", "message new (%p)(%d)\n", msg, type); |
38 | 44 |
39 msg->attr_table = g_hash_table_new_full(g_str_hash, g_str_equal, | 45 msg->header_table = g_hash_table_new_full(g_str_hash, g_str_equal, |
40 g_free, g_free); | 46 g_free, g_free); |
41 | 47 |
42 msn_message_ref(msg); | 48 msn_message_ref(msg); |
43 | 49 |
44 return msg; | 50 return msg; |
62 g_free(msg->remote_user); | 68 g_free(msg->remote_user); |
63 g_free(msg->body); | 69 g_free(msg->body); |
64 g_free(msg->content_type); | 70 g_free(msg->content_type); |
65 g_free(msg->charset); | 71 g_free(msg->charset); |
66 | 72 |
67 g_hash_table_destroy(msg->attr_table); | 73 g_hash_table_destroy(msg->header_table); |
68 g_list_free(msg->attr_list); | 74 g_list_free(msg->header_list); |
75 msn_slpmsgpart_destroy(msg->part); | |
69 | 76 |
70 g_free(msg); | 77 g_free(msg); |
71 } | 78 } |
72 | 79 |
73 MsnMessage * | 80 MsnMessage * |
110 MsnMessage *msg; | 117 MsnMessage *msg; |
111 char *message_cr; | 118 char *message_cr; |
112 | 119 |
113 msg = msn_message_new(MSN_MSG_TEXT); | 120 msg = msn_message_new(MSN_MSG_TEXT); |
114 msg->retries = 1; | 121 msg->retries = 1; |
115 msn_message_set_attr(msg, "User-Agent", PACKAGE_NAME "/" VERSION); | 122 msn_message_set_header(msg, "User-Agent", PACKAGE_NAME "/" VERSION); |
116 msn_message_set_content_type(msg, "text/plain"); | 123 msn_message_set_content_type(msg, "text/plain"); |
117 msn_message_set_charset(msg, "UTF-8"); | 124 msn_message_set_charset(msg, "UTF-8"); |
118 msn_message_set_flag(msg, 'A'); | 125 msn_message_set_flag(msg, 'A'); |
119 msn_message_set_attr(msg, "X-MMS-IM-Format", | 126 msn_message_set_header(msg, "X-MMS-IM-Format", |
120 "FN=Segoe%20UI; EF=; CO=0; CS=1;PF=0"); | 127 "FN=Segoe%20UI; EF=; CO=0; CS=1;PF=0"); |
121 | 128 |
122 message_cr = purple_str_add_cr(message); | 129 message_cr = purple_str_add_cr(message); |
123 msn_message_set_bin_data(msg, message_cr, strlen(message_cr)); | 130 msn_message_set_bin_data(msg, message_cr, strlen(message_cr)); |
124 g_free(message_cr); | 131 g_free(message_cr); |
131 { | 138 { |
132 MsnMessage *msg; | 139 MsnMessage *msg; |
133 | 140 |
134 msg = msn_message_new(MSN_MSG_SLP); | 141 msg = msn_message_new(MSN_MSG_SLP); |
135 | 142 |
136 msn_message_set_attr(msg, "User-Agent", NULL); | 143 msn_message_set_header(msg, "User-Agent", NULL); |
137 | 144 |
138 msg->msnslp_message = TRUE; | 145 msg->msnslp_message = TRUE; |
139 | 146 |
140 msn_message_set_flag(msg, 'D'); | 147 msn_message_set_flag(msg, 'D'); |
141 msn_message_set_content_type(msg, "application/x-msnmsgrp2p"); | 148 msn_message_set_content_type(msg, "application/x-msnmsgrp2p"); |
155 | 162 |
156 return msg; | 163 return msg; |
157 } | 164 } |
158 | 165 |
159 void | 166 void |
160 msn_message_parse_slp_body(MsnMessage *msg, const char *body, size_t len) | |
161 { | |
162 MsnSlpHeader header; | |
163 const char *tmp; | |
164 int body_len; | |
165 | |
166 tmp = body; | |
167 | |
168 if (len < sizeof(header)) { | |
169 g_return_if_reached(); | |
170 } | |
171 | |
172 /* Import the header. */ | |
173 memcpy(&header, tmp, sizeof(header)); | |
174 tmp += sizeof(header); | |
175 | |
176 msg->msnslp_header.session_id = GUINT32_FROM_LE(header.session_id); | |
177 msg->msnslp_header.id = GUINT32_FROM_LE(header.id); | |
178 msg->msnslp_header.offset = GUINT64_FROM_LE(header.offset); | |
179 msg->msnslp_header.total_size = GUINT64_FROM_LE(header.total_size); | |
180 msg->msnslp_header.length = GUINT32_FROM_LE(header.length); | |
181 msg->msnslp_header.flags = GUINT32_FROM_LE(header.flags); | |
182 msg->msnslp_header.ack_id = GUINT32_FROM_LE(header.ack_id); | |
183 msg->msnslp_header.ack_sub_id = GUINT32_FROM_LE(header.ack_sub_id); | |
184 msg->msnslp_header.ack_size = GUINT64_FROM_LE(header.ack_size); | |
185 | |
186 /* Import the body. */ | |
187 body_len = len - (tmp - body); | |
188 /* msg->body_len = msg->msnslp_header.length; */ | |
189 | |
190 if (body_len > 0) { | |
191 msg->body_len = len - (tmp - body); | |
192 msg->body = g_malloc(msg->body_len + 1); | |
193 memcpy(msg->body, tmp, msg->body_len); | |
194 msg->body[msg->body_len] = '\0'; | |
195 tmp += body_len; | |
196 } | |
197 } | |
198 | |
199 void | |
200 msn_message_parse_payload(MsnMessage *msg, | 167 msn_message_parse_payload(MsnMessage *msg, |
201 const char *payload, size_t payload_len, | 168 const char *payload, size_t payload_len, |
202 const char *line_dem,const char *body_dem) | 169 const char *line_dem,const char *body_dem) |
203 { | 170 { |
204 char *tmp_base, *tmp; | 171 char *tmp_base, *tmp; |
209 g_return_if_fail(payload != NULL); | 176 g_return_if_fail(payload != NULL); |
210 tmp_base = tmp = g_malloc(payload_len + 1); | 177 tmp_base = tmp = g_malloc(payload_len + 1); |
211 memcpy(tmp_base, payload, payload_len); | 178 memcpy(tmp_base, payload, payload_len); |
212 tmp_base[payload_len] = '\0'; | 179 tmp_base[payload_len] = '\0'; |
213 | 180 |
214 /* Parse the attributes. */ | 181 /* Find the end of the headers */ |
215 end = strstr(tmp, body_dem); | 182 end = strstr(tmp, body_dem); |
216 /* TODO? some clients use \r delimiters instead of \r\n, the official client | 183 /* TODO? some clients use \r delimiters instead of \r\n, the official client |
217 * doesn't send such messages, but does handle receiving them. We'll just | 184 * doesn't send such messages, but does handle receiving them. We'll just |
218 * avoid crashing for now */ | 185 * avoid crashing for now */ |
219 if (end == NULL) { | 186 if (end == NULL) { |
220 g_free(tmp_base); | 187 g_free(tmp_base); |
221 g_return_if_reached(); | 188 g_return_if_reached(); |
222 } | 189 } |
223 *end = '\0'; | 190 *end = '\0'; |
224 | 191 |
192 /* Split the headers and parse each one */ | |
225 elems = g_strsplit(tmp, line_dem, 0); | 193 elems = g_strsplit(tmp, line_dem, 0); |
226 | |
227 for (cur = elems; *cur != NULL; cur++) | 194 for (cur = elems; *cur != NULL; cur++) |
228 { | 195 { |
229 const char *key, *value; | 196 const char *key, *value; |
230 | 197 |
231 /* If this line starts with whitespace, it's been folded from the | 198 /* If this line starts with whitespace, it's been folded from the |
238 /* The only one I care about is 'boundary' (which is folded from | 205 /* The only one I care about is 'boundary' (which is folded from |
239 the key 'Content-Type'), so only process that. */ | 206 the key 'Content-Type'), so only process that. */ |
240 if (!strcmp(key, "boundary")) { | 207 if (!strcmp(key, "boundary")) { |
241 char *end = strchr(value, '\"'); | 208 char *end = strchr(value, '\"'); |
242 *end = '\0'; | 209 *end = '\0'; |
243 msn_message_set_attr(msg, key, value); | 210 msn_message_set_header(msg, key, value); |
244 } | 211 } |
245 | 212 |
246 g_strfreev(tokens); | 213 g_strfreev(tokens); |
247 continue; | 214 continue; |
248 } | 215 } |
276 | 243 |
277 msn_message_set_content_type(msg, value); | 244 msn_message_set_content_type(msg, value); |
278 } | 245 } |
279 else | 246 else |
280 { | 247 { |
281 msn_message_set_attr(msg, key, value); | 248 msn_message_set_header(msg, key, value); |
282 } | 249 } |
283 | 250 |
284 g_strfreev(tokens); | 251 g_strfreev(tokens); |
285 } | 252 } |
286 | |
287 g_strfreev(elems); | 253 g_strfreev(elems); |
288 | 254 |
289 /* Proceed to the end of the "\r\n\r\n" */ | 255 /* Proceed to the end of the "\r\n\r\n" */ |
290 tmp = end + strlen(body_dem); | 256 tmp = end + strlen(body_dem); |
291 | 257 |
292 /* Now we *should* be at the body. */ | 258 /* Now we *should* be at the body. */ |
293 content_type = msn_message_get_content_type(msg); | 259 content_type = msn_message_get_content_type(msg); |
294 | 260 |
295 if (content_type != NULL && | 261 if (content_type != NULL && |
296 !strcmp(content_type, "application/x-msnmsgrp2p")) | 262 !strcmp(content_type, "application/x-msnmsgrp2p")) { |
297 { | |
298 MsnSlpHeader header; | |
299 MsnSlpFooter footer; | |
300 int body_len; | |
301 | |
302 if (payload_len - (tmp - tmp_base) < sizeof(header)) { | |
303 g_free(tmp_base); | |
304 g_return_if_reached(); | |
305 } | |
306 | |
307 msg->msnslp_message = TRUE; | 263 msg->msnslp_message = TRUE; |
308 | 264 msg->part = msn_slpmsgpart_new_from_data(tmp, payload_len - (tmp - tmp_base)); |
309 /* Import the header. */ | 265 } |
310 memcpy(&header, tmp, sizeof(header)); | 266 |
311 tmp += sizeof(header); | 267 if (payload_len - (tmp - tmp_base) > 0) { |
312 | 268 msg->body_len = payload_len - (tmp - tmp_base); |
313 msg->msnslp_header.session_id = GUINT32_FROM_LE(header.session_id); | 269 g_free(msg->body); |
314 msg->msnslp_header.id = GUINT32_FROM_LE(header.id); | 270 msg->body = g_malloc(msg->body_len + 1); |
315 msg->msnslp_header.offset = GUINT64_FROM_LE(header.offset); | 271 memcpy(msg->body, tmp, msg->body_len); |
316 msg->msnslp_header.total_size = GUINT64_FROM_LE(header.total_size); | 272 msg->body[msg->body_len] = '\0'; |
317 msg->msnslp_header.length = GUINT32_FROM_LE(header.length); | 273 } |
318 msg->msnslp_header.flags = GUINT32_FROM_LE(header.flags); | 274 |
319 msg->msnslp_header.ack_id = GUINT32_FROM_LE(header.ack_id); | 275 if ((!content_type || !strcmp(content_type, "text/plain")) |
320 msg->msnslp_header.ack_sub_id = GUINT32_FROM_LE(header.ack_sub_id); | |
321 msg->msnslp_header.ack_size = GUINT64_FROM_LE(header.ack_size); | |
322 | |
323 body_len = payload_len - (tmp - tmp_base) - sizeof(footer); | |
324 | |
325 /* Import the body. */ | |
326 if (body_len > 0) { | |
327 msg->body_len = body_len; | |
328 g_free(msg->body); | |
329 msg->body = g_malloc(msg->body_len + 1); | |
330 memcpy(msg->body, tmp, msg->body_len); | |
331 msg->body[msg->body_len] = '\0'; | |
332 tmp += body_len; | |
333 } | |
334 | |
335 /* Import the footer. */ | |
336 if (body_len >= 0) { | |
337 memcpy(&footer, tmp, sizeof(footer)); | |
338 tmp += sizeof(footer); | |
339 msg->msnslp_footer.value = GUINT32_FROM_BE(footer.value); | |
340 } | |
341 } | |
342 else | |
343 { | |
344 if (payload_len - (tmp - tmp_base) > 0) { | |
345 msg->body_len = payload_len - (tmp - tmp_base); | |
346 g_free(msg->body); | |
347 msg->body = g_malloc(msg->body_len + 1); | |
348 memcpy(msg->body, tmp, msg->body_len); | |
349 msg->body[msg->body_len] = '\0'; | |
350 } | |
351 | |
352 if ((!content_type || !strcmp(content_type, "text/plain")) | |
353 && msg->charset == NULL) { | 276 && msg->charset == NULL) { |
354 char *body = g_convert(msg->body, msg->body_len, "UTF-8", | 277 char *body = g_convert(msg->body, msg->body_len, "UTF-8", |
355 "ISO-8859-1", NULL, &msg->body_len, NULL); | 278 "ISO-8859-1", NULL, &msg->body_len, NULL); |
356 g_free(msg->body); | 279 g_free(msg->body); |
357 msg->body = body; | 280 msg->body = body; |
358 msg->charset = g_strdup("UTF-8"); | 281 msg->charset = g_strdup("UTF-8"); |
359 } | |
360 } | 282 } |
361 | 283 |
362 g_free(tmp_base); | 284 g_free(tmp_base); |
363 } | 285 } |
364 | 286 |
379 } | 301 } |
380 | 302 |
381 char * | 303 char * |
382 msn_message_gen_slp_body(MsnMessage *msg, size_t *ret_size) | 304 msn_message_gen_slp_body(MsnMessage *msg, size_t *ret_size) |
383 { | 305 { |
384 MsnSlpHeader header; | 306 char *tmp; |
385 | 307 |
386 char *tmp, *base; | 308 tmp = msn_slpmsgpart_serialize(msg->part, ret_size); |
387 const void *body; | 309 return tmp; |
388 size_t len, body_len; | |
389 | |
390 g_return_val_if_fail(msg != NULL, NULL); | |
391 | |
392 len = MSN_BUF_LEN; | |
393 | |
394 base = tmp = g_malloc(len + 1); | |
395 | |
396 body = msn_message_get_bin_data(msg, &body_len); | |
397 | |
398 header.session_id = GUINT32_TO_LE(msg->msnslp_header.session_id); | |
399 header.id = GUINT32_TO_LE(msg->msnslp_header.id); | |
400 header.offset = GUINT64_TO_LE(msg->msnslp_header.offset); | |
401 header.total_size = GUINT64_TO_LE(msg->msnslp_header.total_size); | |
402 header.length = GUINT32_TO_LE(msg->msnslp_header.length); | |
403 header.flags = GUINT32_TO_LE(msg->msnslp_header.flags); | |
404 header.ack_id = GUINT32_TO_LE(msg->msnslp_header.ack_id); | |
405 header.ack_sub_id = GUINT32_TO_LE(msg->msnslp_header.ack_sub_id); | |
406 header.ack_size = GUINT64_TO_LE(msg->msnslp_header.ack_size); | |
407 | |
408 memcpy(tmp, &header, 48); | |
409 tmp += 48; | |
410 | |
411 if (body != NULL) | |
412 { | |
413 memcpy(tmp, body, body_len); | |
414 tmp += body_len; | |
415 } | |
416 | |
417 if (ret_size != NULL) | |
418 *ret_size = tmp - base; | |
419 | |
420 return base; | |
421 } | 310 } |
422 | 311 |
423 char * | 312 char * |
424 msn_message_gen_payload(MsnMessage *msg, size_t *ret_size) | 313 msn_message_gen_payload(MsnMessage *msg, size_t *ret_size) |
425 { | 314 { |
452 msg->content_type, msg->charset); | 341 msg->content_type, msg->charset); |
453 } | 342 } |
454 | 343 |
455 n += strlen(n); | 344 n += strlen(n); |
456 | 345 |
457 for (l = msg->attr_list; l != NULL; l = l->next) | 346 for (l = msg->header_list; l != NULL; l = l->next) |
458 { | 347 { |
459 const char *key; | 348 const char *key; |
460 const char *value; | 349 const char *value; |
461 | 350 |
462 key = l->data; | 351 key = l->data; |
463 value = msn_message_get_attr(msg, key); | 352 value = msn_message_get_header_value(msg, key); |
464 | 353 |
465 g_snprintf(n, end - n, "%s: %s\r\n", key, value); | 354 g_snprintf(n, end - n, "%s: %s\r\n", key, value); |
466 n += strlen(n); | 355 n += strlen(n); |
467 } | 356 } |
468 | 357 |
470 | 359 |
471 body = msn_message_get_bin_data(msg, &body_len); | 360 body = msn_message_get_bin_data(msg, &body_len); |
472 | 361 |
473 if (msg->msnslp_message) | 362 if (msg->msnslp_message) |
474 { | 363 { |
475 MsnSlpHeader header; | 364 size_t siz; |
476 MsnSlpFooter footer; | 365 char *body; |
477 | 366 |
478 header.session_id = GUINT32_TO_LE(msg->msnslp_header.session_id); | 367 body = msn_slpmsgpart_serialize(msg->part, &siz); |
479 header.id = GUINT32_TO_LE(msg->msnslp_header.id); | 368 |
480 header.offset = GUINT64_TO_LE(msg->msnslp_header.offset); | 369 memcpy(n, body, siz); |
481 header.total_size = GUINT64_TO_LE(msg->msnslp_header.total_size); | 370 n += siz; |
482 header.length = GUINT32_TO_LE(msg->msnslp_header.length); | |
483 header.flags = GUINT32_TO_LE(msg->msnslp_header.flags); | |
484 header.ack_id = GUINT32_TO_LE(msg->msnslp_header.ack_id); | |
485 header.ack_sub_id = GUINT32_TO_LE(msg->msnslp_header.ack_sub_id); | |
486 header.ack_size = GUINT64_TO_LE(msg->msnslp_header.ack_size); | |
487 | |
488 memcpy(n, &header, 48); | |
489 n += 48; | |
490 | |
491 if (body != NULL) | |
492 { | |
493 memcpy(n, body, body_len); | |
494 | |
495 n += body_len; | |
496 } | |
497 | |
498 footer.value = GUINT32_TO_BE(msg->msnslp_footer.value); | |
499 | |
500 memcpy(n, &footer, 4); | |
501 n += 4; | |
502 } | 371 } |
503 else | 372 else |
504 { | 373 { |
505 if (body != NULL) | 374 if (body != NULL) |
506 { | 375 { |
608 | 477 |
609 return msg->charset; | 478 return msg->charset; |
610 } | 479 } |
611 | 480 |
612 void | 481 void |
613 msn_message_set_attr(MsnMessage *msg, const char *attr, const char *value) | 482 msn_message_set_header(MsnMessage *msg, const char *name, const char *value) |
614 { | 483 { |
615 const char *temp; | 484 const char *temp; |
616 char *new_attr; | 485 char *new_name; |
617 | 486 |
618 g_return_if_fail(msg != NULL); | 487 g_return_if_fail(msg != NULL); |
619 g_return_if_fail(attr != NULL); | 488 g_return_if_fail(name != NULL); |
620 | 489 |
621 temp = msn_message_get_attr(msg, attr); | 490 temp = msn_message_get_header_value(msg, name); |
622 | 491 |
623 if (value == NULL) | 492 if (value == NULL) |
624 { | 493 { |
625 if (temp != NULL) | 494 if (temp != NULL) |
626 { | 495 { |
627 GList *l; | 496 GList *l; |
628 | 497 |
629 for (l = msg->attr_list; l != NULL; l = l->next) | 498 for (l = msg->header_list; l != NULL; l = l->next) |
630 { | 499 { |
631 if (!g_ascii_strcasecmp(l->data, attr)) | 500 if (!g_ascii_strcasecmp(l->data, name)) |
632 { | 501 { |
633 msg->attr_list = g_list_remove(msg->attr_list, l->data); | 502 msg->header_list = g_list_remove(msg->header_list, l->data); |
634 | 503 |
635 break; | 504 break; |
636 } | 505 } |
637 } | 506 } |
638 | 507 |
639 g_hash_table_remove(msg->attr_table, attr); | 508 g_hash_table_remove(msg->header_table, name); |
640 } | 509 } |
641 | 510 |
642 return; | 511 return; |
643 } | 512 } |
644 | 513 |
645 new_attr = g_strdup(attr); | 514 new_name = g_strdup(name); |
646 | 515 |
647 g_hash_table_insert(msg->attr_table, new_attr, g_strdup(value)); | 516 g_hash_table_insert(msg->header_table, new_name, g_strdup(value)); |
648 | 517 |
649 if (temp == NULL) | 518 if (temp == NULL) |
650 msg->attr_list = g_list_append(msg->attr_list, new_attr); | 519 msg->header_list = g_list_append(msg->header_list, new_name); |
651 } | 520 } |
652 | 521 |
653 const char * | 522 const char * |
654 msn_message_get_attr(const MsnMessage *msg, const char *attr) | 523 msn_message_get_header_value(const MsnMessage *msg, const char *name) |
655 { | 524 { |
656 g_return_val_if_fail(msg != NULL, NULL); | 525 g_return_val_if_fail(msg != NULL, NULL); |
657 g_return_val_if_fail(attr != NULL, NULL); | 526 g_return_val_if_fail(name != NULL, NULL); |
658 | 527 |
659 return g_hash_table_lookup(msg->attr_table, attr); | 528 return g_hash_table_lookup(msg->header_table, name); |
660 } | 529 } |
661 | 530 |
662 GHashTable * | 531 GHashTable * |
663 msn_message_get_hashtable_from_body(const MsnMessage *msg) | 532 msn_message_get_hashtable_from_body(const MsnMessage *msg) |
664 { | 533 { |
739 "MIME-Version: 1.0\r\n" | 608 "MIME-Version: 1.0\r\n" |
740 "Content-Type: %s; charset=%s\r\n", | 609 "Content-Type: %s; charset=%s\r\n", |
741 msg->content_type, msg->charset); | 610 msg->content_type, msg->charset); |
742 } | 611 } |
743 | 612 |
744 for (l = msg->attr_list; l; l = l->next) | 613 for (l = msg->header_list; l; l = l->next) |
745 { | 614 { |
746 char *key; | 615 char *key; |
747 const char *value; | 616 const char *value; |
748 | 617 |
749 key = l->data; | 618 key = l->data; |
750 value = msn_message_get_attr(msg, key); | 619 value = msn_message_get_header_value(msg, key); |
751 | 620 |
752 g_string_append_printf(str, "%s: %s\r\n", key, value); | 621 g_string_append_printf(str, "%s: %s\r\n", key, value); |
753 } | 622 } |
754 | 623 |
755 g_string_append(str, "\r\n"); | 624 g_string_append(str, "\r\n"); |
756 | 625 |
757 body = msn_message_get_bin_data(msg, &body_len); | 626 body = msn_message_get_bin_data(msg, &body_len); |
758 | 627 |
759 if (msg->msnslp_message) | 628 if (msg->msnslp_message) |
760 { | 629 { |
761 g_string_append_printf(str, "Session ID: %u\r\n", msg->msnslp_header.session_id); | 630 g_string_append_printf(str, "Session ID: %u\r\n", msg->part->header->session_id); |
762 g_string_append_printf(str, "ID: %u\r\n", msg->msnslp_header.id); | 631 g_string_append_printf(str, "ID: %u\r\n", msg->part->header->id); |
763 g_string_append_printf(str, "Offset: %" G_GUINT64_FORMAT "\r\n", msg->msnslp_header.offset); | 632 g_string_append_printf(str, "Offset: %" G_GUINT64_FORMAT "\r\n", msg->part->header->offset); |
764 g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", msg->msnslp_header.total_size); | 633 g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", msg->part->header->total_size); |
765 g_string_append_printf(str, "Length: %u\r\n", msg->msnslp_header.length); | 634 g_string_append_printf(str, "Length: %u\r\n", msg->part->header->length); |
766 g_string_append_printf(str, "Flags: 0x%x\r\n", msg->msnslp_header.flags); | 635 g_string_append_printf(str, "Flags: 0x%x\r\n", msg->part->header->flags); |
767 g_string_append_printf(str, "ACK ID: %u\r\n", msg->msnslp_header.ack_id); | 636 g_string_append_printf(str, "ACK ID: %u\r\n", msg->part->header->ack_id); |
768 g_string_append_printf(str, "SUB ID: %u\r\n", msg->msnslp_header.ack_sub_id); | 637 g_string_append_printf(str, "SUB ID: %u\r\n", msg->part->header->ack_sub_id); |
769 g_string_append_printf(str, "ACK Size: %" G_GUINT64_FORMAT "\r\n", msg->msnslp_header.ack_size); | 638 g_string_append_printf(str, "ACK Size: %" G_GUINT64_FORMAT "\r\n", msg->part->header->ack_size); |
770 | 639 |
771 if (purple_debug_is_verbose() && body != NULL) | 640 if (purple_debug_is_verbose() && body != NULL) |
772 { | 641 { |
773 if (text_body) | 642 if (text_body) |
774 { | 643 { |
781 g_string_append(str, "\r\n"); | 650 g_string_append(str, "\r\n"); |
782 } | 651 } |
783 else | 652 else |
784 { | 653 { |
785 int i; | 654 int i; |
786 for (i = 0; i < msg->body_len; i++) | 655 int bin_len; |
656 | |
657 if (msg->part->footer->value == P2P_APPID_SESION) | |
658 bin_len = P2P_PACKET_HEADER_SIZE; | |
659 else | |
660 bin_len = body_len; | |
661 | |
662 for (i = 0; i < bin_len; i++) | |
787 { | 663 { |
788 g_string_append_printf(str, "%.2hhX ", body[i]); | 664 g_string_append_printf(str, "%.2hhX ", body[i]); |
789 if ((i % 16) == 15) | 665 if ((i % 16) == 15) |
790 g_string_append(str, "\r\n"); | 666 g_string_append(str, "\r\n"); |
791 } | 667 } |
668 | |
669 if (bin_len == P2P_PACKET_HEADER_SIZE) | |
670 g_string_append_printf(str, "%s ", body + P2P_PACKET_HEADER_SIZE); | |
792 g_string_append(str, "\r\n"); | 671 g_string_append(str, "\r\n"); |
793 } | 672 } |
794 } | 673 } |
795 | 674 |
796 g_string_append_printf(str, "Footer: %u\r\n", msg->msnslp_footer.value); | 675 g_string_append_printf(str, "Footer: 0x%08X\r\n", msg->part->footer->value); |
797 } | 676 } |
798 else | 677 else |
799 { | 678 { |
800 if (body != NULL) | 679 if (body != NULL) |
801 { | 680 { |
815 void | 694 void |
816 msn_plain_msg(MsnCmdProc *cmdproc, MsnMessage *msg) | 695 msn_plain_msg(MsnCmdProc *cmdproc, MsnMessage *msg) |
817 { | 696 { |
818 PurpleConnection *gc; | 697 PurpleConnection *gc; |
819 const char *body; | 698 const char *body; |
820 char *body_str; | |
821 char *body_enc; | 699 char *body_enc; |
822 char *body_final; | 700 char *body_final; |
823 size_t body_len; | 701 size_t body_len; |
824 const char *passport; | 702 const char *passport; |
825 const char *value; | 703 const char *value; |
826 | 704 |
827 gc = cmdproc->session->account->gc; | 705 gc = cmdproc->session->account->gc; |
828 | 706 |
829 body = msn_message_get_bin_data(msg, &body_len); | 707 body = msn_message_get_bin_data(msg, &body_len); |
830 body_str = g_strndup(body, body_len); | 708 body_enc = g_markup_escape_text(body, body_len); |
831 body_enc = g_markup_escape_text(body_str, -1); | |
832 g_free(body_str); | |
833 | 709 |
834 passport = msg->remote_user; | 710 passport = msg->remote_user; |
835 | 711 |
836 if (!strcmp(passport, "messenger@microsoft.com") && | 712 if (!strcmp(passport, "messenger@microsoft.com") && |
837 strstr(body, "immediate security update")) | 713 strstr(body, "immediate security update")) |
838 { | 714 { |
839 return; | 715 return; |
840 } | 716 } |
841 | 717 |
842 #if 0 | 718 #if 0 |
843 if ((value = msn_message_get_attr(msg, "User-Agent")) != NULL) | 719 if ((value = msn_message_get_header_value(msg, "User-Agent")) != NULL) |
844 { | 720 { |
845 purple_debug_misc("msn", "User-Agent = '%s'\n", value); | 721 purple_debug_misc("msn", "User-Agent = '%s'\n", value); |
846 } | 722 } |
847 #endif | 723 #endif |
848 | 724 |
849 if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) | 725 if ((value = msn_message_get_header_value(msg, "X-MMS-IM-Format")) != NULL) |
850 { | 726 { |
851 char *pre, *post; | 727 char *pre, *post; |
852 | 728 |
853 msn_parse_format(value, &pre, &post); | 729 msn_parse_format(value, &pre, &post); |
854 | 730 |
885 { | 761 { |
886 swboard->conv = purple_find_chat(gc, swboard->chat_id); | 762 swboard->conv = purple_find_chat(gc, swboard->chat_id); |
887 swboard->flag |= MSN_SB_FLAG_IM; | 763 swboard->flag |= MSN_SB_FLAG_IM; |
888 } | 764 } |
889 } | 765 } |
890 else | 766 else if (!g_str_equal(passport, purple_account_get_username(gc->account))) |
891 { | 767 { |
768 /* Don't im ourselves ... */ | |
892 serv_got_im(gc, passport, body_final, 0, time(NULL)); | 769 serv_got_im(gc, passport, body_final, 0, time(NULL)); |
893 if (swboard->conv == NULL) | 770 if (swboard->conv == NULL) |
894 { | 771 { |
895 swboard->conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, | 772 swboard->conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, |
896 passport, purple_connection_get_account(gc)); | 773 passport, purple_connection_get_account(gc)); |
912 char *passport; | 789 char *passport; |
913 | 790 |
914 gc = cmdproc->session->account->gc; | 791 gc = cmdproc->session->account->gc; |
915 passport = msg->remote_user; | 792 passport = msg->remote_user; |
916 | 793 |
917 if (msn_message_get_attr(msg, "TypingUser") == NULL) | 794 if (msn_message_get_header_value(msg, "TypingUser") == NULL) |
918 return; | 795 return; |
919 | 796 |
920 if (cmdproc->servconn->type == MSN_SERVCONN_SB) { | 797 if (cmdproc->servconn->type == MSN_SERVCONN_SB) { |
921 MsnSwitchBoard *swboard = cmdproc->data; | 798 MsnSwitchBoard *swboard = cmdproc->data; |
922 | 799 |
1030 NULL); | 907 NULL); |
1031 } | 908 } |
1032 if (f) | 909 if (f) |
1033 fclose(f); | 910 fclose(f); |
1034 g_free(path); | 911 g_free(path); |
912 } | |
913 | |
914 void | |
915 msn_p2p_msg(MsnCmdProc *cmdproc, MsnMessage *msg) | |
916 { | |
917 MsnSession *session; | |
918 MsnSlpLink *slplink; | |
919 const char *data; | |
920 gsize len; | |
921 | |
922 session = cmdproc->servconn->session; | |
923 slplink = msn_session_get_slplink(session, msg->remote_user); | |
924 | |
925 if (slplink->swboard == NULL) | |
926 { | |
927 /* | |
928 * We will need swboard in order to change its flags. If its | |
929 * NULL, something has probably gone wrong earlier on. I | |
930 * didn't want to do this, but MSN 7 is somehow causing us | |
931 * to crash here, I couldn't reproduce it to debug more, | |
932 * and people are reporting bugs. Hopefully this doesn't | |
933 * cause more crashes. Stu. | |
934 */ | |
935 if (cmdproc->data == NULL) | |
936 g_warning("msn_p2p_msg cmdproc->data was NULL\n"); | |
937 else { | |
938 slplink->swboard = (MsnSwitchBoard *)cmdproc->data; | |
939 slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink); | |
940 } | |
941 } | |
942 | |
943 data = msn_message_get_bin_data(msg, &len); | |
944 | |
945 if (msg->part) { | |
946 len -= P2P_PACKET_HEADER_SIZE; | |
947 len -= P2P_PACKET_FOOTER_SIZE; | |
948 | |
949 msn_slplink_process_msg(slplink, msg->part->header, data+P2P_PACKET_HEADER_SIZE, len); | |
950 } | |
951 else /* This should never happen. */ | |
952 purple_debug_fatal("msn", "P2P message without a Part.\n"); | |
953 } | |
954 | |
955 static void | |
956 got_emoticon(MsnSlpCall *slpcall, | |
957 const guchar *data, gsize size) | |
958 { | |
959 PurpleConversation *conv; | |
960 MsnSwitchBoard *swboard; | |
961 | |
962 swboard = slpcall->slplink->swboard; | |
963 conv = swboard->conv; | |
964 | |
965 if (conv) { | |
966 /* FIXME: it would be better if we wrote the data as we received it | |
967 instead of all at once, calling write multiple times and | |
968 close once at the very end | |
969 */ | |
970 purple_conv_custom_smiley_write(conv, slpcall->data_info, data, size); | |
971 purple_conv_custom_smiley_close(conv, slpcall->data_info ); | |
972 } | |
973 if (purple_debug_is_verbose()) | |
974 purple_debug_info("msn", "Got smiley: %s\n", slpcall->data_info); | |
975 } | |
976 | |
977 void msn_emoticon_msg(MsnCmdProc *cmdproc, MsnMessage *msg) | |
978 { | |
979 MsnSession *session; | |
980 MsnSlpLink *slplink; | |
981 MsnSwitchBoard *swboard; | |
982 MsnObject *obj; | |
983 char **tokens; | |
984 char *smile, *body_str; | |
985 const char *body, *who, *sha1; | |
986 guint tok; | |
987 size_t body_len; | |
988 | |
989 PurpleConversation *conv; | |
990 | |
991 session = cmdproc->servconn->session; | |
992 | |
993 if (!purple_account_get_bool(session->account, "custom_smileys", TRUE)) | |
994 return; | |
995 | |
996 swboard = cmdproc->data; | |
997 conv = swboard->conv; | |
998 | |
999 body = msn_message_get_bin_data(msg, &body_len); | |
1000 if (!body || !body_len) | |
1001 return; | |
1002 body_str = g_strndup(body, body_len); | |
1003 | |
1004 /* MSN Messenger 7 may send more than one MSNObject in a single message... | |
1005 * Maybe 10 tokens is a reasonable max value. */ | |
1006 tokens = g_strsplit(body_str, "\t", 10); | |
1007 | |
1008 g_free(body_str); | |
1009 | |
1010 for (tok = 0; tok < 9; tok += 2) { | |
1011 if (tokens[tok] == NULL || tokens[tok + 1] == NULL) { | |
1012 break; | |
1013 } | |
1014 | |
1015 smile = tokens[tok]; | |
1016 obj = msn_object_new_from_string(purple_url_decode(tokens[tok + 1])); | |
1017 | |
1018 if (obj == NULL) | |
1019 break; | |
1020 | |
1021 who = msn_object_get_creator(obj); | |
1022 sha1 = msn_object_get_sha1(obj); | |
1023 | |
1024 slplink = msn_session_get_slplink(session, who); | |
1025 if (slplink->swboard != swboard) { | |
1026 if (slplink->swboard != NULL) | |
1027 /* | |
1028 * Apparently we're using a different switchboard now or | |
1029 * something? I don't know if this is normal, but it | |
1030 * definitely happens. So make sure the old switchboard | |
1031 * doesn't still have a reference to us. | |
1032 */ | |
1033 slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink); | |
1034 slplink->swboard = swboard; | |
1035 slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink); | |
1036 } | |
1037 | |
1038 /* If the conversation doesn't exist then this is a custom smiley | |
1039 * used in the first message in a MSN conversation: we need to create | |
1040 * the conversation now, otherwise the custom smiley won't be shown. | |
1041 * This happens because every GtkIMHtml has its own smiley tree: if | |
1042 * the conversation doesn't exist then we cannot associate the new | |
1043 * smiley with its GtkIMHtml widget. */ | |
1044 if (!conv) { | |
1045 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, session->account, who); | |
1046 } | |
1047 | |
1048 if (purple_conv_custom_smiley_add(conv, smile, "sha1", sha1, TRUE)) { | |
1049 msn_slplink_request_object(slplink, smile, got_emoticon, NULL, obj); | |
1050 } | |
1051 | |
1052 msn_object_destroy(obj); | |
1053 obj = NULL; | |
1054 who = NULL; | |
1055 sha1 = NULL; | |
1056 } | |
1057 g_strfreev(tokens); | |
1035 } | 1058 } |
1036 | 1059 |
1037 void | 1060 void |
1038 msn_datacast_msg(MsnCmdProc *cmdproc, MsnMessage *msg) | 1061 msn_datacast_msg(MsnCmdProc *cmdproc, MsnMessage *msg) |
1039 { | 1062 { |