libgaim/protocols/msn/userlist.c

branch
cpw.khc.msnp14
changeset 20472
6a6d2ef151e6
parent 13910
fb8f57c2b934
parent 15204
6775ac53169c
child 20473
91e1b3a49d10
equal deleted inserted replaced
13912:463b4fa9f067 20472:6a6d2ef151e6
1 /**
2 * @file userlist.c MSN user list support
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 "userlist.h"
26
27 const char *lists[] = { "FL", "AL", "BL", "RL" };
28
29 typedef struct
30 {
31 GaimConnection *gc;
32 char *who;
33 char *friendly;
34
35 } MsnPermitAdd;
36
37 /**************************************************************************
38 * Callbacks
39 **************************************************************************/
40 static void
41 msn_accept_add_cb(MsnPermitAdd *pa)
42 {
43 if (g_list_find(gaim_connections_get_all(), pa->gc) != NULL)
44 {
45 MsnSession *session = pa->gc->proto_data;
46 MsnUserList *userlist = session->userlist;
47 GaimBuddy *buddy;
48
49 msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_AL, NULL);
50
51 buddy = gaim_find_buddy(pa->gc->account, pa->who);
52
53 if (buddy != NULL)
54 gaim_account_notify_added(pa->gc->account, pa->who,
55 NULL, pa->friendly, NULL);
56 else
57 gaim_account_request_add(pa->gc->account, pa->who,
58 NULL, pa->friendly, NULL);
59 }
60
61 g_free(pa->who);
62 g_free(pa->friendly);
63 g_free(pa);
64 }
65
66 static void
67 msn_cancel_add_cb(MsnPermitAdd *pa)
68 {
69 if (g_list_find(gaim_connections_get_all(), pa->gc) != NULL)
70 {
71 MsnSession *session = pa->gc->proto_data;
72 MsnUserList *userlist = session->userlist;
73
74 msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_BL, NULL);
75 }
76
77 g_free(pa->who);
78 g_free(pa->friendly);
79 g_free(pa);
80 }
81
82 static void
83 got_new_entry(GaimConnection *gc, const char *passport, const char *friendly)
84 {
85 MsnPermitAdd *pa;
86 char *msg;
87
88 pa = g_new0(MsnPermitAdd, 1);
89 pa->who = g_strdup(passport);
90 pa->friendly = g_strdup(friendly);
91 pa->gc = gc;
92
93 if (friendly != NULL)
94 {
95 msg = g_strdup_printf(
96 _("The user %s (%s) wants to add %s to his or her "
97 "buddy list."),
98 passport, friendly,
99 gaim_account_get_username(gc->account));
100 }
101 else
102 {
103 msg = g_strdup_printf(
104 _("The user %s wants to add %s to his or "
105 "her buddy list."),
106 passport, gaim_account_get_username(gc->account));
107 }
108
109 gaim_request_action(gc, NULL, msg, NULL,
110 GAIM_DEFAULT_ACTION_NONE, pa, 2,
111 _("Authorize"), G_CALLBACK(msn_accept_add_cb),
112 _("Deny"), G_CALLBACK(msn_cancel_add_cb));
113
114 g_free(msg);
115 }
116
117 /**************************************************************************
118 * Utility functions
119 **************************************************************************/
120
121 static gboolean
122 user_is_in_group(MsnUser *user, const char * group_id)
123 {
124 if (user == NULL)
125 return FALSE;
126
127 if (group_id == NULL)
128 return FALSE;
129
130 if (g_list_find(user->group_ids, group_id))
131 return TRUE;
132
133 return FALSE;
134 }
135
136 static gboolean
137 user_is_there(MsnUser *user, int list_id, const char * group_id)
138 {
139 int list_op;
140
141 if (user == NULL)
142 return FALSE;
143
144 list_op = 1 << list_id;
145
146 if (!(user->list_op & list_op))
147 return FALSE;
148
149 if (list_id == MSN_LIST_FL){
150 if (group_id != NULL)
151 return user_is_in_group(user, group_id);
152 }
153
154 return TRUE;
155 }
156
157 static const char*
158 get_store_name(MsnUser *user)
159 {
160 const char *store_name;
161
162 g_return_val_if_fail(user != NULL, NULL);
163
164 store_name = msn_user_get_store_name(user);
165
166 if (store_name != NULL)
167 store_name = gaim_url_encode(store_name);
168 else
169 store_name = msn_user_get_passport(user);
170
171 /* this might be a bit of a hack, but it should prevent notification server
172 * disconnections for people who have buddies with insane friendly names
173 * who added you to their buddy list from being disconnected. Stu. */
174 /* Shx: What? Isn't the store_name obtained from the server, and hence it's
175 * below the BUDDY_ALIAS_MAXLEN ? */
176 /* Stu: yeah, that's why it's a bit of a hack, as you pointed out, we're
177 * probably decoding the incoming store_name wrong, or something. bleh. */
178
179 if (strlen(store_name) > BUDDY_ALIAS_MAXLEN)
180 store_name = msn_user_get_passport(user);
181
182 return store_name;
183 }
184
185 static void
186 msn_request_add_group(MsnUserList *userlist, const char *who,
187 const char *old_group_name, const char *new_group_name)
188 {
189 MsnSession *session;
190 MsnCmdProc *cmdproc;
191 MsnTransaction *trans;
192 MsnMoveBuddy *data;
193
194 session = userlist->session;
195 cmdproc = session->notification->cmdproc;
196 data = g_new0(MsnMoveBuddy, 1);
197
198 data->who = g_strdup(who);
199
200 if (old_group_name){
201 data->old_group_name = g_strdup(old_group_name);
202 /*delete the old group via SOAP action*/
203 msn_del_group(session,old_group_name);
204 }
205
206 /*add new group via SOAP action*/
207 msn_add_group(session, new_group_name);
208
209 msn_transaction_set_data(trans, data);
210
211 msn_cmdproc_send_trans(cmdproc, trans);
212 }
213
214 /**************************************************************************
215 * Server functions
216 **************************************************************************/
217
218 MsnListId
219 msn_get_list_id(const char *list)
220 {
221 if (list[0] == 'F')
222 return MSN_LIST_FL;
223 else if (list[0] == 'A')
224 return MSN_LIST_AL;
225 else if (list[0] == 'B')
226 return MSN_LIST_BL;
227 else if (list[0] == 'R')
228 return MSN_LIST_RL;
229
230 return -1;
231 }
232
233 void
234 msn_got_add_user(MsnSession *session, MsnUser *user,
235 MsnListId list_id, const char * group_id)
236 {
237 GaimAccount *account;
238 const char *passport;
239 const char *friendly;
240
241 gaim_debug_info("MaYuan","got add user...\n");
242 account = session->account;
243
244 passport = msn_user_get_passport(user);
245 friendly = msn_user_get_friendly_name(user);
246
247 if (list_id == MSN_LIST_FL)
248 {
249 GaimConnection *gc;
250
251 gc = gaim_account_get_connection(account);
252
253 serv_got_alias(gc, passport, friendly);
254
255 if (group_id != NULL)
256 {
257 msn_user_add_group_id(user, group_id);
258 }
259 else
260 {
261 /* session->sync->fl_users_count++; */
262 }
263 }
264 else if (list_id == MSN_LIST_AL)
265 {
266 gaim_privacy_permit_add(account, passport, TRUE);
267 }
268 else if (list_id == MSN_LIST_BL)
269 {
270 gaim_privacy_deny_add(account, passport, TRUE);
271 }
272 else if (list_id == MSN_LIST_RL)
273 {
274 GaimConnection *gc;
275 GaimConversation *convo;
276
277 gc = gaim_account_get_connection(account);
278
279 gaim_debug_info("msn",
280 "%s has added you to his or her buddy list.\n",
281 passport);
282
283 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, passport, account);
284 if (convo) {
285 GaimBuddy *buddy;
286 char *msg;
287
288 buddy = gaim_find_buddy(account, passport);
289 msg = g_strdup_printf(
290 _("%s has added you to his or her buddy list."),
291 buddy ? gaim_buddy_get_contact_alias(buddy) : passport);
292 gaim_conv_im_write(GAIM_CONV_IM(convo), passport, msg,
293 GAIM_MESSAGE_SYSTEM, time(NULL));
294 g_free(msg);
295 }
296
297 if (!(user->list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP)))
298 {
299 /*
300 * TODO: The friendly name was NULL for me when I
301 * looked at this. Maybe we should use the store
302 * name instead? --KingAnt
303 */
304 // got_new_entry(gc, passport, friendly);
305 }
306 }
307
308 user->list_op |= (1 << list_id);
309 /* gaim_user_add_list_id (user, list_id); */
310 }
311
312 void
313 msn_got_rem_user(MsnSession *session, MsnUser *user,
314 MsnListId list_id, const char * group_id)
315 {
316 GaimAccount *account;
317 const char *passport;
318
319 account = session->account;
320
321 passport = msn_user_get_passport(user);
322
323 if (list_id == MSN_LIST_FL)
324 {
325 /* TODO: When is the user totally removed? */
326 if (group_id != NULL)
327 {
328 msn_user_remove_group_id(user, group_id);
329 return;
330 }
331 else
332 {
333 /* session->sync->fl_users_count--; */
334 }
335 }
336 else if (list_id == MSN_LIST_AL)
337 {
338 gaim_privacy_permit_remove(account, passport, TRUE);
339 }
340 else if (list_id == MSN_LIST_BL)
341 {
342 gaim_privacy_deny_remove(account, passport, TRUE);
343 }
344 else if (list_id == MSN_LIST_RL)
345 {
346 GaimConversation *convo;
347
348 gaim_debug_info("msn",
349 "%s has removed you from his or her buddy list.\n",
350 passport);
351
352 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, passport, account);
353 if (convo) {
354 GaimBuddy *buddy;
355 char *msg;
356
357 buddy = gaim_find_buddy(account, passport);
358 msg = g_strdup_printf(
359 _("%s has removed you from his or her buddy list."),
360 buddy ? gaim_buddy_get_contact_alias(buddy) : passport);
361 gaim_conv_im_write(GAIM_CONV_IM(convo), passport, msg,
362 GAIM_MESSAGE_SYSTEM, time(NULL));
363 g_free(msg);
364 }
365 }
366
367 user->list_op &= ~(1 << list_id);
368 /* gaim_user_remove_list_id (user, list_id); */
369
370 if (user->list_op == 0)
371 {
372 gaim_debug_info("msn", "Buddy '%s' shall be deleted?.\n",
373 passport);
374
375 }
376 }
377
378 void
379 msn_got_lst_user(MsnSession *session, MsnUser *user,
380 int list_op, GSList *group_ids)
381 {
382 GaimConnection *gc;
383 GaimAccount *account;
384 const char *passport;
385 const char *store;
386
387 account = session->account;
388 gc = gaim_account_get_connection(account);
389
390 passport = msn_user_get_passport(user);
391 store = msn_user_get_store_name(user);
392
393 if (list_op & MSN_LIST_FL_OP)
394 {
395 GSList *c;
396 for (c = group_ids; c != NULL; c = g_slist_next(c)) {
397 char *group_id;
398 group_id = c->data;
399 msn_user_add_group_id(user, group_id);
400 }
401
402 /* FIXME: It might be a real alias */
403 /* Umm, what? This might fix bug #1385130 */
404 serv_got_alias(gc, passport, store);
405 }
406
407 if (list_op & MSN_LIST_AL_OP)
408 {
409 /* These are users who are allowed to see our status. */
410 gaim_privacy_deny_remove(account, passport, TRUE);
411 gaim_privacy_permit_add(account, passport, TRUE);
412 }
413
414 if (list_op & MSN_LIST_BL_OP)
415 {
416 /* These are users who are not allowed to see our status. */
417 gaim_privacy_permit_remove(account, passport, TRUE);
418 gaim_privacy_deny_add(account, passport, TRUE);
419 }
420
421 if (list_op & MSN_LIST_RL_OP)
422 {
423 /* These are users who have us on their buddy list. */
424 /*
425 * TODO: What is store name set to when this happens?
426 * For one of my accounts "something@hotmail.com"
427 * the store name was "something." Maybe we
428 * should use the friendly name, instead? --KingAnt
429 */
430
431 if (!(list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP)))
432 {
433 // got_new_entry(gc, passport, store);
434 }
435 }
436
437 user->list_op |= list_op;
438 }
439
440 /**************************************************************************
441 * UserList functions
442 **************************************************************************/
443
444 MsnUserList*
445 msn_userlist_new(MsnSession *session)
446 {
447 MsnUserList *userlist;
448
449 userlist = g_new0(MsnUserList, 1);
450
451 userlist->session = session;
452 userlist->buddy_icon_requests = g_queue_new();
453
454 /* buddy_icon_window is the number of allowed simultaneous buddy icon requests.
455 * XXX With smarter rate limiting code, we could allow more at once... 5 was the limit set when
456 * we weren't retrieiving any more than 5 per MSN session. */
457 userlist->buddy_icon_window = 1;
458
459 return userlist;
460 }
461
462 void
463 msn_userlist_destroy(MsnUserList *userlist)
464 {
465 GList *l;
466
467 /*destroy userlist*/
468 for (l = userlist->users; l != NULL; l = l->next)
469 {
470 msn_user_destroy(l->data);
471 }
472
473 g_list_free(userlist->users);
474
475 /*destroy group list*/
476 for (l = userlist->groups; l != NULL; l = l->next)
477 {
478 msn_group_destroy(l->data);
479 }
480
481 g_list_free(userlist->groups);
482
483 g_queue_free(userlist->buddy_icon_requests);
484
485 if (userlist->buddy_icon_request_timer)
486 gaim_timeout_remove(userlist->buddy_icon_request_timer);
487
488 g_free(userlist);
489 }
490
491 void
492 msn_userlist_add_user(MsnUserList *userlist, MsnUser *user)
493 {
494 userlist->users = g_list_append(userlist->users, user);
495 }
496
497 void
498 msn_userlist_remove_user(MsnUserList *userlist, MsnUser *user)
499 {
500 userlist->users = g_list_remove(userlist->users, user);
501 }
502
503 MsnUser *
504 msn_userlist_find_user(MsnUserList *userlist, const char *passport)
505 {
506 GList *l;
507
508 g_return_val_if_fail(passport != NULL, NULL);
509
510 for (l = userlist->users; l != NULL; l = l->next)
511 {
512 MsnUser *user = (MsnUser *)l->data;
513
514 g_return_val_if_fail(user->passport != NULL, NULL);
515
516 if (!strcmp(passport, user->passport))
517 return user;
518 }
519
520 return NULL;
521 }
522
523 void
524 msn_userlist_add_group(MsnUserList *userlist, MsnGroup *group)
525 {
526 userlist->groups = g_list_append(userlist->groups, group);
527 }
528
529 void
530 msn_userlist_remove_group(MsnUserList *userlist, MsnGroup *group)
531 {
532 userlist->groups = g_list_remove(userlist->groups, group);
533 }
534
535 MsnGroup *
536 msn_userlist_find_group_with_id(MsnUserList *userlist, const char * id)
537 {
538 GList *l;
539
540 g_return_val_if_fail(userlist != NULL, NULL);
541 g_return_val_if_fail(id != NULL, NULL);
542
543 for (l = userlist->groups; l != NULL; l = l->next)
544 {
545 MsnGroup *group = l->data;
546
547 if (!g_strcasecmp(group->id, id))
548 return group;
549 }
550
551 return NULL;
552 }
553
554 MsnGroup *
555 msn_userlist_find_group_with_name(MsnUserList *userlist, const char *name)
556 {
557 GList *l;
558
559 g_return_val_if_fail(userlist != NULL, NULL);
560 g_return_val_if_fail(name != NULL, NULL);
561
562 for (l = userlist->groups; l != NULL; l = l->next)
563 {
564 MsnGroup *group = l->data;
565
566 if ((group->name != NULL) && !g_strcasecmp(name, group->name))
567 return group;
568 }
569
570 return NULL;
571 }
572
573 const char *
574 msn_userlist_find_group_id(MsnUserList *userlist, const char *group_name)
575 {
576 MsnGroup *group;
577
578 group = msn_userlist_find_group_with_name(userlist, group_name);
579
580 if (group != NULL)
581 return msn_group_get_id(group);
582 }
583 else
584 {
585 return NULL;
586 }
587 }
588
589 const char *
590 msn_userlist_find_group_name(MsnUserList *userlist, const char * group_id)
591 {
592 MsnGroup *group;
593
594 group = msn_userlist_find_group_with_id(userlist, group_id);
595
596 if (group != NULL)
597 return msn_group_get_name(group);
598 else
599 return NULL;
600 }
601
602 void
603 msn_userlist_rename_group_id(MsnUserList *userlist, const char * group_id,
604 const char *new_name)
605 {
606 MsnGroup *group;
607
608 group = msn_userlist_find_group_with_id(userlist, group_id);
609
610 if (group != NULL)
611 msn_group_set_name(group, new_name);
612 }
613
614 void
615 msn_userlist_remove_group_id(MsnUserList *userlist, const char * group_id)
616 {
617 MsnGroup *group;
618
619 group = msn_userlist_find_group_with_id(userlist, group_id);
620
621 if (group != NULL)
622 {
623 msn_userlist_remove_group(userlist, group);
624 msn_group_destroy(group);
625 }
626 }
627
628 void
629 msn_userlist_rem_buddy(MsnUserList *userlist,
630 const char *who, int list_id, const char *group_name)
631 {
632 MsnUser *user;
633 const char *group_id;
634 const char *list;
635
636 user = msn_userlist_find_user(userlist, who);
637 group_id = -1;
638
639 g_return_if_fail(user != NULL);
640
641 /*delete the contact from address book via soap action*/
642 msn_delete_contact(userlist->session->contact,user->uid);
643
644 group_id = NULL;
645
646 if (group_name != NULL){
647 group_id = msn_userlist_find_group_id(userlist, group_name);
648
649 if (group_id == NULL){
650 /* Whoa, there is no such group. */
651 gaim_debug_error("msn", "Group doesn't exist: %s\n", group_name);
652 return;
653 }
654 }
655
656 /* First we're going to check if not there. */
657 if (!(user_is_there(user, list_id, group_id)))
658 {
659 list = lists[list_id];
660 gaim_debug_error("msn", "User '%s' is not there: %s\n",
661 who, list);
662 return;
663 }
664
665 /* Then request the rem to the server. */
666 list = lists[list_id];
667
668 msn_notification_rem_buddy(userlist->session->notification, list, who, group_id);
669 }
670
671 /*add buddy*/
672 void
673 msn_userlist_add_buddy(MsnUserList *userlist,
674 const char *who, int list_id,
675 const char *group_name)
676 {
677 MsnUser *user;
678 const char *group_id;
679 const char *list;
680 const char *store_name;
681
682 gaim_debug_info("MaYuan", "userlist add buddy,name:{%s},group:{%s}\n",who ,group_name);
683 group_id = NULL;
684
685 if (!gaim_email_is_valid(who))
686 {
687 /* only notify the user about problems adding to the friends list
688 * maybe we should do something else for other lists, but it probably
689 * won't cause too many problems if we just ignore it */
690 if (list_id == MSN_LIST_FL)
691 {
692 char *str = g_strdup_printf(_("Unable to add \"%s\"."), who);
693 gaim_notify_error(NULL, NULL, str,
694 _("The screen name specified is invalid."));
695 g_free(str);
696 }
697
698 return;
699 }
700
701 if (group_name != NULL)
702 {
703 group_id = msn_userlist_find_group_id(userlist, group_name);
704
705 if (group_id < 0)
706 {
707 /* Whoa, we must add that group first. */
708 msn_request_add_group(userlist, who, NULL, group_name);
709 return;
710 }
711 }
712
713 user = msn_userlist_find_user(userlist, who);
714
715 /* First we're going to check if it's already there. */
716 if (user_is_there(user, list_id, group_id))
717 {
718 list = lists[list_id];
719 gaim_debug_error("msn", "User '%s' is already there: %s\n", who, list);
720 return;
721 }
722
723 store_name = (user != NULL) ? get_store_name(user) : who;
724
725 /* Then request the add to the server. */
726 list = lists[list_id];
727
728 gaim_debug_info("MaYuan", "add user:{%s} to group id {%s}\n",store_name ,group_id);
729 msn_add_contact(userlist->session->contact,who,group_id);
730 msn_notification_add_buddy(userlist->session->notification, list, who,
731 store_name, group_id);
732 }
733
734 void
735 msn_userlist_move_buddy(MsnUserList *userlist, const char *who,
736 const char *old_group_name, const char *new_group_name)
737 {
738 const char *new_group_id;
739
740 new_group_id = msn_userlist_find_group_id(userlist, new_group_name);
741
742 if (new_group_id == NULL)
743 {
744 msn_request_add_group(userlist, who, old_group_name, new_group_name);
745 return;
746 }
747
748 msn_userlist_add_buddy(userlist, who, MSN_LIST_FL, new_group_name);
749 msn_userlist_rem_buddy(userlist, who, MSN_LIST_FL, old_group_name);
750 }

mercurial