comparison src/protocols/msn/notification.c @ 5309:e2e53316a21d

[gaim-migrate @ 5681] Announcing the new MSN prpl! It probably has some bugs, and for the time being, there is no file transfer. That's good though, because the current MSN file transfer is a little broken. I've had many corrupted files. I'll commit new file transfer code when it's written. I want this heavily tested before 0.63! If you use MSN, please talk to people on it. Let me know of any oddities, crashes, bugs, whatever. I'll fix things as I find them. committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Tue, 06 May 2003 02:06:56 +0000
parents
children 89948fedf782
comparison
equal deleted inserted replaced
5308:6aa785e55d0f 5309:e2e53316a21d
1 /**
2 * @file notification.c Notification server functions
3 *
4 * gaim
5 *
6 * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22 #include "msn.h"
23 #include "notification.h"
24 #include "away.h"
25 #include "error.h"
26 #include "utils.h"
27
28 typedef struct
29 {
30 struct gaim_connection *gc;
31 MsnUser *user;
32
33 } MsnPermitAdd;
34
35 static GHashTable *notification_commands = NULL;
36 static GHashTable *notification_msg_types = NULL;
37
38 /**************************************************************************
39 * Callbacks
40 **************************************************************************/
41 static void
42 msn_accept_add_cb(MsnPermitAdd *pa)
43 {
44 if (g_slist_find(connections, pa->gc) != NULL) {
45 MsnSession *session = pa->gc->proto_data;
46 char outparams[MSN_BUF_LEN];
47
48 g_snprintf(outparams, sizeof(outparams), "AL %s %s",
49 msn_user_get_passport(pa->user),
50 msn_url_encode(msn_user_get_name(pa->user)));
51
52 if (msn_servconn_send_command(session->notification_conn,
53 "ADD", outparams) <= 0) {
54 hide_login_progress(pa->gc, _("Write error"));
55 signoff(pa->gc);
56 return;
57 }
58
59 gaim_privacy_permit_add(pa->gc->account,
60 msn_user_get_passport(pa->user));
61 build_allow_list();
62
63 show_got_added(pa->gc, NULL, msn_user_get_passport(pa->user),
64 msn_user_get_name(pa->user), NULL);
65 }
66
67 msn_user_destroy(pa->user);
68 g_free(pa);
69 }
70
71 static void
72 msn_cancel_add_cb(MsnPermitAdd *pa)
73 {
74 if (g_slist_find(connections, pa->gc) != NULL) {
75 MsnSession *session = pa->gc->proto_data;
76 char outparams[MSN_BUF_LEN];
77
78 g_snprintf(outparams, sizeof(outparams), "BL %s %s",
79 msn_user_get_passport(pa->user),
80 msn_url_encode(msn_user_get_name(pa->user)));
81
82 if (msn_servconn_send_command(session->notification_conn,
83 "ADD", outparams) <= 0) {
84 hide_login_progress(pa->gc, _("Write error"));
85 signoff(pa->gc);
86 return;
87 }
88
89 gaim_privacy_deny_add(pa->gc->account,
90 msn_user_get_passport(pa->user));
91 build_block_list();
92 }
93
94 msn_user_destroy(pa->user);
95 g_free(pa);
96 }
97
98 /**************************************************************************
99 * Catch-all commands
100 **************************************************************************/
101 static gboolean
102 __blank_cmd(MsnServConn *servconn, const char *command, const char **params,
103 size_t param_count)
104 {
105 return TRUE;
106 }
107
108 static gboolean
109 __unknown_cmd(MsnServConn *servconn, const char *command, const char **params,
110 size_t param_count)
111 {
112 struct gaim_connection *gc = servconn->session->account->gc;
113
114 if (isdigit(*command)) {
115 hide_login_progress(gc, (char *)msn_error_get_text(atoi(command)));
116 }
117 else
118 hide_login_progress(gc, _("Unable to parse message."));
119
120 signoff(gc);
121
122 return FALSE;
123 }
124
125
126 /**************************************************************************
127 * Login
128 **************************************************************************/
129 static gboolean
130 __ver_cmd(MsnServConn *servconn, const char *command, const char **params,
131 size_t param_count)
132 {
133 struct gaim_connection *gc = servconn->session->account->gc;
134 size_t i;
135 gboolean msnp5_found = FALSE;
136
137 for (i = 1; i < param_count; i++) {
138 if (!strcmp(params[i], "MSNP5")) {
139 msnp5_found = TRUE;
140 break;
141 }
142 }
143
144 if (!msnp5_found) {
145 hide_login_progress(gc, _("Protocol not supported"));
146 signoff(gc);
147
148 return FALSE;
149 }
150
151 if (!msn_servconn_send_command(servconn, "INF", NULL)) {
152 hide_login_progress(gc, _("Unable to request INF"));
153 signoff(gc);
154
155 return FALSE;
156 }
157
158 return TRUE;
159 }
160
161 static gboolean
162 __inf_cmd(MsnServConn *servconn, const char *command, const char **params,
163 size_t param_count)
164 {
165 struct gaim_connection *gc = servconn->session->account->gc;
166 char outparams[MSN_BUF_LEN];
167
168 if (strcmp(params[1], "MD5")) {
169 hide_login_progress(gc, _("Unable to login using MD5"));
170 signoff(gc);
171
172 return FALSE;
173 }
174
175 g_snprintf(outparams, sizeof(outparams), "MD5 I %s", gc->username);
176
177 if (!msn_servconn_send_command(servconn, "USR", outparams)) {
178 hide_login_progress(gc, _("Unable to send USR"));
179 signoff(gc);
180
181 return FALSE;
182 }
183
184 set_login_progress(gc, 3, _("Requesting to send password"));
185
186 return TRUE;
187 }
188
189 static gboolean
190 __usr_cmd(MsnServConn *servconn, const char *command, const char **params,
191 size_t param_count)
192 {
193 struct gaim_connection *gc = servconn->session->account->gc;
194 char outparams[MSN_BUF_LEN];
195
196 /* We're either getting the challenge or the OK. Let's find out. */
197 if (!g_ascii_strcasecmp(params[1], "OK")) {
198 /* OK */
199
200 if (!msn_servconn_send_command(servconn, "SYN", "0")) {
201 hide_login_progress(gc, _("Unable to write"));
202 signoff(gc);
203
204 return FALSE;
205 }
206 }
207 else {
208 /* Challenge */
209 const char *challenge = params[3];
210 char buf[MSN_BUF_LEN];
211 md5_state_t st;
212 md5_byte_t di[16];
213 int i;
214
215 g_snprintf(buf, sizeof(buf), "%s%s", challenge, gc->password);
216
217 md5_init(&st);
218 md5_append(&st, (const md5_byte_t *)buf, strlen(buf));
219 md5_finish(&st, di);
220
221 g_snprintf(outparams, sizeof(outparams), "MD5 S ");
222
223 for (i = 0; i < 16; i++) {
224 g_snprintf(buf, sizeof(buf), "%02x", di[i]);
225 strcat(outparams, buf);
226 }
227
228 if (!msn_servconn_send_command(servconn, "USR", outparams)) {
229 hide_login_progress(gc, _("Unable to send password"));
230 signoff(gc);
231
232 return FALSE;
233 }
234
235 set_login_progress(gc, 4, _("Password sent"));
236 }
237
238 return TRUE;
239 }
240
241 /**************************************************************************
242 * Log out
243 **************************************************************************/
244 static gboolean
245 __out_cmd(MsnServConn *servconn, const char *command, const char **params,
246 size_t param_count)
247 {
248 struct gaim_connection *gc = servconn->session->account->gc;
249
250 if (!g_ascii_strcasecmp(params[0], "OTH")) {
251 hide_login_progress(gc,
252 _("You have been disconnected. You have "
253 "signed on from another location."));
254 signoff(gc);
255 }
256 else if (!g_ascii_strcasecmp(params[0], "SSD")) {
257 hide_login_progress(gc,
258 _("You have been disconnected. The MSN servers "
259 "are going down temporarily."));
260 signoff(gc);
261 }
262
263 return FALSE;
264 }
265
266 /**************************************************************************
267 * Messages
268 **************************************************************************/
269 static gboolean
270 __msg_cmd(MsnServConn *servconn, const char *command, const char **params,
271 size_t param_count)
272 {
273 gaim_debug(GAIM_DEBUG_INFO, "msn", "Found message. Parsing.\n");
274
275 servconn->parsing_msg = TRUE;
276 servconn->msg_passport = g_strdup(params[0]);
277 servconn->msg_friendly = g_strdup(params[1]);
278 servconn->msg_len = atoi(params[2]);
279
280 return TRUE;
281 }
282
283 /**************************************************************************
284 * Challenges
285 **************************************************************************/
286 static gboolean
287 __chl_cmd(MsnServConn *servconn, const char *command, const char **params,
288 size_t param_count)
289 {
290 struct gaim_connection *gc = servconn->session->account->gc;
291 char buf[MSN_BUF_LEN];
292 char buf2[3];
293 md5_state_t st;
294 md5_byte_t di[16];
295 int i;
296
297 md5_init(&st);
298 md5_append(&st, (const md5_byte_t *)params[1], strlen(params[1]));
299 md5_append(&st, (const md5_byte_t *)"Q1P7W2E4J9R8U3S5",
300 strlen("Q1P7W2E4J9R8U3S5"));
301 md5_finish(&st, di);
302
303 g_snprintf(buf, sizeof(buf),
304 "QRY %u msmsgs@msnmsgr.com 32\r\n",
305 servconn->session->trId++);
306
307 for (i = 0; i < 16; i++) {
308 g_snprintf(buf2, sizeof(buf2), "%02x", di[i]);
309 strcat(buf, buf2);
310 }
311
312 if (msn_servconn_write(servconn, buf, strlen(buf)) <= 0) {
313 hide_login_progress(gc, _("Unable to write to server"));
314 signoff(gc);
315 }
316
317 return TRUE;
318 }
319
320 /**************************************************************************
321 * Buddy Lists
322 **************************************************************************/
323 static gboolean
324 __add_cmd(MsnServConn *servconn, const char *command, const char **params,
325 size_t param_count)
326 {
327 MsnSession *session = servconn->session;
328 struct gaim_connection *gc = session->account->gc;
329 MsnPermitAdd *pa;
330 GSList *sl;
331 const char *list, *passport;
332 char *friend;
333 char msg[MSN_BUF_LEN];
334
335 list = params[1];
336 passport = params[3];
337
338 friend = msn_url_decode(params[4]);
339
340 if (g_ascii_strcasecmp(list, "RL"))
341 return TRUE;
342
343 for (sl = gc->account->permit; sl != NULL; sl = sl->next) {
344 if (!gaim_utf8_strcasecmp(sl->data, passport))
345 return TRUE;
346 }
347
348 pa = g_new0(MsnPermitAdd, 1);
349 pa->user = msn_user_new(session, passport, friend);
350 pa->gc = gc;
351
352 g_snprintf(msg, sizeof(msg),
353 _("The user %s (%s) wants to add %s to his or her buddy list."),
354 passport, friend, gc->username);
355
356 do_ask_dialog(msg, NULL, pa,
357 _("Authorize"), msn_accept_add_cb,
358 _("Deny"), msn_cancel_add_cb,
359 session->prpl->handle, FALSE);
360
361 return TRUE;
362 }
363
364 static gboolean
365 __blp_cmd(MsnServConn *servconn, const char *command, const char **params,
366 size_t param_count)
367 {
368 struct gaim_connection *gc = servconn->session->account->gc;
369
370 if (!g_ascii_strcasecmp(params[2], "AL")) {
371 /*
372 * If the current setting is AL, messages from users who
373 * are not in BL will be delivered.
374 *
375 * In other words, deny some.
376 */
377 gc->account->permdeny = DENY_SOME;
378 }
379 else {
380 /* If the current setting is BL, only messages from people
381 * who are in the AL will be delivered.
382 *
383 * In other words, permit some.
384 */
385 gc->account->permdeny = PERMIT_SOME;
386 }
387
388 return TRUE;
389 }
390
391 static gboolean
392 __fln_cmd(MsnServConn *servconn, const char *command, const char **params,
393 size_t param_count)
394 {
395 struct gaim_connection *gc = servconn->session->account->gc;
396
397 serv_got_update(gc, (char *)params[0], 0, 0, 0, 0, 0);
398
399 return TRUE;
400 }
401
402 static gboolean
403 __iln_cmd(MsnServConn *servconn, const char *command, const char **params,
404 size_t param_count)
405 {
406 struct gaim_connection *gc = servconn->session->account->gc;
407 int status = 0;
408 const char *state, *passport, *friend;
409
410 state = params[1];
411 passport = params[2];
412 friend = msn_url_decode(params[3]);
413
414 serv_got_alias(gc, (char *)passport, (char *)friend);
415
416 if (!g_ascii_strcasecmp(state, "BSY"))
417 status |= UC_UNAVAILABLE | (MSN_BUSY << 1);
418 else if (!g_ascii_strcasecmp(state, "IDL"))
419 status |= UC_UNAVAILABLE | (MSN_IDLE << 1);
420 else if (!g_ascii_strcasecmp(state, "BRB"))
421 status |= UC_UNAVAILABLE | (MSN_BRB << 1);
422 else if (!g_ascii_strcasecmp(state, "AWY"))
423 status |= UC_UNAVAILABLE | (MSN_AWAY << 1);
424 else if (!g_ascii_strcasecmp(state, "PHN"))
425 status |= UC_UNAVAILABLE | (MSN_PHONE << 1);
426 else if (!g_ascii_strcasecmp(state, "LUN"))
427 status |= UC_UNAVAILABLE | (MSN_LUNCH << 1);
428
429 serv_got_update(gc, (char *)passport, 1, 0, 0, 0, status);
430
431 return TRUE;
432 }
433
434 static gboolean
435 __lsg_cmd(MsnServConn *servconn, const char *command, const char **params,
436 size_t param_count)
437 {
438 MsnSession *session = servconn->session;
439 struct group *g;
440 const char *name;
441 int group_num, num_groups, group_id;
442
443 group_num = atoi(params[2]);
444 num_groups = atoi(params[3]);
445 group_id = atoi(params[4]);
446 name = msn_url_decode(params[5]);
447
448 if (group_num == 1) {
449 session->groups = g_hash_table_new_full(g_int_hash, g_int_equal,
450 NULL, g_free);
451 }
452
453 g_hash_table_insert(session->groups, GINT_TO_POINTER(group_id),
454 g_strdup(name));
455
456 if ((g = gaim_find_group(name)) == NULL) {
457 g = gaim_group_new(name);
458 gaim_blist_add_group(g, NULL);
459 }
460
461 return TRUE;
462 }
463
464 static gboolean
465 __lst_cmd(MsnServConn *servconn, const char *command, const char **params,
466 size_t param_count)
467 {
468 MsnSession *session = servconn->session;
469 struct gaim_connection *gc = session->account->gc;
470 int user_num;
471 int num_users;
472 const char *type;
473 const char *passport;
474 const char *friend;
475
476 user_num = atoi(params[3]);
477 num_users = atoi(params[4]);
478
479 if (user_num == 0 && num_users == 0)
480 return TRUE; /* There are no users on this list. */
481
482 type = params[1];
483 passport = params[5];
484 friend = msn_url_decode(params[6]);
485
486 if (!g_ascii_strcasecmp(type, "FL") && user_num != 0) {
487 /* These are users on our contact list. */
488 MsnUser *user;
489
490 user = msn_user_new(session, passport, friend);
491
492 if (param_count == 8)
493 msn_user_set_group_id(user, atoi(params[7]));
494
495 session->lists.forward = g_slist_append(session->lists.forward, user);
496 }
497 else if (!g_ascii_strcasecmp(type, "AL") && user_num != 0) {
498 /* These are users who are allowed to see our status. */
499 if (g_slist_find_custom(gc->account->deny, passport,
500 (GCompareFunc)strcmp)) {
501
502 gaim_debug(GAIM_DEBUG_INFO, "msn",
503 "Moving user from deny list to permit: %s (%s)\n",
504 passport, friend);
505
506 gaim_privacy_deny_remove(gc->account, passport);
507 }
508
509 gaim_privacy_permit_add(gc->account, passport);
510 }
511 else if (!g_ascii_strcasecmp(type, "BL") && user_num != 0) {
512 /* These are users who are not allowed to see our status. */
513 gaim_privacy_deny_add(gc->account, passport);
514 }
515 else if (!g_ascii_strcasecmp(type, "RL")) {
516 /* These are users who have us on their contact list. */
517 if (user_num > 0) {
518 gboolean new_entry = TRUE;
519
520 if (g_slist_find_custom(gc->account->permit, passport,
521 (GCompareFunc)g_ascii_strcasecmp)) {
522 new_entry = FALSE;
523 }
524
525 if (g_slist_find_custom(gc->account->deny, passport,
526 (GCompareFunc)g_ascii_strcasecmp)) {
527 new_entry = FALSE;
528 }
529
530 if (new_entry) {
531 MsnPermitAdd *pa;
532 char msg[MSN_BUF_LEN];
533
534 gaim_debug(GAIM_DEBUG_WARNING, "msn",
535 "Unresolved MSN RL entry: %s\n", passport);
536
537 pa = g_new0(MsnPermitAdd, 1);
538 pa->user = msn_user_new(session, passport, friend);
539 pa->gc = gc;
540
541 g_snprintf(msg, sizeof(msg),
542 _("The user %s (%s) wants to add you to their "
543 "buddy list."),
544 msn_user_get_passport(pa->user),
545 msn_user_get_name(pa->user));
546
547 do_ask_dialog(msg, NULL, pa,
548 _("Authorize"), msn_accept_add_cb,
549 _("Deny"), msn_cancel_add_cb,
550 session->prpl->handle, FALSE);
551 }
552 }
553
554 if (user_num != num_users)
555 return TRUE; /* This isn't the last one in the RL. */
556
557 if (!msn_servconn_send_command(servconn, "CHG", "NLN")) {
558 hide_login_progress(gc, _("Unable to write"));
559 signoff(gc);
560
561 return FALSE;
562 }
563
564 account_online(gc);
565 serv_finish_login(gc);
566
567 session->lists.allow = g_slist_copy(gc->account->permit);
568 session->lists.block = g_slist_copy(gc->account->deny);
569
570 while (session->lists.forward != NULL) {
571 MsnUser *user = session->lists.forward->data;
572 struct buddy *b;
573
574 b = gaim_find_buddy(gc->account, msn_user_get_passport(user));
575
576 session->lists.forward = g_slist_remove(session->lists.forward,
577 user);
578
579 if (b == NULL) {
580 struct group *g = NULL;
581 const char *group_name = NULL;
582 int group_id;
583
584 group_id = msn_user_get_group_id(user);
585
586 if (group_id > -1) {
587 group_name = g_hash_table_lookup(session->groups,
588 GINT_TO_POINTER(group_id));
589 }
590
591 if (group_name == NULL) {
592 gaim_debug(GAIM_DEBUG_WARNING, "msn",
593 "Group ID %d for user %s was not defined.\n",
594 group_id, passport);
595 }
596 else if ((g = gaim_find_group(group_name)) == NULL) {
597 gaim_debug(GAIM_DEBUG_ERROR, "msn",
598 "Group '%s' appears in server-side "
599 "buddy list, but not here!",
600 group_name);
601 }
602
603 if (g == NULL) {
604 if ((g = gaim_find_group(_("Buddies"))) == NULL) {
605 g = gaim_group_new(_("Buddies"));
606 gaim_blist_add_group(g, NULL);
607 }
608 }
609
610 b = gaim_buddy_new(gc->account,
611 msn_user_get_passport(user), NULL);
612
613 gaim_blist_add_buddy(b, g, NULL);
614 }
615
616 serv_got_alias(gc, (char *)msn_user_get_passport(user),
617 (char *)msn_user_get_name(user));
618
619 msn_user_destroy(user);
620 }
621 }
622
623 return TRUE;
624 }
625
626 static gboolean
627 __nln_cmd(MsnServConn *servconn, const char *command, const char **params,
628 size_t param_count)
629 {
630 MsnSession *session = servconn->session;
631 struct gaim_connection *gc = session->account->gc;
632 const char *state;
633 const char *passport;
634 const char *friend;
635 int status = 0;
636
637 state = params[0];
638 passport = params[1];
639 friend = msn_url_decode(params[2]);
640
641 serv_got_alias(gc, (char *)passport, (char *)friend);
642
643 if (!g_ascii_strcasecmp(state, "BSY"))
644 status |= UC_UNAVAILABLE | (MSN_BUSY << 1);
645 else if (!g_ascii_strcasecmp(state, "IDL"))
646 status |= UC_UNAVAILABLE | (MSN_IDLE << 1);
647 else if (!g_ascii_strcasecmp(state, "BRB"))
648 status |= UC_UNAVAILABLE | (MSN_BRB << 1);
649 else if (!g_ascii_strcasecmp(state, "AWY"))
650 status |= UC_UNAVAILABLE | (MSN_AWAY << 1);
651 else if (!g_ascii_strcasecmp(state, "PHN"))
652 status |= UC_UNAVAILABLE | (MSN_PHONE << 1);
653 else if (!g_ascii_strcasecmp(state, "LUN"))
654 status |= UC_UNAVAILABLE | (MSN_LUNCH << 1);
655
656 serv_got_update(gc, (char *)passport, 1, 0, 0, 0, status);
657
658 return TRUE;
659 }
660
661 static gboolean
662 __rea_cmd(MsnServConn *servconn, const char *command, const char **params,
663 size_t param_count)
664 {
665 MsnSession *session = servconn->session;
666 struct gaim_connection *gc = session->account->gc;
667 char *friend;
668
669 friend = msn_url_decode(params[2]);
670
671 g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", friend);
672
673 return TRUE;
674 }
675
676 /**************************************************************************
677 * Misc commands
678 **************************************************************************/
679 static gboolean
680 __url_cmd(MsnServConn *servconn, const char *command, const char **params,
681 size_t param_count)
682 {
683 MsnSession *session = servconn->session;
684 struct gaim_connection *gc = session->account->gc;
685 const char *rru;
686 const char *url;
687 md5_state_t st;
688 md5_byte_t di[16];
689 FILE *fd;
690 char buf[2048];
691 char buf2[3];
692 char sendbuf[64];
693 int i;
694
695 rru = params[1];
696 url = params[2];
697
698 g_snprintf(buf, sizeof(buf), "%s%lu%s",
699 session->passport_info.mspauth,
700 time(NULL) - session->passport_info.sl, gc->password);
701
702 md5_init(&st);
703 md5_append(&st, (const md5_byte_t *)buf, strlen(buf));
704 md5_finish(&st, di);
705
706 memset(sendbuf, 0, sizeof(sendbuf));
707
708 for (i = 0; i < 16; i++) {
709 g_snprintf(buf2, sizeof(buf2), "%02x", di[i]);
710 strcat(sendbuf, buf2);
711 }
712
713 if (session->passport_info.file != NULL) {
714 unlink(session->passport_info.file);
715 g_free(session->passport_info.file);
716 }
717
718 if ((fd = gaim_mkstemp(&session->passport_info.file)) == NULL) {
719 gaim_debug(GAIM_DEBUG_ERROR, "msn",
720 "Error opening temp passport file: %s\n",
721 strerror(errno));
722 }
723 else {
724 fputs("<html>\n"
725 "<head>\n"
726 "<noscript>\n"
727 "<meta http-equiv=\"Refresh\" content=\"0; "
728 "url=http://www.hotmail.com\">\n"
729 "</noscript>\n"
730 "</head>\n\n",
731 fd);
732
733 fprintf(fd, "<body onload=\"document.pform.submit(); \">\n");
734 fprintf(fd, "<form name=\"pform\" action=\"%s\" method=\"POST\">\n\n",
735 url);
736 fprintf(fd, "<input type=\"hidden\" name=\"mode\" value=\"ttl\">\n");
737 fprintf(fd, "<input type=\"hidden\" name=\"login\" value=\"%s\">\n",
738 gc->username);
739 fprintf(fd, "<input type=\"hidden\" name=\"username\" value=\"%s\">\n",
740 gc->username);
741 fprintf(fd, "<input type=\"hidden\" name=\"sid\" value=\"%s\">\n",
742 session->passport_info.sid);
743 fprintf(fd, "<input type=\"hidden\" name=\"kv\" value=\"%s\">\n",
744 session->passport_info.kv);
745 fprintf(fd, "<input type=\"hidden\" name=\"id\" value=\"2\">\n");
746 fprintf(fd, "<input type=\"hidden\" name=\"sl\" value=\"%ld\">\n",
747 time(NULL) - session->passport_info.sl);
748 fprintf(fd, "<input type=\"hidden\" name=\"rru\" value=\"%s\">\n",
749 rru);
750 fprintf(fd, "<input type=\"hidden\" name=\"auth\" value=\"%s\">\n",
751 session->passport_info.mspauth);
752 fprintf(fd, "<input type=\"hidden\" name=\"creds\" value=\"%s\">\n",
753 sendbuf); /* TODO Digest me (huh? -- ChipX86) */
754 fprintf(fd, "<input type=\"hidden\" name=\"svc\" value=\"mail\">\n");
755 fprintf(fd, "<input type=\"hiden\" name=\"js\" value=\"yes\">\n");
756 fprintf(fd, "</form></body>\n");
757 fprintf(fd, "</html>\n");
758
759 if (fclose(fd)) {
760 gaim_debug(GAIM_DEBUG_ERROR, "msn",
761 "Error closing temp passport file: %s\n",
762 strerror(errno));
763
764 unlink(session->passport_info.file);
765 g_free(session->passport_info.file);
766 }
767 else {
768 /*
769 * Renaming file with .html extension, so that the
770 * win32 open_url will work.
771 */
772 char *tmp;
773
774 if ((tmp = g_strdup_printf("%s.html",
775 session->passport_info.file)) != NULL) {
776
777 if (rename(session->passport_info.file, tmp) == 0) {
778 g_free(session->passport_info.file);
779 session->passport_info.file = tmp;
780 }
781 else
782 g_free(tmp);
783 }
784 }
785 }
786
787 return TRUE;
788 }
789 /**************************************************************************
790 * Switchboards
791 **************************************************************************/
792 static gboolean
793 __rng_cmd(MsnServConn *servconn, const char *command, const char **params,
794 size_t param_count)
795 {
796 MsnSession *session = servconn->session;
797 MsnSwitchBoard *swboard;
798 MsnUser *user;
799 const char *session_id;
800 char *host, *c;
801 int port;
802
803 session_id = params[0];
804
805 host = g_strdup(params[1]);
806
807 if ((c = strchr(host, ':')) != NULL) {
808 *c = '\0';
809 port = atoi(c + 1);
810 }
811 else
812 port = 1863;
813
814 swboard = msn_switchboard_new(session);
815
816 user = msn_user_new(session, params[4], NULL);
817
818 msn_switchboard_set_invited(swboard, TRUE);
819 msn_switchboard_set_session_id(swboard, params[0]);
820 msn_switchboard_set_auth_key(swboard, params[3]);
821 msn_switchboard_set_user(swboard, user);
822
823 if (!msn_switchboard_connect(swboard, host, port)) {
824 gaim_debug(GAIM_DEBUG_ERROR, "msn",
825 "Unable to connect to switchboard on %s, port %d\n",
826 host, port);
827
828 g_free(host);
829
830 return FALSE;
831 }
832
833 g_free(host);
834
835 return TRUE;
836 }
837
838 static gboolean
839 __xfr_cmd(MsnServConn *servconn, const char *command, const char **params,
840 size_t param_count)
841 {
842 MsnSession *session = servconn->session;
843 MsnSwitchBoard *swboard;
844 struct gaim_connection *gc = session->account->gc;
845 char *host;
846 char *c;
847 int port;
848
849 if (strcmp(params[1], "SB")) {
850 hide_login_progress(gc, _("Got invalid XFR"));
851 signoff(gc);
852
853 return FALSE;
854 }
855
856 host = g_strdup(params[2]);
857
858 if ((c = strchr(host, ':')) != NULL) {
859 *c = '\0';
860 port = atoi(c + 1);
861 }
862 else
863 port = 1863;
864
865 swboard = msn_session_find_unused_switch(session);
866
867 if (swboard == NULL) {
868 gaim_debug(GAIM_DEBUG_ERROR, "msn",
869 "Received an XFR SB request when there's no unused "
870 "switchboards!\n");
871 }
872
873 msn_switchboard_set_auth_key(swboard, params[4]);
874
875 if (!msn_switchboard_connect(swboard, host, port)) {
876 gaim_debug(GAIM_DEBUG_ERROR, "msn",
877 "Unable to connect to switchboard on %s, port %d\n",
878 host, port);
879
880 g_free(host);
881
882 return FALSE;
883 }
884
885 g_free(host);
886
887 return TRUE;
888 }
889
890 /**************************************************************************
891 * Message Types
892 **************************************************************************/
893 static gboolean
894 __profile_msg(MsnServConn *servconn, const MsnMessage *msg)
895 {
896 MsnSession *session = servconn->session;
897 const char *value;
898
899 if ((value = msn_message_get_attr(msg, "kv")) != NULL)
900 session->passport_info.kv = g_strdup(value);
901
902 if ((value = msn_message_get_attr(msg, "sid")) != NULL)
903 session->passport_info.sid = g_strdup(value);
904
905 if ((value = msn_message_get_attr(msg, "MSPAuth")) != NULL)
906 session->passport_info.mspauth = g_strdup(value);
907
908 return TRUE;
909 }
910
911 static gboolean
912 __initial_email_msg(MsnServConn *servconn, const MsnMessage *msg)
913 {
914 MsnSession *session = servconn->session;
915 struct gaim_connection *gc = session->account->gc;
916 GHashTable *table;
917 const char *unread;
918
919 table = msn_message_get_hashtable_from_body(msg);
920
921 unread = g_hash_table_lookup(table, "Inbox-Unread");
922
923 if (unread != NULL)
924 connection_has_mail(gc, atoi(unread), NULL, NULL,
925 session->passport_info.file);
926
927 g_hash_table_destroy(table);
928
929 return TRUE;
930 }
931
932 static gboolean
933 __email_msg(MsnServConn *servconn, const MsnMessage *msg)
934 {
935 MsnSession *session = servconn->session;
936 struct gaim_connection *gc = session->account->gc;
937 GHashTable *table;
938 const char *from, *subject;
939
940 table = msn_message_get_hashtable_from_body(msg);
941
942 from = g_hash_table_lookup(table, "From");
943 subject = g_hash_table_lookup(table, "Subject");
944
945 if (from == NULL || subject == NULL) {
946 connection_has_mail(gc, 1, NULL, NULL, session->passport_info.file);
947 }
948 else {
949 connection_has_mail(gc, -1, from, subject,
950 session->passport_info.file);
951 }
952
953 g_hash_table_destroy(table);
954
955 return TRUE;
956 }
957
958 static gboolean
959 __connect_cb(gpointer data, gint source, GaimInputCondition cond)
960 {
961 MsnServConn *notification = data;
962 MsnSession *session = notification->session;
963 struct gaim_connection *gc = session->account->gc;
964
965 if (source == -1) {
966 hide_login_progress(session->account->gc, _("Unable to connect"));
967 signoff(session->account->gc);
968 return FALSE;
969 }
970
971 if (notification->fd != source)
972 notification->fd = source;
973
974 if (!msn_servconn_send_command(notification, "VER",
975 "MSNP6 MSNP5 MSNP4 CVR0")) {
976 hide_login_progress(gc, _("Unable to write to server"));
977 signoff(gc);
978 return FALSE;
979 }
980
981 set_login_progress(session->account->gc, 2, _("Syncing with server"));
982
983 return TRUE;
984 }
985
986 static void
987 __failed_read_cb(gpointer data, gint source, GaimInputCondition cond)
988 {
989 MsnServConn *notification = data;
990 struct gaim_connection *gc;
991
992 gc = notification->session->account->gc;
993
994 hide_login_progress(gc, _("Error reading from server"));
995 signoff(gc);
996 }
997
998 MsnServConn *
999 msn_notification_new(MsnSession *session, const char *server, int port)
1000 {
1001 MsnServConn *notification;
1002
1003 notification = msn_servconn_new(session);
1004
1005 msn_servconn_set_server(notification, server, port);
1006 msn_servconn_set_connect_cb(notification, __connect_cb);
1007 msn_servconn_set_failed_read_cb(notification, __failed_read_cb);
1008
1009 if (notification_commands == NULL) {
1010 /* Register the command callbacks. */
1011 msn_servconn_register_command(notification, "ADD", __add_cmd);
1012 msn_servconn_register_command(notification, "BLP", __blp_cmd);
1013 msn_servconn_register_command(notification, "BPR", __blank_cmd);
1014 msn_servconn_register_command(notification, "CHG", __blank_cmd);
1015 msn_servconn_register_command(notification, "CHL", __chl_cmd);
1016 msn_servconn_register_command(notification, "FLN", __fln_cmd);
1017 msn_servconn_register_command(notification, "GTC", __blank_cmd);
1018 msn_servconn_register_command(notification, "ILN", __iln_cmd);
1019 msn_servconn_register_command(notification, "INF", __inf_cmd);
1020 msn_servconn_register_command(notification, "LSG", __lsg_cmd);
1021 msn_servconn_register_command(notification, "LST", __lst_cmd);
1022 msn_servconn_register_command(notification, "MSG", __msg_cmd);
1023 msn_servconn_register_command(notification, "NLN", __nln_cmd);
1024 msn_servconn_register_command(notification, "OUT", __out_cmd);
1025 msn_servconn_register_command(notification, "PRP", __blank_cmd);
1026 msn_servconn_register_command(notification, "QNG", __blank_cmd);
1027 msn_servconn_register_command(notification, "QRY", __blank_cmd);
1028 msn_servconn_register_command(notification, "REA", __rea_cmd);
1029 msn_servconn_register_command(notification, "REM", __blank_cmd);
1030 msn_servconn_register_command(notification, "RNG", __rng_cmd);
1031 msn_servconn_register_command(notification, "SYN", __blank_cmd);
1032 msn_servconn_register_command(notification, "URL", __url_cmd);
1033 msn_servconn_register_command(notification, "USR", __usr_cmd);
1034 msn_servconn_register_command(notification, "VER", __ver_cmd);
1035 msn_servconn_register_command(notification, "XFR", __xfr_cmd);
1036 msn_servconn_register_command(notification, "_unknown_", __unknown_cmd);
1037
1038 /* Register the message type callbacks. */
1039 msn_servconn_register_msg_type(notification, "text/x-msmsgsprofile",
1040 __profile_msg);
1041 msn_servconn_register_msg_type(notification,
1042 "text/x-msmsgsinitialemailnotification",
1043 __initial_email_msg);
1044 msn_servconn_register_msg_type(notification,
1045 "text/x-msmsgsemailnotification",
1046 __email_msg);
1047
1048 /* Save these for future use. */
1049 notification_commands = notification->commands;
1050 notification_msg_types = notification->msg_types;
1051 }
1052 else {
1053 g_hash_table_destroy(notification->commands);
1054 g_hash_table_destroy(notification->msg_types);
1055
1056 notification->commands = notification_commands;
1057 notification->msg_types = notification_msg_types;
1058 }
1059
1060 return notification;
1061 }