src/protocols/jabber/roster.c

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

mercurial