2
* @file userlist.c MSN user list support
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
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.
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.
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
27
const char *lists[] = { "FL", "AL", "BL", "RL" };
37
/**************************************************************************
39
**************************************************************************/
41
msn_accept_add_cb(gpointer data)
43
MsnPermitAdd *pa = data;
45
MsnUserList *userlist;
47
if (PURPLE_CONNECTION_IS_VALID(pa->gc)) {
48
session = pa->gc->proto_data;
49
userlist = session->userlist;
51
msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_AL, NULL);
60
msn_cancel_add_cb(gpointer data)
62
MsnPermitAdd *pa = data;
64
MsnUserList *userlist;
66
if (PURPLE_CONNECTION_IS_VALID(pa->gc)) {
67
session = pa->gc->proto_data;
68
userlist = session->userlist;
70
msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_BL, NULL);
79
got_new_entry(PurpleConnection *gc, const char *passport, const char *friendly)
83
pa = g_new0(MsnPermitAdd, 1);
84
pa->who = g_strdup(passport);
85
pa->friendly = g_strdup(friendly);
88
purple_account_request_authorization(purple_connection_get_account(gc), passport, NULL, friendly, NULL,
89
purple_find_buddy(purple_connection_get_account(gc), passport) != NULL,
90
msn_accept_add_cb, msn_cancel_add_cb, pa);
93
/**************************************************************************
95
**************************************************************************/
98
user_is_in_group(MsnUser *user, int group_id)
106
if (g_list_find(user->group_ids, GINT_TO_POINTER(group_id)))
113
user_is_there(MsnUser *user, int list_id, int group_id)
120
list_op = 1 << list_id;
122
if (!(user->list_op & list_op))
125
if (list_id == MSN_LIST_FL)
128
return user_is_in_group(user, group_id);
135
get_friendly_name(MsnUser *user)
137
const char *friendly_name;
139
g_return_val_if_fail(user != NULL, NULL);
141
friendly_name = msn_user_get_friendly_name(user);
143
if (friendly_name != NULL)
144
friendly_name = purple_url_encode(friendly_name);
146
friendly_name = msn_user_get_passport(user);
148
/* this might be a bit of a hack, but it should prevent notification server
149
* disconnections for people who have buddies with insane friendly names
150
* who added you to their buddy list from being disconnected. Stu. */
151
/* Shx: What? Isn't the store_name obtained from the server, and hence it's
152
* below the BUDDY_ALIAS_MAXLEN ? */
153
/* Stu: yeah, that's why it's a bit of a hack, as you pointed out, we're
154
* probably decoding the incoming store_name wrong, or something. bleh. */
156
if (strlen(friendly_name) > BUDDY_ALIAS_MAXLEN)
157
friendly_name = msn_user_get_passport(user);
159
return friendly_name;
163
msn_request_add_group(MsnUserList *userlist, const char *who,
164
const char *old_group_name, const char *new_group_name)
167
MsnTransaction *trans;
170
cmdproc = userlist->session->notification->cmdproc;
171
data = g_new0(MsnMoveBuddy, 1);
173
data->who = g_strdup(who);
176
data->old_group_name = g_strdup(old_group_name);
178
trans = msn_transaction_new(cmdproc, "ADG", "%s %d",
179
purple_url_encode(new_group_name),
182
msn_transaction_set_data(trans, data);
184
msn_cmdproc_send_trans(cmdproc, trans);
187
/**************************************************************************
189
**************************************************************************/
192
msn_get_list_id(const char *list)
196
else if (list[0] == 'A')
198
else if (list[0] == 'B')
200
else if (list[0] == 'R')
207
msn_got_add_user(MsnSession *session, MsnUser *user,
208
MsnListId list_id, int group_id)
210
PurpleAccount *account;
211
const char *passport;
212
const char *friendly;
214
account = session->account;
216
passport = msn_user_get_passport(user);
217
friendly = msn_user_get_friendly_name(user);
219
if (list_id == MSN_LIST_FL)
221
PurpleConnection *gc;
223
gc = purple_account_get_connection(account);
225
serv_got_alias(gc, passport, friendly);
229
msn_user_add_group_id(user, group_id);
233
/* session->sync->fl_users_count++; */
236
else if (list_id == MSN_LIST_AL)
238
purple_privacy_permit_add(account, passport, TRUE);
240
else if (list_id == MSN_LIST_BL)
242
purple_privacy_deny_add(account, passport, TRUE);
244
else if (list_id == MSN_LIST_RL)
246
PurpleConnection *gc;
247
PurpleConversation *convo;
249
gc = purple_account_get_connection(account);
251
purple_debug_info("msn",
252
"%s has added you to his or her buddy list.\n",
255
convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, passport, account);
260
buddy = purple_find_buddy(account, passport);
261
msg = g_strdup_printf(
262
_("%s has added you to his or her buddy list."),
263
buddy ? purple_buddy_get_contact_alias(buddy) : passport);
264
purple_conv_im_write(PURPLE_CONV_IM(convo), passport, msg,
265
PURPLE_MESSAGE_SYSTEM, time(NULL));
269
if (!(user->list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP)))
272
* TODO: The friendly name was NULL for me when I
273
* looked at this. Maybe we should use the store
274
* name instead? --KingAnt
276
got_new_entry(gc, passport, friendly);
280
user->list_op |= (1 << list_id);
281
/* purple_user_add_list_id (user, list_id); */
285
msn_got_rem_user(MsnSession *session, MsnUser *user,
286
MsnListId list_id, int group_id)
288
PurpleAccount *account;
289
const char *passport;
291
account = session->account;
293
passport = msn_user_get_passport(user);
295
if (list_id == MSN_LIST_FL)
297
/* TODO: When is the user totally removed? */
300
msn_user_remove_group_id(user, group_id);
305
/* session->sync->fl_users_count--; */
308
else if (list_id == MSN_LIST_AL)
310
purple_privacy_permit_remove(account, passport, TRUE);
312
else if (list_id == MSN_LIST_BL)
314
purple_privacy_deny_remove(account, passport, TRUE);
316
else if (list_id == MSN_LIST_RL)
318
PurpleConversation *convo;
320
purple_debug_info("msn",
321
"%s has removed you from his or her buddy list.\n",
324
convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, passport, account);
329
buddy = purple_find_buddy(account, passport);
330
msg = g_strdup_printf(
331
_("%s has removed you from his or her buddy list."),
332
buddy ? purple_buddy_get_contact_alias(buddy) : passport);
333
purple_conv_im_write(PURPLE_CONV_IM(convo), passport, msg,
334
PURPLE_MESSAGE_SYSTEM, time(NULL));
339
user->list_op &= ~(1 << list_id);
340
/* purple_user_remove_list_id (user, list_id); */
342
if (user->list_op == 0)
344
purple_debug_info("msn", "Buddy '%s' shall be deleted?.\n",
351
msn_got_lst_user(MsnSession *session, MsnUser *user,
352
int list_op, GSList *group_ids)
354
PurpleConnection *gc;
355
PurpleAccount *account;
356
const char *passport;
359
account = session->account;
360
gc = purple_account_get_connection(account);
362
passport = msn_user_get_passport(user);
363
store = msn_user_get_friendly_name(user);
365
if (list_op & MSN_LIST_FL_OP)
368
for (c = group_ids; c != NULL; c = g_slist_next(c))
371
group_id = GPOINTER_TO_INT(c->data);
372
msn_user_add_group_id(user, group_id);
375
/* FIXME: It might be a real alias */
376
/* Umm, what? This might fix bug #1385130 */
377
serv_got_alias(gc, passport, store);
380
if (list_op & MSN_LIST_AL_OP)
382
/* These are users who are allowed to see our status. */
383
purple_privacy_deny_remove(account, passport, TRUE);
384
purple_privacy_permit_add(account, passport, TRUE);
387
if (list_op & MSN_LIST_BL_OP)
389
/* These are users who are not allowed to see our status. */
390
purple_privacy_permit_remove(account, passport, TRUE);
391
purple_privacy_deny_add(account, passport, TRUE);
394
if (list_op & MSN_LIST_RL_OP)
396
/* These are users who have us on their buddy list. */
398
* TODO: What is store name set to when this happens?
399
* For one of my accounts "something@hotmail.com"
400
* the store name was "something." Maybe we
401
* should use the friendly name, instead? --KingAnt
404
if (!(list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP)))
406
got_new_entry(gc, passport, store);
410
user->list_op = list_op;
413
/**************************************************************************
415
**************************************************************************/
418
msn_userlist_new(MsnSession *session)
420
MsnUserList *userlist;
422
userlist = g_new0(MsnUserList, 1);
424
userlist->session = session;
425
userlist->buddy_icon_requests = g_queue_new();
427
/* buddy_icon_window is the number of allowed simultaneous buddy icon requests.
428
* XXX With smarter rate limiting code, we could allow more at once... 5 was the limit set when
429
* we weren't retrieiving any more than 5 per MSN session. */
430
userlist->buddy_icon_window = 1;
436
msn_userlist_destroy(MsnUserList *userlist)
440
for (l = userlist->users; l != NULL; l = l->next)
442
msn_user_destroy(l->data);
445
g_list_free(userlist->users);
447
for (l = userlist->groups; l != NULL; l = l->next)
449
msn_group_destroy(l->data);
452
g_list_free(userlist->groups);
454
g_queue_free(userlist->buddy_icon_requests);
456
if (userlist->buddy_icon_request_timer)
457
purple_timeout_remove(userlist->buddy_icon_request_timer);
463
msn_userlist_add_user(MsnUserList *userlist, MsnUser *user)
465
userlist->users = g_list_prepend(userlist->users, user);
469
msn_userlist_remove_user(MsnUserList *userlist, MsnUser *user)
471
userlist->users = g_list_remove(userlist->users, user);
475
msn_userlist_find_user(MsnUserList *userlist, const char *passport)
479
g_return_val_if_fail(passport != NULL, NULL);
481
for (l = userlist->users; l != NULL; l = l->next)
483
MsnUser *user = (MsnUser *)l->data;
485
g_return_val_if_fail(user->passport != NULL, NULL);
487
if (!strcmp(passport, user->passport))
495
msn_userlist_add_group(MsnUserList *userlist, MsnGroup *group)
497
userlist->groups = g_list_append(userlist->groups, group);
501
msn_userlist_remove_group(MsnUserList *userlist, MsnGroup *group)
503
userlist->groups = g_list_remove(userlist->groups, group);
507
msn_userlist_find_group_with_id(MsnUserList *userlist, int id)
511
g_return_val_if_fail(userlist != NULL, NULL);
512
g_return_val_if_fail(id >= 0, NULL);
514
for (l = userlist->groups; l != NULL; l = l->next)
516
MsnGroup *group = l->data;
526
msn_userlist_find_group_with_name(MsnUserList *userlist, const char *name)
530
g_return_val_if_fail(userlist != NULL, NULL);
531
g_return_val_if_fail(name != NULL, NULL);
533
for (l = userlist->groups; l != NULL; l = l->next)
535
MsnGroup *group = l->data;
537
if ((group->name != NULL) && !g_ascii_strcasecmp(name, group->name))
545
msn_userlist_find_group_id(MsnUserList *userlist, const char *group_name)
549
group = msn_userlist_find_group_with_name(userlist, group_name);
552
return msn_group_get_id(group);
558
msn_userlist_find_group_name(MsnUserList *userlist, int group_id)
562
group = msn_userlist_find_group_with_id(userlist, group_id);
565
return msn_group_get_name(group);
571
msn_userlist_rename_group_id(MsnUserList *userlist, int group_id,
572
const char *new_name)
576
group = msn_userlist_find_group_with_id(userlist, group_id);
579
msn_group_set_name(group, new_name);
583
msn_userlist_remove_group_id(MsnUserList *userlist, int group_id)
587
group = msn_userlist_find_group_with_id(userlist, group_id);
591
msn_userlist_remove_group(userlist, group);
592
msn_group_destroy(group);
597
msn_userlist_rem_buddy(MsnUserList *userlist,
598
const char *who, int list_id, const char *group_name)
604
user = msn_userlist_find_user(userlist, who);
607
if (group_name != NULL)
609
group_id = msn_userlist_find_group_id(userlist, group_name);
613
/* Whoa, there is no such group. */
614
purple_debug_error("msn", "Group doesn't exist: %s\n", group_name);
619
/* First we're going to check if not there. */
620
if (!(user_is_there(user, list_id, group_id)))
622
list = lists[list_id];
623
purple_debug_error("msn", "User '%s' is not there: %s\n",
628
/* Then request the rem to the server. */
629
list = lists[list_id];
631
msn_notification_rem_buddy(userlist->session->notification, list, who, group_id);
635
msn_userlist_add_buddy(MsnUserList *userlist,
636
const char *who, int list_id,
637
const char *group_name)
642
const char *friendly_name;
646
if (!purple_email_is_valid(who))
648
/* only notify the user about problems adding to the friends list
649
* maybe we should do something else for other lists, but it probably
650
* won't cause too many problems if we just ignore it */
651
if (list_id == MSN_LIST_FL)
653
char *str = g_strdup_printf(_("Unable to add \"%s\"."), who);
654
purple_notify_error(NULL, NULL, str,
655
_("The screen name specified is invalid."));
662
if (group_name != NULL)
664
group_id = msn_userlist_find_group_id(userlist, group_name);
668
/* Whoa, we must add that group first. */
669
msn_request_add_group(userlist, who, NULL, group_name);
674
user = msn_userlist_find_user(userlist, who);
676
/* First we're going to check if it's already there. */
677
if (user_is_there(user, list_id, group_id))
679
list = lists[list_id];
680
purple_debug_error("msn", "User '%s' is already there: %s\n", who, list);
684
friendly_name = (user != NULL) ? get_friendly_name(user) : who;
686
/* Then request the add to the server. */
687
list = lists[list_id];
689
msn_notification_add_buddy(userlist->session->notification, list, who,
690
friendly_name, group_id);
694
msn_userlist_move_buddy(MsnUserList *userlist, const char *who,
695
const char *old_group_name, const char *new_group_name)
699
new_group_id = msn_userlist_find_group_id(userlist, new_group_name);
701
if (new_group_id < 0)
703
msn_request_add_group(userlist, who, old_group_name, new_group_name);
707
msn_userlist_add_buddy(userlist, who, MSN_LIST_FL, new_group_name);
708
msn_userlist_rem_buddy(userlist, who, MSN_LIST_FL, old_group_name);