Sync libjabber with upstream
Sync with jabberd-1.4.4.
--- a/mcabber/libjabber/expat.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/expat.c Thu Sep 01 23:29:21 2005 +0200
@@ -19,6 +19,17 @@
#include <libxode.h>
+/**
+ * callback function used for start elements
+ *
+ * This function is used internally by expat.c as a callback function
+ * given to expat. It will create a new xmlnode and add it to the
+ * already created xmlnode tree.
+ *
+ * @param userdata pointer to the parent xmlnode instance (NULL if this function is called for the root note)
+ * @param name name of the starting element
+ * @param atts attributes that are contained in the start element
+ */
void expat_startElement(void* userdata, const char* name, const char** atts)
{
/* get the xmlnode pointed to by the userdata */
@@ -39,6 +50,16 @@
}
}
+/**
+ * callback function used for end elements
+ *
+ * This function is used internally by expat.c as a callback function
+ * given to expat. It will complete an xmlnode and update the userdata pointer
+ * to point to the node that is parent of the next starting element.
+ *
+ * @param userdata pointer to the current xmlnode
+ * @param name name of the ending element (ignored by this function)
+ */
void expat_endElement(void* userdata, const char* name)
{
xmlnode *x = userdata;
@@ -52,6 +73,15 @@
*x = current;
}
+/**
+ * callback function for CDATA nodes
+ *
+ * This function will insert CDATA in an xmlnode
+ *
+ * @param userdata pointer to the current xmlnode
+ * @param s pointer to the CDATA string (not zero terminated!)
+ * @param len length of the CDATA string
+ */
void expat_charData(void* userdata, const char* s, int len)
{
xmlnode *x = userdata;
@@ -60,7 +90,15 @@
xmlnode_insert_cdata(current, s, len);
}
-
+/**
+ * create an xmlnode instance (possibly including other xmlnode instances) by parsing a string
+ *
+ * This function will parse a string containing an XML document and create an xmlnode graph
+ *
+ * @param str the string containing the XML document (not necessarily zero terminated)
+ * @param len the length of the string (without the zero byte, if present)
+ * @return the graph of xmlnodes that represent the parsed document, NULL on failure
+ */
xmlnode xmlnode_str(char *str, int len)
{
XML_Parser p;
@@ -88,6 +126,14 @@
return node; /* return the xmlnode x points to */
}
+/**
+ * create an xmlnode instance (possibly including other xmlnode instances) by parsing a file
+ *
+ * This function will parse a file containing an XML document and create an xmlnode graph
+ *
+ * @param file the filename
+ * @return the graph of xmlnodes that represent the parsed document, NULL on failure
+ */
xmlnode xmlnode_file(char *file)
{
XML_Parser p;
@@ -128,27 +174,69 @@
return node; /* return the xmlnode x points to */
}
+/**
+ * write an xmlnode to a file (without a size limit)
+ *
+ * @param file the target file
+ * @param node the xmlnode that should be written
+ * @return 1 on success, -1 on failure
+ */
int xmlnode2file(char *file, xmlnode node)
{
- char *doc;
+ return xmlnode2file_limited(file, node, 0);
+}
+
+/**
+ * write an xmlnode to a file, limited by size
+ *
+ * @param file the target file
+ * @param node the xmlnode that should be written
+ * @param sizelimit the maximum length of the file to be written
+ * @return 1 on success, 0 if failed due to size limit, -1 on failure
+ */
+int xmlnode2file_limited(char *file, xmlnode node, size_t sizelimit)
+{
+ char *doc, *ftmp;
int fd, i;
+ size_t doclen;
if(file == NULL || node == NULL)
return -1;
- fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0600);
+ ftmp = spools(xmlnode_pool(node),file,".t.m.p",xmlnode_pool(node));
+ fd = open(ftmp, O_CREAT | O_WRONLY | O_TRUNC, 0600);
if(fd < 0)
return -1;
doc = xmlnode2str(node);
- i = write(fd,doc,strlen(doc));
+ doclen = strlen(doc);
+
+ if (sizelimit > 0 && doclen > sizelimit)
+ {
+ close(fd);
+ return 0;
+ }
+
+ i = write(fd,doc,doclen);
if(i < 0)
return -1;
close(fd);
+
+ if(rename(ftmp,file) < 0)
+ {
+ unlink(ftmp);
+ return -1;
+ }
return 1;
}
+/**
+ * append attributes in the expat format to an existing xmlnode
+ *
+ * @param owner where to add the attributes
+ * @param atts the attributes in expat format (even indexes are the attribute names, odd indexes the values)
+ */
void xmlnode_put_expat_attribs(xmlnode owner, const char** atts)
{
int i = 0;
--- a/mcabber/libjabber/genhash.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/genhash.c Thu Sep 01 23:29:21 2005 +0200
@@ -13,8 +13,19 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Jabber
- * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
+ * 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.
+ *
*/
#include <libxode.h>
--- a/mcabber/libjabber/jabber.h Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/jabber.h Thu Sep 01 23:29:21 2005 +0200
@@ -57,7 +57,7 @@
#define JID_SERVER 4
typedef struct jid_struct
-{
+{
pool p;
char* resource;
char* user;
@@ -65,7 +65,7 @@
char* full;
struct jid_struct *next; /* for lists of jids */
} *jid;
-
+
jid jid_new(pool p, char *idstr); /* Creates a jabber id from the idstr */
void jid_set(jid id, char *str, int item); /* Individually sets jid components */
@@ -75,6 +75,7 @@
jid jid_append(jid a, jid b); /* Appending b to a (list), no dups */
xmlnode jid_xres(jid id); /* Returns xmlnode representation of the resource?query=string */
xmlnode jid_nodescan(jid id, xmlnode x); /* Scans the children of the node for a matching jid attribute */
+jid jid_user(jid a); /* returns the same jid but just of the user@host part */
/* --------------------------------------------------------- */
@@ -104,21 +105,22 @@
#define JPACKET__UNAVAILABLE 13
#define JPACKET__PROBE 14
#define JPACKET__HEADLINE 15
+#define JPACKET__INVISIBLE 16
typedef struct jpacket_struct
{
- unsigned char type;
- int subtype;
- int flag;
- void* aux1;
- xmlnode x;
- jid to;
- jid from;
- char* iqns;
- xmlnode iq;
- pool p;
+ unsigned char type; /**< stanza type (JPACKET_*) */
+ int subtype; /**< subtype of a stanza */
+ int flag; /**< used by the session manager to flag messages, that are read from offline storage */
+ void* aux1; /**< pointer to data passed around with a jpacket, multiple use inside jsm */
+ xmlnode x; /**< xmlnode containing the stanza inside the jpacket */
+ jid to; /**< destination of the stanza */
+ jid from; /**< source address for the stanza */
+ char* iqns; /**< pointer to the namespace inside an IQ stanza */
+ xmlnode iq; /**< "content" of an iq stanza, pointer to the element in its own namespace */
+ pool p; /**< memory pool used for this stanza */
} *jpacket, _jpacket;
-
+
jpacket jpacket_new(xmlnode x); /* Creates a jabber packet from the xmlnode */
jpacket jpacket_reset(jpacket p); /* Resets the jpacket values based on the xmlnode */
int jpacket_subtype(jpacket p); /* Returns the subtype value (looks at xmlnode for it) */
@@ -130,7 +132,7 @@
/* */
/* --------------------------------------------------------- */
typedef struct ppdb_struct
-{
+{
jid id; /* entry data */
int pri;
xmlnode x;
@@ -159,7 +161,7 @@
int maxt, maxp;
pool p;
} *jlimit, _jlimit;
-
+
jlimit jlimit_new(int maxt, int maxp);
void jlimit_free(jlimit r);
int jlimit_check(jlimit r, char *key, int points);
@@ -194,6 +196,49 @@
#define TERROR_EXTTIMEOUT (terror){504,"Remote Server Timeout"}
#define TERROR_DISCONNECTED (terror){510,"Disconnected"}
+/* we define this to signal that we support xterror */
+#define HAS_XTERROR
+
+typedef struct xterror_struct
+{
+ int code;
+ char msg[256];
+ char type[9];
+ char condition[64];
+} xterror;
+
+#define XTERROR_BAD (xterror){400,"Bad Request","modify","bad-request"}
+#define XTERROR_CONFLICT (xterror){409,"Conflict","cancel","conflict"}
+#define XTERROR_NOTIMPL (xterror){501,"Not Implemented","cancel","feature-not-implemented"}
+#define XTERROR_FORBIDDEN (xterror){403,"Forbidden","auth","forbidden"}
+#define XTERROR_GONE (xterror){302,"Gone","modify","gone"}
+#define XTERROR_INTERNAL (xterror){500,"Internal Server Error","wait","internal-server-error"}
+#define XTERROR_NOTFOUND (xterror){404,"Not Found","cancel","item-not-found"}
+#define XTERROR_JIDMALFORMED (xterror){400,"Bad Request","modify","jid-malformed"}
+#define XTERROR_NOTACCEPTABLE (xterror){406,"Not Acceptable","modify","not-acceptable"}
+#define XTERROR_NOTALLOWED (xterror){405,"Not Allowed","cancel","not-allowed"}
+#define XTERROR_AUTH (xterror){401,"Unauthorized","auth","not-authorized"}
+#define XTERROR_PAY (xterror){402,"Payment Required","auth","payment-required"}
+#define XTERROR_RECIPIENTUNAVAIL (xterror){404,"Receipient Is Unavailable","wait","recipient-unavailable"}
+#define XTERROR_REDIRECT (xterror){302,"Redirect","modify","redirect"}
+#define XTERROR_REGISTER (xterror){407,"Registration Required","auth","registration-required"}
+#define XTERROR_REMOTENOTFOUND (xterror){404,"Remote Server Not Found","cancel","remote-server-not-found"}
+#define XTERROR_REMOTETIMEOUT (xterror){504,"Remote Server Timeout","wait","remote-server-timeout"}
+#define XTERROR_RESCONSTRAINT (xterror){500,"Resource Constraint","wait","resource-constraint"}
+#define XTERROR_UNAVAIL (xterror){503,"Service Unavailable","cancel","service-unavailable"}
+#define XTERROR_SUBSCRIPTIONREQ (xterror){407,"Subscription Required","auth","subscription-required"}
+#define XTERROR_UNDEF_CANCEL (xterror){500,NULL,"cancel","undefined-condition"}
+#define XTERROR_UNDEF_CONTINUE (xterror){500,NULL,"continue","undefined-condition"}
+#define XTERROR_UNDEF_MODIFY (xterror){500,NULL,"modify","undefined-condition"}
+#define XTERROR_UNDEF_AUTH (xterror){500,NULL,"auth","undefined-condition"}
+#define XTERROR_UNDEF_WAIT (xterror){500,NULL,"wait","undefined-condition"}
+#define XTERROR_UNEXPECTED (xterror){400,"Unexpected Request","wait","unexpected-request"}
+
+#define XTERROR_REQTIMEOUT (xterror){408,"Request Timeout","wait","remote-server-timeout"}
+#define XTERROR_EXTERNAL (xterror){502,"Remote Server Error","wait","service-unavailable"}
+#define XTERROR_EXTTIMEOUT (xterror){504,"Remote Server Timeout","wait","remote-server-timeout"}
+#define XTERROR_DISCONNECTED (xterror){510,"Disconnected","cancel","service-unavailable"}
+
/* --------------------------------------------------------- */
/* */
/* Namespace constants */
@@ -203,7 +248,9 @@
#define NS_CLIENT "jabber:client"
#define NS_SERVER "jabber:server"
+#define NS_DIALBACK "jabber:server:dialback"
#define NS_AUTH "jabber:iq:auth"
+#define NS_AUTH_CRYPT "jabber:iq:auth:crypt"
#define NS_REGISTER "jabber:iq:register"
#define NS_ROSTER "jabber:iq:roster"
#define NS_OFFLINE "jabber:x:offline"
@@ -220,7 +267,30 @@
#define NS_ADMIN "jabber:iq:admin"
#define NS_FILTER "jabber:iq:filter"
#define NS_AUTH_0K "jabber:iq:auth:0k"
+#define NS_BROWSE "jabber:iq:browse"
+#define NS_EVENT "jabber:x:event"
+#define NS_CONFERENCE "jabber:iq:conference"
+#define NS_SIGNED "jabber:x:signed"
+#define NS_ENCRYPTED "jabber:x:encrypted"
+#define NS_GATEWAY "jabber:iq:gateway"
+#define NS_LAST "jabber:iq:last"
+#define NS_ENVELOPE "jabber:x:envelope"
+#define NS_EXPIRE "jabber:x:expire"
+#define NS_XHTML "http://www.w3.org/1999/xhtml"
+#define NS_DISCO_INFO "http://jabber.org/protocol/disco#info"
+#define NS_DISCO_ITEMS "http://jabber.org/protocol/disco#items"
+#define NS_IQ_AUTH "http://jabber.org/features/iq-auth"
+#define NS_REGISTER_FEATURE "http://jabber.org/features/iq-register"
+#define NS_XDBGINSERT "jabber:xdb:ginsert"
+#define NS_XDBNSLIST "jabber:xdb:nslist"
+
+#define NS_XMPP_STANZAS "urn:ietf:params:xml:ns:xmpp-stanzas"
+#define NS_XMPP_TLS "urn:ietf:params:xml:ns:xmpp-tls"
+#define NS_XMPP_STREAMS "urn:ietf:params:xml:ns:xmpp-streams"
+
+#define NS_JABBERD_STOREDPRESENCE "http://jabberd.org/ns/storedpresence"
+#define NS_JABBERD_HISTORY "http://jabberd.org/ns/history"
/* --------------------------------------------------------- */
/* */
--- a/mcabber/libjabber/jid.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/jid.c Thu Sep 01 23:29:21 2005 +0200
@@ -17,30 +17,474 @@
* Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
*/
+/**
+ * @file jid.c
+ * @brief representation and normalization of JabberIDs
+ */
+
#include "jabber.h"
-jid jid_safe(jid id)
-{
+#ifdef LIBIDN
+
+# include <stringprep.h>
+
+
+/**
+ * @brief datastructure to build the stringprep caches
+ */
+typedef struct _jid_prep_entry_st {
+ char *preped; /**< the result of the preparation, NULL if unchanged */
+ time_t last_used; /**< when this result has last been successfully used */
+ unsigned int used_count; /**< how often this result has been successfully used */
+ int size; /**< the min buffer size needed to hold the result (strlen+1) */
+} *_jid_prep_entry_t;
+
+/**
+ * @brief string preparation cache
+ */
+typedef struct _jid_prep_cache_st {
+ xht hashtable; /**< the hash table containing the preped strings */
+ pth_mutex_t mutex; /**< mutex controling the access to the hashtable */
+ const Stringprep_profile *profile;
+ /**< the stringprep profile used for this cache */
+} *_jid_prep_cache_t;
+
+/**
+ * stringprep cache containging already preped nodes
+ *
+ * we are using global caches here for two reasons:
+ * - I do not see why different instances would want
+ * to have different caches as we are always doing
+ * the same
+ * - For per instance caches I would have to modify the
+ * interface of the jid_*() functions which would break
+ * compatibility with transports
+ */
+_jid_prep_cache_t _jid_prep_cache_node = NULL;
+
+/**
+ * stringprep cache containing already preped domains
+ */
+_jid_prep_cache_t _jid_prep_cache_domain = NULL;
+
+/**
+ * stringprep cache containing already preped resources
+ */
+_jid_prep_cache_t _jid_prep_cache_resource = NULL;
+
+/**
+ * walker for cleaning up stringprep caches
+ *
+ * @param h the hash we are walking through
+ * @param key the key of this item
+ * @param val the value of this item
+ * @param arg delete entries older as this unix timestamp
+ */
+void _jid_clean_walker(xht h, const char *key, void *val, void *arg) {
+ time_t *keep_newer_as = (time_t*)arg;
+ _jid_prep_entry_t entry = (_jid_prep_entry_t)val;
+
+ if (entry == NULL)
+ return;
+
+ if (entry->last_used <= *keep_newer_as) {
+ xhash_zap(h, key);
+ if (entry->preped != NULL)
+ free(entry->preped);
+ free(entry);
+
+ /* sorry, I have to cast the const away */
+ /* any idea how I could delete the key else? */
+ if (key != NULL)
+ free((void*)key);
+ }
+}
+
+/**
+ * walk through a single stringprep cache and check which entries have expired
+ */
+void _jid_clean_single_cache(_jid_prep_cache_t cache, time_t keep_newer_as) {
+ /* acquire the lock on the cache */
+ pth_mutex_acquire(&(cache->mutex), FALSE, NULL);
+
+ /* walk over all entries */
+ xhash_walk(cache->hashtable, _jid_clean_walker, (void*)&keep_newer_as);
+
+ /* we're done, release the lock on the cache */
+ pth_mutex_release(&(cache->mutex));
+}
+
+/**
+ * walk through the stringprep caches and check which entries have expired
+ */
+void jid_clean_cache() {
+ /* XXX make this configurable? */
+ time_t keep_newer_as = time(NULL) - 900;
+
+ /* cleanup the nodeprep cache */
+ _jid_clean_single_cache(_jid_prep_cache_node, keep_newer_as);
+
+ /* cleanup the domain preparation cache */
+ _jid_clean_single_cache(_jid_prep_cache_domain, keep_newer_as);
+
+ /* cleanup the resourceprep cache */
+ _jid_clean_single_cache(_jid_prep_cache_resource, keep_newer_as);
+}
+
+/**
+ * caching wrapper around a stringprep function
+ *
+ * @param in_out_buffer buffer containing what has to be stringpreped and that gets the result
+ * @param max_len size of the buffer
+ * @param cache the used cache, defining also the used stringprep profile
+ * @return the return code of the stringprep call
+ */
+int _jid_cached_stringprep(char *in_out_buffer, int max_len, _jid_prep_cache_t cache) {
+ _jid_prep_entry_t preped;
+ int result = STRINGPREP_OK;
+
+ /* check that the cache already exists
+ * we can not do anything as we don't know which profile has to be used */
+ if (cache == NULL) {
+ return STRINGPREP_UNKNOWN_PROFILE;
+ }
+
+ /* is there something that has to be stringpreped? */
+ if (in_out_buffer == NULL) {
+ return STRINGPREP_OK;
+ }
+
+ /* acquire the lock on the cache */
+ pth_mutex_acquire(&(cache->mutex), FALSE, NULL);
+
+ /* check if the requested preparation has already been done */
+ preped = (_jid_prep_entry_t)xhash_get(cache->hashtable, in_out_buffer);
+ if (preped != NULL) {
+ /* we already prepared this argument */
+ if (preped->size <= max_len) {
+ /* we can use the result */
+
+ /* update the statistic */
+ preped->used_count++;
+ preped->last_used = time(NULL);
+
+ /* do we need to copy the result? */
+ if (preped->preped != NULL) {
+ /* copy the result */
+ strcpy(in_out_buffer, preped->preped);
+ }
+
+ result = STRINGPREP_OK;
+ } else {
+ /* we need a bigger buffer */
+ result = STRINGPREP_TOO_SMALL_BUFFER;
+ }
+
+ /* we're done, release the lock on the cache */
+ pth_mutex_release(&(cache->mutex));
+ } else {
+ char *original;
+
+ /* stringprep needs time, release the lock on the cache for the meantime */
+ pth_mutex_release(&(cache->mutex));
+
+ /* we have to keep the key */
+ original = strdup(in_out_buffer);
+
+ /* try to prepare the string */
+ result = stringprep(in_out_buffer, max_len, STRINGPREP_NO_UNASSIGNED, cache->profile);
+
+ /* did we manage to prepare the string? */
+ if (result == STRINGPREP_OK && original != NULL) {
+ /* generate an entry for the cache */
+ preped = (_jid_prep_entry_t)malloc(sizeof(struct _jid_prep_entry_st));
+ if (preped != NULL) {
+ /* has there been modified something? */
+ if (j_strcmp(in_out_buffer, original) == 0) {
+ /* no, we don't need to store a copy of the original string */
+ preped->preped = NULL;
+ } else {
+ /* yes, store the stringpreped string */
+ preped->preped = strdup(in_out_buffer);
+ }
+ preped->last_used = time(NULL);
+ preped->used_count = 1;
+ preped->size = strlen(in_out_buffer)+1;
+
+ /* acquire the lock on the cache again */
+ pth_mutex_acquire(&(cache->mutex), FALSE, NULL);
+
+ /* store the entry in the cache */
+ xhash_put(cache->hashtable, original, preped);
+
+ /* we're done, release the lock on the cache */
+ pth_mutex_release(&(cache->mutex));
+ } else {
+ /* we don't need the copy of the key, if there is no memory to store it */
+ free(original);
+ }
+ } else {
+ /* we don't need the copy of the original value */
+ if (original != NULL)
+ free(original);
+ }
+ }
+
+ return result;
+}
+
+/**
+ * free a single stringprep cache
+ *
+ * @param cache the cache to free
+ */
+void _jid_stop_single_cache(_jid_prep_cache_t *cache) {
+ if (*cache == NULL)
+ return;
+
+ _jid_clean_single_cache(*cache, time(NULL));
+
+ pth_mutex_acquire(&((*cache)->mutex), FALSE, NULL);
+ xhash_free((*cache)->hashtable);
+
+ free(*cache);
+
+ *cache = NULL;
+}
+
+/**
+ * init a single stringprep cache
+ *
+ * @param cache the cache to init
+ * @param prime the prime used to init the hashtable
+ * @param profile profile used to prepare the strings
+ */
+void _jid_init_single_cache(_jid_prep_cache_t *cache, int prime, const Stringprep_profile *profile) {
+ /* do not init a cache twice */
+ if (*cache == NULL) {
+ *cache = (_jid_prep_cache_t)malloc(sizeof(struct _jid_prep_cache_st));
+ pth_mutex_init(&((*cache)->mutex));
+ (*cache)->hashtable = xhash_new(prime);
+ (*cache)->profile = profile;
+ }
+}
+
+/**
+ * free the stringprep caches
+ */
+void jid_stop_caching() {
+ _jid_stop_single_cache(&_jid_prep_cache_node);
+ _jid_stop_single_cache(&_jid_prep_cache_domain);
+ _jid_stop_single_cache(&_jid_prep_cache_resource);
+}
+
+/**
+ * init the stringprep caches
+ * (do not call this twice at the same time, we do not have the mutexes yet)
+ */
+void jid_init_cache() {
+ /* init the nodeprep cache */
+ _jid_init_single_cache(&_jid_prep_cache_node, 2003, stringprep_xmpp_nodeprep);
+
+ /* init the nameprep cache (domains) */
+ _jid_init_single_cache(&_jid_prep_cache_domain, 2003, stringprep_nameprep);
+
+ /* init the resourceprep cache */
+ _jid_init_single_cache(&_jid_prep_cache_resource, 2003, stringprep_xmpp_resourceprep);
+}
+
+/**
+ * nameprep the domain identifier in a JID and check if it is valid
+ *
+ * @param jid data structure holding the JID
+ * @return 0 if JID is valid, non zero otherwise
+ */
+int _jid_safe_domain(jid id) {
+ int result=0;
+
+ /* there must be a domain identifier */
+ if (j_strlen(id->server) == 0)
+ return 1;
+
+ /* nameprep the domain identifier */
+ result = _jid_cached_stringprep(id->server, strlen(id->server)+1, _jid_prep_cache_domain);
+ if (result == STRINGPREP_TOO_SMALL_BUFFER) {
+ /* nameprep wants to expand the string, e.g. conversion from ß to ss */
+ size_t biggerbuffersize = 1024;
+ char *biggerbuffer = pmalloc(id->p, biggerbuffersize);
+ if (biggerbuffer == NULL)
+ return 1;
+ strcpy(biggerbuffer, id->server);
+ result = _jid_cached_stringprep(biggerbuffer, biggerbuffersize, _jid_prep_cache_domain);
+ id->server = biggerbuffer;
+ }
+ if (result != STRINGPREP_OK)
+ return 1;
+
+ /* the namepreped domain must not be longer than 1023 bytes */
+ if (j_strlen(id->server) > 1023)
+ return 1;
+
+ /* if nothing failed, the domain is valid */
+ return 0;
+}
+
+/**
+ * nodeprep the node identifier in a JID and check if it is valid
+ *
+ * @param jid data structure holding the JID
+ * @return 0 if JID is valid, non zero otherwise
+ */
+int _jid_safe_node(jid id) {
+ int result=0;
+
+ /* it is valid to have no node identifier in the JID */
+ if (id->user == NULL)
+ return 0;
+
+ /* nodeprep */
+ result = _jid_cached_stringprep(id->user, strlen(id->user)+1, _jid_prep_cache_node);
+ if (result == STRINGPREP_TOO_SMALL_BUFFER) {
+ /* nodeprep wants to expand the string, e.g. conversion from ß to ss */
+ size_t biggerbuffersize = 1024;
+ char *biggerbuffer = pmalloc(id->p, biggerbuffersize);
+ if (biggerbuffer == NULL)
+ return 1;
+ strcpy(biggerbuffer, id->user);
+ result = _jid_cached_stringprep(biggerbuffer, biggerbuffersize, _jid_prep_cache_node);
+ id->user = biggerbuffer;
+ }
+ if (result != STRINGPREP_OK)
+ return 1;
+
+ /* the nodepreped node must not be longer than 1023 bytes */
+ if (j_strlen(id->user) > 1023)
+ return 1;
+
+ /* if nothing failed, the node is valid */
+ return 0;
+}
+
+/**
+ * resourceprep the resource identifier in a JID and check if it is valid
+ *
+ * @param jid data structure holding the JID
+ * @return 0 if JID is valid, non zero otherwise
+ */
+int _jid_safe_resource(jid id) {
+ int result=0;
+
+ /* it is valid to have no resource identifier in the JID */
+ if (id->resource == NULL)
+ return 0;
+
+ /* resource prep the resource identifier */
+ result = _jid_cached_stringprep(id->resource, strlen(id->resource)+1, _jid_prep_cache_resource);
+ if (result == STRINGPREP_TOO_SMALL_BUFFER) {
+ /* resourceprep wants to expand the string, e.g. conversion from ß to ss */
+ size_t biggerbuffersize = 1024;
+ char *biggerbuffer = pmalloc(id->p, biggerbuffersize);
+ if (biggerbuffer == NULL)
+ return 1;
+ strcpy(biggerbuffer, id->resource);
+ result = _jid_cached_stringprep(id->resource, strlen(id->resource)+1, _jid_prep_cache_resource);
+ id->resource = biggerbuffer;
+ }
+ if (result != STRINGPREP_OK)
+ return 1;
+
+ /* the resourcepreped node must not be longer than 1023 bytes */
+ if (j_strlen(id->resource) > 1023)
+ return 1;
+
+ /* if nothing failed, the resource is valid */
+ return 0;
+
+}
+
+#else /* no LIBIDN */
+
+/**
+ * check if the domain identifier in a JID is valid
+ *
+ * @param jid data structure holding the JID
+ * @return 0 if domain is valid, non zero otherwise
+ */
+int _jid_safe_domain(jid id) {
char *str;
- if(strlen(id->server) == 0 || strlen(id->server) > 255)
- return NULL;
+ /* there must be a domain identifier */
+ if (j_strlen(id->server) == 0)
+ return 1;
+
+ /* and it must not be longer than 1023 bytes */
+ if (strlen(id->server) > 1023)
+ return 1;
/* lowercase the hostname, make sure it's valid characters */
for(str = id->server; *str != '\0'; str++)
{
- *str = tolower(*str);
- if(!(isalnum(*str) || *str == '.' || *str == '-' || *str == '_')) return NULL;
+ *str = tolower(*str);
+ if(!(isalnum(*str) || *str == '.' || *str == '-' || *str == '_')) return 1;
}
- /* cut off the user */
- if(id->user != NULL && strlen(id->user) > 64)
- id->user[64] = '\0';
+ /* otherwise it's okay as far as we can tell without LIBIDN */
+ return 0;
+}
+
+/**
+ * check if the node identifier in a JID is valid
+ *
+ * @param jid data structure holding the JID
+ * @return 0 if node is valid, non zero otherwise
+ */
+int _jid_safe_node(jid id) {
+ char *str;
+
+ /* node identifiers may not be longer than 1023 bytes */
+ if (j_strlen(id->user) > 1023)
+ return 1;
/* check for low and invalid ascii characters in the username */
if(id->user != NULL)
- for(str = id->user; *str != '\0'; str++)
- if(*str <= 32 || *str == ':' || *str == '@' || *str == '<' || *str == '>' || *str == '\'' || *str == '"' || *str == '&') return NULL;
+ for(str = id->user; *str != '\0'; str++)
+ if(*str <= 32 || *str == ':' || *str == '@' || *str == '<' || *str == '>' || *str == '\'' || *str == '"' || *str == '&') return 1;
+
+ /* otherwise it's okay as far as we can tell without LIBIDN */
+ return 0;
+}
+
+/**
+ * check if the resource identifier in a JID is valid
+ *
+ * @param jid data structure holding the JID
+ * @return 0 if resource is valid, non zero otherwise
+ */
+int _jid_safe_resource(jid id) {
+ /* resources may not be longer than 1023 bytes */
+ if (j_strlen(id->resource) > 1023)
+ return 1;
+
+ /* otherwise it's okay as far as we can tell without LIBIDN */
+ return 0;
+}
+
+#endif
+
+/**
+ * nodeprep/nameprep/resourceprep the JID and check if it is valid
+ *
+ * @param jid data structure holding the JID
+ * @return NULL if the JID is invalid, pointer to the jid otherwise
+ */
+jid jid_safe(jid id)
+{
+ if (_jid_safe_domain(id))
+ return NULL;
+ if (_jid_safe_node(id))
+ return NULL;
+ if (_jid_safe_resource(id))
+ return NULL;
return id;
}
@@ -51,46 +495,44 @@
jid id;
if(p == NULL || idstr == NULL || strlen(idstr) == 0)
- return NULL;
+ return NULL;
/* user@server/resource */
str = pstrdup(p, idstr);
- id = pmalloc(p,sizeof(struct jid_struct));
- id->full = id->server = id->user = id->resource = NULL;
+ id = pmalloco(p,sizeof(struct jid_struct));
id->p = p;
- id->next = NULL;
resource = strstr(str,"/");
if(resource != NULL)
{
- *resource = '\0';
- ++resource;
- if(strlen(resource) > 0)
- id->resource = resource;
+ *resource = '\0';
+ ++resource;
+ if(strlen(resource) > 0)
+ id->resource = resource;
}else{
- resource = str + strlen(str); /* point to end */
+ resource = str + strlen(str); /* point to end */
}
type = strstr(str,":");
if(type != NULL && type < resource)
{
- *type = '\0';
- ++type;
- str = type; /* ignore the type: prefix */
+ *type = '\0';
+ ++type;
+ str = type; /* ignore the type: prefix */
}
server = strstr(str,"@");
if(server == NULL || server > resource)
{ /* if there's no @, it's just the server address */
- id->server = str;
+ id->server = str;
}else{
- *server = '\0';
- ++server;
- id->server = server;
- if(strlen(str) > 0)
- id->user = str;
+ *server = '\0';
+ ++server;
+ id->server = server;
+ if(strlen(str) > 0)
+ id->user = str;
}
return jid_safe(id);
@@ -101,7 +543,7 @@
char *old;
if(id == NULL)
- return;
+ return;
/* invalidate the cached copy */
id->full = NULL;
@@ -109,26 +551,29 @@
switch(item)
{
case JID_RESOURCE:
- if(str != NULL && strlen(str) != 0)
- id->resource = pstrdup(id->p, str);
- else
- id->resource = NULL;
- break;
+ old = id->resource;
+ if(str != NULL && strlen(str) != 0)
+ id->resource = pstrdup(id->p, str);
+ else
+ id->resource = NULL;
+ if(_jid_safe_resource(id))
+ id->resource = old; /* revert if invalid */
+ break;
case JID_USER:
- old = id->user;
- if(str != NULL && strlen(str) != 0)
- id->user = pstrdup(id->p, str);
- else
- id->user = NULL;
- if(jid_safe(id) == NULL)
- id->user = old; /* revert if invalid */
- break;
+ old = id->user;
+ if(str != NULL && strlen(str) != 0)
+ id->user = pstrdup(id->p, str);
+ else
+ id->user = NULL;
+ if(_jid_safe_node(id))
+ id->user = old; /* revert if invalid */
+ break;
case JID_SERVER:
- old = id->server;
- id->server = pstrdup(id->p, str);
- if(jid_safe(id) == NULL)
- id->server = old; /* revert if invalid */
- break;
+ old = id->server;
+ id->server = pstrdup(id->p, str);
+ if(_jid_safe_domain(id))
+ id->server = old; /* revert if invalid */
+ break;
}
}
@@ -138,21 +583,21 @@
spool s;
if(id == NULL)
- return NULL;
+ return NULL;
/* use cached copy */
if(id->full != NULL)
- return id->full;
+ return id->full;
s = spool_new(id->p);
if(id->user != NULL)
- spooler(s, id->user,"@",s);
+ spooler(s, id->user,"@",s);
spool_add(s, id->server);
if(id->resource != NULL)
- spooler(s, "/",id->resource,s);
+ spooler(s, "/",id->resource,s);
id->full = spool_print(s);
return id->full;
@@ -177,24 +622,24 @@
cur = qmark;
while(cur != '\0')
{
- eq = strstr(cur, "=");
- if(eq == NULL) break;
- *eq = '\0';
- eq++;
+ eq = strstr(cur, "=");
+ if(eq == NULL) break;
+ *eq = '\0';
+ eq++;
- amp = strstr(eq, "&");
- if(amp != NULL)
- {
- *amp = '\0';
- amp++;
- }
+ amp = strstr(eq, "&");
+ if(amp != NULL)
+ {
+ *amp = '\0';
+ amp++;
+ }
- xmlnode_put_attrib(x,cur,eq);
+ xmlnode_put_attrib(x,cur,eq);
- if(amp != NULL)
- cur = amp;
- else
- break;
+ if(amp != NULL)
+ cur = amp;
+ else
+ break;
}
return x;
@@ -217,7 +662,7 @@
int jid_cmp(jid a, jid b)
{
if(a == NULL || b == NULL)
- return -1;
+ return -1;
if(_jid_nullstrcmp(a->resource, b->resource) != 0) return -1;
if(_jid_nullstrcasecmp(a->user, b->user) != 0) return -1;
@@ -230,7 +675,7 @@
int jid_cmpx(jid a, jid b, int parts)
{
if(a == NULL || b == NULL)
- return -1;
+ return -1;
if(parts & JID_RESOURCE && _jid_nullstrcmp(a->resource, b->resource) != 0) return -1;
if(parts & JID_USER && _jid_nullstrcasecmp(a->user, b->user) != 0) return -1;
@@ -245,20 +690,20 @@
jid next;
if(a == NULL)
- return NULL;
+ return NULL;
if(b == NULL)
- return a;
+ return a;
next = a;
while(next != NULL)
{
- /* check for dups */
- if(jid_cmp(next,b) == 0)
- break;
- if(next->next == NULL)
- next->next = jid_new(a->p,jid_full(b));
- next = next->next;
+ /* check for dups */
+ if(jid_cmp(next,b) == 0)
+ break;
+ if(next->next == NULL)
+ next->next = jid_new(a->p,jid_full(b));
+ next = next->next;
}
return a;
}
@@ -274,14 +719,28 @@
p = pool_new();
for(cur = xmlnode_get_firstchild(x); cur != NULL; cur = xmlnode_get_nextsibling(cur))
{
- if(xmlnode_get_type(cur) != NTYPE_TAG) continue;
+ if(xmlnode_get_type(cur) != NTYPE_TAG) continue;
- tmp = jid_new(p,xmlnode_get_attrib(cur,"jid"));
- if(tmp == NULL) continue;
+ tmp = jid_new(p,xmlnode_get_attrib(cur,"jid"));
+ if(tmp == NULL) continue;
- if(jid_cmp(tmp,id) == 0) break;
+ if(jid_cmp(tmp,id) == 0) break;
}
pool_free(p);
return cur;
}
+
+jid jid_user(jid a)
+{
+ jid ret;
+
+ if(a == NULL || a->resource == NULL) return a;
+
+ ret = pmalloco(a->p,sizeof(struct jid_struct));
+ ret->p = a->p;
+ ret->user = a->user;
+ ret->server = a->server;
+
+ return ret;
+}
--- a/mcabber/libjabber/jpacket.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/jpacket.c Thu Sep 01 23:29:21 2005 +0200
@@ -13,18 +13,46 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Jabber
- * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
+ * 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 jpacket.c
+ * @brief a jpacket is a wrapper around an xmlnode that contains an XMPP stanza
+ *
+ * A jpacket adds some variables to an xmlnode that contains a stanza, so that
+ * jabberd is able to cache information on the stanza type (message, presence, iq)
+ * that is contained in this jpacket and to further classify the presence stanzas.
+ * It also adds some pointers to important data inside the xmlnode, that has
+ * to be accessed often (e.g. sender and receiver of a stanza).
*/
#include "jabber.h"
+/**
+ * create a new jpacket by wrapping an xmlnode
+ *
+ * @param x the xmlnode that should be wrapped
+ * @return the newly created jpacket (NULL on failure)
+ */
jpacket jpacket_new(xmlnode x)
{
jpacket p;
if(x == NULL)
- return NULL;
+ return NULL;
p = pmalloc(xmlnode_pool(x),sizeof(_jpacket));
p->x = x;
@@ -32,6 +60,12 @@
return jpacket_reset(p);
}
+/**
+ * recalculate the information the jpacket holds about the stanza
+ *
+ * @param p the packet that should get its information recalculated
+ * @return the jpacket (as given as the p parameter)
+ */
jpacket jpacket_reset(jpacket p)
{
char *val;
@@ -42,90 +76,97 @@
p->x = x;
p->p = xmlnode_pool(x);
- if(strncmp(xmlnode_get_name(x),"message",7) == 0)
- {
- p->type = JPACKET_MESSAGE;
- }else if(strncmp(xmlnode_get_name(x),"presence",8) == 0)
- {
- p->type = JPACKET_PRESENCE;
- val = xmlnode_get_attrib(x, "type");
- if(val == NULL)
- p->subtype = JPACKET__AVAILABLE;
- else if(strcmp(val,"unavailable") == 0)
- p->subtype = JPACKET__UNAVAILABLE;
- else if(strcmp(val,"probe") == 0)
- p->subtype = JPACKET__PROBE;
- else if(*val == 's' || *val == 'u')
- p->type = JPACKET_S10N;
- else if(strcmp(val,"available") == 0)
- { /* someone is using type='available' which is frowned upon */
- xmlnode_hide_attrib(x,"type");
- p->subtype = JPACKET__AVAILABLE;
- }else
- p->type = JPACKET_UNKNOWN;
- }else if(strncmp(xmlnode_get_name(x),"iq",2) == 0)
- {
- p->type = JPACKET_IQ;
- p->iq = xmlnode_get_tag(x,"?xmlns");
- p->iqns = xmlnode_get_attrib(p->iq,"xmlns");
+ if(strncmp(xmlnode_get_name(x),"message",7) == 0) {
+ p->type = JPACKET_MESSAGE;
+ } else if(strncmp(xmlnode_get_name(x),"presence",8) == 0) {
+ p->type = JPACKET_PRESENCE;
+ val = xmlnode_get_attrib(x, "type");
+ if(val == NULL)
+ p->subtype = JPACKET__AVAILABLE;
+ else if(strcmp(val,"unavailable") == 0)
+ p->subtype = JPACKET__UNAVAILABLE;
+ else if(strcmp(val,"probe") == 0)
+ p->subtype = JPACKET__PROBE;
+ else if(strcmp(val,"error") == 0)
+ p->subtype = JPACKET__ERROR;
+ else if(strcmp(val,"invisible") == 0)
+ p->subtype = JPACKET__INVISIBLE;
+ else if(*val == 's' || *val == 'u')
+ p->type = JPACKET_S10N;
+ else if(strcmp(val,"available") == 0) {
+ /* someone is using type='available' which is frowned upon */
+ /* XXX better reject this presence? */
+ xmlnode_hide_attrib(x,"type");
+ p->subtype = JPACKET__AVAILABLE;
+ } else
+ p->type = JPACKET_UNKNOWN;
+ } else if(strncmp(xmlnode_get_name(x),"iq",2) == 0) {
+ p->type = JPACKET_IQ;
+ p->iq = xmlnode_get_tag(x,"?xmlns");
+ p->iqns = xmlnode_get_attrib(p->iq,"xmlns");
}
/* set up the jids if any, flag packet as unknown if they are unparseable */
val = xmlnode_get_attrib(x,"to");
if(val != NULL)
- if((p->to = jid_new(p->p, val)) == NULL)
- p->type = JPACKET_UNKNOWN;
+ if((p->to = jid_new(p->p, val)) == NULL)
+ p->type = JPACKET_UNKNOWN;
val = xmlnode_get_attrib(x,"from");
if(val != NULL)
- if((p->from = jid_new(p->p, val)) == NULL)
- p->type = JPACKET_UNKNOWN;
+ if((p->from = jid_new(p->p, val)) == NULL)
+ p->type = JPACKET_UNKNOWN;
return p;
}
-
+/**
+ * get the subtype of a jpacket
+ *
+ * @param p the jpacket for which the caller wants to know the subtype
+ * @return the subtype of the jpacket (one of the JPACKET__* constants)
+ */
int jpacket_subtype(jpacket p)
{
char *type;
int ret = p->subtype;
if(ret != JPACKET__UNKNOWN)
- return ret;
+ return ret;
ret = JPACKET__NONE; /* default, when no type attrib is specified */
type = xmlnode_get_attrib(p->x, "type");
if(j_strcmp(type,"error") == 0)
- ret = JPACKET__ERROR;
+ ret = JPACKET__ERROR;
else
- switch(p->type)
- {
- case JPACKET_MESSAGE:
- if(j_strcmp(type,"chat") == 0)
- ret = JPACKET__CHAT;
- else if(j_strcmp(type,"groupchat") == 0)
- ret = JPACKET__GROUPCHAT;
- else if(j_strcmp(type,"headline") == 0)
- ret = JPACKET__HEADLINE;
- break;
- case JPACKET_S10N:
- if(j_strcmp(type,"subscribe") == 0)
- ret = JPACKET__SUBSCRIBE;
- else if(j_strcmp(type,"subscribed") == 0)
- ret = JPACKET__SUBSCRIBED;
- else if(j_strcmp(type,"unsubscribe") == 0)
- ret = JPACKET__UNSUBSCRIBE;
- else if(j_strcmp(type,"unsubscribed") == 0)
- ret = JPACKET__UNSUBSCRIBED;
- break;
- case JPACKET_IQ:
- if(j_strcmp(type,"get") == 0)
- ret = JPACKET__GET;
- else if(j_strcmp(type,"set") == 0)
- ret = JPACKET__SET;
- else if(j_strcmp(type,"result") == 0)
- ret = JPACKET__RESULT;
- break;
- }
+ switch(p->type)
+ {
+ case JPACKET_MESSAGE:
+ if(j_strcmp(type,"chat") == 0)
+ ret = JPACKET__CHAT;
+ else if(j_strcmp(type,"groupchat") == 0)
+ ret = JPACKET__GROUPCHAT;
+ else if(j_strcmp(type,"headline") == 0)
+ ret = JPACKET__HEADLINE;
+ break;
+ case JPACKET_S10N:
+ if(j_strcmp(type,"subscribe") == 0)
+ ret = JPACKET__SUBSCRIBE;
+ else if(j_strcmp(type,"subscribed") == 0)
+ ret = JPACKET__SUBSCRIBED;
+ else if(j_strcmp(type,"unsubscribe") == 0)
+ ret = JPACKET__UNSUBSCRIBE;
+ else if(j_strcmp(type,"unsubscribed") == 0)
+ ret = JPACKET__UNSUBSCRIBED;
+ break;
+ case JPACKET_IQ:
+ if(j_strcmp(type,"get") == 0)
+ ret = JPACKET__GET;
+ else if(j_strcmp(type,"set") == 0)
+ ret = JPACKET__SET;
+ else if(j_strcmp(type,"result") == 0)
+ ret = JPACKET__RESULT;
+ break;
+ }
p->subtype = ret;
return ret;
--- 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;
}
--- a/mcabber/libjabber/libxode.h Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/libxode.h Thu Sep 01 23:29:21 2005 +0200
@@ -1,3 +1,27 @@
+/*
+ * jabberd - Jabber Open Source Server
+ * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
+ * Ryan Eatmon, Robert Norris
+ *
+ * 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, MA02111-1307USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -7,26 +31,23 @@
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
-#include <syslog.h>
#include <strings.h>
#include <unistd.h>
-#include <sys/socket.h>
+#include <sys/time.h>
+#include <syslog.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
-#include <sys/time.h>
+#include <sys/socket.h>
#include "xmlparse.h"
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif /* HAVE_CONFIG_H */
/*
** Arrange to use either varargs or stdargs
*/
-#define MAXSHORTSTR 203 /* max short string length */
-#define QUAD_T unsigned long long
+#define MAXSHORTSTR 203 /* max short string length */
+#define QUAD_T unsigned long long
#ifdef __STDC__
@@ -77,7 +98,7 @@
#undef POOL_DEBUG
/*
flip these, this should be a prime number for top # of pools debugging
-#define POOL_DEBUG 40009
+#define POOL_DEBUG 40009
*/
/* pheap - singular allocation of memory */
@@ -88,7 +109,7 @@
};
/* pool_cleaner - callback type which is associated
- with a pool entry; invoked when the pool entry is
+ with a pool entry; invoked when the pool entry is
free'd */
typedef void (*pool_cleaner)(void *arg);
@@ -113,16 +134,16 @@
char name[8], zone[32];
int lsize;
} _pool, *pool;
-#define pool_new() _pool_new(ZONE)
-#define pool_heap(i) _pool_new_heap(i,ZONE)
+#define pool_new() _pool_new(__FILE__,__LINE__)
+#define pool_heap(i) _pool_new_heap(i,__FILE__,__LINE__)
#else
} _pool, *pool;
-#define pool_heap(i) _pool_new_heap(i,NULL)
-#define pool_new() _pool_new(NULL)
+#define pool_heap(i) _pool_new_heap(i, NULL, 0)
+#define pool_new() _pool_new(NULL, 0)
#endif
-pool _pool_new(char *zone); /* new pool :) */
-pool _pool_new_heap(int size, char *zone); /* creates a new memory pool with an initial heap size */
+pool _pool_new(char *zone, int line); /* new pool :) */
+pool _pool_new_heap(int size, char *zone, int line); /* creates a new memory pool with an initial heap size */
void *pmalloc(pool p, int size); /* wrapper around malloc, takes from the pool, cleaned up automatically */
void *pmalloc_x(pool p, int size, char c); /* Wrapper around pmalloc which prefils buffer with c */
void *pmalloco(pool p, int size); /* YAPW for zeroing the block */
@@ -246,7 +267,7 @@
spool spool_new(pool p); /* create a string pool */
void spooler(spool s, ...); /* append all the char * args to the pool, terminate args with s again */
char *spool_print(spool s); /* return a big string */
-void spool_add(spool s, char *str); /* add a single char to the pool */
+void spool_add(spool s, char *str); /* add a single string to the pool */
char *spools(pool p, ...); /* wrap all the spooler stuff in one function, the happy fun ball! */
@@ -262,8 +283,8 @@
#define NTYPE_LAST 2
#define NTYPE_UNDEF -1
-/* --------------------------------------------------------------------------
- Node structure. Do not use directly! Always use accessor macros
+/* --------------------------------------------------------------------------
+ Node structure. Do not use directly! Always use accessor macros
and methods!
-------------------------------------------------------------------------- */
typedef struct xmlnode_t
@@ -275,9 +296,9 @@
int complete;
pool p;
struct xmlnode_t* parent;
- struct xmlnode_t* firstchild;
+ struct xmlnode_t* firstchild;
struct xmlnode_t* lastchild;
- struct xmlnode_t* prev;
+ struct xmlnode_t* prev;
struct xmlnode_t* next;
struct xmlnode_t* firstattrib;
struct xmlnode_t* lastattrib;
@@ -287,7 +308,7 @@
xmlnode xmlnode_wrap(xmlnode x,const char* wrapper);
xmlnode xmlnode_new_tag(const char* name);
xmlnode xmlnode_new_tag_pool(pool p, const char* name);
-xmlnode xmlnode_insert_tag(xmlnode parent, const char* name);
+xmlnode xmlnode_insert_tag(xmlnode parent, const char* name);
xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size);
xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node);
void xmlnode_insert_node(xmlnode parent, xmlnode node);
@@ -340,13 +361,14 @@
/* Node-to-string translation */
char* xmlnode2str(xmlnode node);
-/* Node-to-terminated-string translation
+/* Node-to-terminated-string translation
-- useful for interfacing w/ scripting langs */
char* xmlnode2tstr(xmlnode node);
int xmlnode_cmp(xmlnode a, xmlnode b); /* compares a and b for equality */
int xmlnode2file(char *file, xmlnode node); /* writes node to file */
+int xmlnode2file_limited(char *file, xmlnode node, size_t sizelimit);
/* Expat callbacks */
void expat_startElement(void* userdata, const char* name, const char** atts);
@@ -388,32 +410,32 @@
char *xstream_header_char(xmlnode x);
/* SHA.H */
-/*
+/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
- *
+ *
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
- *
+ *
* The Original Code is SHA 180-1 Header File
- *
+ *
* The Initial Developer of the Original Code is Paul Kocher of
- * Cryptography Research. Portions created by Paul Kocher are
+ * Cryptography Research. Portions created by Paul Kocher are
* Copyright (C) 1995-9 by Cryptography Research, Inc. All
* Rights Reserved.
- *
+ *
* Contributor(s):
*
* Paul Kocher
- *
+ *
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
--- a/mcabber/libjabber/pool.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/pool.c Thu Sep 01 23:29:21 2005 +0200
@@ -1,67 +1,140 @@
/*
- * 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.
- *
- * Jabber
+ * pool.c
+ * This code comes from jabberd - Jabber Open Source Server
+ * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
+ * Ryan Eatmon, Robert Norris
* Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
*
- * 2/27/00:3am, random plans by jer
+ * 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.
*
- * ok based on gprof, we really need some innovation here... my thoughs are this:
+ * 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, MA02111-1307USA
+ *
+ * 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.
*
- * most things are strings, so have a string-based true-blue garbage collector
- * one big global hash containing all the strings created by any pstrdup, returning const char *
- * a refcount on each string block
- * when a pool is freed, it moves down the refcount
- * garbage collector collects pools on the free stack, and runs through the hash for unused strings
- * j_strcmp can check for == (if they are both from a pstrdup)
+ * Acknowledgements
+ *
+ * Special thanks to the Jabber Open Source Contributors for their
+ * suggestions and support of Jabber.
+ *
+ */
+
+/**
+ * @file pool.c
+ * @brief Handling of memory pools
*
- * let's see... this would change:
- * pstrdup: do a hash lookup, success=return, fail=pmalloc & hash put
- * pool_free:
+ * Jabberd handles its memory allocations in pools. You create a pool, can
+ * allocate memory from it and all allocations will be freed if you free
+ * the pool. Therefore you don't have to care that each malloc is freed,
+ * you only have to take care that the pool is freed.
*
+ * The normal call-flow for pools is:
*
- *
+ * pool p = pool_new();
+ * struct mystruct *allocation1 = pmalloc(sizeof(struct mystruct));
+ * struct myotherstruct *allocation2 = pmalloc(sizeof(struct myotherstruct));
+ * ...
+ * pool_free(p);
*/
#include "libxode.h"
+#define MAX_MALLOC_TRIES 10 /**< how many seconds we try to allocate memory */
+
#ifdef POOL_DEBUG
-int pool__total = 0;
+int pool__total = 0; /**< how many memory blocks are allocated */
int pool__ltotal = 0;
-HASHTABLE pool__disturbed = NULL;
+xht pool__disturbed = NULL;
+
+/**
+ * create a new memory allocation and increment the pool__total counter
+ *
+ * only used if POOL_DEBUG is defined, else it is an alias for malloc
+ *
+ * @param size size of the memory to allocate
+ * @return pointer to the allocated memory
+ */
void *_pool__malloc(size_t size)
{
pool__total++;
return malloc(size);
}
+
+/**
+ * free memory and decrement the pool__total counter
+ *
+ * only used if POOL_DEBUG is defined, else it is an alias for free
+ *
+ * @param block pointer to the memory allocation that should be freed
+ */
void _pool__free(void *block)
{
pool__total--;
free(block);
}
#else
-#define _pool__malloc malloc
-#define _pool__free free
+#define _pool__malloc malloc /**< _pool__malloc updates pool__total counter if POOL_DEBUG is defined */
+#define _pool__free free /**< _pool__free updates pool__total counter if POOL_DEBUG is defined */
#endif
+/**
+ * try to allocate memory
+ *
+ * If allocation fails, it will be retries for MAX_MALLOC_TRIES seconds.
+ * If it still fails, we exit the process
+ *
+ * @param size how many bytes of memory we allocate
+ * @return pointer to the allocated memory
+ */
+inline void *_retried__malloc(size_t size) {
+ void *allocated_memory;
+ int malloc_tries = 0;
-/* make an empty pool */
-pool _pool_new(char *zone)
+ while ((allocated_memory=_pool__malloc(size)) == NULL) {
+ if (malloc_tries++ > MAX_MALLOC_TRIES) {
+ exit(999);
+ }
+
+ sleep(1); //pth_sleep(1);
+ }
+
+ return allocated_memory;
+}
+
+/**
+ * make an empty pool
+ *
+ * Use the macro pool_new() instead of a direct call to this function. The
+ * macro will create the parameters for you.
+ *
+ * @param zone the file in which the pool_new macro is called
+ * @param line the line in the file in which the pool_new macro is called
+ * @return the new allocated memory pool
+ */
+pool _pool_new(char *zone, int line)
{
- pool p;
- while((p = _pool__malloc(sizeof(_pool))) == NULL) sleep(1);
+ // int malloc_tries = 0;
+#ifdef POOL_DEBUG
+ int old__pool__total;
+#endif
+
+ pool p = _retried__malloc(sizeof(_pool));
+
p->cleanup = NULL;
p->heap = NULL;
p->size = 0;
@@ -70,17 +143,26 @@
p->lsize = -1;
p->zone[0] = '\0';
strcat(p->zone,zone);
- sprintf(p->name,"%X",p);
+ snprintf(p->zone, sizeof(p->zone), "%s:%i", zone, line);
+ snprintf(p->name, sizeof(p->name), "%X", p);
if(pool__disturbed == NULL)
- pool__disturbed = ghash_create(POOL_DEBUG,(KEYHASHFUNC)str_hash_code,(KEYCOMPAREFUNC)j_strcmp);
- ghash_put(pool__disturbed,p->name,p);
+ {
+ pool__disturbed = (xht)1; /* reentrancy flag! */
+ pool__disturbed = ghash_create(POOL_DEBUG,(KEYHASHFUNC)str_hash_code,(KEYCOMPAREFUNC)j_strcmp);
+ }
+ if(pool__disturbed != (xht)1)
+ ghash_put(pool__disturbed,p->name,p);
#endif
return p;
}
-/* free a heap */
+/**
+ * free a memory heap (struct pheap)
+ *
+ * @param arg which heep should be freed
+ */
void _pool_heap_free(void *arg)
{
struct pheap *h = (struct pheap *)arg;
@@ -89,15 +171,25 @@
_pool__free(h);
}
-/* mem should always be freed last */
+/**
+ * append a pool_cleaner function (callback) to a pool
+ *
+ * mem should always be freed last
+ *
+ * All appended pool_cleaner functions will be called if a pool is freed.
+ * This might be used to clean logically subpools.
+ *
+ * @param p to which pool the pool_cleaner should be added
+ * @param pf structure containing the reference to the pool_cleaner and links for the list
+ */
void _pool_cleanup_append(pool p, struct pfree *pf)
{
struct pfree *cur;
if(p->cleanup == NULL)
{
- p->cleanup = pf;
- return;
+ p->cleanup = pf;
+ return;
}
/* fast forward to end of list */
@@ -106,13 +198,22 @@
cur->next = pf;
}
-/* create a cleanup tracker */
+/**
+ * create a cleanup tracker
+ *
+ * this function is used to create a pfree structure that can be passed to _pool_cleanup_append()
+ *
+ * @param p the pool to which the pool_cleaner should be added
+ * @param f the function that should be called if the pool is freed
+ * @param arg the parameter that should be passed to the pool_cleaner function
+ * @return pointer to the new pfree structure
+ */
struct pfree *_pool_free(pool p, pool_cleaner f, void *arg)
{
struct pfree *ret;
/* make the storage for the tracker */
- while((ret = _pool__malloc(sizeof(struct pfree))) == NULL) sleep(1);
+ ret = _retried__malloc(sizeof(struct pfree));
ret->f = f;
ret->arg = arg;
ret->next = NULL;
@@ -120,15 +221,25 @@
return ret;
}
-/* create a heap and make sure it get's cleaned up */
+/**
+ * create a heap and make sure it get's cleaned up
+ *
+ * pheaps are used by memory pools internally to handle the memory allocations
+ *
+ * @note the macro pool_heap calls _pool_new_heap and NOT _pool_heap
+ *
+ * @param p for which pool the heap should be created
+ * @param size how big the pool should be
+ * @return pointer to the new pheap
+ */
struct pheap *_pool_heap(pool p, int size)
{
struct pheap *ret;
struct pfree *clean;
/* make the return heap */
- while((ret = _pool__malloc(sizeof(struct pheap))) == NULL) sleep(1);
- while((ret->block = _pool__malloc(size)) == NULL) sleep(1);
+ ret = _retried__malloc(sizeof(struct pheap));
+ ret->block = _retried__malloc(size);
ret->size = size;
p->size += size;
ret->used = 0;
@@ -141,40 +252,57 @@
return ret;
}
-pool _pool_new_heap(int size, char *zone)
+/**
+ * create a new memory pool and set the initial heap size
+ *
+ * @note you should not call this function but use the macro pool_heap instead which fills zone and line automatically
+ *
+ * @param size the initial size of the memory pool
+ * @param zone the file where this function is called (for debugging)
+ * @param line the line in the file where this function is called
+ * @return the new memory pool
+ */
+pool _pool_new_heap(int size, char *zone, int line)
{
pool p;
- p = _pool_new(zone);
+ p = _pool_new(zone, line);
p->heap = _pool_heap(p,size);
return p;
}
+/**
+ * allocate memory from a memory pool
+ *
+ * @param p the pool to use
+ * @param size how much memory to allocate
+ * @return pointer to the allocated memory
+ */
void *pmalloc(pool p, int size)
{
void *block;
if(p == NULL)
{
- fprintf(stderr,"Memory Leak! [pmalloc received NULL pool, unable to track allocation, exiting]\n");
- abort();
+ fprintf(stderr,"Memory Leak! [pmalloc received NULL pool, unable to track allocation, exiting]\n");
+ abort();
}
/* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */
if(p->heap == NULL || size > (p->heap->size / 2))
{
- while((block = _pool__malloc(size)) == NULL) sleep(1);
- p->size += size;
- _pool_cleanup_append(p, _pool_free(p, _pool__free, block));
- return block;
+ block = _retried__malloc(size);
+ p->size += size;
+ _pool_cleanup_append(p, _pool_free(p, _pool__free, block));
+ return block;
}
/* we have to preserve boundaries, long story :) */
if(size >= 4)
- while(p->heap->used&7) p->heap->used++;
+ while(p->heap->used&7) p->heap->used++;
/* if we don't fit in the old heap, replace it */
if(size > (p->heap->size - p->heap->used))
- p->heap = _pool_heap(p, p->heap->size);
+ p->heap = _pool_heap(p, p->heap->size);
/* the current heap has room */
block = (char *)p->heap->block + p->heap->used;
@@ -182,15 +310,33 @@
return block;
}
+/**
+ * allocate memory and initialize the memory with the given char c
+ *
+ * @deprecated jabberd does use pmalloco instead, this function will be removed
+ *
+ * @param p which pool to use
+ * @param size the size of the allocation
+ * @param c the initialization character
+ * @return pointer to the allocated memory
+ */
void *pmalloc_x(pool p, int size, char c)
{
void* result = pmalloc(p, size);
if (result != NULL)
- memset(result, c, size);
+ memset(result, c, size);
return result;
}
-/* easy safety utility (for creating blank mem for structs, etc) */
+/**
+ * allocate memory and initialize the memory with zero bytes
+ *
+ * easy safety utility (for creating blank mem for structs, etc)
+ *
+ * @param p which pool to use
+ * @param size the size of the allocation
+ * @return pointer to the allocated memory
+ */
void *pmalloco(pool p, int size)
{
void *block = pmalloc(p, size);
@@ -198,13 +344,21 @@
return block;
}
-/* XXX efficient: move this to const char * and then loop throug the existing heaps to see if src is within a block in this pool */
+/**
+ * duplicate a string and allocate memory for it
+ *
+ * @todo efficient: move this to const char* and then loop through the existing heaps to see if src is within a block in this pool
+ *
+ * @param p the pool to use
+ * @param src the string that should be duplicated
+ * @return the duplicated string
+ */
char *pstrdup(pool p, const char *src)
{
char *ret;
if(src == NULL)
- return NULL;
+ return NULL;
ret = pmalloc(p,strlen(src) + 1);
strcpy(ret,src);
@@ -212,12 +366,20 @@
return ret;
}
-/* when move above, this one would actually return a new block */
+/**
+ * when pstrdup() is moved to "const char*", this one would actually return a new block
+ */
char *pstrdupx(pool p, const char *src)
{
return pstrdup(p, src);
}
+/**
+ * get the size of a memory pool
+ *
+ * @param p the pool
+ * @return the size
+ */
int pool_size(pool p)
{
if(p == NULL) return 0;
@@ -225,6 +387,11 @@
return p->size;
}
+/**
+ * free a pool (and all memory that is allocated in it)
+ *
+ * @param p which pool to free
+ */
void pool_free(pool p)
{
struct pfree *cur, *stub;
@@ -234,10 +401,10 @@
cur = p->cleanup;
while(cur != NULL)
{
- (*cur->f)(cur->arg);
- stub = cur->next;
- _pool__free(cur);
- cur = stub;
+ (*cur->f)(cur->arg);
+ stub = cur->next;
+ _pool__free(cur);
+ cur = stub;
}
#ifdef POOL_DEBUG
@@ -248,7 +415,9 @@
}
-/* public cleanup utils, insert in a way that they are run FIFO, before mem frees */
+/**
+ * public cleanup utils, insert in a way that they are run FIFO, before mem frees
+ */
void pool_cleanup(pool p, pool_cleaner f, void *arg)
{
struct pfree *clean;
@@ -260,29 +429,42 @@
#ifdef POOL_DEBUG
void debug_log(char *zone, const char *msgfmt, ...);
-int _pool_stat(void *arg, const void *key, void *data)
+void _pool_stat(xht h, const char *key, void *data, void *arg)
{
pool p = (pool)data;
if(p->lsize == -1)
- debug_log("leak","%s: %X is a new pool",p->zone,p->name);
+ debug_log("pool_debug","%s: %s is a new pool",p->zone, p->name);
else if(p->size > p->lsize)
- debug_log("leak","%s: %X grew %d",p->zone,p->name, p->size - p->lsize);
+ debug_log("pool_debug","%s: %s grew %d",p->zone, p->name, p->size - p->lsize);
else if((int)arg)
- debug_log("leak","%s: %X exists %d",p->zone,p->name, p->size);
+ debug_log("pool_debug","%s: %s exists %d",p->zone,p->name, p->size);
p->lsize = p->size;
- return 1;
}
+/**
+ * print memory pool statistics (for debugging purposes)
+ *
+ * @param full make a full report? (0 = no, 1 = yes)
+ */
void pool_stat(int full)
{
+ if (pool__disturbed == NULL || pool__disturbed == (xht)1)
+ return;
+
ghash_walk(pool__disturbed,_pool_stat,(void *)full);
if(pool__total != pool__ltotal)
- debug_log("leak","%d\ttotal missed mallocs",pool__total);
+ debug_log("pool_debug","%d\ttotal missed mallocs",pool__total);
pool__ltotal = pool__total;
+
return;
}
#else
+/**
+ * dummy implementation: print memory pool statistics (for debugging purposes, real implementation if POOL_DEBUG is defined)
+ *
+ * @param full make a full report? (0 = no, 1 = yes)
+ */
void pool_stat(int full)
{
return;
--- a/mcabber/libjabber/pproxy.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/pproxy.c Thu Sep 01 23:29:21 2005 +0200
@@ -13,8 +13,31 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Jabber
- * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
+ * 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 pproxy.c
+ * @brief presence proxy database - DEPRECATED
+ *
+ * @deprecated these functions are not used by jabberd itself (but aim-t uses them), they will be removed from jabberd
+ *
+ * The presence proxy database is used to store presences for different resources of a JID.
+ *
+ * these aren't the most efficient things in the world, a hash optimized for tiny spaces would be far better
*/
#include "jabber.h"
@@ -42,25 +65,24 @@
if(db == NULL || id == NULL) return NULL;
for(cur = db->next; cur != NULL; cur = cur->next)
- if(jid_cmp(cur->id,id) == 0) return cur;
+ if(jid_cmp(cur->id,id) == 0) return cur;
return NULL;
}
ppdb ppdb_insert(ppdb db, jid id, xmlnode x)
{
- char *res;
ppdb cur, curu;
pool p;
if(id == NULL || id->server == NULL || x == NULL)
- return db;
+ return db;
/* new ppdb list dummy holder */
if(db == NULL)
{
- p = pool_heap(1024);
- db = _ppdb_new(p,id);
+ p = pool_heap(1024);
+ db = _ppdb_new(p,NULL);
}
cur = _ppdb_get(db,id);
@@ -68,10 +90,10 @@
/* just update it */
if(cur != NULL)
{
- xmlnode_free(cur->x);
- cur->x = xmlnode_dup(x);
- cur->pri = jutil_priority(x);
- return db;
+ xmlnode_free(cur->x);
+ cur->x = xmlnode_dup(x);
+ cur->pri = jutil_priority(x);
+ return db;
}
/* make an entry for it */
@@ -81,28 +103,20 @@
cur->next = db->next;
db->next = cur;
- /* this is a presence from a resource, make an entry for just the user */
- if(id->user != NULL && id->resource != NULL)
+ /* if this is a user's resource presence, get the the user entry */
+ if(id->user != NULL && (curu = _ppdb_get(db,jid_user(id))) != cur)
{
- /* modify the id to just user@host */
- res = id->resource;
- jid_set(id,NULL,JID_RESOURCE);
- curu = _ppdb_get(db,id);
+ /* no user entry, make one */
+ if(curu == NULL)
+ {
+ curu = _ppdb_new(db->p,jid_user(id));
+ curu->next = db->next;
+ db->next = curu;
+ }
- /* no user entry, make one */
- if(curu == NULL)
- {
- curu = _ppdb_new(db->p,id);
- curu->next = db->next;
- db->next = curu;
- }
-
- /* restore the id */
- jid_set(id,res,JID_RESOURCE);
-
- /* insert this resource into the user list */
- cur->user = curu->user;
- curu->user = cur;
+ /* insert this resource into the user list */
+ cur->user = curu->user;
+ curu->user = cur;
}
return db;
@@ -123,7 +137,7 @@
top = cur;
for(cur = cur->user; cur != NULL; cur = cur->user)
- if(cur->pri >= top->pri) top = cur;
+ if(cur->pri >= top->pri) top = cur;
if(top != NULL && top->pri >= 0) return top->x;
@@ -141,18 +155,18 @@
/* MODE: if this is NOT just user@host addy, return just the single entry */
if(id->user == NULL || id->resource != NULL)
{
- /* we were just here, return now */
- if(last != NULL)
- {
- last = NULL;
- return NULL;
- }
+ /* we were just here, return now */
+ if(last != NULL)
+ {
+ last = NULL;
+ return NULL;
+ }
- last = _ppdb_get(db,id);
- if(last != NULL)
- return last->x;
- else
- return NULL;
+ last = _ppdb_get(db,id);
+ if(last != NULL)
+ return last->x;
+ else
+ return NULL;
}
/* handle looping for user@host */
@@ -160,15 +174,15 @@
/* we're already in the loop */
if(last != NULL)
{
- /* this is the last entry in the list */
- if(last->user == NULL)
- {
- last = NULL;
- return NULL;
- }
+ /* this is the last entry in the list */
+ if(last->user == NULL)
+ {
+ last = NULL;
+ return NULL;
+ }
- last = last->user;
- return last->x;
+ last = last->user;
+ return last->x;
}
/* start a new loop */
@@ -178,9 +192,9 @@
last = cur->user;
if(last != NULL)
- return last->x;
+ return last->x;
else
- return NULL;
+ return NULL;
}
@@ -191,7 +205,7 @@
if(db == NULL) return;
for(cur = db; cur != NULL; cur = cur->next)
- xmlnode_free(cur->x);
+ xmlnode_free(cur->x);
pool_free(db->p);
}
--- a/mcabber/libjabber/rate.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/rate.c Thu Sep 01 23:29:21 2005 +0200
@@ -13,8 +13,29 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Jabber
- * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
+ * 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.
+ *
+ */
+
+/**
+ * create a new instance of jlimit that is used to limit events
+ *
+ * limit the events to maxp points per maxt seconds
+ *
+ * @param maxt time interval (in seconds) after which the points are cleared
+ * @param maxp maximum number of points available for the time interval given in maxt
+ * @return new instance of jlimit (has to be freed with jlimit_free if not used anymore)
*/
#include "jabber.h"
@@ -35,15 +56,31 @@
return r;
}
+/**
+ * free a jlimit instance
+ *
+ * @param r the jlimit instance that should be freed
+ */
void jlimit_free(jlimit r)
{
if(r != NULL)
{
- if(r->key != NULL) free(r->key);
- pool_free(r->p);
+ if(r->key != NULL) free(r->key);
+ pool_free(r->p);
}
}
+/**
+ * update/check a key in a jlimit instance
+ *
+ * Each jlimit instance can track many limits (that have the same setup).
+ * The limit is selected by the key, which can be an IP address.
+ *
+ * @param r the jlimit instance
+ * @param key for which key the limit should be checked
+ * @param points how many points of the limit should be consumed
+ * @return 1 if limit reached, 0 if we are still within the rate limit
+ */
int jlimit_check(jlimit r, char *key, int points)
{
int now = time(NULL);
@@ -53,15 +90,15 @@
/* make sure we didn't go over the time frame or get a null/new key */
if((now - r->start) > r->maxt || key == NULL || j_strcmp(key,r->key) != 0)
{ /* start a new key */
- free(r->key);
- if(key != NULL)
- /* We use strdup instead of pstrdup since r->key needs to be free'd before
- and more often than the rest of the rlimit structure */
- r->key = strdup(key);
- else
- r->key = NULL;
- r->start = now;
- r->points = 0;
+ free(r->key);
+ if(key != NULL)
+ /* We use strdup instead of pstrdup since r->key needs to be free'd before
+ and more often than the rest of the rlimit structure */
+ r->key = strdup(key);
+ else
+ r->key = NULL;
+ r->start = now;
+ r->points = 0;
}
r->points += points;
@@ -69,7 +106,7 @@
/* if we're within the time frame and over the point limit */
if(r->points > r->maxp && (now - r->start) < r->maxt)
{
- return 1; /* we don't reset the rate here, so that it remains rated until the time runs out */
+ return 1; /* we don't reset the rate here, so that it remains rated until the time runs out */
}
return 0;
--- a/mcabber/libjabber/snprintf.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/snprintf.c Thu Sep 01 23:29:21 2005 +0200
@@ -53,6 +53,15 @@
* <panos@alumni.cs.colorado.edu> for xinetd.
*/
+/**
+ * @file snprintf.c
+ * @brief implement snprintf if not present in the libc
+ *
+ * snprintf is not implemented by all libc implementations, this file implements this
+ * function, if it is not already present. You should not call any of the functions
+ * in this file directly!
+ */
+
#include <libxode.h>
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
@@ -242,8 +251,12 @@
NO = 0, YES = 1
} boolean_e;
-#define FALSE 0
-#define TRUE 1
+#ifndef FALSE
+# define FALSE 0
+#endif
+#ifndef TRUE
+# define TRUE 1
+#endif
#define NUL '\0'
#define INT_NULL ((int *)0)
#define WIDE_INT long
--- a/mcabber/libjabber/socket.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/socket.c Thu Sep 01 23:29:21 2005 +0200
@@ -13,21 +13,40 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Jabber
- * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
+ * 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 socket.c
+ * @brief some misc functions to handle sockets
*/
#include "libxode.h"
#include "connwrap.h"
-/* socket.c
- *
+/**
* Simple wrapper to make socket creation easy.
- * type = NETSOCKET_SERVER is local listening socket
- * type = NETSOCKET_CLIENT is connection socket
- * type = NETSOCKET_UDP
+ *
+ * @param port port number of the socket
+ * @param host hostname where to connect to or listen on
+ * @param type type of socket (NETSOCKET_SERVER, NETSOCKET_CLIENT; or NETSOCKET_UDP)
+ * @return file handle of the new socket
+ *
+ * NETSOCKET_SERVER is local listening socket
+ * NETSOCKET_CLIENT is connection socket
*/
-
int make_netsocket(u_short port, char *host, int type, int ssl)
{
int s, flag = 1;
@@ -41,53 +60,53 @@
bzero((void *)&sa,sizeof(struct sockaddr_in));
if((s = socket(AF_INET,socket_type,0)) < 0)
- return(-1);
+ return(-1);
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(flag)) < 0)
- return(-1);
+ return(-1);
saddr = make_addr(host);
if(saddr == NULL)
- return(-1);
+ return(-1);
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
if(type == NETSOCKET_SERVER)
{
- /* bind to specific address if specified */
- if(host != NULL)
- sa.sin_addr.s_addr = saddr->s_addr;
+ /* bind to specific address if specified */
+ if(host != NULL)
+ sa.sin_addr.s_addr = saddr->s_addr;
- if(bind(s,(struct sockaddr*)&sa,sizeof sa) < 0)
- {
- close(s);
- return(-1);
- }
+ if(bind(s,(struct sockaddr*)&sa,sizeof sa) < 0)
+ {
+ close(s);
+ return(-1);
+ }
}
if(type == NETSOCKET_CLIENT)
{
- sa.sin_addr.s_addr = saddr->s_addr;
- if(cw_connect(s,(struct sockaddr*)&sa,sizeof sa,ssl) < 0)
- {
- close(s);
- return(-1);
- }
+ sa.sin_addr.s_addr = saddr->s_addr;
+ if(cw_connect(s,(struct sockaddr*)&sa,sizeof sa,ssl) < 0)
+ {
+ close(s);
+ return(-1);
+ }
}
if(type == NETSOCKET_UDP)
{
- /* bind to all addresses for now */
- if(bind(s,(struct sockaddr*)&sa,sizeof sa) < 0)
- {
- close(s);
- return(-1);
- }
+ /* bind to all addresses for now */
+ if(bind(s,(struct sockaddr*)&sa,sizeof sa) < 0)
+ {
+ close(s);
+ return(-1);
+ }
- /* specify default recipient for read/write */
- sa.sin_addr.s_addr = saddr->s_addr;
- if(cw_connect(s,(struct sockaddr*)&sa,sizeof sa,ssl) < 0)
- {
- close(s);
- return(-1);
- }
+ /* specify default recipient for read/write */
+ sa.sin_addr.s_addr = saddr->s_addr;
+ if(cw_connect(s,(struct sockaddr*)&sa,sizeof sa,ssl) < 0)
+ {
+ close(s);
+ return(-1);
+ }
}
@@ -131,56 +150,56 @@
bzero((void *)&sa,sizeof(struct sockaddr_in));
if((s = socket(AF_INET,socket_type,0)) < 0)
- return(-1);
+ return(-1);
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(flag)) < 0)
- return(-1);
+ return(-1);
change_socket_to_nonblocking(s);
saddr = make_addr(host);
if(saddr == NULL)
- return(-1);
+ return(-1);
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
if(type == NETSOCKET_SERVER)
{
- /* bind to specific address if specified */
- if(host != NULL)
- sa.sin_addr.s_addr = saddr->s_addr;
+ /* bind to specific address if specified */
+ if(host != NULL)
+ sa.sin_addr.s_addr = saddr->s_addr;
- if(bind(s,(struct sockaddr*)&sa,sizeof sa) < 0)
- {
- close(s);
- return(-1);
- }
+ if(bind(s,(struct sockaddr*)&sa,sizeof sa) < 0)
+ {
+ close(s);
+ return(-1);
+ }
}
if(type == NETSOCKET_CLIENT)
{
- int rc;
- sa.sin_addr.s_addr = saddr->s_addr;
- rc = cw_nb_connect(s,(struct sockaddr*)&sa,sizeof sa,ssl, state);
- if (rc == -1 )
- {
- close(s);
- return(-1);
- }
+ int rc;
+ sa.sin_addr.s_addr = saddr->s_addr;
+ rc = cw_nb_connect(s,(struct sockaddr*)&sa,sizeof sa,ssl, state);
+ if (rc == -1 )
+ {
+ close(s);
+ return(-1);
+ }
}
if(type == NETSOCKET_UDP)
{
- /* bind to all addresses for now */
- if(bind(s,(struct sockaddr*)&sa,sizeof sa) < 0)
- {
- close(s);
- return(-1);
- }
+ /* bind to all addresses for now */
+ if(bind(s,(struct sockaddr*)&sa,sizeof sa) < 0)
+ {
+ close(s);
+ return(-1);
+ }
- /* specify default recipient for read/write */
- sa.sin_addr.s_addr = saddr->s_addr;
- if(cw_connect(s,(struct sockaddr*)&sa,sizeof sa,ssl) < 0)
- {
- close(s);
- return(-1);
- }
+ /* specify default recipient for read/write */
+ sa.sin_addr.s_addr = saddr->s_addr;
+ if(cw_connect(s,(struct sockaddr*)&sa,sizeof sa,ssl) < 0)
+ {
+ close(s);
+ return(-1);
+ }
}
@@ -193,32 +212,32 @@
static struct in_addr addr;
char myname[MAXHOSTNAMELEN + 1];
- if(host == NULL || strlen(host) == 0)
- {
- gethostname(myname,MAXHOSTNAMELEN);
- hp = gethostbyname(myname);
- if(hp != NULL)
- {
- return (struct in_addr *) *hp->h_addr_list;
- }
- }else{
- addr.s_addr = inet_addr(host);
- if(addr.s_addr != -1)
- {
- return &addr;
- }
- hp = gethostbyname(host);
- if(hp != NULL)
- {
- return (struct in_addr *) *hp->h_addr_list;
- }
+ if (host == NULL || strlen(host) == 0) {
+ gethostname(myname,MAXHOSTNAMELEN);
+ hp = gethostbyname(myname);
+ if(hp != NULL) {
+ return (struct in_addr *) *hp->h_addr_list;
+ }
+ } else {
+ addr.s_addr = inet_addr(host);
+ if(addr.s_addr != -1) {
+ return &addr;
+ }
+ hp = gethostbyname(host);
+ if(hp != NULL) {
+ return (struct in_addr *) *hp->h_addr_list;
+ }
}
return NULL;
}
-/* Sets a file descriptor to close on exec. "flag" is 1 to close on exec, 0 to
- * leave open across exec.
- * -- EJB 7/31/2000
+/**
+ * Sets a file descriptor to close on exec.
+ *
+ * @param fd the file descriptor
+ * @param flag 1 to close on exec, 0 to leave open across exec
+ *
+ * @deprecated this function is not used by jabberd14 and might be removed in future versions
*/
int set_fd_close_on_exec(int fd, int flag)
{
@@ -226,12 +245,12 @@
int newflags;
if(flag)
- newflags = oldflags | FD_CLOEXEC;
+ newflags = oldflags | FD_CLOEXEC;
else
- newflags = oldflags & (~FD_CLOEXEC);
+ newflags = oldflags & (~FD_CLOEXEC);
if(newflags==oldflags)
- return 0;
+ return 0;
return fcntl(fd,F_SETFL,(long)newflags);
}
--- a/mcabber/libjabber/str.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/str.c Thu Sep 01 23:29:21 2005 +0200
@@ -13,12 +13,42 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Jabber
- * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
+ * 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 str.c
+ * @brief utilities for string handling
+ *
+ * This file contains utility functions for string handling:
+ * - NULL pointer save versions of many functions in string.c
+ * - string spools
+ * - functions to (un)escape strings for XML usage
+ *
+ * String spools allow to create a string by concatenating several smaller strings
+ * and the spool implementation is allocating the neccessary memory using memory pools.
*/
#include "libxode.h"
+/**
+ * NULL pointer save version of strdup()
+ *
+ * @param str the string the should be duplicated
+ * @return the duplicated string
+ */
char *j_strdup(const char *str)
{
if(str == NULL)
@@ -27,6 +57,17 @@
return strdup(str);
}
+/**
+ * NULL pointer save version of strcat()
+ *
+ * @note the return value of j_strcat() is not compatible with the return value of strcat()
+ *
+ * @todo check if the behaviour of the return value is intended
+ *
+ * @param dest where to append the string
+ * @param txt what to append
+ * @return dest if txt contains a NULL pointer, pointer to the terminating zero byte of the result else
+ */
char *j_strcat(char *dest, char *txt)
{
if(!txt) return(dest);
@@ -38,14 +79,38 @@
return(dest);
}
+/**
+ * NULL pointer save version of strcmp
+ *
+ * If one of the parameters contains a NULL pointer, the string is considered to be unequal.
+ *
+ * @note the return value is not compatible with strcmp()
+ *
+ * @param a the one string
+ * @param b the other string
+ * @return 0 if the strings are equal, -1 if the strings are not equal
+ */
int j_strcmp(const char *a, const char *b)
{
if(a == NULL || b == NULL)
return -1;
- else
- return strcmp(a, b);
+
+ while(*a == *b && *a != '\0' && *b != '\0'){ a++; b++; }
+
+ if(*a == *b) return 0;
+
+ return -1;
}
+/**
+ * NULL pointer save version of strcasecmp()
+ *
+ * If one of the parameters contains a NULL pointer, the string is considered to be unequal
+ *
+ * @param a the one string
+ * @param b the other string
+ * @return 0 if the strings are equal, non zero else
+ */
int j_strcasecmp(const char *a, const char *b)
{
if(a == NULL || b == NULL)
@@ -54,6 +119,16 @@
return strcasecmp(a, b);
}
+/**
+ * NULL pointer save version of strncmp()
+ *
+ * If one of the parameters contains a NULL pointer, the string is considered to be unequal
+ *
+ * @param a the first string
+ * @param b the second string
+ * @param i how many characters to compare at most
+ * @return 0 if the strings are equal (within the given length limitation), non zero else
+ */
int j_strncmp(const char *a, const char *b, int i)
{
if(a == NULL || b == NULL)
@@ -62,6 +137,16 @@
return strncmp(a, b, i);
}
+/**
+ * NULL pointer save version of strncasecmp()
+ *
+ * If one of the parameters contains a NULL pointer, the string is considered to be unequal
+ *
+ * @param a the first string
+ * @param b the second string
+ * @param i how many characters to compare at most
+ * @return 0 if the strings are equal (within the given length limitation), non zero else
+ */
int j_strncasecmp(const char *a, const char *b, int i)
{
if(a == NULL || b == NULL)
@@ -70,6 +155,14 @@
return strncasecmp(a, b, i);
}
+/**
+ * NULL pointer save version of strlen
+ *
+ * If the parameter contains a NULL pointer, 0 is returned
+ *
+ * @param a the string for which the length should be calculated
+ * @return 0 if a==NULL, length of the string else
+ */
int j_strlen(const char *a)
{
if(a == NULL)
@@ -136,7 +229,7 @@
while(1)
{
arg = va_arg(ap,char *);
- if((int)arg == (int)s)
+ if((spool)arg == s)
break;
else
spool_add(s, arg);
@@ -185,7 +278,7 @@
while(1)
{
arg = va_arg(ap,char *);
- if((int)arg == (int)p)
+ if((pool)arg == p)
break;
else
spool_add(s, arg);
@@ -319,61 +412,3 @@
return buff;
}
-
-void str_b64decode(char* str)
-{
- char *cur;
- int d, dlast, phase;
- unsigned char c;
- static int table[256] = {
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
- 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
- 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
- -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
- 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */
- };
-
- dlast = 0;
- phase = 0;
- for (cur = str; *cur != '\0'; ++cur )
- {
- d = table[(int)*cur];
- if(d != -1)
- {
- switch(phase)
- {
- case 0:
- ++phase;
- break;
- case 1:
- c = ((dlast << 2) | ((d & 0x30) >> 4));
- *str++ = c;
- ++phase;
- break;
- case 2:
- c = (((dlast & 0xf) << 4) | ((d & 0x3c) >> 2));
- *str++ = c;
- ++phase;
- break;
- case 3:
- c = (((dlast & 0x03 ) << 6) | d);
- *str++ = c;
- phase = 0;
- break;
- }
- dlast = d;
- }
- }
- *str = '\0';
-}
--- a/mcabber/libjabber/xmlnode.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/xmlnode.c Thu Sep 01 23:29:21 2005 +0200
@@ -13,8 +13,19 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Jabber
- * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
+ * 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.
+ *
*/
#include "libxode.h"
@@ -35,8 +46,7 @@
}
/* Allocate & zero memory */
- result = (xmlnode)pmalloc(p, sizeof(_xmlnode));
- memset(result, '\0', sizeof(_xmlnode));
+ result = (xmlnode)pmalloco(p, sizeof(_xmlnode));
/* Initialize fields */
if (type != NTYPE_CDATA)
@@ -64,7 +74,7 @@
{
xmlnode result;
- if(parent == NULL || name == NULL) return NULL;
+ if(parent == NULL || (type != NTYPE_CDATA && name == NULL)) return NULL;
/* If parent->firstchild is NULL, simply create a new node for the first child */
if (parent->firstchild == NULL)
@@ -100,18 +110,36 @@
return NULL;
}
-static char* _xmlnode_merge(pool p, char* dest, unsigned int destsize, const char* src, unsigned int srcsize)
+void _xmlnode_merge(xmlnode data)
{
- char* result;
- result = (char*)pmalloc(p, destsize + srcsize + 1);
- memcpy(result, dest, destsize);
- memcpy(result+destsize, src, srcsize);
- result[destsize + srcsize] = '\0';
+ xmlnode cur;
+ char *merge, *scur;
+ int imerge;
+
+ /* get total size of all merged cdata */
+ imerge = 0;
+ for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next)
+ imerge += cur->data_sz;
- /* WARNING: major ugly hack: since we're throwing the old data away, let's jump in the pool and subtract it from the size, this is for xmlstream's big-node checking */
- p->size -= destsize;
+ /* copy in current data and then spin through all of them and merge */
+ scur = merge = pmalloc(data->p,imerge + 1);
+ for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next)
+ {
+ memcpy(scur,cur->data,cur->data_sz);
+ scur += cur->data_sz;
+ }
+ *scur = '\0';
- return result;
+ /* this effectively hides all of the merged-in chunks */
+ data->next = cur;
+ if(cur == NULL)
+ data->parent->lastchild = data;
+ else
+ cur->prev = data;
+
+ /* reset data */
+ data->data = merge;
+ data->data_sz = imerge;
}
static void _xmlnode_hide_sibling(xmlnode child)
@@ -155,7 +183,7 @@
xmlnode tmp;
if(!node || xmlnode_get_type(node)!=NTYPE_TAG)
- return NULL;
+ return NULL;
s = spool_new(xmlnode_pool(node));
if(!s) return(NULL);
@@ -164,40 +192,34 @@
{
if(dir==0)
{
- if(xmlnode_get_type(node) == NTYPE_TAG)
- {
- if(xmlnode_has_children(node))
- {
- _xmlnode_tag2str(s,node,1);
- node = xmlnode_get_firstchild(node);
- level++;
- continue;
- }
- else
- {
- _xmlnode_tag2str(s,node,0);
- }
- }
- else
+ if(xmlnode_get_type(node) == NTYPE_TAG)
{
- spool_add(s,strescape(xmlnode_pool(node),xmlnode_get_data(node)));
- }
- }
+ if(xmlnode_has_children(node))
+ {
+ _xmlnode_tag2str(s,node,1);
+ node = xmlnode_get_firstchild(node);
+ level++;
+ continue;
+ }else{
+ _xmlnode_tag2str(s,node,0);
+ }
+ }else{
+ spool_add(s,strescape(xmlnode_pool(node),xmlnode_get_data(node)));
+ }
+ }
- tmp = xmlnode_get_nextsibling(node);
- if(!tmp)
+ tmp = xmlnode_get_nextsibling(node);
+ if(!tmp)
{
- node = xmlnode_get_parent(node);
- level--;
- if(level>=0) _xmlnode_tag2str(s,node,2);
- if(level<1) break;
- dir = 1;
- }
- else
- {
- node = tmp;
- dir = 0;
- }
+ node = xmlnode_get_parent(node);
+ level--;
+ if(level>=0) _xmlnode_tag2str(s,node,2);
+ if(level<1) break;
+ dir = 1;
+ }else{
+ node = tmp;
+ dir = 0;
+ }
}
return s;
@@ -260,8 +282,6 @@
/*
* xmlnode_insert_cdata -- append character data to a tag
- * If last child of the parent is CDATA, merges CDATA nodes. Otherwise
- * creates a CDATA node, and appends it to the parent's child list.
*
* parameters
* parent -- parent tag
@@ -283,22 +303,13 @@
if(size == -1)
size = strlen(CDATA);
- if ((parent->lastchild != NULL) && (parent->lastchild->type == NTYPE_CDATA))
- {
- result = parent->lastchild;
- result->data = _xmlnode_merge(result->p, result->data, result->data_sz, CDATA, size);
- result->data_sz = result->data_sz + size;
- }
- else
+ result = _xmlnode_insert(parent, NULL, NTYPE_CDATA);
+ if (result != NULL)
{
- result = _xmlnode_insert(parent, "", NTYPE_CDATA);
- if (result != NULL)
- {
- result->data = (char*)pmalloc(result->p, size + 1);
- memcpy(result->data, CDATA, size);
- result->data[size] = '\0';
- result->data_sz = size;
- }
+ result->data = (char*)pmalloc(result->p, size + 1);
+ memcpy(result->data, CDATA, size);
+ result->data[size] = '\0';
+ result->data_sz = size;
}
return result;
@@ -314,7 +325,8 @@
* "name/name" for a sub child (recurses)
* "?attrib" to match the first tag with that attrib defined
* "?attrib=value" to match the first tag with that attrib and value
- * or any combination: "name/name/?attrib", etc
+ * "=cdata" to match the cdata contents of the child
+ * or any combination: "name/name/?attrib", "name=cdata", etc
*
* results
* a pointer to the tag matching search criteria
@@ -325,17 +337,43 @@
char *str, *slash, *qmark, *equals;
xmlnode step, ret;
+
if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL;
- if(strstr(name, "/") == NULL && strstr(name,"?") == NULL)
+ if(strstr(name, "/") == NULL && strstr(name,"?") == NULL && strstr(name, "=") == NULL)
return _xmlnode_search(parent->firstchild, name, NTYPE_TAG);
- /* jer's note: why can't I modify the name directly, why do I have to strdup it? damn c grrr! */
str = strdup(name);
slash = strstr(str, "/");
qmark = strstr(str, "?");
equals = strstr(str, "=");
+ if(equals != NULL && (slash == NULL || equals < slash) && (qmark == NULL || equals < qmark))
+ { /* of type =cdata */
+
+ *equals = '\0';
+ equals++;
+
+ for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
+ {
+ if(xmlnode_get_type(step) != NTYPE_TAG)
+ continue;
+
+ if(*str != '\0')
+ if(j_strcmp(xmlnode_get_name(step),str) != 0)
+ continue;
+
+ if(j_strcmp(xmlnode_get_data(step),equals) != 0)
+ continue;
+
+ break;
+ }
+
+ free(str);
+ return step;
+ }
+
+
if(qmark != NULL && (slash == NULL || qmark < slash))
{ /* of type ?attrib */
@@ -528,33 +566,34 @@
char* xmlnode_get_data(xmlnode node)
{
- xmlnode cur;
+ if(xmlnode_get_type(node) == NTYPE_TAG) /* loop till we find a CDATA in the children */
+ for(node = xmlnode_get_firstchild(node); node != NULL; node = xmlnode_get_nextsibling(node))
+ if(xmlnode_get_type(node) == NTYPE_CDATA) break;
if(node == NULL) return NULL;
- if(xmlnode_get_type(node) == NTYPE_TAG) /* loop till we find a CDATA */
- {
- for(cur = xmlnode_get_firstchild(node); cur != NULL; cur = xmlnode_get_nextsibling(cur))
- if(xmlnode_get_type(cur) == NTYPE_CDATA)
- return cur->data;
- }else{
- return node->data;
- }
- return NULL;
+ /* check for a dirty node w/ unassembled cdata chunks */
+ if(xmlnode_get_type(node->next) == NTYPE_CDATA)
+ _xmlnode_merge(node);
+
+ return node->data;
}
int xmlnode_get_datasz(xmlnode node)
{
- if (node != NULL)
- return node->data_sz;
- return (int)NULL;
+ if(xmlnode_get_type(node) != NTYPE_CDATA) return 0;
+
+ /* check for a dirty node w/ unassembled cdata chunks */
+ if(xmlnode_get_type(node->next) == NTYPE_CDATA)
+ _xmlnode_merge(node);
+ return node->data_sz;
}
int xmlnode_get_type(xmlnode node)
{
if (node != NULL)
return node->type;
- return (int)NULL;
+ return NTYPE_UNDEF;
}
int xmlnode_has_children(xmlnode node)
--- a/mcabber/libjabber/xstream.c Thu Sep 01 21:18:19 2005 +0200
+++ b/mcabber/libjabber/xstream.c Thu Sep 01 23:29:21 2005 +0200
@@ -13,16 +13,37 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Jabber
- * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
+ * 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 xstream.c
+ * @brief handling of incoming XML stream based events
+ *
+ * xstream is a way to have a consistent method of handling incoming XML stream based events ...
+ * it doesn't handle the generation of an XML stream, but provides some facilities to help doing that
*/
#include <time.h>
#include <libxode.h>
-/* xstream is a way to have a consistent method of handling incoming XML Stream based events... it doesn't handle the generation of an XML Stream, but provides some facilities to help do that */
+/* ========== internal expat callbacks =========== */
-/******* internal expat callbacks *********/
+/**
+ * internal expat callback for read start tags of an element
+ */
void _xstream_startElement(xstream xs, const char* name, const char** atts)
{
pool p;
@@ -53,7 +74,9 @@
xs->status = XSTREAM_ERR;
}
-
+/**
+ * internal expat callback for read end tags of an element
+ */
void _xstream_endElement(xstream xs, const char* name)
{
xmlnode parent;
@@ -78,7 +101,9 @@
xs->depth--;
}
-
+/**
+ * internal expat callback for read CDATA
+ */
void _xstream_charData(xstream xs, const char *str, int len)
{
/* if xstream is bad, get outa here */
@@ -93,7 +118,11 @@
xmlnode_insert_cdata(xs->node, str, len);
}
-
+/**
+ * internal function to be registered as pool cleaner, frees a stream if the associated memory pool is freed
+ *
+ * @param pointer to the xstream to free
+ */
void _xstream_cleanup(void *arg)
{
xstream xs = (xstream)arg;
@@ -103,7 +132,14 @@
}
-/* creates a new xstream with given pool, xstream will be cleaned up w/ pool */
+/**
+ * creates a new xstream with given pool, xstream will be cleaned up w/ pool
+ *
+ * @param p the memory pool to use for the stream
+ * @param f function pointer to the event handler function
+ * @param arg parameter to pass to the event handler function
+ * @return the created xstream
+ */
xstream xstream_new(pool p, xstream_onNode f, void *arg)
{
xstream newx;
@@ -129,7 +165,14 @@
return newx;
}
-/* attempts to parse the buff onto this stream firing events to the handler, returns the last known status */
+/**
+ * attempts to parse the buff onto this stream firing events to the handler
+ *
+ * @param xs the xstream to parse the data on
+ * @param buff the new data
+ * @param len length of the data
+ * @return last known xstream status
+ */
int xstream_eat(xstream xs, char *buff, int len)
{
char *err;
@@ -174,11 +217,17 @@
/* STREAM CREATION UTILITIES */
-/* give a standard template xmlnode to work from */
+/** give a standard template xmlnode to work from
+ *
+ * @param namespace ("jabber:client", "jabber:server", ...)
+ * @param to where the stream is sent to
+ * @param from where we are (source of the stream)
+ * @return the xmlnode that has been generated as the template
+ */
xmlnode xstream_header(char *namespace, char *to, char *from)
{
xmlnode x;
- char id[10];
+ char id[11];
sprintf(id,"%X",(int)time(NULL));
@@ -195,14 +244,20 @@
return x;
}
-/* trim the xmlnode to only the opening header :) [NO CHILDREN ALLOWED] */
+/**
+ * trim the xmlnode to only the opening header :)
+ *
+ * @note NO CHILDREN ALLOWED
+ *
+ * @param x the xmlnode
+ * @return string representation of the start tag
+ */
char *xstream_header_char(xmlnode x)
{
spool s;
char *fixr, *head;
- if(xmlnode_has_children(x))
- {
+ if(xmlnode_has_children(x)) {
fprintf(stderr,"Fatal Programming Error: xstream_header_char() was sent a header with children!\n");
return NULL;
}