Mercurial > pidgin
annotate src/protocols/jabber/roster.c @ 13152:4bb701a8736f
[gaim-migrate @ 15515]
gaim_utf8_strftime() will now provide %z itself if your C library doesn't have it. I'm going to use this shortly.
committer: Tailor Script <tailor@pidgin.im>
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Tue, 07 Feb 2006 07:25:45 +0000 |
parents | af257d8679fe |
children | a415805c7456 |
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" | |
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; | |
12088 | 72 GaimGroup *g = gaim_buddy_get_group(b); |
7014 | 73 |
74 buddies = g_slist_remove(buddies, b); | |
75 | |
76 if((l = g_slist_find_custom(g2, g->name, (GCompareFunc)strcmp))) { | |
7955 | 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 | |
7014 | 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); | |
7955 | 101 gaim_blist_alias_buddy(b, alias); |
7014 | 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"); | |
7310 | 113 |
114 if(from) { | |
7445 | 115 char *from_norm; |
7310 | 116 gboolean invalid; |
7175 | 117 |
7445 | 118 from_norm = g_strdup(jabber_normalize(js->gc->account, from)); |
119 | |
120 if(!from_norm) | |
7310 | 121 return; |
122 | |
7445 | 123 invalid = g_utf8_collate(from_norm, |
124 jabber_normalize(js->gc->account, | |
125 gaim_account_get_username(js->gc->account))); | |
7175 | 126 |
7310 | 127 g_free(from_norm); |
128 | |
129 if(invalid) | |
130 return; | |
7175 | 131 } |
132 | |
7014 | 133 query = xmlnode_get_child(packet, "query"); |
134 if(!query) | |
135 return; | |
136 | |
137 js->roster_parsed = TRUE; | |
138 | |
8135 | 139 for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item)) |
7014 | 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 | |
8347 | 149 if(!jid) |
150 continue; | |
151 | |
152 if(!(jb = jabber_buddy_find(js, jid, TRUE))) | |
153 continue; | |
7014 | 154 |
10289 | 155 if(subscription) { |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
156 gint me = -1; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
157 char *jid_norm; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
158 const char *username; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
159 |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
160 jid_norm = g_strdup(jabber_normalize(js->gc->account, jid)); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
161 username = gaim_account_get_username(js->gc->account); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
162 me = g_utf8_collate(jid_norm, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
163 jabber_normalize(js->gc->account, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
164 username)); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
165 |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
166 if(me == 0) |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
167 jb->subscription = JABBER_SUB_BOTH; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
168 else if(!strcmp(subscription, "none")) |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
169 jb->subscription = JABBER_SUB_NONE; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
170 else if(!strcmp(subscription, "to")) |
10289 | 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; | |
10941 | 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 */ | |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
181 /* 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
|
182 * anymore, but it's here in case it is. */ |
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 ((jb->subscription & JABBER_SUB_FROM) || |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
185 (jb->subscription & JABBER_SUB_NONE)) { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
186 gaim_prpl_got_user_status(js->gc->account, jid, "offline", NULL); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
187 } |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12088
diff
changeset
|
188 */ |
10289 | 189 } |
7014 | 190 |
191 if(ask && !strcmp(ask, "subscribe")) | |
192 jb->subscription |= JABBER_SUB_PENDING; | |
193 else | |
194 jb->subscription &= ~JABBER_SUB_PENDING; | |
195 | |
8194 | 196 if(jb->subscription == JABBER_SUB_REMOVE) { |
7014 | 197 remove_gaim_buddies(js, jid); |
198 } else { | |
199 GSList *groups = NULL; | |
8135 | 200 for(group = xmlnode_get_child(item, "group"); group; group = xmlnode_get_next_twin(group)) { |
7316 | 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); | |
7014 | 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; | |
12088 | 229 g = gaim_buddy_get_group(b); |
7014 | 230 groups = g_slist_append(groups, g->name); |
231 buddies = g_slist_remove(buddies, b); | |
232 } | |
233 } | |
234 | |
8120 | 235 if(!(b = gaim_find_buddy(js->gc->account, name))) |
236 return; | |
7014 | 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 | |
9285 | 259 void jabber_roster_add_buddy(GaimConnection *gc, GaimBuddy *buddy, |
260 GaimGroup *group) | |
7014 | 261 { |
262 JabberStream *js = gc->proto_data; | |
263 char *who; | |
7425 | 264 GSList *groups = NULL; |
7014 | 265 JabberBuddy *jb; |
7488 | 266 JabberBuddyResource *jbr; |
8194 | 267 char *my_bare_jid; |
7014 | 268 |
269 if(!js->roster_parsed) | |
270 return; | |
271 | |
9285 | 272 if(!(who = jabber_get_bare_jid(buddy->name))) |
7425 | 273 return; |
7014 | 274 |
9285 | 275 jb = jabber_buddy_find(js, buddy->name, FALSE); |
7425 | 276 |
277 if(!jb || !(jb->subscription & JABBER_SUB_TO)) { | |
9285 | 278 groups = g_slist_append(groups, group->name); |
7425 | 279 } |
7014 | 280 |
7449 | 281 jabber_roster_update(js, who, groups); |
7014 | 282 |
8194 | 283 my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain); |
9954 | 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)) { | |
7014 | 292 jabber_presence_subscription_set(js, who, "subscribe"); |
9954 | 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), | |
9990 | 296 "priority", jbr->priority, jbr->status ? "message" : NULL, jbr->status, NULL); |
9954 | 297 } |
7425 | 298 |
8194 | 299 g_free(my_bare_jid); |
7014 | 300 g_free(who); |
301 } | |
302 | |
303 void jabber_roster_alias_change(GaimConnection *gc, const char *name, const char *alias) | |
304 { | |
7449 | 305 GaimBuddy *b = gaim_find_buddy(gc->account, name); |
7482 | 306 char *a; |
7449 | 307 |
7482 | 308 a = g_strdup(alias); |
309 gaim_blist_alias_buddy(b, a); | |
310 g_free(a); | |
7449 | 311 |
7014 | 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; | |
12088 | 328 g = gaim_buddy_get_group(b); |
7014 | 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 | |
9285 | 339 void jabber_roster_group_rename(GaimConnection *gc, const char *old_name, |
340 GaimGroup *group, GList *moved_buddies) | |
7014 | 341 { |
342 GList *l; | |
9285 | 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); | |
7014 | 346 } |
347 } | |
348 | |
9285 | 349 void jabber_roster_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, |
350 GaimGroup *group) { | |
351 GSList *buddies = gaim_find_buddies(gc->account, buddy->name); | |
7014 | 352 GSList *groups = NULL; |
353 | |
9285 | 354 buddies = g_slist_remove(buddies, buddy); |
7014 | 355 if(g_slist_length(buddies)) { |
9285 | 356 GaimBuddy *tmpbuddy; |
357 GaimGroup *tmpgroup; | |
358 | |
7014 | 359 while(buddies) { |
9285 | 360 tmpbuddy = buddies->data; |
12088 | 361 tmpgroup = gaim_buddy_get_group(tmpbuddy); |
9285 | 362 groups = g_slist_append(groups, tmpgroup->name); |
363 buddies = g_slist_remove(buddies, tmpbuddy); | |
7014 | 364 } |
9285 | 365 |
366 jabber_roster_update(gc->proto_data, buddy->name, groups); | |
7014 | 367 } else { |
7171 | 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 | |
9285 | 373 xmlnode_set_attrib(item, "jid", buddy->name); |
7171 | 374 xmlnode_set_attrib(item, "subscription", "remove"); |
375 | |
376 jabber_iq_send(iq); | |
7014 | 377 } |
378 | |
379 if(buddies) | |
380 g_slist_free(buddies); | |
381 if(groups) | |
382 g_slist_free(groups); | |
383 } |