Mercurial > pidgin
annotate src/protocols/jabber/iq.c @ 8236:a8431dd66cc5
[gaim-migrate @ 8959]
Man, I don't want to explain this one. But I will. For Luke.
BECAUSE I CARE. Yaaaaaaayyyyy Luke.
Anyway, the accounts drop down box in the "Add a Buddy Pounce" dialog...
It only shows only accounts, right? Unfortunately the default account
was the top account in the account editor--whether it is online or offline.
This patch makes the default account be the top ONLINE account.
Oh, and even though the dialog LOOKED right before this change, the
actual value of account was incorrect.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Thu, 12 Feb 2004 05:56:16 +0000 |
parents | a64774143a42 |
children | b5dbd1839716 |
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 "prefs.h" | |
24 | |
7395 | 25 #include "buddy.h" |
7014 | 26 #include "iq.h" |
7170 | 27 #include "oob.h" |
7014 | 28 #include "roster.h" |
7395 | 29 #include "si.h" |
7014 | 30 |
7058
06e7697f3fae
[gaim-migrate @ 7621]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
7014
diff
changeset
|
31 #ifdef _WIN32 |
06e7697f3fae
[gaim-migrate @ 7621]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
7014
diff
changeset
|
32 #include "utsname.h" |
06e7697f3fae
[gaim-migrate @ 7621]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
7014
diff
changeset
|
33 #endif |
7014 | 34 |
35 JabberIq *jabber_iq_new(JabberStream *js, JabberIqType type) | |
36 { | |
37 JabberIq *iq; | |
38 | |
39 iq = g_new0(JabberIq, 1); | |
40 | |
41 iq->type = type; | |
42 | |
43 iq->node = xmlnode_new("iq"); | |
44 switch(iq->type) { | |
45 case JABBER_IQ_SET: | |
46 xmlnode_set_attrib(iq->node, "type", "set"); | |
47 break; | |
48 case JABBER_IQ_GET: | |
49 xmlnode_set_attrib(iq->node, "type", "get"); | |
50 break; | |
51 case JABBER_IQ_ERROR: | |
52 xmlnode_set_attrib(iq->node, "type", "error"); | |
53 break; | |
54 case JABBER_IQ_RESULT: | |
55 xmlnode_set_attrib(iq->node, "type", "result"); | |
56 break; | |
57 case JABBER_IQ_NONE: | |
58 /* this shouldn't ever happen */ | |
59 break; | |
60 } | |
61 | |
62 iq->js = js; | |
63 | |
64 if(type == JABBER_IQ_GET || type == JABBER_IQ_SET) { | |
65 iq->id = jabber_get_next_id(js); | |
66 xmlnode_set_attrib(iq->node, "id", iq->id); | |
67 } | |
68 | |
69 return iq; | |
70 } | |
71 | |
72 JabberIq *jabber_iq_new_query(JabberStream *js, JabberIqType type, | |
73 const char *xmlns) | |
74 { | |
75 JabberIq *iq = jabber_iq_new(js, type); | |
76 xmlnode *query; | |
77 | |
78 query = xmlnode_new_child(iq->node, "query"); | |
79 xmlnode_set_attrib(query, "xmlns", xmlns); | |
80 | |
81 return iq; | |
82 } | |
83 | |
7395 | 84 typedef struct _JabberCallbackData { |
85 JabberIqCallback *callback; | |
86 gpointer data; | |
87 } JabberCallbackData; | |
88 | |
89 void | |
90 jabber_iq_set_callback(JabberIq *iq, JabberIqCallback *callback, gpointer data) | |
7014 | 91 { |
92 iq->callback = callback; | |
7395 | 93 iq->callback_data = data; |
7014 | 94 } |
95 | |
96 void jabber_iq_set_id(JabberIq *iq, const char *id) | |
97 { | |
98 if(iq->id) | |
99 g_free(iq->id); | |
100 | |
101 if(id) { | |
102 xmlnode_set_attrib(iq->node, "id", id); | |
103 iq->id = g_strdup(id); | |
104 } else { | |
105 xmlnode_remove_attrib(iq->node, "id"); | |
106 iq->id = NULL; | |
107 } | |
108 } | |
109 | |
110 void jabber_iq_send(JabberIq *iq) | |
111 { | |
7395 | 112 JabberCallbackData *jcd; |
7014 | 113 g_return_if_fail(iq != NULL); |
114 | |
115 jabber_send(iq->js, iq->node); | |
116 | |
7395 | 117 if(iq->id && iq->callback) { |
118 jcd = g_new0(JabberCallbackData, 1); | |
119 jcd->callback = iq->callback; | |
120 jcd->data = iq->callback_data; | |
121 g_hash_table_insert(iq->js->callbacks, g_strdup(iq->id), jcd); | |
122 } | |
7014 | 123 |
124 jabber_iq_free(iq); | |
125 } | |
126 | |
127 void jabber_iq_free(JabberIq *iq) | |
128 { | |
129 g_return_if_fail(iq != NULL); | |
130 | |
131 g_free(iq->id); | |
132 xmlnode_free(iq->node); | |
133 g_free(iq); | |
134 } | |
135 | |
136 static void jabber_iq_handle_last(JabberStream *js, xmlnode *packet) | |
137 { | |
138 JabberIq *iq; | |
8006 | 139 const char *type; |
7014 | 140 const char *from; |
141 const char *id; | |
142 xmlnode *query; | |
143 char *idle_time; | |
144 | |
8006 | 145 type = xmlnode_get_attrib(packet, "type"); |
7014 | 146 from = xmlnode_get_attrib(packet, "from"); |
147 id = xmlnode_get_attrib(packet, "id"); | |
148 | |
8006 | 149 if(type && !strcmp(type, "get")) { |
150 iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:last"); | |
151 jabber_iq_set_id(iq, id); | |
152 xmlnode_set_attrib(iq->node, "to", from); | |
7014 | 153 |
8006 | 154 query = xmlnode_get_child(iq->node, "query"); |
7014 | 155 |
8006 | 156 idle_time = g_strdup_printf("%ld", js->idle ? time(NULL) - js->idle : 0); |
157 xmlnode_set_attrib(query, "seconds", idle_time); | |
158 g_free(idle_time); | |
7401 | 159 |
8006 | 160 jabber_iq_send(iq); |
161 } | |
7014 | 162 } |
163 | |
164 static void jabber_iq_handle_time(JabberStream *js, xmlnode *packet) | |
165 { | |
8006 | 166 const char *type, *from, *id; |
7014 | 167 JabberIq *iq; |
168 char buf[1024]; | |
169 xmlnode *query; | |
170 time_t now_t; | |
171 struct tm now; | |
172 time(&now_t); | |
173 localtime_r(&now_t, &now); | |
174 | |
8006 | 175 type = xmlnode_get_attrib(packet, "type"); |
7014 | 176 from = xmlnode_get_attrib(packet, "from"); |
177 id = xmlnode_get_attrib(packet, "id"); | |
178 | |
8006 | 179 if(type && !strcmp(type, "get")) { |
7014 | 180 |
8006 | 181 iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:time"); |
182 jabber_iq_set_id(iq, id); | |
183 xmlnode_set_attrib(iq->node, "to", from); | |
184 | |
185 query = xmlnode_get_child(iq->node, "query"); | |
7014 | 186 |
8006 | 187 strftime(buf, sizeof(buf), "%Y%m%dT%T", &now); |
188 xmlnode_insert_data(xmlnode_new_child(query, "utc"), buf, -1); | |
189 strftime(buf, sizeof(buf), "%Z", &now); | |
190 xmlnode_insert_data(xmlnode_new_child(query, "tz"), buf, -1); | |
191 strftime(buf, sizeof(buf), "%d %b %Y %T", &now); | |
192 xmlnode_insert_data(xmlnode_new_child(query, "display"), buf, -1); | |
7014 | 193 |
8006 | 194 jabber_iq_send(iq); |
195 } | |
7014 | 196 } |
197 | |
198 static void jabber_iq_handle_version(JabberStream *js, xmlnode *packet) | |
199 { | |
200 JabberIq *iq; | |
8006 | 201 const char *type, *from, *id; |
7014 | 202 xmlnode *query; |
203 char *os = NULL; | |
204 | |
8006 | 205 type = xmlnode_get_attrib(packet, "type"); |
206 | |
207 if(type && !strcmp(type, "get")) { | |
208 | |
209 if(!gaim_prefs_get_bool("/plugins/prpl/jabber/hide_os")) { | |
210 struct utsname osinfo; | |
7014 | 211 |
8006 | 212 uname(&osinfo); |
213 os = g_strdup_printf("%s %s %s", osinfo.sysname, osinfo.release, | |
214 osinfo.machine); | |
215 } | |
7014 | 216 |
8006 | 217 from = xmlnode_get_attrib(packet, "from"); |
218 id = xmlnode_get_attrib(packet, "id"); | |
7014 | 219 |
8006 | 220 iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:version"); |
221 xmlnode_set_attrib(iq->node, "to", from); | |
222 jabber_iq_set_id(iq, id); | |
7014 | 223 |
8006 | 224 query = xmlnode_get_child(iq->node, "query"); |
7014 | 225 |
8006 | 226 xmlnode_insert_data(xmlnode_new_child(query, "name"), PACKAGE, -1); |
227 xmlnode_insert_data(xmlnode_new_child(query, "version"), VERSION, -1); | |
228 if(os) { | |
229 xmlnode_insert_data(xmlnode_new_child(query, "os"), os, -1); | |
230 g_free(os); | |
231 } | |
232 | |
233 jabber_iq_send(iq); | |
7014 | 234 } |
235 } | |
236 | |
7395 | 237 #define SUPPORT_FEATURE(x) \ |
238 feature = xmlnode_new_child(query, "feature"); \ | |
239 xmlnode_set_attrib(feature, "var", x); | |
240 | |
241 | |
242 void jabber_disco_info_parse(JabberStream *js, xmlnode *packet) { | |
243 const char *from = xmlnode_get_attrib(packet, "from"); | |
244 const char *type = xmlnode_get_attrib(packet, "type"); | |
245 | |
246 if(!from || !type) | |
247 return; | |
248 | |
249 if(!strcmp(type, "get")) { | |
250 xmlnode *query, *identity, *feature; | |
251 JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, | |
252 "http://jabber.org/protocol/disco#info"); | |
253 | |
254 jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id")); | |
255 | |
256 xmlnode_set_attrib(iq->node, "to", from); | |
257 query = xmlnode_get_child(iq->node, "query"); | |
258 | |
259 identity = xmlnode_new_child(query, "identity"); | |
260 xmlnode_set_attrib(identity, "category", "client"); | |
261 xmlnode_set_attrib(identity, "type", "pc"); /* XXX: bot, console, | |
262 * handheld, pc, phone, | |
263 * web */ | |
264 | |
265 SUPPORT_FEATURE("jabber:iq:last") | |
266 SUPPORT_FEATURE("jabber:iq:oob") | |
267 SUPPORT_FEATURE("jabber:iq:time") | |
268 SUPPORT_FEATURE("jabber:iq:version") | |
269 SUPPORT_FEATURE("jabber:x:conference") | |
7425 | 270 /* |
7395 | 271 SUPPORT_FEATURE("http://jabber.org/protocol/bytestreams") |
7425 | 272 */ |
7395 | 273 SUPPORT_FEATURE("http://jabber.org/protocol/disco#info") |
274 SUPPORT_FEATURE("http://jabber.org/protocol/disco#items") | |
275 SUPPORT_FEATURE("http://jabber.org/protocol/muc") | |
276 SUPPORT_FEATURE("http://jabber.org/protocol/muc#user") | |
7425 | 277 /* |
7395 | 278 SUPPORT_FEATURE("http://jabber.org/protocol/si") |
279 SUPPORT_FEATURE("http://jabber.org/protocol/si/profile/file-transfer") | |
7425 | 280 */ |
8043 | 281 SUPPORT_FEATURE("http://jabber.org/protocol/xhtml-im") |
7395 | 282 |
283 jabber_iq_send(iq); | |
8006 | 284 } else if(!strcmp(type, "result")) { |
7395 | 285 xmlnode *query = xmlnode_get_child(packet, "query"); |
286 xmlnode *child; | |
287 JabberID *jid; | |
288 JabberBuddy *jb; | |
289 JabberBuddyResource *jbr = NULL; | |
290 | |
291 if(!(jid = jabber_id_new(from))) | |
292 return; | |
293 | |
294 if(jid->resource && (jb = jabber_buddy_find(js, from, TRUE))) | |
295 jbr = jabber_buddy_find_resource(jb, jid->resource); | |
7445 | 296 jabber_id_free(jid); |
7395 | 297 |
298 for(child = query->child; child; child = child->next) { | |
8135 | 299 if(child->type != XMLNODE_TYPE_TAG) |
7395 | 300 continue; |
301 | |
8043 | 302 if(!strcmp(child->name, "identity")) { |
303 const char *category = xmlnode_get_attrib(child, "category"); | |
304 const char *type = xmlnode_get_attrib(child, "type"); | |
305 if(!category || !type) | |
306 continue; | |
307 | |
308 /* we found a groupchat or MUC server, add it to the list */ | |
309 /* XXX: actually check for protocol/muc or gc-1.0 support */ | |
310 if(!strcmp(category, "conference") && !strcmp(type, "text")) | |
311 js->chat_servers = g_list_append(js->chat_servers, g_strdup(from)); | |
312 | |
313 } else if(!strcmp(child->name, "feature")) { | |
7395 | 314 const char *var = xmlnode_get_attrib(child, "var"); |
315 if(!var) | |
316 continue; | |
317 | |
8043 | 318 if(jbr && !strcmp(var, "http://jabber.org/protocol/si")) |
7395 | 319 jbr->capabilities |= JABBER_CAP_SI; |
8043 | 320 else if(jbr && !strcmp(var, |
7395 | 321 "http://jabber.org/protocol/si/profile/file-transfer")) |
322 jbr->capabilities |= JABBER_CAP_SI_FILE_XFER; | |
8043 | 323 else if(jbr && !strcmp(var, "http://jabber.org/protocol/bytestreams")) |
7395 | 324 jbr->capabilities |= JABBER_CAP_BYTESTREAMS; |
325 } | |
326 } | |
327 } | |
328 } | |
329 | |
330 void jabber_disco_items_parse(JabberStream *js, xmlnode *packet) { | |
331 const char *from = xmlnode_get_attrib(packet, "from"); | |
332 const char *type = xmlnode_get_attrib(packet, "type"); | |
333 | |
334 if(!strcmp(type, "get")) { | |
335 JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, | |
336 "http://jabber.org/protocol/disco#items"); | |
337 | |
338 jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id")); | |
339 | |
340 xmlnode_set_attrib(iq->node, "to", from); | |
341 jabber_iq_send(iq); | |
342 } | |
343 } | |
344 | |
8043 | 345 static void |
346 jabber_iq_disco_server_result_cb(JabberStream *js, xmlnode *packet, gpointer data) | |
347 { | |
348 xmlnode *query, *child; | |
349 const char *from = xmlnode_get_attrib(packet, "from"); | |
350 const char *type = xmlnode_get_attrib(packet, "type"); | |
351 | |
352 if(!from || !type) | |
353 return; | |
354 | |
355 if(strcmp(from, js->user->domain)) | |
356 return; | |
357 | |
358 if(strcmp(type, "result")) | |
359 return; | |
360 | |
361 while(js->chat_servers) { | |
362 g_free(js->chat_servers->data); | |
363 js->chat_servers = g_list_delete_link(js->chat_servers, js->chat_servers); | |
364 } | |
365 | |
366 query = xmlnode_get_child(packet, "query"); | |
367 | |
8135 | 368 for(child = xmlnode_get_child(query, "item"); child; |
369 child = xmlnode_get_next_twin(child)) { | |
8043 | 370 JabberIq *iq; |
371 const char *jid; | |
372 | |
373 if(!(jid = xmlnode_get_attrib(child, "jid"))) | |
374 continue; | |
375 | |
376 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#info"); | |
377 xmlnode_set_attrib(iq->node, "to", jid); | |
378 jabber_iq_send(iq); | |
379 } | |
380 } | |
381 | |
382 void jabber_iq_disco_server(JabberStream *js) | |
383 { | |
384 JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_GET, | |
385 "http://jabber.org/protocol/disco#items"); | |
386 | |
387 xmlnode_set_attrib(iq->node, "to", js->user->domain); | |
388 | |
389 jabber_iq_set_callback(iq, jabber_iq_disco_server_result_cb, NULL); | |
390 jabber_iq_send(iq); | |
391 } | |
392 | |
393 | |
7014 | 394 void jabber_iq_parse(JabberStream *js, xmlnode *packet) |
395 { | |
7395 | 396 JabberCallbackData *jcd; |
8169 | 397 xmlnode *query, *error, *x; |
7014 | 398 const char *xmlns; |
8135 | 399 const char *type, *id, *from; |
400 JabberIq *iq; | |
7014 | 401 |
402 query = xmlnode_get_child(packet, "query"); | |
8043 | 403 type = xmlnode_get_attrib(packet, "type"); |
8135 | 404 from = xmlnode_get_attrib(packet, "from"); |
7014 | 405 |
8043 | 406 if(type && query && (xmlns = xmlnode_get_attrib(query, "xmlns"))) { |
407 if(!strcmp(type, "set")) { | |
408 if(!strcmp(xmlns, "jabber:iq:roster")) { | |
409 jabber_roster_parse(js, packet); | |
410 return; | |
411 } else if(!strcmp(xmlns, "jabber:iq:oob")) { | |
412 jabber_oob_parse(js, packet); | |
413 return; | |
414 } | |
415 } else if(!strcmp(type, "get")) { | |
416 if(!strcmp(xmlns, "jabber:iq:last")) { | |
417 jabber_iq_handle_last(js, packet); | |
418 return; | |
419 } else if(!strcmp(xmlns, "jabber:iq:time")) { | |
420 jabber_iq_handle_time(js, packet); | |
421 return; | |
422 } else if(!strcmp(xmlns, "jabber:iq:version")) { | |
423 jabber_iq_handle_version(js, packet); | |
424 return; | |
425 } else if(!strcmp(xmlns, "http://jabber.org/protocol/disco#info")) { | |
426 jabber_disco_info_parse(js, packet); | |
427 return; | |
428 } else if(!strcmp(xmlns, "http://jabber.org/protocol/disco#items")) { | |
429 jabber_disco_items_parse(js, packet); | |
430 return; | |
431 } | |
432 } else if(!strcmp(type, "result")) { | |
433 if(!strcmp(xmlns, "jabber:iq:roster")) { | |
434 jabber_roster_parse(js, packet); | |
435 return; | |
436 } else if(!strcmp(xmlns, "jabber:iq:register")) { | |
437 jabber_register_parse(js, packet); | |
438 return; | |
439 } else if(!strcmp(xmlns, "http://jabber.org/protocol/disco#info")) { | |
440 jabber_disco_info_parse(js, packet); | |
441 return; | |
442 } | |
7395 | 443 } |
444 } | |
445 | |
446 /* If we got here, no pre-defined handlers got it, lets see if a special | |
447 * callback got registered */ | |
448 | |
449 id = xmlnode_get_attrib(packet, "id"); | |
450 | |
8169 | 451 if(type && (!strcmp(type, "result") || !strcmp(type, "error"))) { |
452 if(id && *id && (jcd = g_hash_table_lookup(js->callbacks, id))) { | |
453 jcd->callback(js, packet, jcd->data); | |
454 g_hash_table_remove(js->callbacks, id); | |
455 } | |
8135 | 456 return; |
457 } | |
458 | |
459 /* Default error reply mandated by XMPP-CORE */ | |
460 | |
461 iq = jabber_iq_new(js, JABBER_IQ_ERROR); | |
462 | |
8169 | 463 xmlnode_free(iq->node); |
464 iq->node = xmlnode_copy(packet); | |
465 xmlnode_set_attrib(iq->node, "to", from); | |
466 xmlnode_set_attrib(iq->node, "type", "error"); | |
467 error = xmlnode_new_child(iq->node, "error"); | |
468 xmlnode_set_attrib(error, "type", "cancel"); | |
469 xmlnode_set_attrib(error, "code", "501"); | |
470 x = xmlnode_new_child(error, "feature-not-implemented"); | |
471 xmlnode_set_attrib(x, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas"); | |
472 | |
473 jabber_iq_send(iq); | |
7014 | 474 } |
475 |