Mercurial > ~mikael > mcabber > hg
diff 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 |
line wrap: on
line diff
--- a/mcabber/libjabber/jutil.c Thu Sep 01 21:18:19 2005 +0200 +++ b/mcabber/libjabber/jutil.c Thu Sep 01 23:29:21 2005 +0200 @@ -1,6 +1,48 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyrights + * + * Portions created by or assigned to Jabber.com, Inc. are + * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact + * information for Jabber.com, Inc. is available at http://www.jabber.com/. + * + * Portions Copyright (c) 1998-1999 Jeremie Miller. + * + * Acknowledgements + * + * Special thanks to the Jabber Open Source Contributors for their + * suggestions and support of Jabber. + * + */ + +/** + * @file jutil.c + * @brief various utilities mainly for handling xmlnodes containing stanzas + */ + #include "jabber.h" -/* util for making presence packets */ +/** + * utility for making presence stanzas + * + * @param type the type of the presence (one of the JPACKET__* contants) + * @param to to whom the presence should be sent, NULL for a broadcast presence + * @param status optional status (CDATA for the <status/> element, NULL for now <status/> element) + * @return the xmlnode containing the created presence stanza + */ xmlnode jutil_presnew(int type, char *to, char *status) { xmlnode pres; @@ -9,33 +51,46 @@ switch(type) { case JPACKET__SUBSCRIBE: - xmlnode_put_attrib(pres,"type","subscribe"); - break; + xmlnode_put_attrib(pres,"type","subscribe"); + break; case JPACKET__UNSUBSCRIBE: - xmlnode_put_attrib(pres,"type","unsubscribe"); - break; + xmlnode_put_attrib(pres,"type","unsubscribe"); + break; case JPACKET__SUBSCRIBED: - xmlnode_put_attrib(pres,"type","subscribed"); - break; + xmlnode_put_attrib(pres,"type","subscribed"); + break; case JPACKET__UNSUBSCRIBED: - xmlnode_put_attrib(pres,"type","unsubscribed"); - break; + xmlnode_put_attrib(pres,"type","unsubscribed"); + break; case JPACKET__PROBE: - xmlnode_put_attrib(pres,"type","probe"); - break; + xmlnode_put_attrib(pres,"type","probe"); + break; case JPACKET__UNAVAILABLE: - xmlnode_put_attrib(pres,"type","unavailable"); - break; + xmlnode_put_attrib(pres,"type","unavailable"); + break; + case JPACKET__INVISIBLE: + xmlnode_put_attrib(pres,"type","invisible"); + break; } if(to != NULL) - xmlnode_put_attrib(pres,"to",to); + xmlnode_put_attrib(pres,"to",to); if(status != NULL) - xmlnode_insert_cdata(xmlnode_insert_tag(pres,"status"),status,strlen(status)); + xmlnode_insert_cdata(xmlnode_insert_tag(pres,"status"),status,strlen(status)); return pres; } -/* util for making IQ packets */ +/** + * utility for making IQ stanzas, that contain a <query/> element in a different namespace + * + * @note In traditional Jabber protocols the element inside an iq element has the name "query". + * This util is not able to create IQ stanzas that contain a query which a element that does + * not have the name "query" + * + * @param type the type of the iq stanza (one of JPACKET__GET, JPACKET__SET, JPACKET__RESULT, JPACKET__ERROR) + * @param ns the namespace of the <query/> element + * @return the created xmlnode + */ xmlnode jutil_iqnew(int type, char *ns) { xmlnode iq; @@ -44,43 +99,64 @@ switch(type) { case JPACKET__GET: - xmlnode_put_attrib(iq,"type","get"); - break; + xmlnode_put_attrib(iq,"type","get"); + break; case JPACKET__SET: - xmlnode_put_attrib(iq,"type","set"); - break; + xmlnode_put_attrib(iq,"type","set"); + break; case JPACKET__RESULT: - xmlnode_put_attrib(iq,"type","result"); - break; + xmlnode_put_attrib(iq,"type","result"); + break; case JPACKET__ERROR: - xmlnode_put_attrib(iq,"type","error"); - break; + xmlnode_put_attrib(iq,"type","error"); + break; } xmlnode_put_attrib(xmlnode_insert_tag(iq,"query"),"xmlns",ns); return iq; } -/* util for making message packets */ +/** + * utility for making message stanzas + * + * @param type the type of the message (as a string!) + * @param to the recipient of the message + * @param subj the subject of the message (NULL for no subject element) + * @param body the body of the message + * @return the xmlnode containing the new message stanza + */ xmlnode jutil_msgnew(char *type, char *to, char *subj, char *body) { xmlnode msg; msg = xmlnode_new_tag("message"); - xmlnode_put_attrib (msg, "type", type); - xmlnode_put_attrib (msg, "to", to); - if (subj) - { - xmlnode_insert_cdata (xmlnode_insert_tag (msg, "subject"), subj, strlen (subj)); + if (type != NULL) { + xmlnode_put_attrib (msg, "type", type); } - xmlnode_insert_cdata (xmlnode_insert_tag (msg, "body"), body, strlen (body)); + if (to != NULL) { + xmlnode_put_attrib (msg, "to", to); + } + + if (subj != NULL) { + xmlnode_insert_cdata(xmlnode_insert_tag(msg, "subject"), subj, strlen(subj)); + } + + if (body != NULL) { + xmlnode_insert_cdata(xmlnode_insert_tag(msg, "body"), body, strlen(body)); + } return msg; } -/* util for making stream packets */ +/** + * utility for making stream packets (containing the stream header element) + * + * @param xmlns the default namespace of the stream (e.g. jabber:client or jabber:server) + * @param server the domain of the server + * @return the xmlnode containing the root element of the stream + */ xmlnode jutil_header(char* xmlns, char* server) { xmlnode result; @@ -94,33 +170,41 @@ return result; } -/* returns the priority on a presence packet */ +/** + * returns the priority on an available presence packet + * + * @param xmlnode the xmlnode containing the presence packet + * @return the presence priority, -129 for unavailable presences and errors + */ int jutil_priority(xmlnode x) { char *str; int p; if(x == NULL) - return -1; + return -129; if(xmlnode_get_attrib(x,"type") != NULL) - return -1; + return -129; x = xmlnode_get_tag(x,"priority"); if(x == NULL) - return 0; + return 0; str = xmlnode_get_data((x)); if(str == NULL) - return 0; + return 0; p = atoi(str); - if(p >= 0) - return p; - else - return 0; + /* xmpp-im section 2.2.2.3 */ + return p<-128 ? -128 : p>127 ? 127 : p; } +/** + * reverse sender and destination of a packet + * + * @param x the xmlnode where sender and receiver should be exchanged + */ void jutil_tofrom(xmlnode x) { char *to, *from; @@ -131,6 +215,12 @@ xmlnode_put_attrib(x,"to",from); } +/** + * change and xmlnode to be the result xmlnode for the original iq query + * + * @param x the xmlnode that should become the result for itself + * @return the result xmlnode (same as given as parameter x) + */ xmlnode jutil_iqresult(xmlnode x) { xmlnode cur; @@ -141,11 +231,18 @@ /* hide all children of the iq, they go back empty */ for(cur = xmlnode_get_firstchild(x); cur != NULL; cur = xmlnode_get_nextsibling(cur)) - xmlnode_hide(cur); + xmlnode_hide(cur); return x; } +/** + * get the present time as a textual timestamp in the format YYYYMMDDTHH:MM:SS + * + * @note this function is not thread safe + * + * @return pointer to a static (!) buffer containing the timestamp (or NULL on failure) + */ char *jutil_timestamp(void) { time_t t; @@ -156,35 +253,170 @@ t = time(NULL); if(t == (time_t)-1) - return NULL; + return NULL; new_time = gmtime(&t); ret = snprintf(timestamp, 18, "%d%02d%02dT%02d:%02d:%02d", 1900+new_time->tm_year, - new_time->tm_mon+1, new_time->tm_mday, new_time->tm_hour, - new_time->tm_min, new_time->tm_sec); + new_time->tm_mon+1, new_time->tm_mday, new_time->tm_hour, + new_time->tm_min, new_time->tm_sec); if(ret == -1) - return NULL; + return NULL; return timestamp; } -void jutil_error(xmlnode x, terror E) +/** + * map a terror structure to a xterror structure + * + * terror structures have been used in jabberd14 up to version 1.4.3 but + * are not able to hold XMPP compliant stanza errors. The xterror + * structure has been introduced to be XMPP compliant. This function + * is to ease writting wrappers that accept terror structures and call + * the real functions that require now xterror structures + * + * @param old the terror struct that should be converted + * @param mapped pointer to the xterror struct that should be filled with the converted error + */ +void jutil_error_map(terror old, xterror *mapped) +{ + mapped->code = old.code; + if (old.msg == NULL) + mapped->msg[0] = 0; + else + strncpy(mapped->msg, old.msg, sizeof(mapped->msg)); + + switch (old.code) + { + case 302: + strcpy(mapped->type, "modify"); + strcpy(mapped->condition, "redirect"); + break; + case 400: + strcpy(mapped->type, "modify"); + strcpy(mapped->condition, "bad-request"); + break; + case 401: + strcpy(mapped->type, "auth"); + strcpy(mapped->condition, "not-authorized"); + break; + case 402: + strcpy(mapped->type, "auth"); + strcpy(mapped->condition, "payment-required"); + break; + case 403: + strcpy(mapped->type, "auth"); + strcpy(mapped->condition, "forbidden"); + break; + case 404: + strcpy(mapped->type, "cancel"); + strcpy(mapped->condition, "item-not-found"); + break; + case 405: + strcpy(mapped->type, "cancel"); + strcpy(mapped->condition, "not-allowed"); + break; + case 406: + strcpy(mapped->type, "modify"); + strcpy(mapped->condition, "not-acceptable"); + break; + case 407: + strcpy(mapped->type, "auth"); + strcpy(mapped->condition, "registration-requited"); + break; + case 408: + strcpy(mapped->type, "wait"); + strcpy(mapped->condition, "remote-server-timeout"); + break; + case 409: + strcpy(mapped->type, "cancel"); + strcpy(mapped->condition, "conflict"); + break; + case 500: + strcpy(mapped->type, "wait"); + strcpy(mapped->condition, "internal-server-error"); + break; + case 501: + strcpy(mapped->type, "cancel"); + strcpy(mapped->condition, "feature-not-implemented"); + break; + case 502: + strcpy(mapped->type, "wait"); + strcpy(mapped->condition, "service-unavailable"); + break; + case 503: + strcpy(mapped->type, "cancel"); + strcpy(mapped->condition, "service-unavailable"); + break; + case 504: + strcpy(mapped->type, "wait"); + strcpy(mapped->condition, "remote-server-timeout"); + break; + case 510: + strcpy(mapped->type, "cancel"); + strcpy(mapped->condition, "service-unavailable"); + break; + default: + strcpy(mapped->type, "wait"); + strcpy(mapped->condition, "undefined-condition"); + } +} + +/** + * update an xmlnode to be the error stanza for itself + * + * @param x the xmlnode that should become an stanza error message + * @param E the structure that holds the error information + */ +void jutil_error_xmpp(xmlnode x, xterror E) { xmlnode err; char code[4]; - xmlnode_put_attrib(x,"type","error"); - err = xmlnode_insert_tag(x,"error"); + xmlnode_put_attrib(x, "type", "error"); + err = xmlnode_insert_tag(x, "error"); - snprintf(code,4,"%d",E.code); - xmlnode_put_attrib(err,"code",code); - if(E.msg != NULL) - xmlnode_insert_cdata(err,E.msg,strlen(E.msg)); + snprintf(code, sizeof(code), "%d", E.code); + xmlnode_put_attrib(err, "code", code); + if (E.type != NULL) + xmlnode_put_attrib(err, "type", E.type); + if (E.condition != NULL) + xmlnode_put_attrib(xmlnode_insert_tag(err, E.condition), "xmlns", NS_XMPP_STANZAS); + if (E.msg != NULL) + { + xmlnode text; + text = xmlnode_insert_tag(err, "text"); + xmlnode_put_attrib(text, "xmlns", NS_XMPP_STANZAS); + xmlnode_insert_cdata(text, E.msg, strlen(E.msg)); + } jutil_tofrom(x); } +/** + * wrapper around jutil_error_xmpp for compatibility with modules for jabberd up to version 1.4.3 + * + * @deprecated use jutil_error_xmpp instead! + * + * @param x the xmlnode that should become an stanza error message + * @param E the strucutre that holds the error information + */ +void jutil_error(xmlnode x, terror E) +{ + xterror xE; + jutil_error_map(E, &xE); + jutil_error_xmpp(x, xE); +} + +/** + * add a delayed delivery (JEP-0091) element to a message using the + * present timestamp. + * If a reason is given, this reason will be added as CDATA to the + * inserted element + * + * @param msg the message where the element should be added + * @param reason plain text information why the delayed delivery information has been added + */ void jutil_delay(xmlnode msg, char *reason) { xmlnode delay; @@ -194,11 +426,33 @@ xmlnode_put_attrib(delay,"from",xmlnode_get_attrib(msg,"to")); xmlnode_put_attrib(delay,"stamp",jutil_timestamp()); if(reason != NULL) - xmlnode_insert_cdata(delay,reason,strlen(reason)); + xmlnode_insert_cdata(delay,reason,strlen(reason)); } #define KEYBUF 100 +/** + * create or validate a key value for stone-age jabber protocols + * + * Before dialback had been introduced for s2s (and therefore only in jabberd 1.0), + * Jabber used these keys to protect some iq requests. A client first had to + * request a key with a IQ get and use it inside the IQ set request. By being able + * to receive the key in the IQ get response, the client (more or less) proved to be + * who he claimed to be. + * + * The implementation of this function uses a static array with KEYBUF entries (default + * value of KEYBUF is 100). Therefore a key gets invalid at the 100th key that is created + * afterwards. It is also invalidated after it has been validated once. + * + * @deprecated This function is not really used anymore. jabberd14 does not check any + * keys anymore and only creates them in the jsm's mod_register.c for compatibility. This + * function is also used in mod_groups.c and the key is even checked there, but I do not + * know if mod_groups.c still works at all. + * + * @param key for validation the key the client sent, for generation of a new key NULL + * @param seed the seed for generating the key, must stay the same for the same user + * @return the new key when created, the key if the key has been validated, NULL if the key is invalid + */ char *jutil_regkey(char *key, char *seed) { static char keydb[KEYBUF][41]; @@ -210,37 +464,37 @@ /* blanket the keydb first time */ if(last == -1) { - last = 0; - memset(&keydb,0,KEYBUF*41); - memset(&seeddb,0,KEYBUF*41); - srand(time(NULL)); + last = 0; + memset(&keydb,0,KEYBUF*41); + memset(&seeddb,0,KEYBUF*41); + srand(time(NULL)); } /* creation phase */ if(key == NULL && seed != NULL) { - /* create a random key hash and store it */ - sprintf(strint,"%d",rand()); - strcpy(keydb[last],shahash(strint)); + /* create a random key hash and store it */ + sprintf(strint,"%d",rand()); + strcpy(keydb[last],shahash(strint)); - /* store a hash for the seed associated w/ this key */ - strcpy(seeddb[last],shahash(seed)); + /* store a hash for the seed associated w/ this key */ + strcpy(seeddb[last],shahash(seed)); - /* return it all */ - str = keydb[last]; - last++; - if(last == KEYBUF) last = 0; - return str; + /* return it all */ + str = keydb[last]; + last++; + if(last == KEYBUF) last = 0; + return str; } /* validation phase */ str = shahash(seed); for(i=0;i<KEYBUF;i++) - if(j_strcmp(keydb[i],key) == 0 && j_strcmp(seeddb[i],str) == 0) - { - seeddb[i][0] = '\0'; /* invalidate this key */ - return keydb[i]; - } + if(j_strcmp(keydb[i],key) == 0 && j_strcmp(seeddb[i],str) == 0) + { + seeddb[i][0] = '\0'; /* invalidate this key */ + return keydb[i]; + } return NULL; }