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 {