libpurple/protocols/msnp9/notification.c

changeset 21481
d52b697eaae7
child 21674
7e183cd7e0b5
equal deleted inserted replaced
21480:3fdf3e905e24 21481:d52b697eaae7
1 /**
2 * @file notification.c Notification server functions
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 "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 PurpleAccount *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 PurpleAccount *account;
159 PurpleConnection *gc;
160 char *reason = NULL;
161 char *title = NULL;
162
163 account = session->account;
164 gc = purple_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 purple_account_get_username(account),
189 purple_account_get_protocol_name(account));
190 purple_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 PurpleAccount *account;
215
216 account = cmdproc->session->account;
217
218 msn_cmdproc_send(cmdproc, "USR", "TWN I %s",
219 purple_account_get_username(account));
220 }
221
222 static void
223 usr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
224 {
225 MsnSession *session;
226 PurpleAccount *account;
227 PurpleConnection *gc;
228
229 session = cmdproc->session;
230 account = session->account;
231 gc = purple_account_get_connection(account);
232
233 if (!g_ascii_strcasecmp(cmd->params[1], "OK"))
234 {
235 /* OK */
236 const char *friendly = purple_url_decode(cmd->params[3]);
237
238 purple_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 PurpleAccount *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 purple_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 PurpleCipher *cipher;
409 PurpleCipherContext *context;
410 guchar digest[16];
411 int i;
412
413 cipher = purple_ciphers_find_cipher("md5");
414 context = purple_cipher_context_new(cipher, NULL);
415
416 purple_cipher_context_append(context, (const guchar *)cmd->params[1],
417 strlen(cmd->params[1]));
418
419 challenge_resp = "VT6PX?UQTM4WM%YR";
420
421 purple_cipher_context_append(context, (const guchar *)challenge_resp,
422 strlen(challenge_resp));
423 purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
424 purple_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 = purple_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 PurpleAccount *account;
483 PurpleConnection *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 = purple_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 purple_account_get_username(account),
500 purple_account_get_protocol_name(account));
501 else if (!strcmp(list, "BL"))
502 msg = g_strdup_printf(_("Unable to block user on %s (%s)"),
503 purple_account_get_username(account),
504 purple_account_get_protocol_name(account));
505 else if (!strcmp(list, "AL"))
506 msg = g_strdup_printf(_("Unable to permit user on %s (%s)"),
507 purple_account_get_username(account),
508 purple_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 purple_notify_error(gc, NULL, msg, reason);
539 g_free(msg);
540 }
541
542 if (!strcmp(list, "FL"))
543 {
544 PurpleBuddy *buddy;
545
546 buddy = purple_find_buddy(account, passport);
547
548 if (buddy != NULL)
549 purple_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 = purple_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 qng_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
593 {
594 MsnSession *session;
595 static int count = 0;
596 const char *passport;
597 PurpleAccount *account;
598
599 session = cmdproc->session;
600 account = session->account;
601
602 if (session->passport_info.file == NULL)
603 return;
604
605 passport = purple_normalize(account, purple_account_get_username(account));
606
607 if ((strstr(passport, "@hotmail.") != NULL) ||
608 (strstr(passport, "@msn.com") != NULL))
609 return;
610
611 if (count++ < 26)
612 return;
613
614 count = 0;
615 msn_cmdproc_send(cmdproc, "URL", "%s", "INBOX");
616 }
617
618
619 static void
620 fln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
621 {
622 MsnSlpLink *slplink;
623 MsnUser *user;
624
625 user = msn_userlist_find_user(cmdproc->session->userlist, cmd->params[0]);
626
627 user->status = "offline";
628 msn_user_update(user);
629
630 slplink = msn_session_find_slplink(cmdproc->session, cmd->params[0]);
631
632 if (slplink != NULL)
633 msn_slplink_destroy(slplink);
634
635 }
636
637 static void
638 iln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
639 {
640 MsnSession *session;
641 PurpleAccount *account;
642 PurpleConnection *gc;
643 MsnUser *user;
644 MsnObject *msnobj;
645 const char *state, *passport, *friendly;
646
647 session = cmdproc->session;
648 account = session->account;
649 gc = purple_account_get_connection(account);
650
651 state = cmd->params[1];
652 passport = cmd->params[2];
653 friendly = purple_url_decode(cmd->params[3]);
654
655 user = msn_userlist_find_user(session->userlist, passport);
656
657 serv_got_alias(gc, passport, friendly);
658
659 msn_user_set_friendly_name(user, friendly);
660
661 if (session->protocol_ver >= 9 && cmd->param_count == 6)
662 {
663 msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5]));
664 msn_user_set_object(user, msnobj);
665 }
666
667 msn_user_set_state(user, state);
668 msn_user_update(user);
669 }
670
671 static void
672 ipg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len)
673 {
674 #if 0
675 purple_debug_misc("msn", "Incoming Page: {%s}\n", payload);
676 #endif
677 }
678
679 static void
680 ipg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
681 {
682 cmdproc->servconn->payload_len = atoi(cmd->params[0]);
683 cmdproc->last_cmd->payload_cb = ipg_cmd_post;
684 }
685
686 static void
687 nln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
688 {
689 MsnSession *session;
690 PurpleAccount *account;
691 PurpleConnection *gc;
692 MsnUser *user;
693 MsnObject *msnobj;
694 int clientid;
695 const char *state, *passport, *friendly, *old_friendly;
696
697 session = cmdproc->session;
698 account = session->account;
699 gc = purple_account_get_connection(account);
700
701 state = cmd->params[0];
702 passport = cmd->params[1];
703 friendly = purple_url_decode(cmd->params[2]);
704
705 user = msn_userlist_find_user(session->userlist, passport);
706
707 old_friendly = msn_user_get_friendly_name(user);
708 if (!old_friendly || (old_friendly && (!friendly || strcmp(old_friendly, friendly))))
709 {
710 serv_got_alias(gc, passport, friendly);
711 msn_user_set_friendly_name(user, friendly);
712 }
713
714 if (session->protocol_ver >= 9)
715 {
716 if (cmd->param_count == 5)
717 {
718 msnobj =
719 msn_object_new_from_string(purple_url_decode(cmd->params[4]));
720 msn_user_set_object(user, msnobj);
721 }
722 else
723 {
724 msn_user_set_object(user, NULL);
725 }
726 }
727
728 clientid = atoi(cmd->params[3]);
729 user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE);
730
731 msn_user_set_state(user, state);
732 msn_user_update(user);
733 }
734
735 #if 0
736 static void
737 chg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
738 {
739 char *state = cmd->params[1];
740 int state_id = 0;
741
742 if (!strcmp(state, "NLN"))
743 state_id = MSN_ONLINE;
744 else if (!strcmp(state, "BSY"))
745 state_id = MSN_BUSY;
746 else if (!strcmp(state, "IDL"))
747 state_id = MSN_IDLE;
748 else if (!strcmp(state, "BRB"))
749 state_id = MSN_BRB;
750 else if (!strcmp(state, "AWY"))
751 state_id = MSN_AWAY;
752 else if (!strcmp(state, "PHN"))
753 state_id = MSN_PHONE;
754 else if (!strcmp(state, "LUN"))
755 state_id = MSN_LUNCH;
756 else if (!strcmp(state, "HDN"))
757 state_id = MSN_HIDDEN;
758
759 cmdproc->session->state = state_id;
760 }
761 #endif
762
763
764 static void
765 not_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len)
766 {
767 #if 0
768 MSN_SET_PARAMS("NOT %d\r\n%s", cmdproc->servconn->payload, payload);
769 purple_debug_misc("msn", "Notification: {%s}\n", payload);
770 #endif
771 }
772
773 static void
774 not_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
775 {
776 cmdproc->servconn->payload_len = atoi(cmd->params[0]);
777 cmdproc->last_cmd->payload_cb = not_cmd_post;
778 }
779
780 static void
781 rea_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
782 {
783 /* TODO: This might be for us too */
784
785 MsnSession *session;
786 PurpleConnection *gc;
787 const char *friendly;
788
789 session = cmdproc->session;
790 gc = session->account->gc;
791 friendly = purple_url_decode(cmd->params[3]);
792
793 purple_connection_set_display_name(gc, friendly);
794 }
795
796 static void
797 prp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
798 {
799 MsnSession *session = cmdproc->session;
800 const char *type, *value;
801
802 g_return_if_fail(cmd->param_count >= 3);
803
804 type = cmd->params[2];
805
806 if (cmd->param_count == 4)
807 {
808 value = cmd->params[3];
809 if (!strcmp(type, "PHH"))
810 msn_user_set_home_phone(session->user, purple_url_decode(value));
811 else if (!strcmp(type, "PHW"))
812 msn_user_set_work_phone(session->user, purple_url_decode(value));
813 else if (!strcmp(type, "PHM"))
814 msn_user_set_mobile_phone(session->user, purple_url_decode(value));
815 }
816 else
817 {
818 if (!strcmp(type, "PHH"))
819 msn_user_set_home_phone(session->user, NULL);
820 else if (!strcmp(type, "PHW"))
821 msn_user_set_work_phone(session->user, NULL);
822 else if (!strcmp(type, "PHM"))
823 msn_user_set_mobile_phone(session->user, NULL);
824 }
825 }
826
827 static void
828 reg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
829 {
830 MsnSession *session;
831 int group_id;
832 const char *group_name;
833
834 session = cmdproc->session;
835 group_id = atoi(cmd->params[2]);
836 group_name = purple_url_decode(cmd->params[3]);
837
838 msn_userlist_rename_group_id(session->userlist, group_id, group_name);
839 }
840
841 static void
842 reg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
843 {
844 int group_id;
845 char **params;
846
847 params = g_strsplit(trans->params, " ", 0);
848
849 group_id = atoi(params[0]);
850
851 group_error_helper(cmdproc->session, _("Unable to rename group"), group_id, error);
852
853 g_strfreev(params);
854 }
855
856 static void
857 rem_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
858 {
859 MsnSession *session;
860 MsnUser *user;
861 const char *list;
862 const char *passport;
863 MsnListId list_id;
864 int group_id;
865
866 session = cmdproc->session;
867 list = cmd->params[1];
868 passport = cmd->params[3];
869 user = msn_userlist_find_user(session->userlist, passport);
870
871 g_return_if_fail(user != NULL);
872
873 list_id = msn_get_list_id(list);
874
875 if (cmd->param_count == 5)
876 group_id = atoi(cmd->params[4]);
877 else
878 group_id = -1;
879
880 msn_got_rem_user(session, user, list_id, group_id);
881 msn_user_update(user);
882 }
883
884 static void
885 rmg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
886 {
887 MsnSession *session;
888 int group_id;
889
890 session = cmdproc->session;
891 group_id = atoi(cmd->params[2]);
892
893 msn_userlist_remove_group_id(session->userlist, group_id);
894 }
895
896 static void
897 rmg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
898 {
899 int group_id;
900 char **params;
901
902 params = g_strsplit(trans->params, " ", 0);
903
904 group_id = atoi(params[0]);
905
906 group_error_helper(cmdproc->session, _("Unable to delete group"), group_id, error);
907
908 g_strfreev(params);
909 }
910
911 static void
912 syn_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
913 {
914 MsnSession *session;
915 MsnSync *sync;
916 int total_users;
917
918 session = cmdproc->session;
919
920 if (cmd->param_count == 2)
921 {
922 /*
923 * This can happen if we sent a SYN with an up-to-date
924 * buddy list revision, but we send 0 to get a full list.
925 * So, error out.
926 */
927
928 msn_session_set_error(cmdproc->session, MSN_ERROR_BAD_BLIST, NULL);
929 return;
930 }
931
932 total_users = atoi(cmd->params[2]);
933
934 sync = msn_sync_new(session);
935 sync->total_users = total_users;
936 sync->old_cbs_table = cmdproc->cbs_table;
937
938 session->sync = sync;
939 cmdproc->cbs_table = sync->cbs_table;
940 }
941
942 /**************************************************************************
943 * Misc commands
944 **************************************************************************/
945
946 static void
947 url_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
948 {
949 MsnSession *session;
950 PurpleAccount *account;
951 const char *rru;
952 const char *url;
953 PurpleCipher *cipher;
954 PurpleCipherContext *context;
955 guchar digest[16];
956 FILE *fd;
957 char *buf;
958 char buf2[3];
959 char sendbuf[64];
960 int i;
961
962 session = cmdproc->session;
963 account = session->account;
964
965 rru = cmd->params[1];
966 url = cmd->params[2];
967
968 buf = g_strdup_printf("%s%lu%s",
969 session->passport_info.mspauth ? session->passport_info.mspauth : "BOGUS",
970 time(NULL) - session->passport_info.sl,
971 purple_connection_get_password(account->gc));
972
973 cipher = purple_ciphers_find_cipher("md5");
974 context = purple_cipher_context_new(cipher, NULL);
975
976 purple_cipher_context_append(context, (const guchar *)buf, strlen(buf));
977 purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
978 purple_cipher_context_destroy(context);
979
980 g_free(buf);
981
982 memset(sendbuf, 0, sizeof(sendbuf));
983
984 for (i = 0; i < 16; i++)
985 {
986 g_snprintf(buf2, sizeof(buf2), "%02x", digest[i]);
987 strcat(sendbuf, buf2);
988 }
989
990 if (session->passport_info.file != NULL)
991 {
992 g_unlink(session->passport_info.file);
993 g_free(session->passport_info.file);
994 }
995
996 if ((fd = purple_mkstemp(&session->passport_info.file, FALSE)) == NULL)
997 {
998 purple_debug_error("msn",
999 "Error opening temp passport file: %s\n",
1000 strerror(errno));
1001 }
1002 else
1003 {
1004 #ifdef _WIN32
1005 fputs("<!-- saved from url=(0013)about:internet -->\n", fd);
1006 #endif
1007 fputs("<html>\n"
1008 "<head>\n"
1009 "<noscript>\n"
1010 "<meta http-equiv=\"Refresh\" content=\"0; "
1011 "url=http://www.hotmail.com\">\n"
1012 "</noscript>\n"
1013 "</head>\n\n",
1014 fd);
1015
1016 fprintf(fd, "<body onload=\"document.pform.submit(); \">\n");
1017 fprintf(fd, "<form name=\"pform\" action=\"%s\" method=\"POST\">\n\n",
1018 url);
1019 fprintf(fd, "<input type=\"hidden\" name=\"mode\" value=\"ttl\">\n");
1020 fprintf(fd, "<input type=\"hidden\" name=\"login\" value=\"%s\">\n",
1021 purple_account_get_username(account));
1022 fprintf(fd, "<input type=\"hidden\" name=\"username\" value=\"%s\">\n",
1023 purple_account_get_username(account));
1024 if (session->passport_info.sid != NULL)
1025 fprintf(fd, "<input type=\"hidden\" name=\"sid\" value=\"%s\">\n",
1026 session->passport_info.sid);
1027 if (session->passport_info.kv != NULL)
1028 fprintf(fd, "<input type=\"hidden\" name=\"kv\" value=\"%s\">\n",
1029 session->passport_info.kv);
1030 fprintf(fd, "<input type=\"hidden\" name=\"id\" value=\"2\">\n");
1031 fprintf(fd, "<input type=\"hidden\" name=\"sl\" value=\"%ld\">\n",
1032 time(NULL) - session->passport_info.sl);
1033 fprintf(fd, "<input type=\"hidden\" name=\"rru\" value=\"%s\">\n",
1034 rru);
1035 if (session->passport_info.mspauth != NULL)
1036 fprintf(fd, "<input type=\"hidden\" name=\"auth\" value=\"%s\">\n",
1037 session->passport_info.mspauth);
1038 fprintf(fd, "<input type=\"hidden\" name=\"creds\" value=\"%s\">\n",
1039 sendbuf); /* TODO Digest me (huh? -- ChipX86) */
1040 fprintf(fd, "<input type=\"hidden\" name=\"svc\" value=\"mail\">\n");
1041 fprintf(fd, "<input type=\"hidden\" name=\"js\" value=\"yes\">\n");
1042 fprintf(fd, "</form></body>\n");
1043 fprintf(fd, "</html>\n");
1044
1045 if (fclose(fd))
1046 {
1047 purple_debug_error("msn",
1048 "Error closing temp passport file: %s\n",
1049 strerror(errno));
1050
1051 g_unlink(session->passport_info.file);
1052 g_free(session->passport_info.file);
1053 session->passport_info.file = NULL;
1054 }
1055 #ifdef _WIN32
1056 else
1057 {
1058 /*
1059 * Renaming file with .html extension, so that the
1060 * win32 open_url will work.
1061 */
1062 char *tmp;
1063
1064 if ((tmp =
1065 g_strdup_printf("%s.html",
1066 session->passport_info.file)) != NULL)
1067 {
1068 if (g_rename(session->passport_info.file,
1069 tmp) == 0)
1070 {
1071 g_free(session->passport_info.file);
1072 session->passport_info.file = tmp;
1073 }
1074 else
1075 g_free(tmp);
1076 }
1077 }
1078 #endif
1079 }
1080 }
1081 /**************************************************************************
1082 * Switchboards
1083 **************************************************************************/
1084
1085 static void
1086 rng_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
1087 {
1088 MsnSession *session;
1089 MsnSwitchBoard *swboard;
1090 const char *session_id;
1091 char *host;
1092 int port;
1093
1094 session = cmdproc->session;
1095 session_id = cmd->params[0];
1096
1097 msn_parse_socket(cmd->params[1], &host, &port);
1098
1099 if (session->http_method)
1100 port = 80;
1101
1102 swboard = msn_switchboard_new(session);
1103
1104 msn_switchboard_set_invited(swboard, TRUE);
1105 msn_switchboard_set_session_id(swboard, cmd->params[0]);
1106 msn_switchboard_set_auth_key(swboard, cmd->params[3]);
1107 swboard->im_user = g_strdup(cmd->params[4]);
1108 /* msn_switchboard_add_user(swboard, cmd->params[4]); */
1109
1110 if (!msn_switchboard_connect(swboard, host, port))
1111 msn_switchboard_destroy(swboard);
1112
1113 g_free(host);
1114 }
1115
1116 static void
1117 xfr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
1118 {
1119 char *host;
1120 int port;
1121
1122 if (strcmp(cmd->params[1], "SB") && strcmp(cmd->params[1], "NS"))
1123 {
1124 /* Maybe we can have a generic bad command error. */
1125 purple_debug_error("msn", "Bad XFR command (%s)\n", cmd->params[1]);
1126 return;
1127 }
1128
1129 msn_parse_socket(cmd->params[2], &host, &port);
1130
1131 if (!strcmp(cmd->params[1], "SB"))
1132 {
1133 purple_debug_error("msn", "This shouldn't be handled here.\n");
1134 }
1135 else if (!strcmp(cmd->params[1], "NS"))
1136 {
1137 MsnSession *session;
1138
1139 session = cmdproc->session;
1140
1141 msn_session_set_login_step(session, MSN_LOGIN_STEP_TRANSFER);
1142
1143 msn_notification_connect(session->notification, host, port);
1144 }
1145
1146 g_free(host);
1147 }
1148
1149 /**************************************************************************
1150 * Message Types
1151 **************************************************************************/
1152
1153 static void
1154 profile_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
1155 {
1156 MsnSession *session;
1157 const char *value;
1158
1159 session = cmdproc->session;
1160
1161 if (strcmp(msg->remote_user, "Hotmail"))
1162 /* This isn't an official message. */
1163 return;
1164
1165 if ((value = msn_message_get_attr(msg, "kv")) != NULL)
1166 {
1167 g_free(session->passport_info.kv);
1168 session->passport_info.kv = g_strdup(value);
1169 }
1170
1171 if ((value = msn_message_get_attr(msg, "sid")) != NULL)
1172 {
1173 g_free(session->passport_info.sid);
1174 session->passport_info.sid = g_strdup(value);
1175 }
1176
1177 if ((value = msn_message_get_attr(msg, "MSPAuth")) != NULL)
1178 {
1179 g_free(session->passport_info.mspauth);
1180 session->passport_info.mspauth = g_strdup(value);
1181 }
1182
1183 if ((value = msn_message_get_attr(msg, "ClientIP")) != NULL)
1184 {
1185 g_free(session->passport_info.client_ip);
1186 session->passport_info.client_ip = g_strdup(value);
1187 }
1188
1189 if ((value = msn_message_get_attr(msg, "ClientPort")) != NULL)
1190 session->passport_info.client_port = ntohs(atoi(value));
1191
1192 if ((value = msn_message_get_attr(msg, "LoginTime")) != NULL)
1193 session->passport_info.sl = atol(value);
1194 }
1195
1196 static void
1197 initial_email_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
1198 {
1199 MsnSession *session;
1200 PurpleConnection *gc;
1201 GHashTable *table;
1202 const char *unread;
1203
1204 session = cmdproc->session;
1205 gc = session->account->gc;
1206
1207 if (strcmp(msg->remote_user, "Hotmail"))
1208 /* This isn't an official message. */
1209 return;
1210
1211 if (session->passport_info.file == NULL)
1212 {
1213 MsnTransaction *trans;
1214 trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
1215 msn_transaction_queue_cmd(trans, msg->cmd);
1216
1217 msn_cmdproc_send_trans(cmdproc, trans);
1218
1219 return;
1220 }
1221
1222 if (!purple_account_get_check_mail(session->account))
1223 return;
1224
1225 table = msn_message_get_hashtable_from_body(msg);
1226
1227 unread = g_hash_table_lookup(table, "Inbox-Unread");
1228
1229 if (unread != NULL)
1230 {
1231 int count = atoi(unread);
1232
1233 if (count > 0)
1234 {
1235 const char *passport;
1236 const char *url;
1237
1238 passport = msn_user_get_passport(session->user);
1239 url = session->passport_info.file;
1240
1241 purple_notify_emails(gc, atoi(unread), FALSE, NULL, NULL,
1242 &passport, &url, NULL, NULL);
1243 }
1244 }
1245
1246 g_hash_table_destroy(table);
1247 }
1248
1249 static void
1250 email_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
1251 {
1252 MsnSession *session;
1253 PurpleConnection *gc;
1254 GHashTable *table;
1255 char *from, *subject, *tmp;
1256
1257 session = cmdproc->session;
1258 gc = session->account->gc;
1259
1260 if (strcmp(msg->remote_user, "Hotmail"))
1261 /* This isn't an official message. */
1262 return;
1263
1264 if (session->passport_info.file == NULL)
1265 {
1266 MsnTransaction *trans;
1267 trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX");
1268 msn_transaction_queue_cmd(trans, msg->cmd);
1269
1270 msn_cmdproc_send_trans(cmdproc, trans);
1271
1272 return;
1273 }
1274
1275 if (!purple_account_get_check_mail(session->account))
1276 return;
1277
1278 table = msn_message_get_hashtable_from_body(msg);
1279
1280 from = subject = NULL;
1281
1282 tmp = g_hash_table_lookup(table, "From");
1283 if (tmp != NULL)
1284 from = purple_mime_decode_field(tmp);
1285
1286 tmp = g_hash_table_lookup(table, "Subject");
1287 if (tmp != NULL)
1288 subject = purple_mime_decode_field(tmp);
1289
1290 purple_notify_email(gc,
1291 (subject != NULL ? subject : ""),
1292 (from != NULL ? from : ""),
1293 msn_user_get_passport(session->user),
1294 session->passport_info.file, NULL, NULL);
1295
1296 g_free(from);
1297 g_free(subject);
1298
1299 g_hash_table_destroy(table);
1300 }
1301
1302 static void
1303 system_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
1304 {
1305 GHashTable *table;
1306 const char *type_s;
1307
1308 if (strcmp(msg->remote_user, "Hotmail"))
1309 /* This isn't an official message. */
1310 return;
1311
1312 table = msn_message_get_hashtable_from_body(msg);
1313
1314 if ((type_s = g_hash_table_lookup(table, "Type")) != NULL)
1315 {
1316 int type = atoi(type_s);
1317 char buf[MSN_BUF_LEN];
1318 int minutes;
1319
1320 switch (type)
1321 {
1322 case 1:
1323 minutes = atoi(g_hash_table_lookup(table, "Arg1"));
1324 g_snprintf(buf, sizeof(buf), dngettext(PACKAGE,
1325 "The MSN server will shut down for maintenance "
1326 "in %d minute. You will automatically be "
1327 "signed out at that time. Please finish any "
1328 "conversations in progress.\n\nAfter the "
1329 "maintenance has been completed, you will be "
1330 "able to successfully sign in.",
1331 "The MSN server will shut down for maintenance "
1332 "in %d minutes. You will automatically be "
1333 "signed out at that time. Please finish any "
1334 "conversations in progress.\n\nAfter the "
1335 "maintenance has been completed, you will be "
1336 "able to successfully sign in.", minutes),
1337 minutes);
1338 default:
1339 break;
1340 }
1341
1342 if (*buf != '\0')
1343 purple_notify_info(cmdproc->session->account->gc, NULL, buf, NULL);
1344 }
1345
1346 g_hash_table_destroy(table);
1347 }
1348
1349 void
1350 msn_notification_add_buddy(MsnNotification *notification, const char *list,
1351 const char *who, const char *store_name,
1352 int group_id)
1353 {
1354 MsnCmdProc *cmdproc;
1355 cmdproc = notification->servconn->cmdproc;
1356
1357 if (group_id < 0 && !strcmp(list, "FL"))
1358 group_id = 0;
1359
1360 if (group_id >= 0)
1361 {
1362 msn_cmdproc_send(cmdproc, "ADD", "%s %s %s %d",
1363 list, who, store_name, group_id);
1364 }
1365 else
1366 {
1367 msn_cmdproc_send(cmdproc, "ADD", "%s %s %s", list, who, store_name);
1368 }
1369 }
1370
1371 void
1372 msn_notification_rem_buddy(MsnNotification *notification, const char *list,
1373 const char *who, int group_id)
1374 {
1375 MsnCmdProc *cmdproc;
1376 cmdproc = notification->servconn->cmdproc;
1377
1378 if (group_id >= 0)
1379 {
1380 msn_cmdproc_send(cmdproc, "REM", "%s %s %d", list, who, group_id);
1381 }
1382 else
1383 {
1384 msn_cmdproc_send(cmdproc, "REM", "%s %s", list, who);
1385 }
1386 }
1387
1388 /**************************************************************************
1389 * Init
1390 **************************************************************************/
1391
1392 void
1393 msn_notification_init(void)
1394 {
1395 /* TODO: check prp, blp */
1396
1397 cbs_table = msn_table_new();
1398
1399 /* Synchronous */
1400 msn_table_add_cmd(cbs_table, "CHG", "CHG", NULL);
1401 msn_table_add_cmd(cbs_table, "CHG", "ILN", iln_cmd);
1402 msn_table_add_cmd(cbs_table, "ADD", "ADD", add_cmd);
1403 msn_table_add_cmd(cbs_table, "ADD", "ILN", iln_cmd);
1404 msn_table_add_cmd(cbs_table, "REM", "REM", rem_cmd);
1405 msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd);
1406 msn_table_add_cmd(cbs_table, "USR", "XFR", xfr_cmd);
1407 msn_table_add_cmd(cbs_table, "SYN", "SYN", syn_cmd);
1408 msn_table_add_cmd(cbs_table, "CVR", "CVR", cvr_cmd);
1409 msn_table_add_cmd(cbs_table, "VER", "VER", ver_cmd);
1410 msn_table_add_cmd(cbs_table, "REA", "REA", rea_cmd);
1411 msn_table_add_cmd(cbs_table, "PRP", "PRP", prp_cmd);
1412 /* msn_table_add_cmd(cbs_table, "BLP", "BLP", blp_cmd); */
1413 msn_table_add_cmd(cbs_table, "BLP", "BLP", NULL);
1414 msn_table_add_cmd(cbs_table, "REG", "REG", reg_cmd);
1415 msn_table_add_cmd(cbs_table, "ADG", "ADG", adg_cmd);
1416 msn_table_add_cmd(cbs_table, "RMG", "RMG", rmg_cmd);
1417 msn_table_add_cmd(cbs_table, "XFR", "XFR", xfr_cmd);
1418
1419 /* Asynchronous */
1420 msn_table_add_cmd(cbs_table, NULL, "IPG", ipg_cmd);
1421 msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd);
1422 msn_table_add_cmd(cbs_table, NULL, "NOT", not_cmd);
1423
1424 msn_table_add_cmd(cbs_table, NULL, "CHL", chl_cmd);
1425 msn_table_add_cmd(cbs_table, NULL, "REM", rem_cmd);
1426 msn_table_add_cmd(cbs_table, NULL, "ADD", add_cmd);
1427
1428 msn_table_add_cmd(cbs_table, NULL, "QRY", NULL);
1429 msn_table_add_cmd(cbs_table, NULL, "QNG", qng_cmd);
1430 msn_table_add_cmd(cbs_table, NULL, "FLN", fln_cmd);
1431 msn_table_add_cmd(cbs_table, NULL, "NLN", nln_cmd);
1432 msn_table_add_cmd(cbs_table, NULL, "ILN", iln_cmd);
1433 msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd);
1434 msn_table_add_cmd(cbs_table, NULL, "RNG", rng_cmd);
1435
1436 msn_table_add_cmd(cbs_table, NULL, "URL", url_cmd);
1437
1438 msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd);
1439
1440 msn_table_add_error(cbs_table, "ADD", add_error);
1441 msn_table_add_error(cbs_table, "REG", reg_error);
1442 msn_table_add_error(cbs_table, "RMG", rmg_error);
1443 /* msn_table_add_error(cbs_table, "REA", rea_error); */
1444 msn_table_add_error(cbs_table, "USR", usr_error);
1445
1446 msn_table_add_msg_type(cbs_table,
1447 "text/x-msmsgsprofile",
1448 profile_msg);
1449 msn_table_add_msg_type(cbs_table,
1450 "text/x-msmsgsinitialemailnotification",
1451 initial_email_msg);
1452 msn_table_add_msg_type(cbs_table,
1453 "text/x-msmsgsemailnotification",
1454 email_msg);
1455 msn_table_add_msg_type(cbs_table,
1456 "application/x-msmsgssystemmessage",
1457 system_msg);
1458 }
1459
1460 void
1461 msn_notification_end(void)
1462 {
1463 msn_table_destroy(cbs_table);
1464 }

mercurial