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