Mercurial > pidgin.yaz
annotate src/protocols/jabber/roster.c @ 13968:6fc412e59214
[gaim-migrate @ 16525]
A bunch of little things
* Use GAIM_CONNECTION_IS_VALID(gc) in a lot of places where
we were doing g_list_find(gaim_connections_get_all(), gc)
* Get rid of a lot of places where we were doing
g_list_find(gaim_connections_get_all(), gc). The handle used
by the request API ensures that the ok and cancel callback
functions won't be called if the gc is destroyed. However,
GAIM_CONNECTION_IS_VALID(gc) is still very important for
callback functions where we can't cancel the request.
For example, gaim_proxy_connect() callback functions.
* "Added" a function to Yahoo! that should help us notice
when our buddies change their buddy icon/display picture
* Some comments in a few places
* Changed GAIM_CONNECTION_IS_VALID(gc) to only look through
the list of "all" connections and not the list of
"connecting" connections. Some time ago we changed how
this was done so that the list of "all" connections now
includes the "connection" connections.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Thu, 20 Jul 2006 08:11:54 +0000 |
parents | 60f39c405dff |
children |
rev | line source |
---|---|
7014 | 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" | |
13807 | 24 #include "util.h" |
7014 | 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; | |
13925 | 59 gchar *my_bare_jid; |
7014 | 60 |
61 buddies = gaim_find_buddies(js->gc->account, jid); | |
62 | |
63 g2 = groups; | |
64 | |
65 if(!groups) { | |
66 if(!buddies) | |
67 g2 = g_slist_append(g2, g_strdup(_("Buddies"))); | |
68 else | |
69 return; | |
70 } | |
71 | |
13925 | 72 my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain); |
73 | |
7014 | 74 while(buddies) { |
75 GaimBuddy *b = buddies->data; | |
12088 | 76 GaimGroup *g = gaim_buddy_get_group(b); |
7014 | 77 |
78 buddies = g_slist_remove(buddies, b); | |
79 | |
80 if((l = g_slist_find_custom(g2, g->name, (GCompareFunc)strcmp))) { | |
7955 | 81 const char *servernick; |
82 | |
83 if((servernick = gaim_blist_node_get_string((GaimBlistNode*)b, "servernick"))) | |
84 serv_got_alias(js->gc, jid, servernick); | |
85 | |
7014 | 86 if(alias && (!b->alias || strcmp(b->alias, alias))) |
87 gaim_blist_alias_buddy(b, alias); | |
88 g_free(l->data); | |
89 g2 = g_slist_delete_link(g2, l); | |
90 } else { | |
91 gaim_blist_remove_buddy(b); | |
92 } | |
93 } | |
94 | |
95 while(g2) { | |
96 GaimBuddy *b = gaim_buddy_new(js->gc->account, jid, alias); | |
97 GaimGroup *g = gaim_find_group(g2->data); | |
98 | |
99 if(!g) { | |
100 g = gaim_group_new(g2->data); | |
101 gaim_blist_add_group(g, NULL); | |
102 } | |
103 | |
104 gaim_blist_add_buddy(b, NULL, g, NULL); | |
7955 | 105 gaim_blist_alias_buddy(b, alias); |
13925 | 106 |
107 /* If we just learned about ourself, then fake our status, | |
108 * because we won't be receiving a normal presence message | |
109 * about ourself. */ | |
110 if(!strcmp(b->name, my_bare_jid)) { | |
111 GaimPresence *gpresence; | |
112 GaimStatus *status; | |
113 | |
114 gpresence = gaim_account_get_presence(js->gc->account); | |
115 status = gaim_presence_get_active_status(gpresence); | |
116 jabber_presence_fake_to_self(js, status); | |
117 } | |
118 | |
7014 | 119 g_free(g2->data); |
120 g2 = g_slist_delete_link(g2, g2); | |
121 } | |
122 | |
13925 | 123 g_free(my_bare_jid); |
7014 | 124 g_slist_free(buddies); |
125 } | |
126 | |
127 void jabber_roster_parse(JabberStream *js, xmlnode *packet) | |
128 { | |
129 xmlnode *query, *item, *group; | |
130 const char *from = xmlnode_get_attrib(packet, "from"); | |
7310 | 131 |
132 if(from) { | |
7445 | 133 char *from_norm; |
7310 | 134 gboolean invalid; |
7175 | 135 |
7445 | 136 from_norm = g_strdup(jabber_normalize(js->gc->account, from)); |
137 | |
138 if(!from_norm) | |
7310 | 139 return; |
140 | |
7445 | 141 invalid = g_utf8_collate(from_norm, |
142 jabber_normalize(js->gc->account, | |
143 gaim_account_get_username(js->gc->account))); | |
7175 | 144 |
7310 | 145 g_free(from_norm); |
146 | |
147 if(invalid) | |
148 return; | |
7175 | 149 } |
150 | |
7014 | 151 query = xmlnode_get_child(packet, "query"); |
152 if(!query) | |
153 return; | |
154 | |
155 js->roster_parsed = TRUE; | |
156 | |
8135 | 157 for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item)) |
7014 | 158 { |
159 const char *jid, *name, *subscription, *ask; | |
160 JabberBuddy *jb; | |
161 | |
162 subscription = xmlnode_get_attrib(item, "subscription"); | |
163 jid = xmlnode_get_attrib(item, "jid"); | |
164 name = xmlnode_get_attrib(item, "name"); | |
165 ask = xmlnode_get_attrib(item, "ask"); | |
166 | |
8347 | 167 if(!jid) |
168 continue; | |
169 | |
170 if(!(jb = jabber_buddy_find(js, jid, TRUE))) | |
171 continue; | |
7014 | 172 |
10289 | 173 if(subscription) { |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
174 gint me = -1; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
175 char *jid_norm; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
176 const char *username; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
177 |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
178 jid_norm = g_strdup(jabber_normalize(js->gc->account, jid)); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
179 username = gaim_account_get_username(js->gc->account); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
180 me = g_utf8_collate(jid_norm, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
181 jabber_normalize(js->gc->account, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
182 username)); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
183 |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
184 if(me == 0) |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
185 jb->subscription = JABBER_SUB_BOTH; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
186 else if(!strcmp(subscription, "none")) |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
187 jb->subscription = JABBER_SUB_NONE; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
188 else if(!strcmp(subscription, "to")) |
10289 | 189 jb->subscription = JABBER_SUB_TO; |
190 else if(!strcmp(subscription, "from")) | |
191 jb->subscription = JABBER_SUB_FROM; | |
192 else if(!strcmp(subscription, "both")) | |
193 jb->subscription = JABBER_SUB_BOTH; | |
194 else if(!strcmp(subscription, "remove")) | |
195 jb->subscription = JABBER_SUB_REMOVE; | |
10941 | 196 /* XXX: if subscription is now "from" or "none" we need to |
197 * fake a signoff, since we won't get any presence from them | |
198 * anymore */ | |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
199 /* YYY: I was going to use this, but I'm not sure it's necessary |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
200 * anymore, but it's here in case it is. */ |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
201 /* |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
202 if ((jb->subscription & JABBER_SUB_FROM) || |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
203 (jb->subscription & JABBER_SUB_NONE)) { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
204 gaim_prpl_got_user_status(js->gc->account, jid, "offline", NULL); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
205 } |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
206 */ |
10289 | 207 } |
7014 | 208 |
209 if(ask && !strcmp(ask, "subscribe")) | |
210 jb->subscription |= JABBER_SUB_PENDING; | |
211 else | |
212 jb->subscription &= ~JABBER_SUB_PENDING; | |
213 | |
8194 | 214 if(jb->subscription == JABBER_SUB_REMOVE) { |
7014 | 215 remove_gaim_buddies(js, jid); |
216 } else { | |
217 GSList *groups = NULL; | |
8135 | 218 for(group = xmlnode_get_child(item, "group"); group; group = xmlnode_get_next_twin(group)) { |
7316 | 219 char *group_name; |
220 | |
221 if(!(group_name = xmlnode_get_data(group))) | |
222 group_name = g_strdup(""); | |
13807 | 223 |
224 if (g_slist_find_custom(groups, group_name, (GCompareFunc)gaim_utf8_strcasecmp) == NULL) | |
225 groups = g_slist_append(groups, group_name); | |
7014 | 226 } |
227 add_gaim_buddies_in_groups(js, jid, name, groups); | |
228 } | |
229 } | |
230 } | |
231 | |
232 static void jabber_roster_update(JabberStream *js, const char *name, | |
233 GSList *grps) | |
234 { | |
235 GaimBuddy *b; | |
236 GaimGroup *g; | |
237 GSList *groups = NULL, *l; | |
238 JabberIq *iq; | |
239 xmlnode *query, *item, *group; | |
240 | |
241 if(grps) { | |
242 groups = grps; | |
243 } else { | |
244 GSList *buddies = gaim_find_buddies(js->gc->account, name); | |
245 if(!buddies) | |
246 return; | |
247 while(buddies) { | |
248 b = buddies->data; | |
12088 | 249 g = gaim_buddy_get_group(b); |
7014 | 250 groups = g_slist_append(groups, g->name); |
251 buddies = g_slist_remove(buddies, b); | |
252 } | |
253 } | |
254 | |
8120 | 255 if(!(b = gaim_find_buddy(js->gc->account, name))) |
256 return; | |
7014 | 257 |
258 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster"); | |
259 | |
260 query = xmlnode_get_child(iq->node, "query"); | |
261 item = xmlnode_new_child(query, "item"); | |
262 | |
263 xmlnode_set_attrib(item, "jid", name); | |
264 | |
265 if(b->alias) | |
266 xmlnode_set_attrib(item, "name", b->alias); | |
267 | |
268 for(l = groups; l; l = l->next) { | |
269 group = xmlnode_new_child(item, "group"); | |
270 xmlnode_insert_data(group, l->data, -1); | |
271 } | |
272 | |
273 if(!grps) | |
274 g_slist_free(groups); | |
275 | |
276 jabber_iq_send(iq); | |
277 } | |
278 | |
9285 | 279 void jabber_roster_add_buddy(GaimConnection *gc, GaimBuddy *buddy, |
280 GaimGroup *group) | |
7014 | 281 { |
282 JabberStream *js = gc->proto_data; | |
283 char *who; | |
7425 | 284 GSList *groups = NULL; |
7014 | 285 JabberBuddy *jb; |
7488 | 286 JabberBuddyResource *jbr; |
8194 | 287 char *my_bare_jid; |
7014 | 288 |
289 if(!js->roster_parsed) | |
290 return; | |
291 | |
9285 | 292 if(!(who = jabber_get_bare_jid(buddy->name))) |
7425 | 293 return; |
7014 | 294 |
9285 | 295 jb = jabber_buddy_find(js, buddy->name, FALSE); |
7425 | 296 |
297 if(!jb || !(jb->subscription & JABBER_SUB_TO)) { | |
9285 | 298 groups = g_slist_append(groups, group->name); |
7425 | 299 } |
7014 | 300 |
7449 | 301 jabber_roster_update(js, who, groups); |
7014 | 302 |
8194 | 303 my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain); |
9954 | 304 if(!strcmp(who, my_bare_jid)) { |
305 GaimPresence *gpresence; | |
306 GaimStatus *status; | |
307 | |
308 gpresence = gaim_account_get_presence(js->gc->account); | |
309 status = gaim_presence_get_active_status(gpresence); | |
310 jabber_presence_fake_to_self(js, status); | |
311 } else if(!jb || !(jb->subscription & JABBER_SUB_TO)) { | |
7014 | 312 jabber_presence_subscription_set(js, who, "subscribe"); |
9954 | 313 } else if((jbr =jabber_buddy_find_resource(jb, NULL))) { |
314 gaim_prpl_got_user_status(gc->account, who, | |
315 jabber_buddy_state_get_status_id(jbr->state), | |
9990 | 316 "priority", jbr->priority, jbr->status ? "message" : NULL, jbr->status, NULL); |
9954 | 317 } |
7425 | 318 |
8194 | 319 g_free(my_bare_jid); |
7014 | 320 g_free(who); |
321 } | |
322 | |
323 void jabber_roster_alias_change(GaimConnection *gc, const char *name, const char *alias) | |
324 { | |
7449 | 325 GaimBuddy *b = gaim_find_buddy(gc->account, name); |
7482 | 326 char *a; |
7449 | 327 |
7482 | 328 a = g_strdup(alias); |
329 gaim_blist_alias_buddy(b, a); | |
330 g_free(a); | |
7449 | 331 |
7014 | 332 jabber_roster_update(gc->proto_data, name, NULL); |
333 } | |
334 | |
335 void jabber_roster_group_change(GaimConnection *gc, const char *name, | |
336 const char *old_group, const char *new_group) | |
337 { | |
338 GSList *buddies, *groups = NULL; | |
339 GaimBuddy *b; | |
340 GaimGroup *g; | |
341 | |
342 if(!old_group || !new_group || !strcmp(old_group, new_group)) | |
343 return; | |
344 | |
345 buddies = gaim_find_buddies(gc->account, name); | |
346 while(buddies) { | |
347 b = buddies->data; | |
12088 | 348 g = gaim_buddy_get_group(b); |
7014 | 349 if(!strcmp(g->name, old_group)) |
350 groups = g_slist_append(groups, (char*)new_group); /* ick */ | |
351 else | |
352 groups = g_slist_append(groups, g->name); | |
353 buddies = g_slist_remove(buddies, b); | |
354 } | |
355 jabber_roster_update(gc->proto_data, name, groups); | |
356 g_slist_free(groups); | |
357 } | |
358 | |
9285 | 359 void jabber_roster_group_rename(GaimConnection *gc, const char *old_name, |
360 GaimGroup *group, GList *moved_buddies) | |
7014 | 361 { |
362 GList *l; | |
9285 | 363 for(l = moved_buddies; l; l = l->next) { |
364 GaimBuddy *buddy = l->data; | |
365 jabber_roster_group_change(gc, buddy->name, old_name, group->name); | |
7014 | 366 } |
367 } | |
368 | |
9285 | 369 void jabber_roster_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, |
370 GaimGroup *group) { | |
371 GSList *buddies = gaim_find_buddies(gc->account, buddy->name); | |
7014 | 372 GSList *groups = NULL; |
373 | |
9285 | 374 buddies = g_slist_remove(buddies, buddy); |
7014 | 375 if(g_slist_length(buddies)) { |
9285 | 376 GaimBuddy *tmpbuddy; |
377 GaimGroup *tmpgroup; | |
378 | |
7014 | 379 while(buddies) { |
9285 | 380 tmpbuddy = buddies->data; |
12088 | 381 tmpgroup = gaim_buddy_get_group(tmpbuddy); |
9285 | 382 groups = g_slist_append(groups, tmpgroup->name); |
383 buddies = g_slist_remove(buddies, tmpbuddy); | |
7014 | 384 } |
9285 | 385 |
386 jabber_roster_update(gc->proto_data, buddy->name, groups); | |
7014 | 387 } else { |
7171 | 388 JabberIq *iq = jabber_iq_new_query(gc->proto_data, JABBER_IQ_SET, |
389 "jabber:iq:roster"); | |
390 xmlnode *query = xmlnode_get_child(iq->node, "query"); | |
391 xmlnode *item = xmlnode_new_child(query, "item"); | |
392 | |
9285 | 393 xmlnode_set_attrib(item, "jid", buddy->name); |
7171 | 394 xmlnode_set_attrib(item, "subscription", "remove"); |
395 | |
396 jabber_iq_send(iq); | |
7014 | 397 } |
398 | |
399 if(buddies) | |
400 g_slist_free(buddies); | |
401 if(groups) | |
402 g_slist_free(groups); | |
403 } |