Mercurial > pidgin.yaz
comparison libpurple/protocols/msnp9/slp.c @ 21312:a07cfce78345
Add MSNP9 back as an alternative alongside the existing MSN prpl. Cowardly
old fools like me who prefer the stability of our MSNP9 code over the
features of MSNP14 can enable this using the --disable-msnp14 ./configure
option.
If we want to release from i.p.p and MSN stability is the only blocker, we
can trivially flick the default to use MSNP9 in configure.ac
author | Stu Tomlinson <stu@nosnilmot.com> |
---|---|
date | Sun, 11 Nov 2007 12:57:52 +0000 |
parents | |
children | 981a0bfc3d9d |
comparison
equal
deleted
inserted
replaced
21311:7d031cec5ba2 | 21312:a07cfce78345 |
---|---|
1 /** | |
2 * @file msnslp.c MSNSLP support | |
3 * | |
4 * purple | |
5 * | |
6 * Purple is the legal property of its developers, whose names are too numerous | |
7 * to list here. Please refer to the COPYRIGHT file distributed with this | |
8 * source distribution. | |
9 * | |
10 * This program is free software; you can redistribute it and/or modify | |
11 * it under the terms of the GNU General Public License as published by | |
12 * the Free Software Foundation; either version 2 of the License, or | |
13 * (at your option) any later version. | |
14 * | |
15 * This program is distributed in the hope that it will be useful, | |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 * GNU General Public License for more details. | |
19 * | |
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 | |
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA | |
23 */ | |
24 #include "msn.h" | |
25 #include "slp.h" | |
26 #include "slpcall.h" | |
27 #include "slpmsg.h" | |
28 #include "slpsession.h" | |
29 | |
30 #include "object.h" | |
31 #include "user.h" | |
32 #include "switchboard.h" | |
33 | |
34 /* ms to delay between sending buddy icon requests to the server. */ | |
35 #define BUDDY_ICON_DELAY 20000 | |
36 | |
37 static void send_ok(MsnSlpCall *slpcall, const char *branch, | |
38 const char *type, const char *content); | |
39 | |
40 static void send_decline(MsnSlpCall *slpcall, const char *branch, | |
41 const char *type, const char *content); | |
42 | |
43 void msn_request_user_display(MsnUser *user); | |
44 | |
45 /************************************************************************** | |
46 * Util | |
47 **************************************************************************/ | |
48 | |
49 static char * | |
50 get_token(const char *str, const char *start, const char *end) | |
51 { | |
52 const char *c, *c2; | |
53 | |
54 if ((c = strstr(str, start)) == NULL) | |
55 return NULL; | |
56 | |
57 c += strlen(start); | |
58 | |
59 if (end != NULL) | |
60 { | |
61 if ((c2 = strstr(c, end)) == NULL) | |
62 return NULL; | |
63 | |
64 return g_strndup(c, c2 - c); | |
65 } | |
66 else | |
67 { | |
68 /* This has to be changed */ | |
69 return g_strdup(c); | |
70 } | |
71 | |
72 } | |
73 | |
74 /************************************************************************** | |
75 * Xfer | |
76 **************************************************************************/ | |
77 | |
78 static void | |
79 msn_xfer_init(PurpleXfer *xfer) | |
80 { | |
81 MsnSlpCall *slpcall; | |
82 /* MsnSlpLink *slplink; */ | |
83 char *content; | |
84 | |
85 purple_debug_info("msn", "xfer_init\n"); | |
86 | |
87 slpcall = xfer->data; | |
88 | |
89 /* Send Ok */ | |
90 content = g_strdup_printf("SessionID: %lu\r\n\r\n", | |
91 slpcall->session_id); | |
92 | |
93 send_ok(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody", | |
94 content); | |
95 | |
96 g_free(content); | |
97 msn_slplink_unleash(slpcall->slplink); | |
98 } | |
99 | |
100 void | |
101 msn_xfer_cancel(PurpleXfer *xfer) | |
102 { | |
103 MsnSlpCall *slpcall; | |
104 char *content; | |
105 | |
106 g_return_if_fail(xfer != NULL); | |
107 g_return_if_fail(xfer->data != NULL); | |
108 | |
109 slpcall = xfer->data; | |
110 | |
111 if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) | |
112 { | |
113 if (slpcall->started) | |
114 { | |
115 msn_slp_call_close(slpcall); | |
116 } | |
117 else | |
118 { | |
119 content = g_strdup_printf("SessionID: %lu\r\n\r\n", | |
120 slpcall->session_id); | |
121 | |
122 send_decline(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody", | |
123 content); | |
124 | |
125 g_free(content); | |
126 msn_slplink_unleash(slpcall->slplink); | |
127 | |
128 msn_slp_call_destroy(slpcall); | |
129 } | |
130 } | |
131 } | |
132 | |
133 void | |
134 msn_xfer_progress_cb(MsnSlpCall *slpcall, gsize total_length, gsize len, gsize offset) | |
135 { | |
136 PurpleXfer *xfer; | |
137 | |
138 xfer = slpcall->xfer; | |
139 | |
140 xfer->bytes_sent = (offset + len); | |
141 xfer->bytes_remaining = total_length - (offset + len); | |
142 | |
143 purple_xfer_update_progress(xfer); | |
144 } | |
145 | |
146 void | |
147 msn_xfer_end_cb(MsnSlpCall *slpcall, MsnSession *session) | |
148 { | |
149 if ((purple_xfer_get_status(slpcall->xfer) != PURPLE_XFER_STATUS_DONE) && | |
150 (purple_xfer_get_status(slpcall->xfer) != PURPLE_XFER_STATUS_CANCEL_REMOTE) && | |
151 (purple_xfer_get_status(slpcall->xfer) != PURPLE_XFER_STATUS_CANCEL_LOCAL)) | |
152 { | |
153 purple_xfer_cancel_remote(slpcall->xfer); | |
154 } | |
155 } | |
156 | |
157 void | |
158 msn_xfer_completed_cb(MsnSlpCall *slpcall, const guchar *body, | |
159 gsize size) | |
160 { | |
161 PurpleXfer *xfer = slpcall->xfer; | |
162 purple_xfer_set_completed(xfer, TRUE); | |
163 purple_xfer_end(xfer); | |
164 } | |
165 | |
166 /************************************************************************** | |
167 * SLP Control | |
168 **************************************************************************/ | |
169 | |
170 #if 0 | |
171 static void | |
172 got_transresp(MsnSlpCall *slpcall, const char *nonce, | |
173 const char *ips_str, int port) | |
174 { | |
175 MsnDirectConn *directconn; | |
176 char **ip_addrs, **c; | |
177 | |
178 directconn = msn_directconn_new(slpcall->slplink); | |
179 | |
180 directconn->initial_call = slpcall; | |
181 | |
182 /* msn_directconn_parse_nonce(directconn, nonce); */ | |
183 directconn->nonce = g_strdup(nonce); | |
184 | |
185 ip_addrs = g_strsplit(ips_str, " ", -1); | |
186 | |
187 for (c = ip_addrs; *c != NULL; c++) | |
188 { | |
189 purple_debug_info("msn", "ip_addr = %s\n", *c); | |
190 if (msn_directconn_connect(directconn, *c, port)) | |
191 break; | |
192 } | |
193 | |
194 g_strfreev(ip_addrs); | |
195 } | |
196 #endif | |
197 | |
198 static void | |
199 send_ok(MsnSlpCall *slpcall, const char *branch, | |
200 const char *type, const char *content) | |
201 { | |
202 MsnSlpLink *slplink; | |
203 MsnSlpMessage *slpmsg; | |
204 | |
205 slplink = slpcall->slplink; | |
206 | |
207 /* 200 OK */ | |
208 slpmsg = msn_slpmsg_sip_new(slpcall, 1, | |
209 "MSNSLP/1.0 200 OK", | |
210 branch, type, content); | |
211 | |
212 #ifdef MSN_DEBUG_SLP | |
213 slpmsg->info = "SLP 200 OK"; | |
214 slpmsg->text_body = TRUE; | |
215 #endif | |
216 | |
217 msn_slplink_queue_slpmsg(slplink, slpmsg); | |
218 | |
219 msn_slp_call_session_init(slpcall); | |
220 } | |
221 | |
222 static void | |
223 send_decline(MsnSlpCall *slpcall, const char *branch, | |
224 const char *type, const char *content) | |
225 { | |
226 MsnSlpLink *slplink; | |
227 MsnSlpMessage *slpmsg; | |
228 | |
229 slplink = slpcall->slplink; | |
230 | |
231 /* 603 Decline */ | |
232 slpmsg = msn_slpmsg_sip_new(slpcall, 1, | |
233 "MSNSLP/1.0 603 Decline", | |
234 branch, type, content); | |
235 | |
236 #ifdef MSN_DEBUG_SLP | |
237 slpmsg->info = "SLP 603 Decline"; | |
238 slpmsg->text_body = TRUE; | |
239 #endif | |
240 | |
241 msn_slplink_queue_slpmsg(slplink, slpmsg); | |
242 } | |
243 | |
244 #define MAX_FILE_NAME_LEN 0x226 | |
245 | |
246 static void | |
247 got_sessionreq(MsnSlpCall *slpcall, const char *branch, | |
248 const char *euf_guid, const char *context) | |
249 { | |
250 if (!strcmp(euf_guid, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6")) | |
251 { | |
252 /* Emoticon or UserDisplay */ | |
253 char *content; | |
254 gsize len; | |
255 MsnSlpSession *slpsession; | |
256 MsnSlpLink *slplink; | |
257 MsnSlpMessage *slpmsg; | |
258 MsnObject *obj; | |
259 char *msnobj_data; | |
260 PurpleStoredImage *img; | |
261 int type; | |
262 | |
263 /* Send Ok */ | |
264 content = g_strdup_printf("SessionID: %lu\r\n\r\n", | |
265 slpcall->session_id); | |
266 | |
267 send_ok(slpcall, branch, "application/x-msnmsgr-sessionreqbody", | |
268 content); | |
269 | |
270 g_free(content); | |
271 | |
272 slplink = slpcall->slplink; | |
273 | |
274 msnobj_data = (char *)purple_base64_decode(context, &len); | |
275 obj = msn_object_new_from_string(msnobj_data); | |
276 type = msn_object_get_type(obj); | |
277 g_free(msnobj_data); | |
278 | |
279 if (!(type == MSN_OBJECT_USERTILE)) | |
280 { | |
281 purple_debug_error("msn", "Wrong object?\n"); | |
282 msn_object_destroy(obj); | |
283 g_return_if_reached(); | |
284 } | |
285 | |
286 img = msn_object_get_image(obj); | |
287 if (img == NULL) | |
288 { | |
289 purple_debug_error("msn", "Wrong object.\n"); | |
290 msn_object_destroy(obj); | |
291 g_return_if_reached(); | |
292 } | |
293 | |
294 msn_object_destroy(obj); | |
295 | |
296 slpsession = msn_slplink_find_slp_session(slplink, | |
297 slpcall->session_id); | |
298 | |
299 /* DATA PREP */ | |
300 slpmsg = msn_slpmsg_new(slplink); | |
301 slpmsg->slpcall = slpcall; | |
302 slpmsg->slpsession = slpsession; | |
303 slpmsg->session_id = slpsession->id; | |
304 msn_slpmsg_set_body(slpmsg, NULL, 4); | |
305 #ifdef MSN_DEBUG_SLP | |
306 slpmsg->info = "SLP DATA PREP"; | |
307 #endif | |
308 msn_slplink_queue_slpmsg(slplink, slpmsg); | |
309 | |
310 /* DATA */ | |
311 slpmsg = msn_slpmsg_new(slplink); | |
312 slpmsg->slpcall = slpcall; | |
313 slpmsg->slpsession = slpsession; | |
314 slpmsg->flags = 0x20; | |
315 #ifdef MSN_DEBUG_SLP | |
316 slpmsg->info = "SLP DATA"; | |
317 #endif | |
318 msn_slpmsg_set_image(slpmsg, img); | |
319 msn_slplink_queue_slpmsg(slplink, slpmsg); | |
320 } | |
321 else if (!strcmp(euf_guid, "5D3E02AB-6190-11D3-BBBB-00C04F795683")) | |
322 { | |
323 /* File Transfer */ | |
324 PurpleAccount *account; | |
325 PurpleXfer *xfer; | |
326 char *bin; | |
327 gsize bin_len; | |
328 guint32 file_size; | |
329 char *file_name; | |
330 gunichar2 *uni_name; | |
331 | |
332 account = slpcall->slplink->session->account; | |
333 | |
334 slpcall->cb = msn_xfer_completed_cb; | |
335 slpcall->end_cb = msn_xfer_end_cb; | |
336 slpcall->progress_cb = msn_xfer_progress_cb; | |
337 slpcall->branch = g_strdup(branch); | |
338 | |
339 slpcall->pending = TRUE; | |
340 | |
341 xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE, | |
342 slpcall->slplink->remote_user); | |
343 if (xfer) | |
344 { | |
345 bin = (char *)purple_base64_decode(context, &bin_len); | |
346 file_size = GUINT32_FROM_LE(*(gsize *)(bin + 8)); | |
347 | |
348 uni_name = (gunichar2 *)(bin + 20); | |
349 while(*uni_name != 0 && ((char *)uni_name - (bin + 20)) < MAX_FILE_NAME_LEN) { | |
350 *uni_name = GUINT16_FROM_LE(*uni_name); | |
351 uni_name++; | |
352 } | |
353 | |
354 file_name = g_utf16_to_utf8((const gunichar2 *)(bin + 20), -1, | |
355 NULL, NULL, NULL); | |
356 | |
357 g_free(bin); | |
358 | |
359 purple_xfer_set_filename(xfer, file_name); | |
360 purple_xfer_set_size(xfer, file_size); | |
361 purple_xfer_set_init_fnc(xfer, msn_xfer_init); | |
362 purple_xfer_set_request_denied_fnc(xfer, msn_xfer_cancel); | |
363 purple_xfer_set_cancel_recv_fnc(xfer, msn_xfer_cancel); | |
364 | |
365 slpcall->xfer = xfer; | |
366 purple_xfer_ref(slpcall->xfer); | |
367 | |
368 xfer->data = slpcall; | |
369 | |
370 purple_xfer_request(xfer); | |
371 } | |
372 } | |
373 } | |
374 | |
375 void | |
376 send_bye(MsnSlpCall *slpcall, const char *type) | |
377 { | |
378 MsnSlpLink *slplink; | |
379 MsnSlpMessage *slpmsg; | |
380 char *header; | |
381 | |
382 slplink = slpcall->slplink; | |
383 | |
384 g_return_if_fail(slplink != NULL); | |
385 | |
386 header = g_strdup_printf("BYE MSNMSGR:%s MSNSLP/1.0", | |
387 slplink->local_user); | |
388 | |
389 slpmsg = msn_slpmsg_sip_new(slpcall, 0, header, | |
390 "A0D624A6-6C0C-4283-A9E0-BC97B4B46D32", | |
391 type, | |
392 "\r\n"); | |
393 g_free(header); | |
394 | |
395 #ifdef MSN_DEBUG_SLP | |
396 slpmsg->info = "SLP BYE"; | |
397 slpmsg->text_body = TRUE; | |
398 #endif | |
399 | |
400 msn_slplink_queue_slpmsg(slplink, slpmsg); | |
401 } | |
402 | |
403 static void | |
404 got_invite(MsnSlpCall *slpcall, | |
405 const char *branch, const char *type, const char *content) | |
406 { | |
407 MsnSlpLink *slplink; | |
408 | |
409 slplink = slpcall->slplink; | |
410 | |
411 if (!strcmp(type, "application/x-msnmsgr-sessionreqbody")) | |
412 { | |
413 char *euf_guid, *context; | |
414 char *temp; | |
415 | |
416 euf_guid = get_token(content, "EUF-GUID: {", "}\r\n"); | |
417 | |
418 temp = get_token(content, "SessionID: ", "\r\n"); | |
419 if (temp != NULL) | |
420 slpcall->session_id = atoi(temp); | |
421 g_free(temp); | |
422 | |
423 temp = get_token(content, "AppID: ", "\r\n"); | |
424 if (temp != NULL) | |
425 slpcall->app_id = atoi(temp); | |
426 g_free(temp); | |
427 | |
428 context = get_token(content, "Context: ", "\r\n"); | |
429 | |
430 if (context != NULL) | |
431 got_sessionreq(slpcall, branch, euf_guid, context); | |
432 | |
433 g_free(context); | |
434 g_free(euf_guid); | |
435 } | |
436 else if (!strcmp(type, "application/x-msnmsgr-transreqbody")) | |
437 { | |
438 /* A direct connection? */ | |
439 | |
440 char *listening, *nonce; | |
441 char *content; | |
442 | |
443 if (FALSE) | |
444 { | |
445 #if 0 | |
446 MsnDirectConn *directconn; | |
447 /* const char *ip_addr; */ | |
448 char *ip_port; | |
449 int port; | |
450 | |
451 /* ip_addr = purple_prefs_get_string("/purple/ft/public_ip"); */ | |
452 ip_port = "5190"; | |
453 listening = "true"; | |
454 nonce = rand_guid(); | |
455 | |
456 directconn = msn_directconn_new(slplink); | |
457 | |
458 /* msn_directconn_parse_nonce(directconn, nonce); */ | |
459 directconn->nonce = g_strdup(nonce); | |
460 | |
461 msn_directconn_listen(directconn); | |
462 | |
463 port = directconn->port; | |
464 | |
465 content = g_strdup_printf( | |
466 "Bridge: TCPv1\r\n" | |
467 "Listening: %s\r\n" | |
468 "Nonce: {%s}\r\n" | |
469 "Ipv4Internal-Addrs: 192.168.0.82\r\n" | |
470 "Ipv4Internal-Port: %d\r\n" | |
471 "\r\n", | |
472 listening, | |
473 nonce, | |
474 port); | |
475 #endif | |
476 } | |
477 else | |
478 { | |
479 listening = "false"; | |
480 nonce = g_strdup("00000000-0000-0000-0000-000000000000"); | |
481 | |
482 content = g_strdup_printf( | |
483 "Bridge: TCPv1\r\n" | |
484 "Listening: %s\r\n" | |
485 "Nonce: {%s}\r\n" | |
486 "\r\n", | |
487 listening, | |
488 nonce); | |
489 } | |
490 | |
491 send_ok(slpcall, branch, | |
492 "application/x-msnmsgr-transrespbody", content); | |
493 | |
494 g_free(content); | |
495 g_free(nonce); | |
496 } | |
497 else if (!strcmp(type, "application/x-msnmsgr-transrespbody")) | |
498 { | |
499 #if 0 | |
500 char *ip_addrs; | |
501 char *temp; | |
502 char *nonce; | |
503 int port; | |
504 | |
505 nonce = get_token(content, "Nonce: {", "}\r\n"); | |
506 ip_addrs = get_token(content, "IPv4Internal-Addrs: ", "\r\n"); | |
507 | |
508 temp = get_token(content, "IPv4Internal-Port: ", "\r\n"); | |
509 if (temp != NULL) | |
510 port = atoi(temp); | |
511 else | |
512 port = -1; | |
513 g_free(temp); | |
514 | |
515 if (ip_addrs == NULL) | |
516 return; | |
517 | |
518 if (port > 0) | |
519 got_transresp(slpcall, nonce, ip_addrs, port); | |
520 | |
521 g_free(nonce); | |
522 g_free(ip_addrs); | |
523 #endif | |
524 } | |
525 } | |
526 | |
527 static void | |
528 got_ok(MsnSlpCall *slpcall, | |
529 const char *type, const char *content) | |
530 { | |
531 g_return_if_fail(slpcall != NULL); | |
532 g_return_if_fail(type != NULL); | |
533 | |
534 if (!strcmp(type, "application/x-msnmsgr-sessionreqbody")) | |
535 { | |
536 #if 0 | |
537 if (slpcall->type == MSN_SLPCALL_DC) | |
538 { | |
539 /* First let's try a DirectConnection. */ | |
540 | |
541 MsnSlpLink *slplink; | |
542 MsnSlpMessage *slpmsg; | |
543 char *header; | |
544 char *content; | |
545 char *branch; | |
546 | |
547 slplink = slpcall->slplink; | |
548 | |
549 branch = rand_guid(); | |
550 | |
551 content = g_strdup_printf( | |
552 "Bridges: TRUDPv1 TCPv1\r\n" | |
553 "NetID: 0\r\n" | |
554 "Conn-Type: Direct-Connect\r\n" | |
555 "UPnPNat: false\r\n" | |
556 "ICF: false\r\n" | |
557 ); | |
558 | |
559 header = g_strdup_printf("INVITE MSNMSGR:%s MSNSLP/1.0", | |
560 slplink->remote_user); | |
561 | |
562 slpmsg = msn_slp_sipmsg_new(slpcall, 0, header, branch, | |
563 "application/x-msnmsgr-transreqbody", | |
564 content); | |
565 | |
566 #ifdef MSN_DEBUG_SLP | |
567 slpmsg->info = "SLP INVITE"; | |
568 slpmsg->text_body = TRUE; | |
569 #endif | |
570 msn_slplink_send_slpmsg(slplink, slpmsg); | |
571 | |
572 g_free(header); | |
573 g_free(content); | |
574 | |
575 g_free(branch); | |
576 } | |
577 else | |
578 { | |
579 msn_slp_call_session_init(slpcall); | |
580 } | |
581 #else | |
582 msn_slp_call_session_init(slpcall); | |
583 #endif | |
584 } | |
585 else if (!strcmp(type, "application/x-msnmsgr-transreqbody")) | |
586 { | |
587 /* Do we get this? */ | |
588 purple_debug_info("msn", "OK with transreqbody\n"); | |
589 } | |
590 else if (!strcmp(type, "application/x-msnmsgr-transrespbody")) | |
591 { | |
592 #if 0 | |
593 char *ip_addrs; | |
594 char *temp; | |
595 char *nonce; | |
596 int port; | |
597 | |
598 nonce = get_token(content, "Nonce: {", "}\r\n"); | |
599 ip_addrs = get_token(content, "IPv4Internal-Addrs: ", "\r\n"); | |
600 | |
601 temp = get_token(content, "IPv4Internal-Port: ", "\r\n"); | |
602 if (temp != NULL) | |
603 port = atoi(temp); | |
604 else | |
605 port = -1; | |
606 g_free(temp); | |
607 | |
608 if (ip_addrs == NULL) | |
609 return; | |
610 | |
611 if (port > 0) | |
612 got_transresp(slpcall, nonce, ip_addrs, port); | |
613 | |
614 g_free(nonce); | |
615 g_free(ip_addrs); | |
616 #endif | |
617 } | |
618 } | |
619 | |
620 MsnSlpCall * | |
621 msn_slp_sip_recv(MsnSlpLink *slplink, const char *body) | |
622 { | |
623 MsnSlpCall *slpcall; | |
624 | |
625 if (body == NULL) | |
626 { | |
627 purple_debug_warning("msn", "received bogus message\n"); | |
628 return NULL; | |
629 } | |
630 | |
631 if (!strncmp(body, "INVITE", strlen("INVITE"))) | |
632 { | |
633 char *branch; | |
634 char *content; | |
635 char *content_type; | |
636 | |
637 slpcall = msn_slp_call_new(slplink); | |
638 | |
639 /* From: <msnmsgr:buddy@hotmail.com> */ | |
640 #if 0 | |
641 slpcall->remote_user = get_token(body, "From: <msnmsgr:", ">\r\n"); | |
642 #endif | |
643 | |
644 branch = get_token(body, ";branch={", "}"); | |
645 | |
646 slpcall->id = get_token(body, "Call-ID: {", "}"); | |
647 | |
648 #if 0 | |
649 long content_len = -1; | |
650 | |
651 temp = get_token(body, "Content-Length: ", "\r\n"); | |
652 if (temp != NULL) | |
653 content_len = atoi(temp); | |
654 g_free(temp); | |
655 #endif | |
656 content_type = get_token(body, "Content-Type: ", "\r\n"); | |
657 | |
658 content = get_token(body, "\r\n\r\n", NULL); | |
659 | |
660 got_invite(slpcall, branch, content_type, content); | |
661 | |
662 g_free(branch); | |
663 g_free(content_type); | |
664 g_free(content); | |
665 } | |
666 else if (!strncmp(body, "MSNSLP/1.0 ", strlen("MSNSLP/1.0 "))) | |
667 { | |
668 char *content; | |
669 char *content_type; | |
670 /* Make sure this is "OK" */ | |
671 const char *status = body + strlen("MSNSLP/1.0 "); | |
672 char *call_id; | |
673 | |
674 call_id = get_token(body, "Call-ID: {", "}"); | |
675 slpcall = msn_slplink_find_slp_call(slplink, call_id); | |
676 g_free(call_id); | |
677 | |
678 g_return_val_if_fail(slpcall != NULL, NULL); | |
679 | |
680 if (strncmp(status, "200 OK", 6)) | |
681 { | |
682 /* It's not valid. Kill this off. */ | |
683 char temp[32]; | |
684 const char *c; | |
685 | |
686 /* Eww */ | |
687 if ((c = strchr(status, '\r')) || (c = strchr(status, '\n')) || | |
688 (c = strchr(status, '\0'))) | |
689 { | |
690 size_t offset = c - status; | |
691 if (offset >= sizeof(temp)) | |
692 offset = sizeof(temp) - 1; | |
693 | |
694 strncpy(temp, status, offset); | |
695 temp[offset] = '\0'; | |
696 } | |
697 | |
698 purple_debug_error("msn", "Received non-OK result: %s\n", temp); | |
699 | |
700 slpcall->wasted = TRUE; | |
701 | |
702 /* msn_slp_call_destroy(slpcall); */ | |
703 return slpcall; | |
704 } | |
705 | |
706 content_type = get_token(body, "Content-Type: ", "\r\n"); | |
707 | |
708 content = get_token(body, "\r\n\r\n", NULL); | |
709 | |
710 got_ok(slpcall, content_type, content); | |
711 | |
712 g_free(content_type); | |
713 g_free(content); | |
714 } | |
715 else if (!strncmp(body, "BYE", strlen("BYE"))) | |
716 { | |
717 char *call_id; | |
718 | |
719 call_id = get_token(body, "Call-ID: {", "}"); | |
720 slpcall = msn_slplink_find_slp_call(slplink, call_id); | |
721 g_free(call_id); | |
722 | |
723 if (slpcall != NULL) | |
724 slpcall->wasted = TRUE; | |
725 | |
726 /* msn_slp_call_destroy(slpcall); */ | |
727 } | |
728 else | |
729 slpcall = NULL; | |
730 | |
731 return slpcall; | |
732 } | |
733 | |
734 /************************************************************************** | |
735 * Msg Callbacks | |
736 **************************************************************************/ | |
737 | |
738 void | |
739 msn_p2p_msg(MsnCmdProc *cmdproc, MsnMessage *msg) | |
740 { | |
741 MsnSession *session; | |
742 MsnSlpLink *slplink; | |
743 | |
744 session = cmdproc->servconn->session; | |
745 slplink = msn_session_get_slplink(session, msg->remote_user); | |
746 | |
747 if (slplink->swboard == NULL) | |
748 { | |
749 /* We will need this in order to change its flags. */ | |
750 slplink->swboard = (MsnSwitchBoard *)cmdproc->data; | |
751 /* If swboard is NULL, something has probably gone wrong earlier on | |
752 * I didn't want to do this, but MSN 7 is somehow causing us to crash | |
753 * here, I couldn't reproduce it to debug more, and people are | |
754 * reporting bugs. Hopefully this doesn't cause more crashes. Stu. | |
755 */ | |
756 if (slplink->swboard != NULL) | |
757 slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink); | |
758 else | |
759 purple_debug_error("msn", "msn_p2p_msg, swboard is NULL, ouch!\n"); | |
760 } | |
761 | |
762 msn_slplink_process_msg(slplink, msg); | |
763 } | |
764 | |
765 static void | |
766 got_emoticon(MsnSlpCall *slpcall, | |
767 const guchar *data, gsize size) | |
768 { | |
769 | |
770 PurpleConversation *conv; | |
771 PurpleConnection *gc; | |
772 const char *who; | |
773 | |
774 gc = slpcall->slplink->session->account->gc; | |
775 who = slpcall->slplink->remote_user; | |
776 | |
777 if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, gc->account))) { | |
778 | |
779 /* FIXME: it would be better if we wrote the data as we received it | |
780 instead of all at once, calling write multiple times and | |
781 close once at the very end | |
782 */ | |
783 purple_conv_custom_smiley_write(conv, slpcall->data_info, data, size); | |
784 purple_conv_custom_smiley_close(conv, slpcall->data_info); | |
785 } | |
786 #ifdef MSN_DEBUG_UD | |
787 purple_debug_info("msn", "Got smiley: %s\n", slpcall->data_info); | |
788 #endif | |
789 } | |
790 | |
791 void | |
792 msn_emoticon_msg(MsnCmdProc *cmdproc, MsnMessage *msg) | |
793 { | |
794 MsnSession *session; | |
795 MsnSlpLink *slplink; | |
796 MsnObject *obj; | |
797 char **tokens; | |
798 char *smile, *body_str; | |
799 const char *body, *who, *sha1; | |
800 guint tok; | |
801 size_t body_len; | |
802 | |
803 PurpleConversation *conv; | |
804 | |
805 session = cmdproc->servconn->session; | |
806 | |
807 if (!purple_account_get_bool(session->account, "custom_smileys", TRUE)) | |
808 return; | |
809 | |
810 body = msn_message_get_bin_data(msg, &body_len); | |
811 body_str = g_strndup(body, body_len); | |
812 | |
813 /* MSN Messenger 7 may send more than one MSNObject in a single message... | |
814 * Maybe 10 tokens is a reasonable max value. */ | |
815 tokens = g_strsplit(body_str, "\t", 10); | |
816 | |
817 g_free(body_str); | |
818 | |
819 for (tok = 0; tok < 9; tok += 2) { | |
820 if (tokens[tok] == NULL || tokens[tok + 1] == NULL) { | |
821 break; | |
822 } | |
823 | |
824 smile = tokens[tok]; | |
825 obj = msn_object_new_from_string(purple_url_decode(tokens[tok + 1])); | |
826 | |
827 if (obj == NULL) | |
828 break; | |
829 | |
830 who = msn_object_get_creator(obj); | |
831 sha1 = msn_object_get_sha1(obj); | |
832 | |
833 slplink = msn_session_get_slplink(session, who); | |
834 | |
835 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, | |
836 session->account); | |
837 | |
838 /* If the conversation doesn't exist then this is a custom smiley | |
839 * used in the first message in a MSN conversation: we need to create | |
840 * the conversation now, otherwise the custom smiley won't be shown. | |
841 * This happens because every GtkIMHtml has its own smiley tree: if | |
842 * the conversation doesn't exist then we cannot associate the new | |
843 * smiley with its GtkIMHtml widget. */ | |
844 if (!conv) { | |
845 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, session->account, who); | |
846 } | |
847 | |
848 if (purple_conv_custom_smiley_add(conv, smile, "sha1", sha1, TRUE)) { | |
849 msn_slplink_request_object(slplink, smile, got_emoticon, NULL, obj); | |
850 } | |
851 | |
852 msn_object_destroy(obj); | |
853 obj = NULL; | |
854 who = NULL; | |
855 sha1 = NULL; | |
856 } | |
857 g_strfreev(tokens); | |
858 } | |
859 | |
860 static gboolean | |
861 buddy_icon_cached(PurpleConnection *gc, MsnObject *obj) | |
862 { | |
863 PurpleAccount *account; | |
864 PurpleBuddy *buddy; | |
865 const char *old; | |
866 const char *new; | |
867 | |
868 g_return_val_if_fail(obj != NULL, FALSE); | |
869 | |
870 account = purple_connection_get_account(gc); | |
871 | |
872 buddy = purple_find_buddy(account, msn_object_get_creator(obj)); | |
873 if (buddy == NULL) | |
874 return FALSE; | |
875 | |
876 old = purple_buddy_icons_get_checksum_for_user(buddy); | |
877 new = msn_object_get_sha1(obj); | |
878 | |
879 if (new == NULL) | |
880 return FALSE; | |
881 | |
882 /* If the old and new checksums are the same, and the file actually exists, | |
883 * then return TRUE */ | |
884 if (old != NULL && !strcmp(old, new)) | |
885 return TRUE; | |
886 | |
887 return FALSE; | |
888 } | |
889 | |
890 static void | |
891 msn_release_buddy_icon_request(MsnUserList *userlist) | |
892 { | |
893 MsnUser *user; | |
894 | |
895 g_return_if_fail(userlist != NULL); | |
896 | |
897 #ifdef MSN_DEBUG_UD | |
898 purple_debug_info("msn", "Releasing buddy icon request\n"); | |
899 #endif | |
900 | |
901 if (userlist->buddy_icon_window > 0) | |
902 { | |
903 GQueue *queue; | |
904 PurpleAccount *account; | |
905 const char *username; | |
906 | |
907 queue = userlist->buddy_icon_requests; | |
908 | |
909 if (g_queue_is_empty(userlist->buddy_icon_requests)) | |
910 return; | |
911 | |
912 user = g_queue_pop_head(queue); | |
913 | |
914 account = userlist->session->account; | |
915 username = user->passport; | |
916 | |
917 userlist->buddy_icon_window--; | |
918 msn_request_user_display(user); | |
919 | |
920 #ifdef MSN_DEBUG_UD | |
921 purple_debug_info("msn", "msn_release_buddy_icon_request(): buddy_icon_window-- yields =%d\n", | |
922 userlist->buddy_icon_window); | |
923 #endif | |
924 } | |
925 } | |
926 | |
927 /* | |
928 * Called on a timeout from end_user_display(). Frees a buddy icon window slow and dequeues the next | |
929 * buddy icon request if there is one. | |
930 */ | |
931 static gboolean | |
932 msn_release_buddy_icon_request_timeout(gpointer data) | |
933 { | |
934 MsnUserList *userlist = (MsnUserList *)data; | |
935 | |
936 /* Free one window slot */ | |
937 userlist->buddy_icon_window++; | |
938 | |
939 /* Clear the tag for our former request timer */ | |
940 userlist->buddy_icon_request_timer = 0; | |
941 | |
942 msn_release_buddy_icon_request(userlist); | |
943 | |
944 return FALSE; | |
945 } | |
946 | |
947 void | |
948 msn_queue_buddy_icon_request(MsnUser *user) | |
949 { | |
950 PurpleAccount *account; | |
951 MsnObject *obj; | |
952 GQueue *queue; | |
953 | |
954 g_return_if_fail(user != NULL); | |
955 | |
956 account = user->userlist->session->account; | |
957 | |
958 obj = msn_user_get_object(user); | |
959 | |
960 if (obj == NULL) | |
961 { | |
962 purple_buddy_icons_set_for_user(account, user->passport, NULL, 0, NULL); | |
963 return; | |
964 } | |
965 | |
966 if (!buddy_icon_cached(account->gc, obj)) | |
967 { | |
968 MsnUserList *userlist; | |
969 | |
970 userlist = user->userlist; | |
971 queue = userlist->buddy_icon_requests; | |
972 | |
973 #ifdef MSN_DEBUG_UD | |
974 purple_debug_info("msn", "Queueing buddy icon request for %s (buddy_icon_window = %i)\n", | |
975 user->passport, userlist->buddy_icon_window); | |
976 #endif | |
977 | |
978 g_queue_push_tail(queue, user); | |
979 | |
980 if (userlist->buddy_icon_window > 0) | |
981 msn_release_buddy_icon_request(userlist); | |
982 } | |
983 } | |
984 | |
985 static void | |
986 got_user_display(MsnSlpCall *slpcall, | |
987 const guchar *data, gsize size) | |
988 { | |
989 MsnUserList *userlist; | |
990 const char *info; | |
991 PurpleAccount *account; | |
992 | |
993 g_return_if_fail(slpcall != NULL); | |
994 | |
995 info = slpcall->data_info; | |
996 #ifdef MSN_DEBUG_UD | |
997 purple_debug_info("msn", "Got User Display: %s\n", slpcall->slplink->remote_user); | |
998 #endif | |
999 | |
1000 userlist = slpcall->slplink->session->userlist; | |
1001 account = slpcall->slplink->session->account; | |
1002 | |
1003 purple_buddy_icons_set_for_user(account, slpcall->slplink->remote_user, | |
1004 g_memdup(data, size), size, info); | |
1005 | |
1006 #if 0 | |
1007 /* Free one window slot */ | |
1008 userlist->buddy_icon_window++; | |
1009 | |
1010 purple_debug_info("msn", "got_user_display(): buddy_icon_window++ yields =%d\n", | |
1011 userlist->buddy_icon_window); | |
1012 | |
1013 msn_release_buddy_icon_request(userlist); | |
1014 #endif | |
1015 } | |
1016 | |
1017 static void | |
1018 end_user_display(MsnSlpCall *slpcall, MsnSession *session) | |
1019 { | |
1020 MsnUserList *userlist; | |
1021 | |
1022 g_return_if_fail(session != NULL); | |
1023 | |
1024 #ifdef MSN_DEBUG_UD | |
1025 purple_debug_info("msn", "End User Display\n"); | |
1026 #endif | |
1027 | |
1028 userlist = session->userlist; | |
1029 | |
1030 /* If the session is being destroyed we better stop doing anything. */ | |
1031 if (session->destroying) | |
1032 return; | |
1033 | |
1034 /* Delay before freeing a buddy icon window slot and requesting the next icon, if appropriate. | |
1035 * If we don't delay, we'll rapidly hit the MSN equivalent of AIM's rate limiting; the server will | |
1036 * send us an error 800 like so: | |
1037 * | |
1038 * C: NS 000: XFR 21 SB | |
1039 * S: NS 000: 800 21 | |
1040 */ | |
1041 if (userlist->buddy_icon_request_timer) { | |
1042 /* Free the window slot used by this previous request */ | |
1043 userlist->buddy_icon_window++; | |
1044 | |
1045 /* Clear our pending timeout */ | |
1046 purple_timeout_remove(userlist->buddy_icon_request_timer); | |
1047 } | |
1048 | |
1049 /* Wait BUDDY_ICON_DELAY ms before freeing our window slot and requesting the next icon. */ | |
1050 userlist->buddy_icon_request_timer = purple_timeout_add(BUDDY_ICON_DELAY, | |
1051 msn_release_buddy_icon_request_timeout, userlist); | |
1052 } | |
1053 | |
1054 void | |
1055 msn_request_user_display(MsnUser *user) | |
1056 { | |
1057 PurpleAccount *account; | |
1058 MsnSession *session; | |
1059 MsnSlpLink *slplink; | |
1060 MsnObject *obj; | |
1061 const char *info; | |
1062 | |
1063 session = user->userlist->session; | |
1064 account = session->account; | |
1065 | |
1066 slplink = msn_session_get_slplink(session, user->passport); | |
1067 | |
1068 obj = msn_user_get_object(user); | |
1069 | |
1070 info = msn_object_get_sha1(obj); | |
1071 | |
1072 if (g_ascii_strcasecmp(user->passport, | |
1073 purple_account_get_username(account))) | |
1074 { | |
1075 msn_slplink_request_object(slplink, info, got_user_display, | |
1076 end_user_display, obj); | |
1077 } | |
1078 else | |
1079 { | |
1080 MsnObject *my_obj = NULL; | |
1081 gconstpointer data = NULL; | |
1082 size_t len = 0; | |
1083 | |
1084 #ifdef MSN_DEBUG_UD | |
1085 purple_debug_info("msn", "Requesting our own user display\n"); | |
1086 #endif | |
1087 | |
1088 my_obj = msn_user_get_object(session->user); | |
1089 | |
1090 if (my_obj != NULL) | |
1091 { | |
1092 PurpleStoredImage *img = msn_object_get_image(my_obj); | |
1093 data = purple_imgstore_get_data(img); | |
1094 len = purple_imgstore_get_size(img); | |
1095 } | |
1096 | |
1097 purple_buddy_icons_set_for_user(account, user->passport, g_memdup(data, len), len, info); | |
1098 | |
1099 /* Free one window slot */ | |
1100 session->userlist->buddy_icon_window++; | |
1101 | |
1102 #ifdef MSN_DEBUG_UD | |
1103 purple_debug_info("msn", "msn_request_user_display(): buddy_icon_window++ yields =%d\n", | |
1104 session->userlist->buddy_icon_window); | |
1105 #endif | |
1106 | |
1107 msn_release_buddy_icon_request(session->userlist); | |
1108 } | |
1109 } |