comparison libpurple/protocols/jabber/iq.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 32c366eeeb99
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 "prefs.h"
24 #include "util.h"
25
26 #include "buddy.h"
27 #include "disco.h"
28 #include "google.h"
29 #include "iq.h"
30 #include "oob.h"
31 #include "roster.h"
32 #include "si.h"
33
34 #ifdef _WIN32
35 #include "utsname.h"
36 #endif
37
38 GHashTable *iq_handlers = NULL;
39
40
41 JabberIq *jabber_iq_new(JabberStream *js, JabberIqType type)
42 {
43 JabberIq *iq;
44
45 iq = g_new0(JabberIq, 1);
46
47 iq->type = type;
48
49 iq->node = xmlnode_new("iq");
50 switch(iq->type) {
51 case JABBER_IQ_SET:
52 xmlnode_set_attrib(iq->node, "type", "set");
53 break;
54 case JABBER_IQ_GET:
55 xmlnode_set_attrib(iq->node, "type", "get");
56 break;
57 case JABBER_IQ_ERROR:
58 xmlnode_set_attrib(iq->node, "type", "error");
59 break;
60 case JABBER_IQ_RESULT:
61 xmlnode_set_attrib(iq->node, "type", "result");
62 break;
63 case JABBER_IQ_NONE:
64 /* this shouldn't ever happen */
65 break;
66 }
67
68 iq->js = js;
69
70 if(type == JABBER_IQ_GET || type == JABBER_IQ_SET) {
71 iq->id = jabber_get_next_id(js);
72 xmlnode_set_attrib(iq->node, "id", iq->id);
73 }
74
75 return iq;
76 }
77
78 JabberIq *jabber_iq_new_query(JabberStream *js, JabberIqType type,
79 const char *xmlns)
80 {
81 JabberIq *iq = jabber_iq_new(js, type);
82 xmlnode *query;
83
84 query = xmlnode_new_child(iq->node, "query");
85 xmlnode_set_namespace(query, xmlns);
86
87 return iq;
88 }
89
90 typedef struct _JabberCallbackData {
91 JabberIqCallback *callback;
92 gpointer data;
93 } JabberCallbackData;
94
95 void
96 jabber_iq_set_callback(JabberIq *iq, JabberIqCallback *callback, gpointer data)
97 {
98 iq->callback = callback;
99 iq->callback_data = data;
100 }
101
102 void jabber_iq_set_id(JabberIq *iq, const char *id)
103 {
104 if(iq->id)
105 g_free(iq->id);
106
107 if(id) {
108 xmlnode_set_attrib(iq->node, "id", id);
109 iq->id = g_strdup(id);
110 } else {
111 xmlnode_remove_attrib(iq->node, "id");
112 iq->id = NULL;
113 }
114 }
115
116 void jabber_iq_send(JabberIq *iq)
117 {
118 JabberCallbackData *jcd;
119 g_return_if_fail(iq != NULL);
120
121 jabber_send(iq->js, iq->node);
122
123 if(iq->id && iq->callback) {
124 jcd = g_new0(JabberCallbackData, 1);
125 jcd->callback = iq->callback;
126 jcd->data = iq->callback_data;
127 g_hash_table_insert(iq->js->iq_callbacks, g_strdup(iq->id), jcd);
128 }
129
130 jabber_iq_free(iq);
131 }
132
133 void jabber_iq_free(JabberIq *iq)
134 {
135 g_return_if_fail(iq != NULL);
136
137 g_free(iq->id);
138 xmlnode_free(iq->node);
139 g_free(iq);
140 }
141
142 static void jabber_iq_last_parse(JabberStream *js, xmlnode *packet)
143 {
144 JabberIq *iq;
145 const char *type;
146 const char *from;
147 const char *id;
148 xmlnode *query;
149 char *idle_time;
150
151 type = xmlnode_get_attrib(packet, "type");
152 from = xmlnode_get_attrib(packet, "from");
153 id = xmlnode_get_attrib(packet, "id");
154
155 if(type && !strcmp(type, "get")) {
156 iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:last");
157 jabber_iq_set_id(iq, id);
158 xmlnode_set_attrib(iq->node, "to", from);
159
160 query = xmlnode_get_child(iq->node, "query");
161
162 idle_time = g_strdup_printf("%ld", js->idle ? time(NULL) - js->idle : 0);
163 xmlnode_set_attrib(query, "seconds", idle_time);
164 g_free(idle_time);
165
166 jabber_iq_send(iq);
167 }
168 }
169
170 static void jabber_iq_time_parse(JabberStream *js, xmlnode *packet)
171 {
172 const char *type, *from, *id;
173 JabberIq *iq;
174 xmlnode *query;
175 time_t now_t;
176 struct tm *now;
177
178 time(&now_t);
179 now = localtime(&now_t);
180
181 type = xmlnode_get_attrib(packet, "type");
182 from = xmlnode_get_attrib(packet, "from");
183 id = xmlnode_get_attrib(packet, "id");
184
185 if(type && !strcmp(type, "get")) {
186 const char *date;
187
188 iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:time");
189 jabber_iq_set_id(iq, id);
190 xmlnode_set_attrib(iq->node, "to", from);
191
192 query = xmlnode_get_child(iq->node, "query");
193
194 date = gaim_utf8_strftime("%Y%m%dT%T", now);
195 xmlnode_insert_data(xmlnode_new_child(query, "utc"), date, -1);
196
197 date = gaim_utf8_strftime("%Z", now);
198 xmlnode_insert_data(xmlnode_new_child(query, "tz"), date, -1);
199
200 date = gaim_utf8_strftime("%d %b %Y %T", now);
201 xmlnode_insert_data(xmlnode_new_child(query, "display"), date, -1);
202
203 jabber_iq_send(iq);
204 }
205 }
206
207 static void jabber_iq_version_parse(JabberStream *js, xmlnode *packet)
208 {
209 JabberIq *iq;
210 const char *type, *from, *id;
211 xmlnode *query;
212 char *os = NULL;
213
214 type = xmlnode_get_attrib(packet, "type");
215
216 if(type && !strcmp(type, "get")) {
217
218 if(!gaim_prefs_get_bool("/plugins/prpl/jabber/hide_os")) {
219 struct utsname osinfo;
220
221 uname(&osinfo);
222 os = g_strdup_printf("%s %s %s", osinfo.sysname, osinfo.release,
223 osinfo.machine);
224 }
225
226 from = xmlnode_get_attrib(packet, "from");
227 id = xmlnode_get_attrib(packet, "id");
228
229 iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:version");
230 xmlnode_set_attrib(iq->node, "to", from);
231 jabber_iq_set_id(iq, id);
232
233 query = xmlnode_get_child(iq->node, "query");
234
235 xmlnode_insert_data(xmlnode_new_child(query, "name"), PACKAGE, -1);
236 xmlnode_insert_data(xmlnode_new_child(query, "version"), VERSION, -1);
237 if(os) {
238 xmlnode_insert_data(xmlnode_new_child(query, "os"), os, -1);
239 g_free(os);
240 }
241
242 jabber_iq_send(iq);
243 }
244 }
245
246 void jabber_iq_remove_callback_by_id(JabberStream *js, const char *id)
247 {
248 g_hash_table_remove(js->iq_callbacks, id);
249 }
250
251 void jabber_iq_parse(JabberStream *js, xmlnode *packet)
252 {
253 JabberCallbackData *jcd;
254 xmlnode *query, *error, *x;
255 const char *xmlns;
256 const char *type, *id, *from;
257 JabberIqHandler *jih;
258
259 query = xmlnode_get_child(packet, "query");
260 type = xmlnode_get_attrib(packet, "type");
261 from = xmlnode_get_attrib(packet, "from");
262 id = xmlnode_get_attrib(packet, "id");
263
264 /* First, lets see if a special callback got registered */
265
266 if(type && (!strcmp(type, "result") || !strcmp(type, "error"))) {
267 if(id && *id && (jcd = g_hash_table_lookup(js->iq_callbacks, id))) {
268 jcd->callback(js, packet, jcd->data);
269 jabber_iq_remove_callback_by_id(js, id);
270 return;
271 }
272 }
273
274 /* Apparently not, so lets see if we have a pre-defined handler */
275
276 if(type && query && (xmlns = xmlnode_get_namespace(query))) {
277 if((jih = g_hash_table_lookup(iq_handlers, xmlns))) {
278 jih(js, packet);
279 return;
280 }
281 }
282
283 if(xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si")) {
284 jabber_si_parse(js, packet);
285 return;
286 }
287
288 if(xmlnode_get_child_with_namespace(packet, "new-mail", "google:mail:notify")) {
289 jabber_gmail_poke(js, packet);
290 return;
291 }
292
293 /* If we get here, send the default error reply mandated by XMPP-CORE */
294 if(type && (!strcmp(type, "set") || !strcmp(type, "get"))) {
295 JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR);
296
297 xmlnode_free(iq->node);
298 iq->node = xmlnode_copy(packet);
299 xmlnode_set_attrib(iq->node, "to", from);
300 xmlnode_remove_attrib(iq->node, "from");
301 xmlnode_set_attrib(iq->node, "type", "error");
302 error = xmlnode_new_child(iq->node, "error");
303 xmlnode_set_attrib(error, "type", "cancel");
304 xmlnode_set_attrib(error, "code", "501");
305 x = xmlnode_new_child(error, "feature-not-implemented");
306 xmlnode_set_namespace(x, "urn:ietf:params:xml:ns:xmpp-stanzas");
307
308 jabber_iq_send(iq);
309 }
310 }
311
312 void jabber_iq_register_handler(const char *xmlns, JabberIqHandler handlerfunc)
313 {
314 g_hash_table_replace(iq_handlers, g_strdup(xmlns), handlerfunc);
315 }
316
317 void jabber_iq_init(void)
318 {
319 iq_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
320
321 jabber_iq_register_handler("jabber:iq:roster", jabber_roster_parse);
322 jabber_iq_register_handler("jabber:iq:oob", jabber_oob_parse);
323 jabber_iq_register_handler("http://jabber.org/protocol/bytestreams", jabber_bytestreams_parse);
324 jabber_iq_register_handler("jabber:iq:last", jabber_iq_last_parse);
325 jabber_iq_register_handler("jabber:iq:time", jabber_iq_time_parse);
326 jabber_iq_register_handler("jabber:iq:version", jabber_iq_version_parse);
327 jabber_iq_register_handler("http://jabber.org/protocol/disco#info", jabber_disco_info_parse);
328 jabber_iq_register_handler("http://jabber.org/protocol/disco#items", jabber_disco_items_parse);
329 jabber_iq_register_handler("jabber:iq:register", jabber_register_parse);
330 }
331
332 void jabber_iq_uninit(void)
333 {
334 g_hash_table_destroy(iq_handlers);
335 }
336