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