core/protocols/msn/userlist.c

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

mercurial