comparison mcabber/libjabber/jutil.c @ 417:c3ae9251c197

Sync libjabber with upstream Sync with jabberd-1.4.4.
author Mikael Berthe <mikael@lilotux.net>
date Thu, 01 Sep 2005 23:29:21 +0200
parents bf3d6e241714
children f791f5f0cfce
comparison
equal deleted inserted replaced
416:48e7808c4191 417:c3ae9251c197
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 *
16 * Copyrights
17 *
18 * Portions created by or assigned to Jabber.com, Inc. are
19 * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact
20 * information for Jabber.com, Inc. is available at http://www.jabber.com/.
21 *
22 * Portions Copyright (c) 1998-1999 Jeremie Miller.
23 *
24 * Acknowledgements
25 *
26 * Special thanks to the Jabber Open Source Contributors for their
27 * suggestions and support of Jabber.
28 *
29 */
30
31 /**
32 * @file jutil.c
33 * @brief various utilities mainly for handling xmlnodes containing stanzas
34 */
35
1 #include "jabber.h" 36 #include "jabber.h"
2 37
3 /* util for making presence packets */ 38 /**
39 * utility for making presence stanzas
40 *
41 * @param type the type of the presence (one of the JPACKET__* contants)
42 * @param to to whom the presence should be sent, NULL for a broadcast presence
43 * @param status optional status (CDATA for the <status/> element, NULL for now <status/> element)
44 * @return the xmlnode containing the created presence stanza
45 */
4 xmlnode jutil_presnew(int type, char *to, char *status) 46 xmlnode jutil_presnew(int type, char *to, char *status)
5 { 47 {
6 xmlnode pres; 48 xmlnode pres;
7 49
8 pres = xmlnode_new_tag("presence"); 50 pres = xmlnode_new_tag("presence");
9 switch(type) 51 switch(type)
10 { 52 {
11 case JPACKET__SUBSCRIBE: 53 case JPACKET__SUBSCRIBE:
12 xmlnode_put_attrib(pres,"type","subscribe"); 54 xmlnode_put_attrib(pres,"type","subscribe");
13 break; 55 break;
14 case JPACKET__UNSUBSCRIBE: 56 case JPACKET__UNSUBSCRIBE:
15 xmlnode_put_attrib(pres,"type","unsubscribe"); 57 xmlnode_put_attrib(pres,"type","unsubscribe");
16 break; 58 break;
17 case JPACKET__SUBSCRIBED: 59 case JPACKET__SUBSCRIBED:
18 xmlnode_put_attrib(pres,"type","subscribed"); 60 xmlnode_put_attrib(pres,"type","subscribed");
19 break; 61 break;
20 case JPACKET__UNSUBSCRIBED: 62 case JPACKET__UNSUBSCRIBED:
21 xmlnode_put_attrib(pres,"type","unsubscribed"); 63 xmlnode_put_attrib(pres,"type","unsubscribed");
22 break; 64 break;
23 case JPACKET__PROBE: 65 case JPACKET__PROBE:
24 xmlnode_put_attrib(pres,"type","probe"); 66 xmlnode_put_attrib(pres,"type","probe");
25 break; 67 break;
26 case JPACKET__UNAVAILABLE: 68 case JPACKET__UNAVAILABLE:
27 xmlnode_put_attrib(pres,"type","unavailable"); 69 xmlnode_put_attrib(pres,"type","unavailable");
28 break; 70 break;
71 case JPACKET__INVISIBLE:
72 xmlnode_put_attrib(pres,"type","invisible");
73 break;
29 } 74 }
30 if(to != NULL) 75 if(to != NULL)
31 xmlnode_put_attrib(pres,"to",to); 76 xmlnode_put_attrib(pres,"to",to);
32 if(status != NULL) 77 if(status != NULL)
33 xmlnode_insert_cdata(xmlnode_insert_tag(pres,"status"),status,strlen(status)); 78 xmlnode_insert_cdata(xmlnode_insert_tag(pres,"status"),status,strlen(status));
34 79
35 return pres; 80 return pres;
36 } 81 }
37 82
38 /* util for making IQ packets */ 83 /**
84 * utility for making IQ stanzas, that contain a <query/> element in a different namespace
85 *
86 * @note In traditional Jabber protocols the element inside an iq element has the name "query".
87 * This util is not able to create IQ stanzas that contain a query which a element that does
88 * not have the name "query"
89 *
90 * @param type the type of the iq stanza (one of JPACKET__GET, JPACKET__SET, JPACKET__RESULT, JPACKET__ERROR)
91 * @param ns the namespace of the <query/> element
92 * @return the created xmlnode
93 */
39 xmlnode jutil_iqnew(int type, char *ns) 94 xmlnode jutil_iqnew(int type, char *ns)
40 { 95 {
41 xmlnode iq; 96 xmlnode iq;
42 97
43 iq = xmlnode_new_tag("iq"); 98 iq = xmlnode_new_tag("iq");
44 switch(type) 99 switch(type)
45 { 100 {
46 case JPACKET__GET: 101 case JPACKET__GET:
47 xmlnode_put_attrib(iq,"type","get"); 102 xmlnode_put_attrib(iq,"type","get");
48 break; 103 break;
49 case JPACKET__SET: 104 case JPACKET__SET:
50 xmlnode_put_attrib(iq,"type","set"); 105 xmlnode_put_attrib(iq,"type","set");
51 break; 106 break;
52 case JPACKET__RESULT: 107 case JPACKET__RESULT:
53 xmlnode_put_attrib(iq,"type","result"); 108 xmlnode_put_attrib(iq,"type","result");
54 break; 109 break;
55 case JPACKET__ERROR: 110 case JPACKET__ERROR:
56 xmlnode_put_attrib(iq,"type","error"); 111 xmlnode_put_attrib(iq,"type","error");
57 break; 112 break;
58 } 113 }
59 xmlnode_put_attrib(xmlnode_insert_tag(iq,"query"),"xmlns",ns); 114 xmlnode_put_attrib(xmlnode_insert_tag(iq,"query"),"xmlns",ns);
60 115
61 return iq; 116 return iq;
62 } 117 }
63 118
64 /* util for making message packets */ 119 /**
120 * utility for making message stanzas
121 *
122 * @param type the type of the message (as a string!)
123 * @param to the recipient of the message
124 * @param subj the subject of the message (NULL for no subject element)
125 * @param body the body of the message
126 * @return the xmlnode containing the new message stanza
127 */
65 xmlnode jutil_msgnew(char *type, char *to, char *subj, char *body) 128 xmlnode jutil_msgnew(char *type, char *to, char *subj, char *body)
66 { 129 {
67 xmlnode msg; 130 xmlnode msg;
68 131
69 msg = xmlnode_new_tag("message"); 132 msg = xmlnode_new_tag("message");
70 xmlnode_put_attrib (msg, "type", type); 133
71 xmlnode_put_attrib (msg, "to", to); 134 if (type != NULL) {
72 135 xmlnode_put_attrib (msg, "type", type);
73 if (subj) 136 }
74 { 137
75 xmlnode_insert_cdata (xmlnode_insert_tag (msg, "subject"), subj, strlen (subj)); 138 if (to != NULL) {
76 } 139 xmlnode_put_attrib (msg, "to", to);
77 140 }
78 xmlnode_insert_cdata (xmlnode_insert_tag (msg, "body"), body, strlen (body)); 141
142 if (subj != NULL) {
143 xmlnode_insert_cdata(xmlnode_insert_tag(msg, "subject"), subj, strlen(subj));
144 }
145
146 if (body != NULL) {
147 xmlnode_insert_cdata(xmlnode_insert_tag(msg, "body"), body, strlen(body));
148 }
79 149
80 return msg; 150 return msg;
81 } 151 }
82 152
83 /* util for making stream packets */ 153 /**
154 * utility for making stream packets (containing the stream header element)
155 *
156 * @param xmlns the default namespace of the stream (e.g. jabber:client or jabber:server)
157 * @param server the domain of the server
158 * @return the xmlnode containing the root element of the stream
159 */
84 xmlnode jutil_header(char* xmlns, char* server) 160 xmlnode jutil_header(char* xmlns, char* server)
85 { 161 {
86 xmlnode result; 162 xmlnode result;
87 if ((xmlns == NULL)||(server == NULL)) 163 if ((xmlns == NULL)||(server == NULL))
88 return NULL; 164 return NULL;
92 xmlnode_put_attrib(result, "to", server); 168 xmlnode_put_attrib(result, "to", server);
93 169
94 return result; 170 return result;
95 } 171 }
96 172
97 /* returns the priority on a presence packet */ 173 /**
174 * returns the priority on an available presence packet
175 *
176 * @param xmlnode the xmlnode containing the presence packet
177 * @return the presence priority, -129 for unavailable presences and errors
178 */
98 int jutil_priority(xmlnode x) 179 int jutil_priority(xmlnode x)
99 { 180 {
100 char *str; 181 char *str;
101 int p; 182 int p;
102 183
103 if(x == NULL) 184 if(x == NULL)
104 return -1; 185 return -129;
105 186
106 if(xmlnode_get_attrib(x,"type") != NULL) 187 if(xmlnode_get_attrib(x,"type") != NULL)
107 return -1; 188 return -129;
108 189
109 x = xmlnode_get_tag(x,"priority"); 190 x = xmlnode_get_tag(x,"priority");
110 if(x == NULL) 191 if(x == NULL)
111 return 0; 192 return 0;
112 193
113 str = xmlnode_get_data((x)); 194 str = xmlnode_get_data((x));
114 if(str == NULL) 195 if(str == NULL)
115 return 0; 196 return 0;
116 197
117 p = atoi(str); 198 p = atoi(str);
118 if(p >= 0) 199 /* xmpp-im section 2.2.2.3 */
119 return p; 200 return p<-128 ? -128 : p>127 ? 127 : p;
120 else 201 }
121 return 0; 202
122 } 203 /**
123 204 * reverse sender and destination of a packet
205 *
206 * @param x the xmlnode where sender and receiver should be exchanged
207 */
124 void jutil_tofrom(xmlnode x) 208 void jutil_tofrom(xmlnode x)
125 { 209 {
126 char *to, *from; 210 char *to, *from;
127 211
128 to = xmlnode_get_attrib(x,"to"); 212 to = xmlnode_get_attrib(x,"to");
129 from = xmlnode_get_attrib(x,"from"); 213 from = xmlnode_get_attrib(x,"from");
130 xmlnode_put_attrib(x,"from",to); 214 xmlnode_put_attrib(x,"from",to);
131 xmlnode_put_attrib(x,"to",from); 215 xmlnode_put_attrib(x,"to",from);
132 } 216 }
133 217
218 /**
219 * change and xmlnode to be the result xmlnode for the original iq query
220 *
221 * @param x the xmlnode that should become the result for itself
222 * @return the result xmlnode (same as given as parameter x)
223 */
134 xmlnode jutil_iqresult(xmlnode x) 224 xmlnode jutil_iqresult(xmlnode x)
135 { 225 {
136 xmlnode cur; 226 xmlnode cur;
137 227
138 jutil_tofrom(x); 228 jutil_tofrom(x);
139 229
140 xmlnode_put_attrib(x,"type","result"); 230 xmlnode_put_attrib(x,"type","result");
141 231
142 /* hide all children of the iq, they go back empty */ 232 /* hide all children of the iq, they go back empty */
143 for(cur = xmlnode_get_firstchild(x); cur != NULL; cur = xmlnode_get_nextsibling(cur)) 233 for(cur = xmlnode_get_firstchild(x); cur != NULL; cur = xmlnode_get_nextsibling(cur))
144 xmlnode_hide(cur); 234 xmlnode_hide(cur);
145 235
146 return x; 236 return x;
147 } 237 }
148 238
239 /**
240 * get the present time as a textual timestamp in the format YYYYMMDDTHH:MM:SS
241 *
242 * @note this function is not thread safe
243 *
244 * @return pointer to a static (!) buffer containing the timestamp (or NULL on failure)
245 */
149 char *jutil_timestamp(void) 246 char *jutil_timestamp(void)
150 { 247 {
151 time_t t; 248 time_t t;
152 struct tm *new_time; 249 struct tm *new_time;
153 static char timestamp[18]; 250 static char timestamp[18];
154 int ret; 251 int ret;
155 252
156 t = time(NULL); 253 t = time(NULL);
157 254
158 if(t == (time_t)-1) 255 if(t == (time_t)-1)
159 return NULL; 256 return NULL;
160 new_time = gmtime(&t); 257 new_time = gmtime(&t);
161 258
162 ret = snprintf(timestamp, 18, "%d%02d%02dT%02d:%02d:%02d", 1900+new_time->tm_year, 259 ret = snprintf(timestamp, 18, "%d%02d%02dT%02d:%02d:%02d", 1900+new_time->tm_year,
163 new_time->tm_mon+1, new_time->tm_mday, new_time->tm_hour, 260 new_time->tm_mon+1, new_time->tm_mday, new_time->tm_hour,
164 new_time->tm_min, new_time->tm_sec); 261 new_time->tm_min, new_time->tm_sec);
165 262
166 if(ret == -1) 263 if(ret == -1)
167 return NULL; 264 return NULL;
168 265
169 return timestamp; 266 return timestamp;
170 } 267 }
171 268
172 void jutil_error(xmlnode x, terror E) 269 /**
270 * map a terror structure to a xterror structure
271 *
272 * terror structures have been used in jabberd14 up to version 1.4.3 but
273 * are not able to hold XMPP compliant stanza errors. The xterror
274 * structure has been introduced to be XMPP compliant. This function
275 * is to ease writting wrappers that accept terror structures and call
276 * the real functions that require now xterror structures
277 *
278 * @param old the terror struct that should be converted
279 * @param mapped pointer to the xterror struct that should be filled with the converted error
280 */
281 void jutil_error_map(terror old, xterror *mapped)
282 {
283 mapped->code = old.code;
284 if (old.msg == NULL)
285 mapped->msg[0] = 0;
286 else
287 strncpy(mapped->msg, old.msg, sizeof(mapped->msg));
288
289 switch (old.code)
290 {
291 case 302:
292 strcpy(mapped->type, "modify");
293 strcpy(mapped->condition, "redirect");
294 break;
295 case 400:
296 strcpy(mapped->type, "modify");
297 strcpy(mapped->condition, "bad-request");
298 break;
299 case 401:
300 strcpy(mapped->type, "auth");
301 strcpy(mapped->condition, "not-authorized");
302 break;
303 case 402:
304 strcpy(mapped->type, "auth");
305 strcpy(mapped->condition, "payment-required");
306 break;
307 case 403:
308 strcpy(mapped->type, "auth");
309 strcpy(mapped->condition, "forbidden");
310 break;
311 case 404:
312 strcpy(mapped->type, "cancel");
313 strcpy(mapped->condition, "item-not-found");
314 break;
315 case 405:
316 strcpy(mapped->type, "cancel");
317 strcpy(mapped->condition, "not-allowed");
318 break;
319 case 406:
320 strcpy(mapped->type, "modify");
321 strcpy(mapped->condition, "not-acceptable");
322 break;
323 case 407:
324 strcpy(mapped->type, "auth");
325 strcpy(mapped->condition, "registration-requited");
326 break;
327 case 408:
328 strcpy(mapped->type, "wait");
329 strcpy(mapped->condition, "remote-server-timeout");
330 break;
331 case 409:
332 strcpy(mapped->type, "cancel");
333 strcpy(mapped->condition, "conflict");
334 break;
335 case 500:
336 strcpy(mapped->type, "wait");
337 strcpy(mapped->condition, "internal-server-error");
338 break;
339 case 501:
340 strcpy(mapped->type, "cancel");
341 strcpy(mapped->condition, "feature-not-implemented");
342 break;
343 case 502:
344 strcpy(mapped->type, "wait");
345 strcpy(mapped->condition, "service-unavailable");
346 break;
347 case 503:
348 strcpy(mapped->type, "cancel");
349 strcpy(mapped->condition, "service-unavailable");
350 break;
351 case 504:
352 strcpy(mapped->type, "wait");
353 strcpy(mapped->condition, "remote-server-timeout");
354 break;
355 case 510:
356 strcpy(mapped->type, "cancel");
357 strcpy(mapped->condition, "service-unavailable");
358 break;
359 default:
360 strcpy(mapped->type, "wait");
361 strcpy(mapped->condition, "undefined-condition");
362 }
363 }
364
365 /**
366 * update an xmlnode to be the error stanza for itself
367 *
368 * @param x the xmlnode that should become an stanza error message
369 * @param E the structure that holds the error information
370 */
371 void jutil_error_xmpp(xmlnode x, xterror E)
173 { 372 {
174 xmlnode err; 373 xmlnode err;
175 char code[4]; 374 char code[4];
176 375
177 xmlnode_put_attrib(x,"type","error"); 376 xmlnode_put_attrib(x, "type", "error");
178 err = xmlnode_insert_tag(x,"error"); 377 err = xmlnode_insert_tag(x, "error");
179 378
180 snprintf(code,4,"%d",E.code); 379 snprintf(code, sizeof(code), "%d", E.code);
181 xmlnode_put_attrib(err,"code",code); 380 xmlnode_put_attrib(err, "code", code);
182 if(E.msg != NULL) 381 if (E.type != NULL)
183 xmlnode_insert_cdata(err,E.msg,strlen(E.msg)); 382 xmlnode_put_attrib(err, "type", E.type);
383 if (E.condition != NULL)
384 xmlnode_put_attrib(xmlnode_insert_tag(err, E.condition), "xmlns", NS_XMPP_STANZAS);
385 if (E.msg != NULL)
386 {
387 xmlnode text;
388 text = xmlnode_insert_tag(err, "text");
389 xmlnode_put_attrib(text, "xmlns", NS_XMPP_STANZAS);
390 xmlnode_insert_cdata(text, E.msg, strlen(E.msg));
391 }
184 392
185 jutil_tofrom(x); 393 jutil_tofrom(x);
186 } 394 }
187 395
396 /**
397 * wrapper around jutil_error_xmpp for compatibility with modules for jabberd up to version 1.4.3
398 *
399 * @deprecated use jutil_error_xmpp instead!
400 *
401 * @param x the xmlnode that should become an stanza error message
402 * @param E the strucutre that holds the error information
403 */
404 void jutil_error(xmlnode x, terror E)
405 {
406 xterror xE;
407 jutil_error_map(E, &xE);
408 jutil_error_xmpp(x, xE);
409 }
410
411 /**
412 * add a delayed delivery (JEP-0091) element to a message using the
413 * present timestamp.
414 * If a reason is given, this reason will be added as CDATA to the
415 * inserted element
416 *
417 * @param msg the message where the element should be added
418 * @param reason plain text information why the delayed delivery information has been added
419 */
188 void jutil_delay(xmlnode msg, char *reason) 420 void jutil_delay(xmlnode msg, char *reason)
189 { 421 {
190 xmlnode delay; 422 xmlnode delay;
191 423
192 delay = xmlnode_insert_tag(msg,"x"); 424 delay = xmlnode_insert_tag(msg,"x");
193 xmlnode_put_attrib(delay,"xmlns",NS_DELAY); 425 xmlnode_put_attrib(delay,"xmlns",NS_DELAY);
194 xmlnode_put_attrib(delay,"from",xmlnode_get_attrib(msg,"to")); 426 xmlnode_put_attrib(delay,"from",xmlnode_get_attrib(msg,"to"));
195 xmlnode_put_attrib(delay,"stamp",jutil_timestamp()); 427 xmlnode_put_attrib(delay,"stamp",jutil_timestamp());
196 if(reason != NULL) 428 if(reason != NULL)
197 xmlnode_insert_cdata(delay,reason,strlen(reason)); 429 xmlnode_insert_cdata(delay,reason,strlen(reason));
198 } 430 }
199 431
200 #define KEYBUF 100 432 #define KEYBUF 100
201 433
434 /**
435 * create or validate a key value for stone-age jabber protocols
436 *
437 * Before dialback had been introduced for s2s (and therefore only in jabberd 1.0),
438 * Jabber used these keys to protect some iq requests. A client first had to
439 * request a key with a IQ get and use it inside the IQ set request. By being able
440 * to receive the key in the IQ get response, the client (more or less) proved to be
441 * who he claimed to be.
442 *
443 * The implementation of this function uses a static array with KEYBUF entries (default
444 * value of KEYBUF is 100). Therefore a key gets invalid at the 100th key that is created
445 * afterwards. It is also invalidated after it has been validated once.
446 *
447 * @deprecated This function is not really used anymore. jabberd14 does not check any
448 * keys anymore and only creates them in the jsm's mod_register.c for compatibility. This
449 * function is also used in mod_groups.c and the key is even checked there, but I do not
450 * know if mod_groups.c still works at all.
451 *
452 * @param key for validation the key the client sent, for generation of a new key NULL
453 * @param seed the seed for generating the key, must stay the same for the same user
454 * @return the new key when created, the key if the key has been validated, NULL if the key is invalid
455 */
202 char *jutil_regkey(char *key, char *seed) 456 char *jutil_regkey(char *key, char *seed)
203 { 457 {
204 static char keydb[KEYBUF][41]; 458 static char keydb[KEYBUF][41];
205 static char seeddb[KEYBUF][41]; 459 static char seeddb[KEYBUF][41];
206 static int last = -1; 460 static int last = -1;
208 int i; 462 int i;
209 463
210 /* blanket the keydb first time */ 464 /* blanket the keydb first time */
211 if(last == -1) 465 if(last == -1)
212 { 466 {
213 last = 0; 467 last = 0;
214 memset(&keydb,0,KEYBUF*41); 468 memset(&keydb,0,KEYBUF*41);
215 memset(&seeddb,0,KEYBUF*41); 469 memset(&seeddb,0,KEYBUF*41);
216 srand(time(NULL)); 470 srand(time(NULL));
217 } 471 }
218 472
219 /* creation phase */ 473 /* creation phase */
220 if(key == NULL && seed != NULL) 474 if(key == NULL && seed != NULL)
221 { 475 {
222 /* create a random key hash and store it */ 476 /* create a random key hash and store it */
223 sprintf(strint,"%d",rand()); 477 sprintf(strint,"%d",rand());
224 strcpy(keydb[last],shahash(strint)); 478 strcpy(keydb[last],shahash(strint));
225 479
226 /* store a hash for the seed associated w/ this key */ 480 /* store a hash for the seed associated w/ this key */
227 strcpy(seeddb[last],shahash(seed)); 481 strcpy(seeddb[last],shahash(seed));
228 482
229 /* return it all */ 483 /* return it all */
230 str = keydb[last]; 484 str = keydb[last];
231 last++; 485 last++;
232 if(last == KEYBUF) last = 0; 486 if(last == KEYBUF) last = 0;
233 return str; 487 return str;
234 } 488 }
235 489
236 /* validation phase */ 490 /* validation phase */
237 str = shahash(seed); 491 str = shahash(seed);
238 for(i=0;i<KEYBUF;i++) 492 for(i=0;i<KEYBUF;i++)
239 if(j_strcmp(keydb[i],key) == 0 && j_strcmp(seeddb[i],str) == 0) 493 if(j_strcmp(keydb[i],key) == 0 && j_strcmp(seeddb[i],str) == 0)
240 { 494 {
241 seeddb[i][0] = '\0'; /* invalidate this key */ 495 seeddb[i][0] = '\0'; /* invalidate this key */
242 return keydb[i]; 496 return keydb[i];
243 } 497 }
244 498
245 return NULL; 499 return NULL;
246 } 500 }
247 501