comparison src/protocols/msn/slplink.c @ 9193:502707ca1836

[gaim-migrate @ 9988] Patch by Felipe Contreras to add MSN file transfer and buddy icons. Please test and report any bugs! committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Sun, 06 Jun 2004 02:39:08 +0000
parents
children ab6636c5a136
comparison
equal deleted inserted replaced
9192:5655dcd94d0f 9193:502707ca1836
1 #include "msn.h"
2 #include "slplink.h"
3
4 #include "switchboard.h"
5 #include "slp.h"
6
7 void msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg);
8
9 #ifdef DEBUG_SLP_FILES
10 static int m_sc = 0;
11 static int m_rc = 0;
12
13 static void
14 debug_msg_to_file(MsnMessage *msg, gboolean send)
15 {
16 char *tmp;
17 char *dir;
18 char *pload;
19 FILE *tf;
20 int c;
21 gsize pload_size;
22
23 dir = send ? "send" : "recv";
24 c = send ? m_sc++ : m_rc++;
25 tmp = g_strdup_printf("%s/msntest/%s/%03d", g_get_home_dir(), dir, c);
26 tf = fopen(tmp, "w");
27 pload = msn_message_gen_payload(msg, &pload_size);
28 fwrite(pload, 1, pload_size, tf);
29 fclose(tf);
30 g_free(tmp);
31 }
32 #endif
33
34 MsnSlpLink *
35 msn_slplink_new(MsnSession *session, const char *username)
36 {
37 MsnSlpLink *slplink;
38
39 slplink = g_new0(MsnSlpLink, 1);
40
41 slplink->session = session;
42 slplink->slp_seq_id = rand() % 0xFFFFFF00 + 4;
43
44 slplink->local_user = g_strdup(msn_user_get_passport(session->user));
45 slplink->remote_user = g_strdup(username);
46
47 slplink->slp_msg_queue = g_queue_new();
48
49 session->slplinks =
50 g_list_append(session->slplinks, slplink);
51
52 return slplink;
53 }
54
55 void
56 msn_slplink_destroy(MsnSlpLink *slplink)
57 {
58 MsnSession *session;
59
60 session = slplink->session;
61
62 if (slplink->local_user != NULL)
63 g_free(slplink->local_user);
64
65 if (slplink->remote_user != NULL)
66 g_free(slplink->remote_user);
67
68 if (slplink->directconn != NULL)
69 msn_directconn_destroy(slplink->directconn);
70
71 session->slplinks =
72 g_list_remove(session->slplinks, slplink);
73
74 g_free(slplink);
75 }
76
77 MsnSlpLink *
78 msn_session_find_slplink(MsnSession *session, const char *who)
79 {
80 MsnSlpLink *slplink;
81 GList *l;
82
83 for (l = session->slplinks; l != NULL; l = l->next)
84 {
85 slplink = l->data;
86
87 if (!strcmp(slplink->remote_user, who))
88 return slplink;
89 }
90
91 return NULL;
92 }
93
94 MsnSlpLink *
95 msn_session_get_slplink(MsnSession *session, const char *username)
96 {
97 MsnSlpLink *slplink;
98
99 slplink = msn_session_find_slplink(session, username);
100
101 if (slplink == NULL)
102 slplink = msn_slplink_new(session, username);
103
104 return slplink;
105 }
106
107 MsnSlpSession *
108 msn_slplink_find_slp_session(MsnSlpLink *slplink, long session_id)
109 {
110 GList *l;
111 MsnSlpSession *slpsession;
112
113 for (l = slplink->slp_sessions; l != NULL; l = l->next)
114 {
115 slpsession = l->data;
116
117 if (slpsession->id == session_id)
118 return slpsession;
119 }
120
121 return NULL;
122 }
123
124 MsnSlpCall *
125 msn_slplink_find_slp_call(MsnSlpLink *slplink, const char *id)
126 {
127 GList *l;
128 MsnSlpCall *slpcall;
129
130 for (l = slplink->slp_calls; l != NULL; l = l->next)
131 {
132 slpcall = l->data;
133
134 if (!strcmp(slpcall->id, id))
135 return slpcall;
136 }
137
138 return NULL;
139 }
140
141 MsnSlpCall *
142 msn_slplink_find_slp_call_with_session_id(MsnSlpLink *slplink, long id)
143 {
144 GList *l;
145 MsnSlpCall *slpcall;
146
147 for (l = slplink->slp_calls; l != NULL; l = l->next)
148 {
149 slpcall = l->data;
150
151 if (slpcall->session_id == id)
152 return slpcall;
153 }
154
155 return NULL;
156 }
157
158 void
159 msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg)
160 {
161 if (slplink->directconn != NULL)
162 {
163 msn_directconn_send_msg(slplink->directconn, msg);
164 }
165 else
166 {
167 MsnSwitchBoard *swboard;
168
169 swboard = msn_session_get_swboard(slplink->session, slplink->remote_user);
170
171 if (swboard == NULL)
172 return;
173
174 if (!g_queue_is_empty(swboard->im_queue) ||
175 !swboard->user_joined)
176 {
177 msn_switchboard_queue_msg(swboard, msg);
178 }
179 else
180 {
181 msn_switchboard_send_msg(swboard, msg);
182 }
183 }
184 }
185
186 void t_ack(MsnCmdProc *cmdproc, MsnCommand *cmd)
187 {
188 MsnSlpMessage *slpmsg;
189 long long real_size;
190
191 slpmsg = cmd->trans->data;
192
193 #if 0
194 if (slpmsg->wasted)
195 {
196 gaim_debug_info("msn", "slpmsg cancelled %p\n", slpmsg);
197
198 if (slpmsg->slpcall != NULL)
199 {
200 if (slpmsg->slpcall->cb != NULL)
201 slpmsg->slpcall->cb(slpmsg->slpcall, NULL, -1);
202
203 msn_slpcall_destroy(slpmsg->slpcall);
204 }
205
206 msn_slpmsg_destroy(slpmsg);
207 }
208 #endif
209
210 real_size = (slpmsg->flags == 0x2) ? 0 : slpmsg->size;
211
212 if (slpmsg->offset < real_size)
213 {
214 msn_slplink_send_msgpart(slpmsg->slplink, slpmsg);
215 }
216 else
217 {
218 /* The whole message has been sent */
219
220 if ((slpmsg->slpcall != NULL) &&
221 (slpmsg->slpcall->cb != NULL))
222 {
223 slpmsg->slpcall->cb(slpmsg->slpcall, NULL, 0);
224 }
225
226 msn_slpmsg_destroy(slpmsg);
227 }
228 }
229
230 void
231 msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
232 {
233 MsnMessage *msg;
234 long long real_size;
235 size_t len = 0;
236
237 msg = slpmsg->msg;
238
239 real_size = (slpmsg->flags == 0x2) ? 0 : slpmsg->size;
240
241 if (slpmsg->offset < real_size)
242 {
243 if (slpmsg->fp)
244 {
245 char data[1202];
246 len = fread(data, 1, sizeof(data), slpmsg->fp);
247 msn_message_set_bin_data(msg, data, len);
248 }
249 else
250 {
251 len = slpmsg->size - slpmsg->offset;
252
253 if (len > 1202)
254 len = 1202;
255
256 msn_message_set_bin_data(msg, slpmsg->buffer + slpmsg->offset, len);
257 }
258
259 msg->msnslp_header.offset = slpmsg->offset;
260 msg->msnslp_header.length = len;
261 }
262
263 #ifdef DEBUG_SLP
264 msn_message_show_readable(msg, slpmsg->info, slpmsg->text_body);
265 #endif
266
267 #ifdef DEBUG_SLP_FILES
268 debug_msg_to_file(msg, TRUE);
269 #endif
270
271 msn_slplink_send_msg(slplink, msg);
272
273 if ((slpmsg->slpcall != NULL) &&
274 (slpmsg->slpcall->progress_cb != NULL))
275 {
276 slpmsg->slpcall->progress_cb(slpmsg->slpcall, slpmsg->size, len,
277 slpmsg->offset);
278 }
279
280 slpmsg->offset += len;
281 }
282
283 void
284 msn_slplink_release_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
285 {
286 MsnMessage *msg;
287
288 slpmsg->msg = msg = msn_message_new_msnslp();
289
290 if (slpmsg->flags == 0x0)
291 {
292 msg->msnslp_header.session_id = slpmsg->session_id;
293 msg->msnslp_header.ack_id = rand() % 0xFFFFFF00;
294 }
295 else if (slpmsg->flags == 0x2)
296 {
297 msg->msnslp_header.session_id = slpmsg->session_id;
298 msg->msnslp_header.ack_id = slpmsg->ack_id;
299 msg->msnslp_header.ack_size = slpmsg->ack_size;
300 }
301 else if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030)
302 {
303 MsnSlpSession *slpsession;
304 slpsession = slpmsg->slpsession;
305
306 g_return_if_fail(slpsession != NULL);
307 msg->msnslp_header.session_id = slpsession->id;
308 msg->msnslp_footer.value = slpsession->app_id;
309 msg->msnslp_header.ack_id = rand() % 0xFFFFFF00;
310 }
311 else if (slpmsg->flags == 0x100)
312 {
313 msg->msnslp_header.ack_id = slpmsg->ack_id;
314 msg->msnslp_header.ack_sub_id = slpmsg->ack_sub_id;
315 msg->msnslp_header.ack_size = slpmsg->ack_size;
316 }
317
318 msg->msnslp_header.id = slpmsg->id;
319 msg->msnslp_header.flags = slpmsg->flags;
320
321 msg->msnslp_header.total_size = slpmsg->size;
322
323 msn_message_set_attr(msg, "P2P-Dest", slplink->remote_user);
324
325 msg->ack_cb = t_ack;
326 msg->ack_data = slpmsg;
327
328 msn_slplink_send_msgpart(slplink, slpmsg);
329 }
330
331 void
332 msn_slplink_queue_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
333 {
334 slpmsg->id = slplink->slp_seq_id++;
335
336 g_queue_push_head(slplink->slp_msg_queue, slpmsg);
337 }
338
339 void
340 msn_slplink_send_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
341 {
342 slpmsg->id = slplink->slp_seq_id++;
343
344 msn_slplink_release_msg(slplink, slpmsg);
345 }
346
347 void
348 msn_slplink_unleash(MsnSlpLink *slplink)
349 {
350 MsnSlpMessage *slpmsg;
351
352 /* Send the queued msgs in the order they came. */
353
354 while ((slpmsg = g_queue_pop_tail(slplink->slp_msg_queue)) != NULL)
355 msn_slplink_release_msg(slplink, slpmsg);
356 }
357
358 void
359 msn_slplink_send_ack(MsnSlpLink *slplink, MsnMessage *msg)
360 {
361 MsnSlpMessage *slpmsg;
362
363 slpmsg = msn_slpmsg_new(slplink);
364
365 slpmsg->session_id = msg->msnslp_header.session_id;
366 slpmsg->size = msg->msnslp_header.total_size;
367 slpmsg->flags = 0x02;
368 slpmsg->ack_id = msg->msnslp_header.id;
369 slpmsg->ack_sub_id = msg->msnslp_header.ack_id;
370 slpmsg->ack_size = msg->msnslp_header.total_size;
371
372 #ifdef DEBUG_SLP
373 slpmsg->info = "SLP ACK";
374 #endif
375
376 msn_slplink_send_slpmsg(slplink, slpmsg);
377 }
378
379 void
380 send_file(MsnSlpSession *slpsession)
381 {
382 MsnSlpCall *slpcall;
383 MsnSlpMessage *slpmsg;
384
385 slpcall = slpsession->slpcall;
386 slpmsg = msn_slpmsg_new(slpcall->slplink);
387 slpmsg->flags = 0x1000030;
388 slpmsg->slpsession = slpsession;
389 #ifdef DEBUG_SLP
390 slpmsg->info = "SLP FILE";
391 #endif
392 slpmsg->slpcall = slpcall;
393 msn_slpmsg_open_file(slpmsg, gaim_xfer_get_local_filename(slpcall->xfer));
394
395 gaim_xfer_add(slpcall->xfer);
396 msn_slplink_send_slpmsg(slpcall->slplink, slpmsg);
397 }
398
399 void
400 msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg)
401 {
402 MsnSlpMessage *slpmsg;
403 const char *data;
404 gsize offset;
405 gsize len;
406
407 #ifdef DEBUG_SLP
408 msn_slpmsg_show(msg);
409 #endif
410
411 #ifdef DEBUG_SLP_FILES
412 debug_msg_to_file(msg, FALSE);
413 #endif
414
415 if (msg->msnslp_header.total_size < msg->msnslp_header.length)
416 {
417 gaim_debug_error("msn", "This can't be good\n");
418 g_return_if_reached();
419 }
420
421 slpmsg = NULL;
422 data = msn_message_get_bin_data(msg, &len);
423
424 /*
425 OVERHEAD!
426 if (msg->msnslp_header.length < msg->msnslp_header.total_size)
427 */
428
429 offset = msg->msnslp_header.offset;
430
431 if (offset == 0)
432 {
433 slpmsg = msn_slpmsg_new(slplink);
434 slpmsg->id = msg->msnslp_header.id;
435 slpmsg->session_id = msg->msnslp_header.session_id;
436 slpmsg->size = msg->msnslp_header.total_size;
437 slpmsg->flags = msg->msnslp_header.flags;
438 slpmsg->buffer = g_malloc(slpmsg->size);
439
440 if (slpmsg->session_id)
441 {
442 if (slpmsg->slpcall == NULL)
443 slpmsg->slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id);
444
445 if (slpmsg->slpcall != NULL)
446 {
447 GaimXfer *xfer;
448
449 xfer = slpmsg->slpcall->xfer;
450
451 if (xfer != NULL)
452 {
453 slpmsg->fp =
454 fopen(gaim_xfer_get_local_filename(slpmsg->slpcall->xfer), "w");
455 }
456 }
457 }
458 }
459 else
460 {
461 slpmsg = msn_slplink_message_find(slplink, msg->msnslp_header.id);
462 }
463
464 if (slpmsg != NULL)
465 {
466 if (slpmsg->fp)
467 {
468 /* fseek(slpmsg->fp, offset, SEEK_SET); */
469 len = fwrite(data, 1, len, slpmsg->fp);
470 }
471 else
472 {
473 memcpy(slpmsg->buffer + offset, data, len);
474 }
475 }
476 else
477 {
478 gaim_debug_error("msn", "Couldn't find slpmsg\n");
479 g_return_if_reached();
480 }
481
482 if ((slpmsg->slpcall != NULL) &&
483 (slpmsg->slpcall->progress_cb != NULL))
484 {
485 slpmsg->slpcall->progress_cb(slpmsg->slpcall, slpmsg->size, len, offset);
486 }
487
488 #if 0
489 if (slpmsg->buffer == NULL)
490 return;
491 #endif
492
493 if (msg->msnslp_header.offset + msg->msnslp_header.length
494 >= msg->msnslp_header.total_size)
495 {
496 /* All the pieces of the slpmsg have been received */
497 MsnSlpCall *slpcall;
498
499 slpcall = msn_slp_process_msg(slplink, slpmsg);
500
501 if (slpmsg->flags == 0x100)
502 {
503 MsnDirectConn *directconn;
504
505 directconn = slplink->directconn;
506
507 if (!directconn->acked)
508 msn_directconn_send_handshake(directconn);
509 }
510 else if (slpmsg->flags == 0x0 || slpmsg->flags == 0x20 ||
511 slpmsg->flags == 0x1000030)
512 {
513 /* Release all the messages and send the ACK */
514
515 msn_slplink_send_ack(slplink, msg);
516 msn_slplink_unleash(slplink);
517 }
518
519 msn_slpmsg_destroy(slpmsg);
520
521 if (slpcall != NULL && slpcall->wasted)
522 msn_slp_call_destroy(slpcall);
523 }
524 }
525
526 MsnSlpMessage *
527 msn_slplink_message_find(MsnSlpLink *slplink, long id)
528 {
529 GList *e;
530
531 for (e = slplink->slp_msgs; e != NULL; e = e->next)
532 {
533 MsnSlpMessage *slpmsg = e->data;
534
535 if (slpmsg->id == id)
536 return slpmsg;
537 }
538
539 return NULL;
540 }
541
542 typedef struct
543 {
544 guint32 length;
545 guint32 unk1;
546 guint32 file_size;
547 guint32 unk2;
548 guint32 unk3;
549 } MsnContextHeader;
550
551 #define MAX_FILE_NAME_LEN 0x226
552
553 char *
554 gen_context(const char *file_name)
555 {
556 struct stat st;
557 gsize size = 0;
558 MsnContextHeader header;
559 gchar *u8;
560 gchar *base, *n;
561 gunichar2 *uni;
562 glong uni_len;
563 gsize len;
564
565 if (stat(file_name, &st) == 0)
566 size = st.st_size;
567
568 u8 = g_locale_to_utf8(g_basename(file_name), -1, NULL, NULL, NULL);
569 uni = g_utf8_to_utf16(u8, -1, NULL, &uni_len, NULL);
570 g_free(u8);
571
572 len = sizeof(MsnContextHeader) + MAX_FILE_NAME_LEN + 4;
573
574 header.length = GUINT32_TO_LE(len);
575 header.unk1 = GUINT32_TO_LE(2);
576 header.file_size = GUINT32_TO_LE(size);
577 header.unk2 = GUINT32_TO_LE(0);
578 header.unk3 = GUINT32_TO_LE(0);
579
580 base = n = g_malloc(len + 1);
581
582 memcpy(n, &header, sizeof(MsnContextHeader));
583 n += sizeof(MsnContextHeader);
584
585 memset(n, 0x00, MAX_FILE_NAME_LEN);
586 memcpy(n, uni, uni_len * 2);
587 n += MAX_FILE_NAME_LEN;
588
589 memset(n, 0xFF, 4);
590 n += 4;
591
592 g_free(uni);
593
594 return gaim_base64_encode(base, len);
595 }
596
597 void
598 msn_slplink_request_ft(MsnSlpLink *slplink, GaimXfer *xfer)
599 {
600 MsnSlpCall *slpcall;
601 char *context;
602 const char *fn;
603
604 fn = gaim_xfer_get_local_filename(xfer);
605
606 g_return_if_fail(slplink != NULL);
607 g_return_if_fail(fn != NULL);
608
609 slpcall = msn_slp_call_new(slplink);
610 msn_slp_call_init(slpcall, MSN_SLPCALL_DC);
611
612 slpcall->session_init_cb = send_file;
613 slpcall->progress_cb = msn_xfer_progress_cb;
614 slpcall->cb = msn_xfer_finish_cb;
615 slpcall->xfer = xfer;
616
617 gaim_xfer_set_cancel_send_fnc(xfer, msn_xfer_cancel);
618
619 xfer->data = slpcall;
620
621 context = gen_context(fn);
622
623 msn_slp_call_invite(slpcall, "5D3E02AB-6190-11D3-BBBB-00C04F795683", 2,
624 context);
625
626 g_free(context);
627 }
628
629 void
630 msn_slplink_request_object(MsnSlpLink *slplink,
631 const char *info,
632 MsnSlpCb cb,
633 const MsnObject *obj)
634 {
635 MsnSlpCall *slpcall;
636 char *msnobj_data;
637 char *msnobj_base64;
638
639 g_return_if_fail(slplink != NULL);
640 g_return_if_fail(obj != NULL);
641
642 msnobj_data = msn_object_to_string(obj);
643 msnobj_base64 = gaim_base64_encode(msnobj_data, strlen(msnobj_data));
644 g_free(msnobj_data);
645
646 slpcall = msn_slp_call_new(slplink);
647 msn_slp_call_init(slpcall, MSN_SLPCALL_ANY);
648
649 slpcall->data_info = g_strdup(info);
650 slpcall->cb = cb;
651
652 msn_slp_call_invite(slpcall, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6", 1,
653 msnobj_base64);
654
655 g_free(msnobj_base64);
656 }