comparison libpurple/protocols/msn/notification.c @ 15373:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children 32c366eeeb99
comparison
equal deleted inserted replaced
15372:f79e0f4df793 15373:5fe8042783c1
1 /**
2 * @file notification.c Notification server functions
3 *
4 * gaim
5 *
6 * Gaim 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 #include "msn.h"
25 #include "notification.h"
26 #include "state.h"
27 #include "error.h"
28 #include "msn-utils.h"
29 #include "page.h"
30
31 #include "userlist.h"
32 #include "sync.h"
33 #include "slplink.h"
34
35 static MsnTable *cbs_table;
36
37 /**************************************************************************
38 * Main
39 **************************************************************************/
40
41 static void
42 destroy_cb(MsnServConn *servconn)
43 {
44 MsnNotification *notification;
45
46 notification = servconn->cmdproc->data;
47 g_return_if_fail(notification != NULL);
48
49 msn_notification_destroy(notification);
50 }
51
52 MsnNotification *
53 msn_notification_new(MsnSession *session)
54 {
55 MsnNotification *notification;
56 MsnServConn *servconn;
57
58 g_return_val_if_fail(session != NULL, NULL);
59
60 notification = g_new0(MsnNotification, 1);
61
62 notification->session = session;
63 notification->servconn = servconn = msn_servconn_new(session, MSN_SERVCONN_NS);
64 msn_servconn_set_destroy_cb(servconn, destroy_cb);
65
66 notification->cmdproc = servconn->cmdproc;
67 notification->cmdproc->data = notification;
68 notification->cmdproc->cbs_table = cbs_table;
69
70 return notification;
71 }
72
73 void
74 msn_notification_destroy(MsnNotification *notification)
75 {
76 notification->cmdproc->data = NULL;
77
78 msn_servconn_set_destroy_cb(notification->servconn, NULL);
79
80 msn_servconn_destroy(notification->servconn);
81
82 g_free(notification);
83 }
84
85 /**************************************************************************
86 * Connect
87 **************************************************************************/
88
89 static void
90 connect_cb(MsnServConn *servconn)
91 {
92 MsnCmdProc *cmdproc;
93 MsnSession *session;
94 GaimAccount *account;
95 char **a, **c, *vers;
96 int i;
97
98 g_return_if_fail(servconn != NULL);
99
100 cmdproc = servconn->cmdproc;
101 session = servconn->session;
102 account = session->account;
103
104 /* Allocate an array for CVR0, NULL, and all the versions */
105 a = c = g_new0(char *, session->protocol_ver - 8 + 3);
106
107 for (i = session->protocol_ver; i >= 8; i--)
108 *c++ = g_strdup_printf("MSNP%d", i);
109
110 *c++ = g_strdup("CVR0");
111
112 vers = g_strjoinv(" ", a);
113
114 if (session->login_step == MSN_LOGIN_STEP_START)
115 msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE);
116 else
117 msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE2);
118
119 msn_cmdproc_send(cmdproc, "VER", "%s", vers);
120
121 g_strfreev(a);
122 g_free(vers);
123 }
124
125 gboolean
126 msn_notification_connect(MsnNotification *notification, const char *host, int port)
127 {
128 MsnServConn *servconn;
129
130 g_return_val_if_fail(notification != NULL, FALSE);
131
132 servconn = notification->servconn;
133
134 msn_servconn_set_connect_cb(servconn, connect_cb);
135 notification->in_use = msn_servconn_connect(servconn, host, port);
136
137 return notification->in_use;
138 }
139
140 void
141 msn_notification_disconnect(MsnNotification *notification)
142 {
143 g_return_if_fail(notification != NULL);
144 g_return_if_fail(notification->in_use);
145
146 msn_servconn_disconnect(notification->servconn);
147
148 notification->in_use = FALSE;
149 }
150
151 /**************************************************************************
152 * Util
153 **************************************************************************/
154
155 static void
156 group_error_helper(MsnSession *session, const char *msg, int group_id, int error)
157 {
158 GaimAccount *account;
159 GaimConnection *gc;
160 char *reason = NULL;
161 char *title = NULL;
162
163 account = session->account;
164 gc = gaim_account_get_connection(account);
165
166 if (error == 224)
167 {
168 if (group_id == 0)
169 {
170 return;
171 }
172 else
173 {
174 const char *group_name;
175 group_name =
176 msn_userlist_find_group_name(session->userlist,
177 group_id);
178 reason = g_strdup_printf(_("%s is not a valid group."),
179 group_name);
180 }
181 }
182 else
183 {
184 reason = g_strdup(_("Unknown error."));
185 }
186
187 title = g_strdup_printf(_("%s on %s (%s)"), msg,
188 gaim_account_get_username(account),
189 gaim_account_get_protocol_name(account));
190 gaim_notify_error(gc, NULL, title, reason);
191 g_free(title);
192 g_free(reason);
193 }
194
195 /**************************************************************************
196 * Login
197 **************************************************************************/
198
199 void
200 msn_got_login_params(MsnSession *session, const char *login_params)
201 {
202 MsnCmdProc *cmdproc;
203
204 cmdproc = session->notification->cmdproc;
205
206 msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_END);
207
208 msn_cmdproc_send(cmdproc, "USR", "TWN S %s", login_params);
209 }
210
211 static void
212 cvr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
213 {
214 GaimAccount *account;
215
216 account = cmdproc->session->account;
217
218 msn_cmdproc_send(cmdproc, "USR", "TWN I %s",
219 gaim_account_get_username(account));
220 }
221
222 static void
223 usr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
224 {
225 MsnSession *session;
226 GaimAccount *account;
227 GaimConnection *gc;
228
229 session = cmdproc->session;
230 account = session->account;
231 gc = gaim_account_get_connection(account);
232
233 if (!g_ascii_strcasecmp(cmd->params[1], "OK"))
234 {
235 /* OK */
236 const char *friendly = gaim_url_decode(cmd->params[3]);
237
238 gaim_connection_set_display_name(gc, friendly);
239
240 msn_session_set_login_step(session, MSN_LOGIN_STEP_SYN);
241
242 msn_cmdproc_send(cmdproc, "SYN", "%s", "0");
243 }
244 else if (!g_ascii_strcasecmp(cmd->params[1], "TWN"))
245 {
246 /* Passport authentication */
247 char **elems, **cur, **tokens;
248
249 session->nexus = msn_nexus_new(session);
250
251 /* Parse the challenge data. */
252
253 elems = g_strsplit(cmd->params[3], ",", 0);
254
255 for (cur = elems; *cur != NULL; cur++)
256 {
257 tokens = g_strsplit(*cur, "=", 2);
258 g_hash_table_insert(session->nexus->challenge_data, tokens[0], tokens[1]);
259 /* Don't free each of the tokens, only the array. */
260 g_free(tokens);
261 }
262
263 g_strfreev(elems);
264
265 msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_START);
266
267 msn_nexus_connect(session->nexus);
268 }
269 }
270
271 static void
272 usr_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
273 {
274 MsnErrorType msnerr = 0;
275
276 switch (error)
277 {
278 case 500:
279 case 601:
280 case 910:
281 case 921:
282 msnerr = MSN_ERROR_SERV_UNAVAILABLE;
283 break;
284 case 911:
285 msnerr = MSN_ERROR_AUTH;
286 break;
287 default:
288 return;
289 break;
290 }
291
292 msn_session_set_error(cmdproc->session, msnerr, NULL);
293 }
294
295 static void
296 ver_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
297 {
298 MsnSession *session;
299 GaimAccount *account;
300 gboolean protocol_supported = FALSE;
301 char proto_str[8];
302 size_t i;
303
304 session = cmdproc->session;
305 account = session->account;
306
307 g_snprintf(proto_str, sizeof(proto_str), "MSNP%d", session->protocol_ver);
308
309 for (i = 1; i < cmd->param_count; i++)
310 {
311 if (!strcmp(cmd->params[i], proto_str))
312 {
313 protocol_supported = TRUE;
314 break;
315 }
316 }
317
318 if (!protocol_supported)
319 {
320 msn_session_set_error(session, MSN_ERROR_UNSUPPORTED_PROTOCOL,
321 NULL);
322 return;
323 }
324
325 msn_cmdproc_send(cmdproc, "CVR",
326 "0x0409 winnt 5.1 i386 MSNMSGR 6.0.0602 MSMSGS %s",
327 gaim_account_get_username(account));
328 }
329
330 /**************************************************************************
331 * Log out
332 **************************************************************************/
333
334 static void
335 out_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
336 {
337 if (!g_ascii_strcasecmp(cmd->params[0], "OTH"))
338 msn_session_set_error(cmdproc->session, MSN_ERROR_SIGN_OTHER,
339 NULL);
340 else if (!g_ascii_strcasecmp(cmd->params[0], "SSD"))
341 msn_session_set_error(cmdproc->session, MSN_ERROR_SERV_DOWN, NULL);
342 }
343
344 void
345 msn_notification_close(MsnNotification *notification)
346 {
347 g_return_if_fail(notification != NULL);
348
349 if (!notification->in_use)
350 return;
351
352 msn_cmdproc_send_quick(notification->cmdproc, "OUT", NULL, NULL);
353
354 msn_notification_disconnect(notification);
355 }
356
357 /**************************************************************************
358 * Messages
359 **************************************************************************/
360
361 static void
362 msg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
363 size_t len)
364 {
365 MsnMessage *msg;
366
367 msg = msn_message_new_from_cmd(cmdproc->session, cmd);
368
369 msn_message_parse_payload(msg, payload, len);
370 #ifdef MSN_DEBUG_NS
371 msn_message_show_readable(msg, "Notification", TRUE);
372 #endif
373
374 msn_cmdproc_process_msg(cmdproc, msg);
375
376 msn_message_destroy(msg);
377 }
378
379 static void
380 msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
381 {
382 /* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued
383 * command and we are processing it */
384
385 if (cmd->payload == NULL)
386 {
387 cmdproc->last_cmd->payload_cb = msg_cmd_post;
388 cmdproc->servconn->payload_len = atoi(cmd->params[2]);
389 }
390 else
391 {
392 g_return_if_fail(cmd->payload_cb != NULL);
393
394 cmd->payload_cb(cmdproc, cmd, cmd->payload, cmd->payload_len);
395 }
396 }
397
398 /**************************************************************************
399 * Challenges
400 **************************************************************************/
401
402 static void
403 chl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
404 {
405 MsnTransaction *trans;
406 char buf[33];
407 const char *challenge_resp;
408 GaimCipher *cipher;
409 GaimCipherContext *context;
410 guchar digest[16];
411 int i;
412
413 cipher = gaim_ciphers_find_cipher("md5");
414 context = gaim_cipher_context_new(cipher, NULL);
415
416 gaim_cipher_context_append(context, (const guchar *)cmd->params[1],
417 strlen(cmd->params[1]));
418
419 challenge_resp = "VT6PX?UQTM4WM%YR";
420
421 gaim_cipher_context_append(context, (const guchar *)challenge_resp,
422 strlen(challenge_resp));
423 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL);
424 gaim_cipher_context_destroy(context);
425
426 for (i = 0; i < 16; i++)
427 g_snprintf(buf + (i*2), 3, "%02x", digest[i]);
428
429 trans = msn_transaction_new(cmdproc, "QRY", "%s 32", "PROD0038W!61ZTF9");
430
431 msn_transaction_set_payload(trans, buf, 32);
432
433 msn_cmdproc_send_trans(cmdproc, trans);
434 }
435
436 /**************************************************************************
437 * Buddy Lists
438 **************************************************************************/
439
440 static void
441 add_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
442 {
443 MsnSession *session;
444 MsnUser *user;
445 const char *list;
446 const char *passport;
447 const char *friendly;
448 MsnListId list_id;
449 int group_id;
450
451 list = cmd->params[1];
452 passport = cmd->params[3];
453 friendly = gaim_url_decode(cmd->params[4]);
454
455 session = cmdproc->session;
456
457 user = msn_userlist_find_user(session->userlist, passport);
458
459 if (user == NULL)
460 {
461 user = msn_user_new(session->userlist, passport, friendly);
462 msn_userlist_add_user(session->userlist, user);
463 }
464 else
465 msn_user_set_friendly_name(user, friendly);
466
467 list_id = msn_get_list_id(list);
468
469 if (cmd->param_count >= 6)
470 group_id = atoi(cmd->params[5]);
471 else
472 group_id = -1;
473
474 msn_got_add_user(session, user, list_id, group_id);
475 msn_user_update(user);
476 }
477
478 static void
479 add_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
480 {
481 MsnSession *session;
482 GaimAccount *account;
483 GaimConnection *gc;
484 const char *list, *passport;
485 char *reason = NULL;
486 char *msg = NULL;
487 char **params;
488
489 session = cmdproc->session;
490 account = session->account;
491 gc = gaim_account_get_connection(account);
492 params = g_strsplit(trans->params, " ", 0);
493
494 list = params[0];
495 passport = params[1];
496
497 if (!strcmp(list, "FL"))
498 msg = g_strdup_printf(_("Unable to add user on %s (%s)"),
499 gaim_account_get_username(account),
500 gaim_account_get_protocol_name(account));
501 else if (!strcmp(list, "BL"))
502 msg = g_strdup_printf(_("Unable to block user on %s (%s)"),
503 gaim_account_get_username(account),
504 gaim_account_get_protocol_name(account));
505 else if (!strcmp(list, "AL"))
506 msg = g_strdup_printf(_("Unable to permit user on %s (%s)"),
507 gaim_account_get_username(account),
508 gaim_account_get_protocol_name(account));
509
510 if (!strcmp(list, "FL"))
511 {
512 if (error == 210)
513 {
514 reason = g_strdup_printf(_("%s could not be added because "
515 "your buddy list is full."), passport);
516 }
517 }
518
519 if (reason == NULL)
520 {
521 if (error == 208)
522 {
523 reason = g_strdup_printf(_("%s is not a valid passport account."),
524 passport);
525 }
526 else if (error == 500)
527 {
528 reason = g_strdup(_("Service Temporarily Unavailable."));
529 }
530 else
531 {
532 reason = g_strdup(_("Unknown error."));
533 }
534 }
535
536 if (msg != NULL)
537 {
538 gaim_notify_error(gc, NULL, msg, reason);
539 g_free(msg);
540 }
541
542 if (!strcmp(list, "FL"))
543 {
544 GaimBuddy *buddy;
545
546 buddy = gaim_find_buddy(account, passport);
547
548 if (buddy != NULL)
549 gaim_blist_remove_buddy(buddy);
550 }
551
552 g_free(reason);
553
554 g_strfreev(params);
555 }
556
557 static void
558 adg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
559 {
560 MsnSession *session;
561 gint group_id;
562 const char *group_name;
563
564 session = cmdproc->session;
565
566 group_id = atoi(cmd->params[3]);
567
568 group_name = gaim_url_decode(cmd->params[2]);
569
570 msn_group_new(session->userlist, group_id, group_name);
571
572 /* There is a user that must me moved to this group */
573 if (cmd->trans->data)
574 {
575 /* msn_userlist_move_buddy(); */
576 MsnUserList *userlist = cmdproc->session->userlist;
577 MsnMoveBuddy *data = cmd->trans->data;
578
579 if (data->old_group_name != NULL)
580 {
581 msn_userlist_rem_buddy(userlist, data->who, MSN_LIST_FL, data->old_group_name);
582 g_free(data->old_group_name);
583 }
584
585 msn_userlist_add_buddy(userlist, data->who, MSN_LIST_FL, group_name);
586 g_free(data->who);
587
588 }
589 }
590
591 static void
592 fln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
593 {
594 MsnSlpLink *slplink;
595 MsnUser *user;
596
597 user = msn_userlist_find_user(cmdproc->session->userlist, cmd->params[0]);
598
599 user->status = "offline";
600 msn_user_update(user);
601
602 slplink = msn_session_find_slplink(cmdproc->session, cmd->params[0]);
603
604 if (slplink != NULL)
605 msn_slplink_destroy(slplink);
606
607 }
608
609 static void
610 iln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
611 {
612 MsnSession *session;
613 GaimAccount *account;
614 GaimConnection *gc;
615 MsnUser *user;
616 MsnObject *msnobj;
617 const char *state, *passport, *friendly;
618
619 session = cmdproc->session;
620 account = session->account;
621 gc = gaim_account_get_connection(account);
622
623 state = cmd->params[1];
624 passport = cmd->params[2];
625 friendly = gaim_url_decode(cmd->params[3]);
626
627 user = msn_userlist_find_user(session->userlist, passport);
628
629 serv_got_alias(gc, passport, friendly);
630
631 msn_user_set_friendly_name(user, friendly);
632
633 if (session->protocol_ver >= 9 && cmd->param_count == 6)
634 {
635 msnobj = msn_object_new_from_string(gaim_url_decode(cmd->params[5]));
636 msn_user_set_object(user, msnobj);
637 }
638
639 msn_user_set_state(user, state);
640 msn_user_update(user);
641 }
642
643 static void
644 ipg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len)
645 {
646 #if 0
647 gaim_debug_misc("msn", "Incoming Page: {%s}\n", payload);
648 #endif
649 }
650
651 static void
652 ipg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
653 {
654 cmdproc->servconn->payload_len = atoi(cmd->params[0]);
655 cmdproc->last_cmd->payload_cb = ipg_cmd_post;
656 }
657
658 static void
659 nln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
660 {
661 MsnSession *session;
662 GaimAccount *account;
663 GaimConnection *gc;
664 MsnUser *user;
665 MsnObject *msnobj;
666 int clientid;
667 const char *state, *passport, *friendly, *old_friendly;
668
669 session = cmdproc->session;
670 account = session->account;
671 gc = gaim_account_get_connection(account);
672
673 state = cmd->params[0];
674 passport = cmd->params[1];
675 friendly = gaim_url_decode(cmd->params[2]);
676
677 user = msn_userlist_find_user(session->userlist, passport);
678
679 old_friendly = msn_user_get_friendly_name(user);
680 if (!old_friendly || (old_friendly && strcmp(old_friendly, friendly)))
681 {
682 serv_got_alias(gc, passport, friendly);
683 msn_user_set_friendly_name(user, friendly);
684 }
685
686 if (session->protocol_ver >= 9)
687 {
688 if (cmd->param_count == 5)
689 {
690 msnobj =
691 msn_object_new_from_string(gaim_url_decode(cmd->params[4]));
692 msn_user_set_object(user, msnobj);
693 }
694 else
695 {
696 msn_user_set_object(user, NULL);
697 }
698 }
699
700 clientid = atoi(cmd->params[3]);
701 user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE);
702
703 msn_user_set_state(user, state);
704 msn_user_update(user);
705 }
706
707 #if 0
708 static void
709 chg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
710 {
711 char *state = cmd->params[1];
712 int state_id = 0;
713
714 if (!strcmp(state, "NLN"))
715 state_id = MSN_ONLINE;
716 else if (!strcmp(state, "BSY"))
717 state_id = MSN_BUSY;
718 else if (!strcmp(state, "IDL"))
719 state_id = MSN_IDLE;
720 else if (!strcmp(state, "BRB"))
721 state_id = MSN_BRB;
722 else if (!strcmp(state, "AWY"))
723 state_id = MSN_AWAY;
724 else if (!strcmp(state, "PHN"))
725 state_id = MSN_PHONE;
726 else if (!strcmp(state, "LUN"))
727 state_id = MSN_LUNCH;
728 else if (!strcmp(state, "HDN"))
729 state_id = MSN_HIDDEN;
730
731 cmdproc->session->state = state_id;
732 }
733 #endif
734
735
736 static void
737 not_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len)
738 {
739 #if 0
740 MSN_SET_PARAMS("NOT %d\r\n%s", cmdproc->servconn->payload, payload);
741 gaim_debug_misc("msn", "Notification: {%s}\n", payload);
742 #endif
743 }
744
745 static void
746 not_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
747 {
748 cmdproc->servconn->payload_len = atoi(cmd->params[0]);
749 cmdproc->last_cmd->payload_cb = not_cmd_post;
750 }
751
752 static void
753 rea_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
754 {
755 /* TODO: This might be for us too */
756
757 MsnSession *session;
758 GaimConnection *gc;
759 const char *friendly;
760
761 session = cmdproc->session;
762 gc = session->account->gc;
763 friendly = gaim_url_decode(cmd->params[3]);
764
765 gaim_connection_set_display_name(gc, friendly);
766 }
767
768 static void
769 prp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
770 {
771 MsnSession *session = cmdproc->session;
772 const char *type, *value;
773
774 g_return_if_fail(cmd->param_count >= 3);
775
776 type = cmd->params[2];
777
778 if (cmd->param_count == 4)
779 {
780 value = cmd->params[3];
781 if (!strcmp(type, "PHH"))
782 msn_user_set_home_phone(session->user, gaim_url_decode(value));
783 else if (!strcmp(type, "PHW"))
784 msn_user_set_work_phone(session->user, gaim_url_decode(value));
785 else if (!strcmp(type, "PHM"))
786 msn_user_set_mobile_phone(session->user, gaim_url_decode(value));
787 }
788 else
789 {
790 if (!strcmp(type, "PHH"))
791 msn_user_set_home_phone(session->user, NULL);
792 else if (!strcmp(type, "PHW"))
793 msn_user_set_work_phone(session->user, NULL);
794 else if (!strcmp(type, "PHM"))
795 msn_user_set_mobile_phone(session->user, NULL);
796 }
797 }
798
799 static void
800 reg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
801 {
802 MsnSession *session;
803 int group_id;
804 const char *group_name;
805
806 session = cmdproc->session;
807 group_id = atoi(cmd->params[2]);
808 group_name = gaim_url_decode(cmd->params[3]);
809
810 msn_userlist_rename_group_id(session->userlist, group_id, group_name);
811 }
812
813 static void
814 reg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
815 {
816 int group_id;
817 char **params;
818
819 params = g_strsplit(trans->params, " ", 0);
820
821 group_id = atoi(params[0]);
822
823 group_error_helper(cmdproc->session, _("Unable to rename group"), group_id, error);
824
825 g_strfreev(params);
826 }
827
828 static void
829 rem_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
830 {
831 MsnSession *session;
832 MsnUser *user;
833 const char *list;
834 const char *passport;
835 MsnListId list_id;
836 int group_id;
837
838 session = cmdproc->session;
839 list = cmd->params[1];
840 passport = cmd->params[3];
841 user = msn_userlist_find_user(session->userlist, passport);
842
843 g_return_if_fail(user != NULL);
844
845 list_id = msn_get_list_id(list);
846
847 if (cmd->param_count == 5)
848 group_id = atoi(cmd->params[4]);
849 else
850 group_id = -1;
851
852 msn_got_rem_user(session, user, list_id, group_id);
853 msn_user_update(user);
854 }
855
856 static void
857 rmg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
858 {
859 MsnSession *session;
860 int group_id;
861
862 session = cmdproc->session;
863 group_id = atoi(cmd->params[2]);
864
865 msn_userlist_remove_group_id(session->userlist, group_id);
866 }
867
868 static void
869 rmg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
870 {
871 int group_id;
872 char **params;
873
874 params = g_strsplit(trans->params, " ", 0);
875
876 group_id = atoi(params[0]);
877
878 group_error_helper(cmdproc->session, _("Unable to delete group"), group_id, error);
879
880 g_strfreev(params);
881 }
882
883 static void
884 syn_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
885 {
886 MsnSession *session;
887 int total_users;
888
889 session = cmdproc->session;
890
891 if (cmd->param_count == 2)
892 {
893 /*
894 * This can happen if we sent a SYN with an up-to-date
895 * buddy list revision, but we send 0 to get a full list.
896 * So, error out.
897 */
898
899 msn_session_set_error(cmdproc->session, MSN_ERROR_BAD_BLIST, NULL);
900 return;
901 }
902
903 total_users = atoi(cmd->params[2]);
904
905 if (total_users == 0)
906 {
907 msn_session_finish_login(session);
908 }
909 else
910 {
911 /* syn_table */
912 MsnSync *sync;
913
914 sync = msn_sync_new(session);
915 sync->total_users = total_users;
916 sync->old_cbs_table = cmdproc->cbs_table;
917
918 session->sync = sync;
919 cmdproc->cbs_table = sync->cbs_table;
920 }
921 }
922
923 /**************************************************************************
924 * Misc commands
925 **************************************************************************/
926
927 static void
928 url_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
929 {
930 MsnSession *session;
931 GaimAccount *account;
932 const char *rru;
933 const char *url;
934 GaimCipher *cipher;
935 GaimCipherContext *context;
936 guchar digest[16];
937 FILE *fd;
938 char *buf;
939 char buf2[3];
940 char sendbuf[64];
941 int i;
942
943 session = cmdproc->session;
944 account = session->account;
945
946 rru = cmd->params[1];
947 url = cmd->params[2];
948
949 buf = g_strdup_printf("%s%lu%s",
950 session->passport_info.mspauth,
951 time(NULL) - session->passport_info.sl,
952 gaim_connection_get_password(account->gc));
953
954 cipher = gaim_ciphers_find_cipher("md5");
955 context = gaim_cipher_context_new(cipher, NULL);
956
957 gaim_cipher_context_append(context, (const guchar *)buf, strlen(buf));
958 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL);
959 gaim_cipher_context_destroy(context);
960
961 g_free(buf);
962
963 memset(sendbuf, 0, sizeof(sendbuf));
964
965 for (i = 0; i < 16; i++)
966 {
967 g_snprintf(buf2, sizeof(buf2), "%02x", digest[i]);
968 strcat(sendbuf, buf2);
969 }
970
971 if (session->passport_info.file != NULL)
972 {
973 g_unlink(session->passport_info.file);
974 g_free(session->passport_info.file);
975 }
976
977 if ((fd = gaim_mkstemp(&session->passport_info.file, FALSE)) == NULL)
978 {
979 gaim_debug_error("msn",
980 "Error opening temp passport file: %s\n",
981 strerror(errno));
982 }
983 else
984 {
985 fputs("<html>\n"
986 "<head>\n"
987 "<noscript>\n"
988 "<meta http-equiv=\"Refresh\" content=\"0; "
989 "url=http://www.hotmail.com\">\n"
990 "</noscript>\n"
991 "</head>\n\n",
992 fd);
993
994 fprintf(fd, "<body onload=\"document.pform.submit(); \">\n");
995 fprintf(fd, "<form name=\"pform\" action=\"%s\" method=\"POST\">\n\n",
996 url);
997 fprintf(fd, "<input type=\"hidden\" name=\"mode\" value=\"ttl\">\n");
998 fprintf(fd, "<input type=\"hidden\" name=\"login\" value=\"%s\">\n",
999 gaim_account_get_username(account));
1000 fprintf(fd, "<input type=\"hidden\" name=\"username\" value=\"%s\">\n",
1001 gaim_account_get_username(account));
1002 if (session->passport_info.sid != NULL)
1003 fprintf(fd, "<input type=\"hidden\" name=\"sid\" value=\"%s\">\n",
1004 session->passport_info.sid);
1005 if (session->passport_info.kv != NULL)
1006 fprintf(fd, "<input type=\"hidden\" name=\"kv\" value=\"%s\">\n",
1007 session->passport_info.kv);
1008 fprintf(fd, "<input type=\"hidden\" name=\"id\" value=\"2\">\n");
1009 fprintf(fd, "<input type=\"hidden\" name=\"sl\" value=\"%ld\">\n",
1010 time(NULL) - session->passport_info.sl);
1011 fprintf(fd, "<input type=\"hidden\" name=\"rru\" value=\"%s\">\n",
1012 rru);
1013 if (session->passport_info.mspauth != NULL)
1014 fprintf(fd, "<input type=\"hidden\" name=\"auth\" value=\"%s\">\n",
1015 session->passport_info.mspauth);
1016 fprintf(fd, "<input type=\"hidden\" name=\"creds\" value=\"%s\">\n",
1017 sendbuf); /* TODO Digest me (huh? -- ChipX86) */
1018 fprintf(fd, "<input type=\"hidden\" name=\"svc\" value=\"mail\">\n");
1019 fprintf(fd, "<input type=\"hidden\" name=\"js\" value=\"yes\">\n");
1020 fprintf(fd, "</form></body>\n");
1021 fprintf(fd, "</html>\n");
1022
1023 if (fclose(fd))
1024 {
1025 gaim_debug_error("msn",
1026 "Error closing temp passport file: %s\n",
1027 strerror(errno));
1028
1029 g_unlink(session->passport_info.file);
1030 g_free(session->passport_info.file);
1031 session->passport_info.file = NULL;
1032 }
1033 #ifdef _WIN32
1034 else
1035 {
1036 /*
1037 * Renaming file with .html extension, so that the
1038 * win32 open_url will work.
1039 */
1040 char *tmp;
1041
1042 if ((tmp =
1043 g_strdup_printf("%s.html",
1044 session->passport_info.file)) != NULL)
1045 {
1046 if (g_rename(session->passport_info.file,
1047 tmp) == 0)
1048 {
1049 g_free(session->passport_info.file);
1050 session->passport_info.file = tmp;
1051 }
1052 else
1053 g_free(tmp);
1054 }
1055 }
1056 #endif
1057 }
1058 }
1059 /**************************************************************************
1060 * Switchboards
1061 **************************************************************************/
1062
1063 static void
1064 rng_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
1065 {
1066 MsnSession *session;
1067 MsnSwitchBoard *swboard;
1068 const char *session_id;
1069 char *host;
1070 int port;
1071
1072 session = cmdproc->session;
1073 session_id = cmd->params[0];
1074
1075 msn_parse_socket(cmd->params[1], &host, &port);
1076
1077 if (session->http_method)
1078 port = 80;
1079
1080 swboard = msn_switchboard_new(session);
1081
1082 msn_switchboard_set_invited(swboard, TRUE);
1083 msn_switchboard_set_session_id(swboard, cmd->params[0]);
1084 msn_switchboard_set_auth_key(swboard, cmd->params[3]);
1085 swboard->im_user = g_strdup(cmd->params[4]);
1086 /* msn_switchboard_add_user(swboard, cmd->params[4]); */
1087
1088 if (!msn_switchboard_connect(swboard, host, port))
1089 msn_switchboard_destroy(swboard);
1090
1091 g_free(host);
1092 }
1093
1094 static void
1095 xfr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
1096 {
1097 char *host;
1098 int port;
1099
1100 if (strcmp(cmd->params[1], "SB") && strcmp(cmd->params[1], "NS"))
1101 {
1102 /* Maybe we can have a generic bad command error. */
1103 gaim_debug_error("msn", "Bad XFR command (%s)\n", cmd->params[1]);
1104 return;
1105 }
1106
1107 msn_parse_socket(cmd->params[2], &host, &port);
1108
1109 if (!strcmp(cmd->params[1], "SB"))
1110 {
1111 gaim_debug_error("msn", "This shouldn't be handled here.\n");
1112 }
1113 else if (!strcmp(cmd->params[1], "NS"))
1114 {
1115 MsnSession *session;
1116
1117 session = cmdproc->session;
1118
1119 msn_session_set_login_step(session, MSN_LOGIN_STEP_TRANSFER);
1120
1121 msn_notification_connect(session->notification, host, port);
1122 }
1123
1124 g_free(host);
1125 }
1126
1127 /**************************************************************************
1128 * Message Types
1129 **************************************************************************/
1130
1131 static void
1132 profile_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
1133 {
1134 MsnSession *session;
1135 const char *value;
1136
1137 session = cmdproc->session;
1138
1139 if (strcmp(msg->remote_user, "Hotmail"))
1140 /* This isn't an official message. */
1141 return;
1142
1143 if ((value = msn_message_get_attr(msg, "kv")) != NULL)
1144 {
1145 if (session->passport_info.kv != NULL)
1146 g_free(session->passport_info.kv);
1147
1148 session->passport_info.kv = g_strdup(value);
1149 }
1150
1151 if ((value = msn_message_get_attr(msg, "sid")) != NULL)
1152 {
1153 if (session->passport_info.sid != NULL)
1154 g_free(session->passport_info.sid);
1155
1156 session->passport_info.sid = g_strdup(value);
1157 }
1158
1159 if ((value = msn_message_get_attr(msg, "MSPAuth")) != NULL)
1160 {
1161 if (session->passport_info.mspauth != NULL)
1162 g_free(session->passport_info.mspauth);
1163
1164 session->passport_info.mspauth = g_strdup(value);
1165 }
1166
1167 if ((value = msn_message_get_attr(msg, "ClientIP")) != NULL)
1168 {
1169 if (session->passport_info.client_ip != NULL)
1170 g_free(session->passport_info.client_ip);
1171
1172 session->passport_info.client_ip = g_strdup(value);
1173 }
1174
1175 if ((value = msn_message_get_attr(msg, "ClientPort")) != NULL)
1176 session->passport_info.client_port = ntohs(atoi(value));
1177
1178 if ((value = msn_message_get_attr(msg, "LoginTime")) != NULL)
1179 session->passport_info.sl = atol(value);
1180 }
1181
1182 static void
1183 initial_email_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
1184 {
1185 MsnSession *session;
1186 GaimConnection *gc;
1187 GHashTable *table;
1188 const char *unread;
1189
1190 session = cmdproc->session;
1191 gc = session->account->gc;
1192
1193 if (strcmp(msg->remote_user, "Hotmail"))
1194 /* This isn't an official message. */
1195 return;
1196
1197 if (session->passport_info.file == NULL)
1198 {
1199 MsnTransaction *trans;
1200 trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
1201 msn_transaction_queue_cmd(trans, msg->cmd);
1202
1203 msn_cmdproc_send_trans(cmdproc, trans);
1204
1205 return;
1206 }
1207
1208 if (!gaim_account_get_check_mail(session->account))
1209 return;
1210
1211 table = msn_message_get_hashtable_from_body(msg);
1212
1213 unread = g_hash_table_lookup(table, "Inbox-Unread");
1214
1215 if (unread != NULL)
1216 {
1217 int count = atoi(unread);
1218
1219 if (count > 0)
1220 {
1221 const char *passport;
1222 const char *url;
1223
1224 passport = msn_user_get_passport(session->user);
1225 url = session->passport_info.file;
1226
1227 gaim_notify_emails(gc, atoi(unread), FALSE, NULL, NULL,
1228 &passport, &url, NULL, NULL);
1229 }
1230 }
1231
1232 g_hash_table_destroy(table);
1233 }
1234
1235 static void
1236 email_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
1237 {
1238 MsnSession *session;
1239 GaimConnection *gc;
1240 GHashTable *table;
1241 char *from, *subject, *tmp;
1242
1243 session = cmdproc->session;
1244 gc = session->account->gc;
1245
1246 if (strcmp(msg->remote_user, "Hotmail"))
1247 /* This isn't an official message. */
1248 return;
1249
1250 if (session->passport_info.file == NULL)
1251 {
1252 MsnTransaction *trans;
1253 trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
1254 msn_transaction_queue_cmd(trans, msg->cmd);
1255
1256 msn_cmdproc_send_trans(cmdproc, trans);
1257
1258 return;
1259 }
1260
1261 if (!gaim_account_get_check_mail(session->account))
1262 return;
1263
1264 table = msn_message_get_hashtable_from_body(msg);
1265
1266 from = subject = NULL;
1267
1268 tmp = g_hash_table_lookup(table, "From");
1269 if (tmp != NULL)
1270 from = gaim_mime_decode_field(tmp);
1271
1272 tmp = g_hash_table_lookup(table, "Subject");
1273 if (tmp != NULL)
1274 subject = gaim_mime_decode_field(tmp);
1275
1276 gaim_notify_email(gc,
1277 (subject != NULL ? subject : ""),
1278 (from != NULL ? from : ""),
1279 msn_user_get_passport(session->user),
1280 session->passport_info.file, NULL, NULL);
1281
1282 if (from != NULL)
1283 g_free(from);
1284
1285 if (subject != NULL)
1286 g_free(subject);
1287
1288 g_hash_table_destroy(table);
1289 }
1290
1291 static void
1292 system_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
1293 {
1294 GHashTable *table;
1295 const char *type_s;
1296
1297 if (strcmp(msg->remote_user, "Hotmail"))
1298 /* This isn't an official message. */
1299 return;
1300
1301 table = msn_message_get_hashtable_from_body(msg);
1302
1303 if ((type_s = g_hash_table_lookup(table, "Type")) != NULL)
1304 {
1305 int type = atoi(type_s);
1306 char buf[MSN_BUF_LEN];
1307 int minutes;
1308
1309 switch (type)
1310 {
1311 case 1:
1312 minutes = atoi(g_hash_table_lookup(table, "Arg1"));
1313 g_snprintf(buf, sizeof(buf), ngettext(
1314 "The MSN server will shut down for maintenance "
1315 "in %d minute. You will automatically be "
1316 "signed out at that time. Please finish any "
1317 "conversations in progress.\n\nAfter the "
1318 "maintenance has been completed, you will be "
1319 "able to successfully sign in.",
1320 "The MSN server will shut down for maintenance "
1321 "in %d minutes. You will automatically be "
1322 "signed out at that time. Please finish any "
1323 "conversations in progress.\n\nAfter the "
1324 "maintenance has been completed, you will be "
1325 "able to successfully sign in.", minutes),
1326 minutes);
1327 default:
1328 break;
1329 }
1330
1331 if (*buf != '\0')
1332 gaim_notify_info(cmdproc->session->account->gc, NULL, buf, NULL);
1333 }
1334
1335 g_hash_table_destroy(table);
1336 }
1337
1338 void
1339 msn_notification_add_buddy(MsnNotification *notification, const char *list,
1340 const char *who, const char *store_name,
1341 int group_id)
1342 {
1343 MsnCmdProc *cmdproc;
1344 cmdproc = notification->servconn->cmdproc;
1345
1346 if (group_id < 0 && !strcmp(list, "FL"))
1347 group_id = 0;
1348
1349 if (group_id >= 0)
1350 {
1351 msn_cmdproc_send(cmdproc, "ADD", "%s %s %s %d",
1352 list, who, store_name, group_id);
1353 }
1354 else
1355 {
1356 msn_cmdproc_send(cmdproc, "ADD", "%s %s %s", list, who, store_name);
1357 }
1358 }
1359
1360 void
1361 msn_notification_rem_buddy(MsnNotification *notification, const char *list,
1362 const char *who, int group_id)
1363 {
1364 MsnCmdProc *cmdproc;
1365 cmdproc = notification->servconn->cmdproc;
1366
1367 if (group_id >= 0)
1368 {
1369 msn_cmdproc_send(cmdproc, "REM", "%s %s %d", list, who, group_id);
1370 }
1371 else
1372 {
1373 msn_cmdproc_send(cmdproc, "REM", "%s %s", list, who);
1374 }
1375 }
1376
1377 /**************************************************************************
1378 * Init
1379 **************************************************************************/
1380
1381 void
1382 msn_notification_init(void)
1383 {
1384 /* TODO: check prp, blp */
1385
1386 cbs_table = msn_table_new();
1387
1388 /* Synchronous */
1389 msn_table_add_cmd(cbs_table, "CHG", "CHG", NULL);
1390 msn_table_add_cmd(cbs_table, "CHG", "ILN", iln_cmd);
1391 msn_table_add_cmd(cbs_table, "ADD", "ADD", add_cmd);
1392 msn_table_add_cmd(cbs_table, "ADD", "ILN", iln_cmd);
1393 msn_table_add_cmd(cbs_table, "REM", "REM", rem_cmd);
1394 msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd);
1395 msn_table_add_cmd(cbs_table, "USR", "XFR", xfr_cmd);
1396 msn_table_add_cmd(cbs_table, "SYN", "SYN", syn_cmd);
1397 msn_table_add_cmd(cbs_table, "CVR", "CVR", cvr_cmd);
1398 msn_table_add_cmd(cbs_table, "VER", "VER", ver_cmd);
1399 msn_table_add_cmd(cbs_table, "REA", "REA", rea_cmd);
1400 msn_table_add_cmd(cbs_table, "PRP", "PRP", prp_cmd);
1401 /* msn_table_add_cmd(cbs_table, "BLP", "BLP", blp_cmd); */
1402 msn_table_add_cmd(cbs_table, "BLP", "BLP", NULL);
1403 msn_table_add_cmd(cbs_table, "REG", "REG", reg_cmd);
1404 msn_table_add_cmd(cbs_table, "ADG", "ADG", adg_cmd);
1405 msn_table_add_cmd(cbs_table, "RMG", "RMG", rmg_cmd);
1406 msn_table_add_cmd(cbs_table, "XFR", "XFR", xfr_cmd);
1407
1408 /* Asynchronous */
1409 msn_table_add_cmd(cbs_table, NULL, "IPG", ipg_cmd);
1410 msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd);
1411 msn_table_add_cmd(cbs_table, NULL, "NOT", not_cmd);
1412
1413 msn_table_add_cmd(cbs_table, NULL, "CHL", chl_cmd);
1414 msn_table_add_cmd(cbs_table, NULL, "REM", rem_cmd);
1415 msn_table_add_cmd(cbs_table, NULL, "ADD", add_cmd);
1416
1417 msn_table_add_cmd(cbs_table, NULL, "QRY", NULL);
1418 msn_table_add_cmd(cbs_table, NULL, "QNG", NULL);
1419 msn_table_add_cmd(cbs_table, NULL, "FLN", fln_cmd);
1420 msn_table_add_cmd(cbs_table, NULL, "NLN", nln_cmd);
1421 msn_table_add_cmd(cbs_table, NULL, "ILN", iln_cmd);
1422 msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd);
1423 msn_table_add_cmd(cbs_table, NULL, "RNG", rng_cmd);
1424
1425 msn_table_add_cmd(cbs_table, NULL, "URL", url_cmd);
1426
1427 msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd);
1428
1429 msn_table_add_error(cbs_table, "ADD", add_error);
1430 msn_table_add_error(cbs_table, "REG", reg_error);
1431 msn_table_add_error(cbs_table, "RMG", rmg_error);
1432 /* msn_table_add_error(cbs_table, "REA", rea_error); */
1433 msn_table_add_error(cbs_table, "USR", usr_error);
1434
1435 msn_table_add_msg_type(cbs_table,
1436 "text/x-msmsgsprofile",
1437 profile_msg);
1438 msn_table_add_msg_type(cbs_table,
1439 "text/x-msmsgsinitialemailnotification",
1440 initial_email_msg);
1441 msn_table_add_msg_type(cbs_table,
1442 "text/x-msmsgsemailnotification",
1443 email_msg);
1444 msn_table_add_msg_type(cbs_table,
1445 "application/x-msmsgssystemmessage",
1446 system_msg);
1447 }
1448
1449 void
1450 msn_notification_end(void)
1451 {
1452 msn_table_destroy(cbs_table);
1453 }