src/protocols/jabber/roster.c

branch
cpw.khc.msnp14
changeset 20472
6a6d2ef151e6
parent 13912
463b4fa9f067
parent 20469
b2836a24d81e
child 20473
91e1b3a49d10
equal deleted inserted replaced
13912:463b4fa9f067 20472:6a6d2ef151e6
1 /*
2 * gaim - Jabber Protocol Plugin
3 *
4 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21 #include "internal.h"
22 #include "debug.h"
23 #include "server.h"
24 #include "util.h"
25
26 #include "buddy.h"
27 #include "presence.h"
28 #include "roster.h"
29 #include "iq.h"
30
31 #include <string.h>
32
33
34 void jabber_roster_request(JabberStream *js)
35 {
36 JabberIq *iq;
37
38 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:roster");
39
40 jabber_iq_send(iq);
41 }
42
43 static void remove_gaim_buddies(JabberStream *js, const char *jid)
44 {
45 GSList *buddies, *l;
46
47 buddies = gaim_find_buddies(js->gc->account, jid);
48
49 for(l = buddies; l; l = l->next)
50 gaim_blist_remove_buddy(l->data);
51
52 g_slist_free(buddies);
53 }
54
55 static void add_gaim_buddies_in_groups(JabberStream *js, const char *jid,
56 const char *alias, GSList *groups)
57 {
58 GSList *buddies, *g2, *l;
59
60 buddies = gaim_find_buddies(js->gc->account, jid);
61
62 g2 = groups;
63
64 if(!groups) {
65 if(!buddies)
66 g2 = g_slist_append(g2, g_strdup(_("Buddies")));
67 else
68 return;
69 }
70
71 while(buddies) {
72 GaimBuddy *b = buddies->data;
73 GaimGroup *g = gaim_buddy_get_group(b);
74
75 buddies = g_slist_remove(buddies, b);
76
77 if((l = g_slist_find_custom(g2, g->name, (GCompareFunc)strcmp))) {
78 const char *servernick;
79
80 if((servernick = gaim_blist_node_get_string((GaimBlistNode*)b, "servernick")))
81 serv_got_alias(js->gc, jid, servernick);
82
83 if(alias && (!b->alias || strcmp(b->alias, alias)))
84 gaim_blist_alias_buddy(b, alias);
85 g_free(l->data);
86 g2 = g_slist_delete_link(g2, l);
87 } else {
88 gaim_blist_remove_buddy(b);
89 }
90 }
91
92 while(g2) {
93 GaimBuddy *b = gaim_buddy_new(js->gc->account, jid, alias);
94 GaimGroup *g = gaim_find_group(g2->data);
95
96 if(!g) {
97 g = gaim_group_new(g2->data);
98 gaim_blist_add_group(g, NULL);
99 }
100
101 gaim_blist_add_buddy(b, NULL, g, NULL);
102 gaim_blist_alias_buddy(b, alias);
103 g_free(g2->data);
104 g2 = g_slist_delete_link(g2, g2);
105 }
106
107 g_slist_free(buddies);
108 }
109
110 void jabber_roster_parse(JabberStream *js, xmlnode *packet)
111 {
112 xmlnode *query, *item, *group;
113 const char *from = xmlnode_get_attrib(packet, "from");
114
115 if(from) {
116 char *from_norm;
117 gboolean invalid;
118
119 from_norm = g_strdup(jabber_normalize(js->gc->account, from));
120
121 if(!from_norm)
122 return;
123
124 invalid = g_utf8_collate(from_norm,
125 jabber_normalize(js->gc->account,
126 gaim_account_get_username(js->gc->account)));
127
128 g_free(from_norm);
129
130 if(invalid)
131 return;
132 }
133
134 query = xmlnode_get_child(packet, "query");
135 if(!query)
136 return;
137
138 js->roster_parsed = TRUE;
139
140 for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item))
141 {
142 const char *jid, *name, *subscription, *ask;
143 JabberBuddy *jb;
144
145 subscription = xmlnode_get_attrib(item, "subscription");
146 jid = xmlnode_get_attrib(item, "jid");
147 name = xmlnode_get_attrib(item, "name");
148 ask = xmlnode_get_attrib(item, "ask");
149
150 if(!jid)
151 continue;
152
153 if(!(jb = jabber_buddy_find(js, jid, TRUE)))
154 continue;
155
156 if(subscription) {
157 gint me = -1;
158 char *jid_norm;
159 const char *username;
160
161 jid_norm = g_strdup(jabber_normalize(js->gc->account, jid));
162 username = gaim_account_get_username(js->gc->account);
163 me = g_utf8_collate(jid_norm,
164 jabber_normalize(js->gc->account,
165 username));
166
167 if(me == 0)
168 jb->subscription = JABBER_SUB_BOTH;
169 else if(!strcmp(subscription, "none"))
170 jb->subscription = JABBER_SUB_NONE;
171 else if(!strcmp(subscription, "to"))
172 jb->subscription = JABBER_SUB_TO;
173 else if(!strcmp(subscription, "from"))
174 jb->subscription = JABBER_SUB_FROM;
175 else if(!strcmp(subscription, "both"))
176 jb->subscription = JABBER_SUB_BOTH;
177 else if(!strcmp(subscription, "remove"))
178 jb->subscription = JABBER_SUB_REMOVE;
179 /* XXX: if subscription is now "from" or "none" we need to
180 * fake a signoff, since we won't get any presence from them
181 * anymore */
182 /* YYY: I was going to use this, but I'm not sure it's necessary
183 * anymore, but it's here in case it is. */
184 /*
185 if ((jb->subscription & JABBER_SUB_FROM) ||
186 (jb->subscription & JABBER_SUB_NONE)) {
187 gaim_prpl_got_user_status(js->gc->account, jid, "offline", NULL);
188 }
189 */
190 }
191
192 if(ask && !strcmp(ask, "subscribe"))
193 jb->subscription |= JABBER_SUB_PENDING;
194 else
195 jb->subscription &= ~JABBER_SUB_PENDING;
196
197 if(jb->subscription == JABBER_SUB_REMOVE) {
198 remove_gaim_buddies(js, jid);
199 } else {
200 GSList *groups = NULL;
201 for(group = xmlnode_get_child(item, "group"); group; group = xmlnode_get_next_twin(group)) {
202 char *group_name;
203
204 if(!(group_name = xmlnode_get_data(group)))
205 group_name = g_strdup("");
206
207 if (g_slist_find_custom(groups, group_name, (GCompareFunc)gaim_utf8_strcasecmp) == NULL)
208 groups = g_slist_append(groups, group_name);
209 }
210 add_gaim_buddies_in_groups(js, jid, name, groups);
211 }
212 }
213 }
214
215 static void jabber_roster_update(JabberStream *js, const char *name,
216 GSList *grps)
217 {
218 GaimBuddy *b;
219 GaimGroup *g;
220 GSList *groups = NULL, *l;
221 JabberIq *iq;
222 xmlnode *query, *item, *group;
223
224 if(grps) {
225 groups = grps;
226 } else {
227 GSList *buddies = gaim_find_buddies(js->gc->account, name);
228 if(!buddies)
229 return;
230 while(buddies) {
231 b = buddies->data;
232 g = gaim_buddy_get_group(b);
233 groups = g_slist_append(groups, g->name);
234 buddies = g_slist_remove(buddies, b);
235 }
236 }
237
238 if(!(b = gaim_find_buddy(js->gc->account, name)))
239 return;
240
241 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster");
242
243 query = xmlnode_get_child(iq->node, "query");
244 item = xmlnode_new_child(query, "item");
245
246 xmlnode_set_attrib(item, "jid", name);
247
248 if(b->alias)
249 xmlnode_set_attrib(item, "name", b->alias);
250
251 for(l = groups; l; l = l->next) {
252 group = xmlnode_new_child(item, "group");
253 xmlnode_insert_data(group, l->data, -1);
254 }
255
256 if(!grps)
257 g_slist_free(groups);
258
259 jabber_iq_send(iq);
260 }
261
262 void jabber_roster_add_buddy(GaimConnection *gc, GaimBuddy *buddy,
263 GaimGroup *group)
264 {
265 JabberStream *js = gc->proto_data;
266 char *who;
267 GSList *groups = NULL;
268 JabberBuddy *jb;
269 JabberBuddyResource *jbr;
270 char *my_bare_jid;
271
272 if(!js->roster_parsed)
273 return;
274
275 if(!(who = jabber_get_bare_jid(buddy->name)))
276 return;
277
278 jb = jabber_buddy_find(js, buddy->name, FALSE);
279
280 if(!jb || !(jb->subscription & JABBER_SUB_TO)) {
281 groups = g_slist_append(groups, group->name);
282 }
283
284 jabber_roster_update(js, who, groups);
285
286 my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain);
287 if(!strcmp(who, my_bare_jid)) {
288 GaimPresence *gpresence;
289 GaimStatus *status;
290
291 gpresence = gaim_account_get_presence(js->gc->account);
292 status = gaim_presence_get_active_status(gpresence);
293 jabber_presence_fake_to_self(js, status);
294 } else if(!jb || !(jb->subscription & JABBER_SUB_TO)) {
295 jabber_presence_subscription_set(js, who, "subscribe");
296 } else if((jbr =jabber_buddy_find_resource(jb, NULL))) {
297 gaim_prpl_got_user_status(gc->account, who,
298 jabber_buddy_state_get_status_id(jbr->state),
299 "priority", jbr->priority, jbr->status ? "message" : NULL, jbr->status, NULL);
300 }
301
302 g_free(my_bare_jid);
303 g_free(who);
304 }
305
306 void jabber_roster_alias_change(GaimConnection *gc, const char *name, const char *alias)
307 {
308 GaimBuddy *b = gaim_find_buddy(gc->account, name);
309 char *a;
310
311 a = g_strdup(alias);
312 gaim_blist_alias_buddy(b, a);
313 g_free(a);
314
315 jabber_roster_update(gc->proto_data, name, NULL);
316 }
317
318 void jabber_roster_group_change(GaimConnection *gc, const char *name,
319 const char *old_group, const char *new_group)
320 {
321 GSList *buddies, *groups = NULL;
322 GaimBuddy *b;
323 GaimGroup *g;
324
325 if(!old_group || !new_group || !strcmp(old_group, new_group))
326 return;
327
328 buddies = gaim_find_buddies(gc->account, name);
329 while(buddies) {
330 b = buddies->data;
331 g = gaim_buddy_get_group(b);
332 if(!strcmp(g->name, old_group))
333 groups = g_slist_append(groups, (char*)new_group); /* ick */
334 else
335 groups = g_slist_append(groups, g->name);
336 buddies = g_slist_remove(buddies, b);
337 }
338 jabber_roster_update(gc->proto_data, name, groups);
339 g_slist_free(groups);
340 }
341
342 void jabber_roster_group_rename(GaimConnection *gc, const char *old_name,
343 GaimGroup *group, GList *moved_buddies)
344 {
345 GList *l;
346 for(l = moved_buddies; l; l = l->next) {
347 GaimBuddy *buddy = l->data;
348 jabber_roster_group_change(gc, buddy->name, old_name, group->name);
349 }
350 }
351
352 void jabber_roster_remove_buddy(GaimConnection *gc, GaimBuddy *buddy,
353 GaimGroup *group) {
354 GSList *buddies = gaim_find_buddies(gc->account, buddy->name);
355 GSList *groups = NULL;
356
357 buddies = g_slist_remove(buddies, buddy);
358 if(g_slist_length(buddies)) {
359 GaimBuddy *tmpbuddy;
360 GaimGroup *tmpgroup;
361
362 while(buddies) {
363 tmpbuddy = buddies->data;
364 tmpgroup = gaim_buddy_get_group(tmpbuddy);
365 groups = g_slist_append(groups, tmpgroup->name);
366 buddies = g_slist_remove(buddies, tmpbuddy);
367 }
368
369 jabber_roster_update(gc->proto_data, buddy->name, groups);
370 } else {
371 JabberIq *iq = jabber_iq_new_query(gc->proto_data, JABBER_IQ_SET,
372 "jabber:iq:roster");
373 xmlnode *query = xmlnode_get_child(iq->node, "query");
374 xmlnode *item = xmlnode_new_child(query, "item");
375
376 xmlnode_set_attrib(item, "jid", buddy->name);
377 xmlnode_set_attrib(item, "subscription", "remove");
378
379 jabber_iq_send(iq);
380 }
381
382 if(buddies)
383 g_slist_free(buddies);
384 if(groups)
385 g_slist_free(groups);
386 }

mercurial