Mercurial > pidgin
annotate libgaim/protocols/jabber/disco.c @ 15282:8e39ca9b954a
[gaim-migrate @ 18072]
Fixed retrieval of initial presence from jabber contacts for non-Talk accounts: We are notified of presence for contacts one we set our own presence, so wait to do so until after we've requested the roster.
committer: Tailor Script <tailor@pidgin.im>
author | Evan Schoenberg <evan.s@dreskin.net> |
---|---|
date | Thu, 04 Jan 2007 19:21:10 +0000 |
parents | b5dff06f9c84 |
children | 4bcc40bd4e20 |
rev | line source |
---|---|
14192 | 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 | |
22 #include "internal.h" | |
23 #include "prefs.h" | |
24 | |
25 #include "buddy.h" | |
15163 | 26 #include "google.h" |
14192 | 27 #include "iq.h" |
28 #include "disco.h" | |
29 #include "jabber.h" | |
15282
8e39ca9b954a
[gaim-migrate @ 18072]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15261
diff
changeset
|
30 #include "presence.h" |
15203 | 31 #include "roster.h" |
14192 | 32 |
33 struct _jabber_disco_info_cb_data { | |
34 gpointer data; | |
35 JabberDiscoInfoCallback *callback; | |
36 }; | |
37 | |
38 #define SUPPORT_FEATURE(x) \ | |
39 feature = xmlnode_new_child(query, "feature"); \ | |
40 xmlnode_set_attrib(feature, "var", x); | |
41 | |
42 | |
43 void jabber_disco_info_parse(JabberStream *js, xmlnode *packet) { | |
44 const char *from = xmlnode_get_attrib(packet, "from"); | |
45 const char *type = xmlnode_get_attrib(packet, "type"); | |
46 | |
47 if(!from || !type) | |
48 return; | |
49 | |
50 if(!strcmp(type, "get")) { | |
51 xmlnode *query, *identity, *feature; | |
52 JabberIq *iq; | |
53 | |
54 xmlnode *in_query; | |
55 const char *node = NULL; | |
56 | |
57 if((in_query = xmlnode_get_child(packet, "query"))) { | |
58 node = xmlnode_get_attrib(in_query, "node"); | |
59 } | |
60 | |
61 | |
62 iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, | |
63 "http://jabber.org/protocol/disco#info"); | |
64 | |
65 jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id")); | |
66 | |
67 xmlnode_set_attrib(iq->node, "to", from); | |
68 query = xmlnode_get_child(iq->node, "query"); | |
69 | |
70 if(node) | |
71 xmlnode_set_attrib(query, "node", node); | |
72 | |
73 if(!node || !strcmp(node, CAPS0115_NODE "#" VERSION)) { | |
74 | |
75 identity = xmlnode_new_child(query, "identity"); | |
76 xmlnode_set_attrib(identity, "category", "client"); | |
77 xmlnode_set_attrib(identity, "type", "pc"); /* XXX: bot, console, | |
78 * handheld, pc, phone, | |
79 * web */ | |
80 xmlnode_set_attrib(identity, "name", PACKAGE); | |
81 | |
82 SUPPORT_FEATURE("jabber:iq:last") | |
83 SUPPORT_FEATURE("jabber:iq:oob") | |
84 SUPPORT_FEATURE("jabber:iq:time") | |
85 SUPPORT_FEATURE("jabber:iq:version") | |
86 SUPPORT_FEATURE("jabber:x:conference") | |
87 SUPPORT_FEATURE("http://jabber.org/protocol/bytestreams") | |
88 SUPPORT_FEATURE("http://jabber.org/protocol/disco#info") | |
89 SUPPORT_FEATURE("http://jabber.org/protocol/disco#items") | |
90 #if 0 | |
91 SUPPORT_FEATURE("http://jabber.org/protocol/ibb") | |
92 #endif | |
93 SUPPORT_FEATURE("http://jabber.org/protocol/muc") | |
94 SUPPORT_FEATURE("http://jabber.org/protocol/muc#user") | |
95 SUPPORT_FEATURE("http://jabber.org/protocol/si") | |
96 SUPPORT_FEATURE("http://jabber.org/protocol/si/profile/file-transfer") | |
97 SUPPORT_FEATURE("http://jabber.org/protocol/xhtml-im") | |
98 } else { | |
99 xmlnode *error, *inf; | |
100 | |
101 /* XXX: gross hack, implement jabber_iq_set_type or something */ | |
102 xmlnode_set_attrib(iq->node, "type", "error"); | |
103 iq->type = JABBER_IQ_ERROR; | |
104 | |
105 error = xmlnode_new_child(query, "error"); | |
106 xmlnode_set_attrib(error, "code", "404"); | |
107 xmlnode_set_attrib(error, "type", "cancel"); | |
108 inf = xmlnode_new_child(error, "item-not-found"); | |
109 xmlnode_set_namespace(inf, "urn:ietf:params:xml:ns:xmpp-stanzas"); | |
110 } | |
111 | |
112 jabber_iq_send(iq); | |
113 } else if(!strcmp(type, "result")) { | |
114 xmlnode *query = xmlnode_get_child(packet, "query"); | |
115 xmlnode *child; | |
116 JabberID *jid; | |
117 JabberBuddy *jb; | |
118 JabberBuddyResource *jbr = NULL; | |
119 JabberCapabilities capabilities = JABBER_CAP_NONE; | |
120 struct _jabber_disco_info_cb_data *jdicd; | |
121 | |
122 if((jid = jabber_id_new(from))) { | |
123 if(jid->resource && (jb = jabber_buddy_find(js, from, TRUE))) | |
124 jbr = jabber_buddy_find_resource(jb, jid->resource); | |
125 jabber_id_free(jid); | |
126 } | |
127 | |
128 if(jbr) | |
129 capabilities = jbr->capabilities; | |
130 | |
131 for(child = query->child; child; child = child->next) { | |
132 if(child->type != XMLNODE_TYPE_TAG) | |
133 continue; | |
134 | |
135 if(!strcmp(child->name, "identity")) { | |
136 const char *category = xmlnode_get_attrib(child, "category"); | |
137 const char *type = xmlnode_get_attrib(child, "type"); | |
138 if(!category || !type) | |
139 continue; | |
140 | |
141 if(!strcmp(category, "conference") && !strcmp(type, "text")) { | |
142 /* we found a groupchat or MUC server, add it to the list */ | |
143 /* XXX: actually check for protocol/muc or gc-1.0 support */ | |
144 js->chat_servers = g_list_append(js->chat_servers, g_strdup(from)); | |
145 } else if(!strcmp(category, "directory") && !strcmp(type, "user")) { | |
146 /* we found a JUD */ | |
147 js->user_directories = g_list_append(js->user_directories, g_strdup(from)); | |
148 } | |
149 | |
150 } else if(!strcmp(child->name, "feature")) { | |
151 const char *var = xmlnode_get_attrib(child, "var"); | |
152 if(!var) | |
153 continue; | |
154 | |
155 if(!strcmp(var, "http://jabber.org/protocol/si")) | |
156 capabilities |= JABBER_CAP_SI; | |
157 else if(!strcmp(var, "http://jabber.org/protocol/si/profile/file-transfer")) | |
158 capabilities |= JABBER_CAP_SI_FILE_XFER; | |
159 else if(!strcmp(var, "http://jabber.org/protocol/bytestreams")) | |
160 capabilities |= JABBER_CAP_BYTESTREAMS; | |
161 else if(!strcmp(var, "jabber:iq:search")) | |
162 capabilities |= JABBER_CAP_IQ_SEARCH; | |
163 else if(!strcmp(var, "jabber:iq:register")) | |
164 capabilities |= JABBER_CAP_IQ_REGISTER; | |
165 } | |
166 } | |
167 | |
168 capabilities |= JABBER_CAP_RETRIEVED; | |
169 | |
170 if(jbr) | |
171 jbr->capabilities = capabilities; | |
172 | |
173 if((jdicd = g_hash_table_lookup(js->disco_callbacks, from))) { | |
174 jdicd->callback(js, from, capabilities, jdicd->data); | |
175 g_hash_table_remove(js->disco_callbacks, from); | |
176 } | |
177 } else if(!strcmp(type, "error")) { | |
178 JabberID *jid; | |
179 JabberBuddy *jb; | |
180 JabberBuddyResource *jbr = NULL; | |
181 JabberCapabilities capabilities = JABBER_CAP_NONE; | |
182 struct _jabber_disco_info_cb_data *jdicd; | |
183 | |
184 if(!(jdicd = g_hash_table_lookup(js->disco_callbacks, from))) | |
185 return; | |
186 | |
187 if((jid = jabber_id_new(from))) { | |
188 if(jid->resource && (jb = jabber_buddy_find(js, from, TRUE))) | |
189 jbr = jabber_buddy_find_resource(jb, jid->resource); | |
190 jabber_id_free(jid); | |
191 } | |
192 | |
193 if(jbr) | |
194 capabilities = jbr->capabilities; | |
195 | |
196 jdicd->callback(js, from, capabilities, jdicd->data); | |
197 g_hash_table_remove(js->disco_callbacks, from); | |
198 } | |
199 } | |
200 | |
201 void jabber_disco_items_parse(JabberStream *js, xmlnode *packet) { | |
202 const char *from = xmlnode_get_attrib(packet, "from"); | |
203 const char *type = xmlnode_get_attrib(packet, "type"); | |
204 | |
14294 | 205 if(type && !strcmp(type, "get")) { |
14192 | 206 JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, |
207 "http://jabber.org/protocol/disco#items"); | |
208 | |
209 jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id")); | |
210 | |
211 xmlnode_set_attrib(iq->node, "to", from); | |
212 jabber_iq_send(iq); | |
213 } | |
214 } | |
215 | |
216 static void | |
15135 | 217 jabber_disco_server_info_result_cb(JabberStream *js, xmlnode *packet, gpointer data) |
218 { | |
15282
8e39ca9b954a
[gaim-migrate @ 18072]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15261
diff
changeset
|
219 GaimPresence *gpresence; |
8e39ca9b954a
[gaim-migrate @ 18072]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15261
diff
changeset
|
220 GaimStatus *status; |
15135 | 221 xmlnode *query, *child; |
222 const char *from = xmlnode_get_attrib(packet, "from"); | |
223 const char *type = xmlnode_get_attrib(packet, "type"); | |
224 | |
225 if(!from || !type) | |
226 return; | |
227 | |
228 if(strcmp(from, js->user->domain)) | |
229 return; | |
230 | |
231 if(strcmp(type, "result")) | |
232 return; | |
233 | |
234 query = xmlnode_get_child(packet, "query"); | |
235 | |
236 if (!query) return; | |
237 | |
238 for (child = xmlnode_get_child(query, "category"); child; | |
239 child = xmlnode_get_next_twin(child)) { | |
240 const char *category, *type, *name; | |
241 category = xmlnode_get_attrib(child, "category"); | |
242 if (!category || strcmp(category, "server")) | |
243 continue; | |
244 type = xmlnode_get_attrib(child, "type"); | |
245 if (!type || strcmp(type, "im")) | |
246 continue; | |
247 | |
248 name = xmlnode_get_attrib(child, "name"); | |
249 if (!name) | |
250 continue; | |
251 | |
252 g_free(js->server_name); | |
253 js->server_name = g_strdup(name); | |
254 if (!strcmp(name, "Google Talk")) | |
255 js->googletalk = TRUE; | |
256 } | |
15163 | 257 |
258 for (child = xmlnode_get_child(query, "feature"); child; | |
259 child = xmlnode_get_next_twin(child)) { | |
260 const char *var; | |
261 var = xmlnode_get_attrib(child, "var"); | |
262 if (!var) | |
263 continue; | |
264 | |
265 if (!strcmp("google:mail:notify", var)) { | |
266 js->server_caps |= JABBER_CAP_GMAIL_NOTIFY; | |
267 jabber_gmail_init(js); | |
15203 | 268 } else if (!strcmp("google:roster", var)) { |
269 js->server_caps |= JABBER_CAP_GOOGLE_ROSTER; | |
270 jabber_google_roster_init(js); | |
15163 | 271 } |
272 } | |
15203 | 273 |
15261
b5dff06f9c84
[gaim-migrate @ 18051]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15203
diff
changeset
|
274 if (!(js->server_caps & JABBER_CAP_GOOGLE_ROSTER)) |
15203 | 275 jabber_roster_request(js); |
15282
8e39ca9b954a
[gaim-migrate @ 18072]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15261
diff
changeset
|
276 |
8e39ca9b954a
[gaim-migrate @ 18072]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15261
diff
changeset
|
277 gpresence = gaim_account_get_presence(js->gc->account); |
8e39ca9b954a
[gaim-migrate @ 18072]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15261
diff
changeset
|
278 status = gaim_presence_get_active_status(gpresence); |
8e39ca9b954a
[gaim-migrate @ 18072]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15261
diff
changeset
|
279 jabber_presence_send(js->gc->account, status); |
15135 | 280 } |
281 | |
282 static void | |
283 jabber_disco_server_items_result_cb(JabberStream *js, xmlnode *packet, gpointer data) | |
14192 | 284 { |
285 xmlnode *query, *child; | |
286 const char *from = xmlnode_get_attrib(packet, "from"); | |
287 const char *type = xmlnode_get_attrib(packet, "type"); | |
288 | |
289 if(!from || !type) | |
290 return; | |
291 | |
292 if(strcmp(from, js->user->domain)) | |
293 return; | |
294 | |
295 if(strcmp(type, "result")) | |
296 return; | |
297 | |
298 while(js->chat_servers) { | |
299 g_free(js->chat_servers->data); | |
300 js->chat_servers = g_list_delete_link(js->chat_servers, js->chat_servers); | |
301 } | |
302 | |
303 query = xmlnode_get_child(packet, "query"); | |
304 | |
305 for(child = xmlnode_get_child(query, "item"); child; | |
306 child = xmlnode_get_next_twin(child)) { | |
307 JabberIq *iq; | |
308 const char *jid; | |
309 | |
310 if(!(jid = xmlnode_get_attrib(child, "jid"))) | |
311 continue; | |
312 | |
313 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#info"); | |
314 xmlnode_set_attrib(iq->node, "to", jid); | |
315 jabber_iq_send(iq); | |
316 } | |
317 } | |
318 | |
319 void jabber_disco_items_server(JabberStream *js) | |
320 { | |
321 JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_GET, | |
322 "http://jabber.org/protocol/disco#items"); | |
323 | |
324 xmlnode_set_attrib(iq->node, "to", js->user->domain); | |
325 | |
15135 | 326 jabber_iq_set_callback(iq, jabber_disco_server_items_result_cb, NULL); |
327 jabber_iq_send(iq); | |
328 | |
329 iq = jabber_iq_new_query(js, JABBER_IQ_GET, | |
330 "http://jabber.org/protocol/disco#info"); | |
331 xmlnode_set_attrib(iq->node, "to", js->user->domain); | |
332 jabber_iq_set_callback(iq, jabber_disco_server_info_result_cb, NULL); | |
14192 | 333 jabber_iq_send(iq); |
334 } | |
335 | |
336 void jabber_disco_info_do(JabberStream *js, const char *who, JabberDiscoInfoCallback *callback, gpointer data) | |
337 { | |
338 JabberID *jid; | |
339 JabberBuddy *jb; | |
340 JabberBuddyResource *jbr = NULL; | |
341 struct _jabber_disco_info_cb_data *jdicd; | |
342 JabberIq *iq; | |
343 | |
344 if((jid = jabber_id_new(who))) { | |
345 if(jid->resource && (jb = jabber_buddy_find(js, who, TRUE))) | |
346 jbr = jabber_buddy_find_resource(jb, jid->resource); | |
347 jabber_id_free(jid); | |
348 } | |
349 | |
350 if(jbr && jbr->capabilities & JABBER_CAP_RETRIEVED) { | |
351 callback(js, who, jbr->capabilities, data); | |
352 return; | |
353 } | |
354 | |
355 jdicd = g_new0(struct _jabber_disco_info_cb_data, 1); | |
356 jdicd->data = data; | |
357 jdicd->callback = callback; | |
358 | |
359 g_hash_table_insert(js->disco_callbacks, g_strdup(who), jdicd); | |
360 | |
361 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#info"); | |
362 xmlnode_set_attrib(iq->node, "to", who); | |
363 | |
364 jabber_iq_send(iq); | |
365 } | |
366 | |
367 |