comparison libgaim/protocols/jabber/iq.c @ 14192:60b1bc8dbf37

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