More Doxygen. API cleanup.
[vcard2ldap.git] / patch / patch-v2l-jabberd-2.1.14.diff
blob151e20daf1ba8816323263d1b37f72de2ba82aea
1 diff -Naurb jabberd-2.1.14.orig/configure.ac jabberd-2.1.14/configure.ac
2 --- jabberd-2.1.14.orig/configure.ac 2007-08-14 00:35:21.000000000 +0200
3 +++ jabberd-2.1.14/configure.ac 2007-08-23 03:37:44.000000000 +0200
4 @@ -733,6 +733,17 @@
5 fi
6 AM_CONDITIONAL(STORAGE_ANON, [test "x-$want_anon" = "x-yes"])
8 +######################
9 +# vCard <-> LDAP (Iris)
10 +AC_ARG_ENABLE(v2l, AC_HELP_STRING([--enable-v2l],
11 + [enable vCard LDAP storage support (no)]),
12 + want_v2l=$enableval, want_v2l=no)
13 +AM_CONDITIONAL(V2L, [test "x-$want_v2l" = "x-yes"])
15 +if test "x-$want_v2l" = "x-yes" ; then
16 + AC_MSG_NOTICE(vCard <-> LDAP support activated.)
17 +fi
18 +#####################
20 # Filesystem storage
21 AC_ARG_ENABLE(fs, AC_HELP_STRING([--enable-fs], [enable filesystem storage support (no)]),
22 diff -Naurb jabberd-2.1.14.orig/sm/Makefile.am jabberd-2.1.14/sm/Makefile.am
23 --- jabberd-2.1.14.orig/sm/Makefile.am 2007-06-17 17:13:17.000000000 +0200
24 +++ jabberd-2.1.14/sm/Makefile.am 2007-09-08 21:37:16.000000000 +0200
25 @@ -26,6 +26,10 @@
27 noinst_HEADERS = sm.h
29 +if V2L
30 +noinst_HEADERS += v2l_config.h v2l_conn.h v2l_vcard.h xmlnode.h
31 +endif
33 sm_SOURCES = aci.c \
34 dispatch.c \
35 feature.c \
36 @@ -98,6 +102,12 @@
37 mod_iq_vcard_la_LDFLAGS = -module -export-dynamic
38 mod_iq_vcard_la_LIBADD = $(top_builddir)/subst/libsubst.la
40 +if V2L
41 +mod_iq_vcard_la_SOURCES += v2l_config.c v2l_conn.c v2l_vcard.c xmlnode.c
42 +mod_iq_vcard_la_LIBADD += -lpthread -lexpat -lresolv -lldap -llber
43 +mod_iq_vcard_la_CPPFLAGS = -D_V2L_JABBER2
44 +endif
46 mod_iq_version_la_SOURCES = mod_iq_version.c
47 mod_iq_version_la_LDFLAGS = -module -export-dynamic
48 mod_iq_version_la_LIBADD = $(top_builddir)/subst/libsubst.la
49 diff -Naurb jabberd-2.1.14.orig/sm/mod_iq_vcard.c jabberd-2.1.14/sm/mod_iq_vcard.c
50 --- jabberd-2.1.14.orig/sm/mod_iq_vcard.c 2007-08-29 16:56:58.000000000 +0200
51 +++ jabberd-2.1.14/sm/mod_iq_vcard.c 2007-09-25 17:45:15.000000000 +0200
52 @@ -27,6 +27,23 @@
53 * $Revision: 1.25 $
56 +#ifdef _V2L_JABBER2
57 +#include <xmlnode.h>
58 +#include <v2l_config.h>
59 +#include <v2l_conn.h>
60 +#include <v2l_vcard.h>
62 +static v2l_Config *_v2l_get_config(config_t cfg) {
63 + static v2l_Config ldap_config = { NULL, NULL, NULL, LDAP_PORT, NULL,
64 + NULL, NULL, NULL };
66 + if(!cfg || ldap_config.master_conn)
67 + return &ldap_config;
69 + return v2l_config_init(&ldap_config, cfg) ? &ldap_config : NULL;
71 +#endif
73 #define uri_VCARD "vcard-temp"
74 static int ns_VCARD = 0;
76 @@ -100,8 +117,37 @@
77 char ekey[10], cdata[VCARD_MAX_FIELD_SIZE];
78 const char *vkey, *dkey, *vskey;
80 +#ifdef _V2L_JABBER2
81 + v2l_LdapConn *ldap_conn = NULL;
82 + v2l_Config *ldap_config;
84 + xmlnode vcard, node = NULL;
85 + char gtag[10], prev_gtag[10];
87 + gtag[0] = 0;
88 + prev_gtag[0] = 0;
89 +#endif
91 log_debug(ZONE, "building object from packet");
93 +#ifdef _V2L_JABBER2
94 + vcard = NULL; /* Warning */
95 + ldap_config = _v2l_get_config(pkt->sm->config);
97 + if(!ldap_config) {
98 + log_debug(ZONE, "Cannot connect to LDAP/V2L not configured");
99 + } else {
100 + ldap_conn = v2l_get_conn(ldap_config,
101 + (char *) (pkt->source->user->jid->node));
103 + if(ldap_conn)
104 + vcard = xmlnode_new_tag ("vCard");
105 + else
106 + log_debug(ZONE, "Unable to create connection for \"%s\" user",
107 + pkt->source->user->jid->node);
109 +#endif
111 os = os_new();
112 o = os_object_new(os);
114 @@ -115,12 +161,26 @@
115 if(vskey == NULL) {
116 vskey = vkey;
117 elem = 2;
118 +#ifdef _V2L_JABBER2
119 + gtag[0] = 0;
120 +#endif
121 } else {
122 sprintf(ekey, "%.*s", vskey - vkey, vkey);
123 elem = nad_find_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 2), ekey, 1);
124 if(elem < 0)
125 continue;
126 vskey++;
128 +#ifdef _V2L_JABBER2
129 + if(vcard) {
130 + strcpy(gtag, ekey);
132 + if(strcmp(gtag, prev_gtag)) {
133 + strcpy(prev_gtag, gtag);
134 + node = xmlnode_insert_tag(vcard, gtag);
137 +#endif
140 elem = nad_find_elem(pkt->nad, elem, NAD_ENS(pkt->nad, 2), vskey, 1);
141 @@ -131,27 +191,79 @@
143 snprintf(cdata, sizeof(cdata), "%.*s", NAD_CDATA_L(pkt->nad, elem), NAD_CDATA(pkt->nad, elem));
144 cdata[sizeof(cdata)-1] = '\0';
146 +#ifdef _V2L_JABBER2
147 + if(vcard) {
148 + xmlnode tmp;
150 + if (!gtag[0])
151 + node = vcard;
153 + tmp = xmlnode_insert_tag(node, vskey);
154 + xmlnode_insert_cdata(tmp, cdata, strlen(cdata));
156 +#endif
157 os_object_put(o, dkey, cdata, os_type_STRING);
160 +#ifdef _V2L_JABBER2
161 + if(vcard) {
162 + v2l_vcard_set(ldap_config, ldap_conn, vcard);
163 + xmlnode_free(vcard);
165 +#endif
167 return os;
170 +#ifndef _V2L_JABBER2
171 static pkt_t _iq_vcard_to_pkt(sm_t sm, os_t os) {
172 +#else
173 +static pkt_t _iq_vcard_to_pkt(sm_t sm, os_t os, const char *user) {
174 +#endif
175 pkt_t pkt;
176 os_object_t o;
177 int i = 0, elem;
178 char ekey[10], *dval;
179 const char *vkey, *dkey, *vskey;
181 +#ifdef _V2L_JABBER2
182 + v2l_LdapConn *ldap_conn = NULL;
183 + v2l_Config *ldap_config;
184 + xmlnode vcard, node = NULL;
185 +#endif
187 log_debug(ZONE, "building packet from object");
189 +#ifdef _V2L_JABBER2
190 + vcard = NULL; /* WARNING */
191 + ldap_config = _v2l_get_config(sm->config);
193 + if(!ldap_config) {
194 + log_debug(ZONE, "Cannot connect to LDAP/V2L not configured");
195 + } else {
196 + ldap_conn = v2l_get_conn(ldap_config, user);
198 + if(ldap_conn)
199 + vcard = v2l_vcard_get (ldap_config, ldap_conn);
200 + else
201 + log_debug(ZONE, "Unable to create connection for \"%s\" user",
202 + user);
204 +#endif
206 pkt = pkt_create(sm, "iq", "result", NULL, NULL);
207 nad_append_elem(pkt->nad, nad_add_namespace(pkt->nad, uri_VCARD, NULL), "vCard", 2);
209 +#ifdef _V2L_JABBER2
210 + if(!vcard) {
211 +#endif
212 if(!os_iter_first(os))
213 return pkt;
214 o = os_iter_object(os);
215 +#ifdef _V2L_JABBER2
217 +#endif
219 while(_iq_vcard_map[i] != NULL) {
220 vkey = _iq_vcard_map[i];
221 @@ -159,8 +271,15 @@
223 i += 2;
225 +#ifdef _V2L_JABBER2
226 + if(!vcard) {
227 +#endif
228 if(!os_object_get_str(os, o, dkey, &dval))
229 continue;
230 +#ifdef _V2L_JABBER2
231 + } else
232 + node = vcard;
233 +#endif
235 vskey = strchr(vkey, '/');
236 if(vskey == NULL) {
237 @@ -172,14 +291,30 @@
238 if(elem < 0)
239 elem = nad_append_elem(pkt->nad, NAD_ENS(pkt->nad, 2), ekey, 3);
240 vskey++;
241 +#ifdef _V2L_JABBER2
242 + if(vcard)
243 + node = xmlnode_get_tag(node, ekey);
244 +#endif
247 +#ifdef _V2L_JABBER2
248 + if(vcard) {
249 + node = xmlnode_get_tag(node, vskey);
250 + dval = node ? xmlnode_get_data(node) : "";
252 +#endif
254 log_debug(ZONE, "extracted dbkey %s val '%s' for vcard key %s", dkey, dval, vkey);
256 nad_append_elem(pkt->nad, NAD_ENS(pkt->nad, 2), vskey, pkt->nad->elems[elem].depth + 1);
257 nad_append_cdata(pkt->nad, dval, strlen(dval), pkt->nad->elems[elem].depth + 2);
260 +#ifdef _V2L_JABBER2
261 + if(vcard)
262 + xmlnode_free(vcard);
263 +#endif
265 return pkt;
268 @@ -212,7 +347,11 @@
269 return mod_HANDLED;
271 case st_SUCCESS:
272 +#ifndef _V2L_JABBER2
273 result = _iq_vcard_to_pkt(sess->user->sm, os);
274 +#else
275 + result = _iq_vcard_to_pkt(sess->user->sm, os, sess->jid->node);
276 +#endif
277 os_free(os);
279 nad_set_attr(result->nad, 1, -1, "type", "result", 6);
280 @@ -283,7 +422,11 @@
281 return -stanza_err_SERVICE_UNAVAILABLE;
283 case st_SUCCESS:
284 +#ifndef _V2L_JABBER2
285 result = _iq_vcard_to_pkt(user->sm, os);
286 +#else
287 + result = _iq_vcard_to_pkt(user->sm, os, user->jid->node);
288 +#endif
289 os_free(os);
291 result->to = jid_dup(pkt->from);
292 @@ -315,6 +458,10 @@
293 static void _iq_vcard_free(module_t mod) {
294 sm_unregister_ns(mod->mm->sm, uri_VCARD);
295 feature_unregister(mod->mm->sm, uri_VCARD);
297 +#ifdef _VL2
298 + v2l_config_shutdown(_v2l_get_config(NULL));
299 +#endif
302 DLLEXPORT int module_init(mod_instance_t mi, char *arg) {
303 diff -Naurb jabberd-2.1.14.orig/sm/v2l_config.c jabberd-2.1.14/sm/v2l_config.c
304 --- jabberd-2.1.14.orig/sm/v2l_config.c 1970-01-01 01:00:00.000000000 +0100
305 +++ jabberd-2.1.14/sm/v2l_config.c 2007-09-26 23:51:26.000000000 +0200
306 @@ -0,0 +1,176 @@
308 + * This program is free software; you can redistribute it and/or modify
309 + * it under the terms of the GNU General Public License as published by
310 + * the Free Software Foundation; either version 2 of the License, or
311 + * (at your option) any later version.
313 + * This program is distributed in the hope that it will be useful,
314 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
315 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
316 + * GNU General Public License for more details.
318 + * You should have received a copy of the GNU General Public License
319 + * along with this program; if not, write to the Free Software
320 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
321 + */
323 +/*! \file v2l_config.c
324 + \brief Config handling functions. Implementation
327 +#include <stdlib.h>
328 +#include <strings.h>
330 +#ifndef _V2L_JABBER2
331 +#include <jabberd.h>
332 +#else
333 +#include "../util/util.h"
335 +#define log_warn log_debug
336 +#define log_error log_debug
337 +typedef pool_t pool;
338 +#endif
340 +#include <v2l_config.h>
341 +#include <v2l_conn.h>
343 +/*! \brief Gets value for tag from config
344 + Generic (preprocessor) function for handling Jabberd14/2 config differences
346 +static char *_v2l_config_get_tag (T_CONF conn_base, const char *tag);
348 +int
349 +v2l_config_init (v2l_Config *self, T_CONF cfgroot)
351 + T_CONF conn_base;
352 + const char *portstr;
354 + if (!cfgroot)
356 + log_error(ZONE, "xdb_v2l configuration not present");
357 + return 0;
360 +#ifndef _V2L_JABBER2
361 + /* Have a look in the XML configuration data for connection information. */
362 + conn_base = xmlnode_get_tag (cfgroot, "connection");
364 + if (conn_base == NULL)
366 + log_error(ZONE,"<connection> tag is not present");
367 + return 0;
369 +#else
370 + conn_base = cfgroot;
371 +#endif
373 + self->host = _v2l_config_get_tag (conn_base, "host");
375 + if (self->host == NULL)
377 + log_error (ZONE, "LDAP server is not specified");
378 + return 0;
381 + portstr = _v2l_config_get_tag (conn_base, "port");
382 + self->port = portstr != NULL ? atoi (portstr) : LDAP_PORT;
384 + self->suffix = _v2l_config_get_tag (conn_base, "suffix");
386 + if (self->suffix == NULL)
388 + log_error (ZONE, "LDAP suffix is not specified");
389 + return 0;
392 + self->uniqattr = _v2l_config_get_tag (conn_base, "uniqattr");
394 + if (self->uniqattr == NULL)
396 + log_error (ZONE, "LDAP unique attribute is not specified");
397 + return 0;
400 + self->binddn = _v2l_config_get_tag (conn_base, "binddn");
402 + if (self->binddn == NULL)
404 + log_error (ZONE, "LDAP jabber admin dn is not specified");
405 + return 0;
408 + self->bindpw = _v2l_config_get_tag (conn_base, "bindpw");
410 + if (self->bindpw == NULL)
412 + log_error (ZONE,
413 + "LDAP jabber admin password is not specified");
414 + return 0;
417 + self->confpath = _v2l_config_get_tag (conn_base, "tpl");
419 + if (self->confpath == NULL)
421 + log_error (ZONE,
422 + "Path to vCard <->LDAP is not specified");
423 + return 0;
426 + self->poolref = pool_new ();
428 + if (self->poolref == NULL)
430 + log_error (ZONE, "Cannot create pool");
431 + return 0;
434 + /* Get a handle to an LDAP connection. */
435 + log_debug (ZONE, "LDAP server: %s / port : %d", self->host, self->port);
437 + self->master_conn = v2l_get_master_conn (self);
439 + if (self->master_conn == NULL)
441 + log_error (ZONE,
442 + "Unable to create the LDAP main connection");
443 + return 0;
446 + return 1;
449 +void
450 +v2l_config_shutdown (v2l_Config *self)
452 + if (self != NULL && self->master_conn != NULL)
454 + v2l_free_allconn ();
455 + ldap_unbind_s (self->master_conn->ld);
456 + pool_free (self->master_conn->poolref);
457 + pool_free (self->poolref);
461 +/* public api ends here */
463 +static char *
464 +_v2l_config_get_tag (T_CONF conn_base, const char *tag)
466 +#ifndef _V2L_JABBER2
467 + xmlnode tmp;
469 + tmp = xmlnode_get_tag (conn_base, tag);
471 + if (tmp == NULL)
473 + return NULL;
476 + return (char *) xmlnode_get_data (xmlnode_get_firstchild (tmp));
477 +#else
478 + char str[32] = "v2l.";
480 + return config_get_one (conn_base, strncat (str, tag, 27), 0);
481 +#endif
483 diff -Naurb jabberd-2.1.14.orig/sm/v2l_config.h jabberd-2.1.14/sm/v2l_config.h
484 --- jabberd-2.1.14.orig/sm/v2l_config.h 1970-01-01 01:00:00.000000000 +0100
485 +++ jabberd-2.1.14/sm/v2l_config.h 2007-09-27 01:05:30.000000000 +0200
486 @@ -0,0 +1,73 @@
488 + * This program is free software; you can redistribute it and/or modify
489 + * it under the terms of the GNU General Public License as published by
490 + * the Free Software Foundation; either version 2 of the License, or
491 + * (at your option) any later version.
493 + * This program is distributed in the hope that it will be useful,
494 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
495 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
496 + * GNU General Public License for more details.
498 + * You should have received a copy of the GNU General Public License
499 + * along with this program; if not, write to the Free Software
500 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
501 + */
503 +/*! \file v2l_config.h
504 + \brief Config handling functions.
507 +#ifndef __V2L_CONFIG_H
508 +#define __V2L_CONFIG_H
510 +/*! Forward declaration */
511 +typedef struct v2l_LdapConn* v2l_LdapConnPtr;
513 +/*! The username associated with the master connection */
514 +#define V2L_ADMIN "jabberadmin"
516 +/*! \brief Type of the jabberd global config.
517 + 'xmlnode' for jabberd14, 'config_t' por jabberd2
519 +#ifdef _V2L_JABBER2
520 +#define T_CONF config_t
521 +#else
522 +#define T_CONF xmlnode
523 +#endif
525 +/*! \brief VCard2LDAP configuration.
526 + Shared config for the module API.
528 +typedef struct v2l_Config
530 +#ifndef _V2L_JABBER2
531 + xmlnode config; /*! reference to config file (jabber14) */
532 +#endif
533 + pool poolref;
534 + v2l_LdapConnPtr master_conn; /*! root connection to LDAP */
535 + char *host; /*!< LDAP hostname */
536 + int port; /*!< LDAP port */
537 + char *suffix; /*!< LDAP root dn */
538 + char *uniqattr; /*!< unique attr used to retrieve/set objects */
539 + char *binddn; /*!< dn used for "master" connections */
540 + char *bindpw; /*!< pw used for "master" connections */
541 + char *confpath; /*!< path to the translation template */
542 +} v2l_Config;
544 +/*! \brief Reads global config and initialize module config.
545 + \pre jabberd config exists and it's valid.
546 + \post all fields of self are set.
547 + \param self Module config.
548 + \param cfgroot Global config. T_CONF type.
549 + \return 1 if no error, otherwise returns 0.
551 +extern int v2l_config_init (v2l_Config *self, T_CONF cfgroot);
553 +/*! \brief Shutdown function, closes all connections and frees mempools.
554 + \pre self != NULL and self->master_conn is open.
555 + \post self->master_conn closed, all pools freeds.
556 + \param self Module config.
558 +extern void v2l_config_shutdown (v2l_Config *self);
559 +#endif
560 diff -Naurb jabberd-2.1.14.orig/sm/v2l_conn.c jabberd-2.1.14/sm/v2l_conn.c
561 --- jabberd-2.1.14.orig/sm/v2l_conn.c 1970-01-01 01:00:00.000000000 +0100
562 +++ jabberd-2.1.14/sm/v2l_conn.c 2007-09-27 01:47:13.000000000 +0200
563 @@ -0,0 +1,875 @@
565 + * This program is free software; you can redistribute it and/or modify
566 + * it under the terms of the GNU General Public License as published by
567 + * the Free Software Foundation; either version 2 of the License, or
568 + * (at your option) any later version.
570 + * This program is distributed in the hope that it will be useful,
571 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
572 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
573 + * GNU General Public License for more details.
575 + * You should have received a copy of the GNU General Public License
576 + * along with this program; if not, write to the Free Software
577 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
578 + */
580 +/*! \file v2l_conn.c
581 + \brief Handling the LDAP directory. Implementation
584 +#include <stdlib.h>
586 +#ifndef _V2L_JABBER2
587 +#include <jabberd.h>
588 +#else
589 +#include <pthread.h>
590 +#include "../util/util.h"
592 +#define log_warn log_debug
593 +#define log_error log_debug
594 +typedef pool_t pool;
595 +#endif
597 +#include <v2l_conn.h>
599 +/*! \brief Lifetime of an ephemeral connection, in seconds
600 + The recall connections thread period.
602 +#define V2L_CONN_LIFETIME 30
604 +/*! How often thread checks for LDAP results, in seconds */
605 +#define V2L_POLL_INTERVAL 1
607 +#define LOG_ERROR_MEM log_error(ZONE, "Unable to allocate memory")
609 +/*! Global hashtable of all currently active LDAP connections */
610 +static xht V2L_CONN_LIST = NULL;
612 +/*! \brief Creates new LDAP connection
613 + \param host LDAP hostname.
614 + \param port LDAP port.
615 + \param binddn Bind DN.
616 + \param user User name.
617 + \param passwd User password.
618 + \param expire Boolean, ephemeral connection?
619 + \return LDAP connectior or NULL if error.
621 +static v2l_LdapConn *_v2l_create_conn (char *host, int port, const char *binddn,
622 + const char *user, const char *passwd, int expire);
624 +/*! \brief Gets user password
625 + Retrieves user password from LDAP directory using master connection.
626 + \note Allocated memory must be freed by the caller.
627 + \param self Module config.
628 + \param user User name.
629 + \pre self is valid, user is not NULL
630 + \return user password string or NULL if doesn't exist or error.
632 +static char *_v2l_ldap_get_passwd (v2l_Config *self, const char *user);
634 +/*! \brief Closes and frees a connection.
635 + Utility function, common code for two hash walker functions.
636 + \param h Jabberd hash. Hash table "username"->connection.
637 + \param user User name.
638 + \param val deference pointer to connection.
639 + \sa _v2l_free_walker
640 + \sa _v2l_free_expired_walker
642 +static void _v2l_free_conn (xht h, const char *user, void *val);
644 +/*! \brief Gets the number or attributes in a LDAP request.
645 + \param[in,out] req The SLL of LDAP requests.
646 + \return number of attributes, 0 if req is NULL.
648 +static int _v2l_count_attrs (v2l_LdapRequest *req);
650 +/*! \brief Modifies an entry in the LDAP directory
651 + Utility function.
652 + \param dn Entry bind DN
653 + \param attrs List of attributes changed.
654 + \param[in,out] evt_res Control and info parameter.
655 + \return LDAP error code.
657 +static int _v2l_ldap_modify (char *dn, LDAPMod **attrs, v2l_LdapEvt *evt_res);
659 +/*! \brief Searchs and retrieves an entry from the LDAP directory
660 + Utility function.
661 + \param dn Entry bind DN.
662 + \param suffix LDAP suffix
663 + \param[out] attrs Entry attributes.
664 + \param subtree boolean. Search in a one level or in entire subtree?
665 + \param[in,out] evt_res Control and info parameter.
666 + \return LDAP error code.
668 +static int _v2l_ldap_search (char *dn, char *suffix, char **attrs, int subtree,
669 + v2l_LdapEvt *evt_res);
671 +/*! \brief Waits for LDAP results
672 + Operations on the directory are asynchronous. This is a sync wait function.
673 + \param \param[in,out] evt_res Control and info parameter.
675 +static void _v2l_ldap_sync (v2l_LdapEvt *evt_res);
677 +/*! \brief Adds LDAP attr to request.
678 + Utility function, hides OpenLDAP API to upper level.
679 + \param[in,out] req The SLL of LDAP requests.
680 + \param attr The attr, LDAPMod pointer.
681 + \return The list of requests + the last added. The list of request if error.
683 +static v2l_LdapRequest *_v2l_add_attr (v2l_LdapRequest *req, LDAPMod *attr);
685 +/*! \brief Adds a conn to the global list.
686 + If list is empty, initializes it and starts the thread who recalls expired
687 + connections.
688 + \param ldap_conn New connection.
690 +static void _v2l_add_conn (v2l_LdapConn *ldap_conn);
692 +/*! \brief Frees connection unconditionally.
693 + Utility function. Hash walker function.
694 + See jabberd API for details.
696 +static void _v2l_free_walker (xht h, const char *key, void *val,
697 + void *arg);
699 +/*! \brief Frees connections when its slice time expired (periodic thread)
700 + \dot
701 + digraph G {
702 + rankdir = LR
703 + node [shape = ellipse, fontname = Helvetica fontsize = 12]
704 + {node[style = filled, fontsize = 16, bgcolor = grey] sleep}
705 + {node[shape = circle, label = delete] free}
706 + {node[label = "expired?" ] is_expired}
707 + {node[label = "conn left?" ] any_conn}
708 + sleep -> sleep
709 + sleep -> any_conn [label = " "]
710 + any_conn -> sleep [label = no]
711 + any_conn -> is_expired [label = yes]
712 + is_expired -> free [label = yes]
713 + is_expired -> any_conn [label = no]
714 + free -> any_conn
716 + \enddot
717 + \param arg Unused.
719 +static void *_v2l_purge_conn_callback (void *arg);
721 +/*! \brief Frees expired connections.
722 + Utility function. Hash walker function.
723 + See jabberd API for details.
725 +static void _v2l_free_expired_walker (xht h, const char *key, void *val,
726 + void *arg);
728 +/*! A thread for active wait for LDAP results */
729 +static int _v2l_ldap_wait_callback(void *arg);
731 +#ifdef _V2L_JABBER2
732 +static void *_v2l_ldap_wait_callback_g (void *arg);
733 +#endif
735 +/* public api */
737 +v2l_LdapConn *
738 +v2l_get_conn (v2l_Config *self, const char *user)
740 + v2l_LdapConn *user_conn;
742 + user_conn = (v2l_LdapConn *) xhash_get (V2L_CONN_LIST, user);
744 + if(user_conn == NULL)
746 + char *passwd, *binddn;
748 + /* Get the user password for connecting him to LDAP server */
749 + passwd = _v2l_ldap_get_passwd (self, user);
751 + /* user exists? */
752 + if (passwd == NULL)
754 + log_error (ZONE, "User \"%s\" not found in the directory", user);
755 + return NULL;
758 + binddn = (char *) malloc (sizeof(char) * (strlen (self->suffix) +
759 + strlen (self->uniqattr) + strlen (user) + 3));
761 + if (binddn == NULL)
763 + LOG_ERROR_MEM;
764 + free (passwd);
765 + return NULL;
768 + sprintf (binddn, "%s=%s,%s", self->uniqattr, user, self->suffix);
770 + log_debug (ZONE, "Attempting to connect with DN: %s", binddn);
772 + user_conn = _v2l_create_conn (self->host, self->port, binddn, user,
773 + passwd, 1);
775 + free (passwd);
776 + free (binddn);
778 + } /* user_conn == NULL */
780 + return user_conn;
783 +v2l_LdapConn *
784 +v2l_get_master_conn (v2l_Config *self)
786 + return _v2l_create_conn (self->host, self->port, self->binddn, V2L_ADMIN,
787 + self->bindpw, 0);
790 +void
791 +v2l_free_allconn ()
793 + xhash_walk (V2L_CONN_LIST, _v2l_free_walker, NULL);
794 + xhash_free (V2L_CONN_LIST);
797 +v2l_LdapEvt *
798 +v2l_ldap_get_entry (v2l_Config *self, v2l_LdapConn *curr_conn)
800 + v2l_LdapEvt *evt_res;
801 + int rc;
803 + evt_res = (v2l_LdapEvt *) malloc (sizeof (v2l_LdapEvt));
805 + if (evt_res == NULL)
807 + LOG_ERROR_MEM;
808 + return NULL;
811 + evt_res->ld = curr_conn->ld;
813 + rc = _v2l_ldap_search (curr_conn->entry, self->suffix, NULL, 1, evt_res);
815 + if (rc != LDAP_SUCCESS)
817 + log_error (ZONE, "LDAP error attempting to retrieve user info: %s",
818 + ldap_err2string (rc));
819 + free (evt_res);
820 + return NULL;
823 + _v2l_ldap_sync(evt_res);
825 + if (ldap_count_entries (evt_res->ld, evt_res->result) != 1)
827 + log_warn (ZONE, "Multiple users with the same dn?");
828 + free (evt_res);
829 + return NULL;
832 + return evt_res;
835 +int
836 +v2l_request_record (v2l_Config *self, v2l_LdapConn *curr_conn,
837 + v2l_LdapRequest *req)
839 + LDAPMod **attrs;
840 + int i, nbmod, ret;
841 + v2l_LdapRequest *cur_req, *cur_temp;
842 + v2l_LdapEvt *evt_res;
844 + if (req == NULL)
846 + log_warn (ZONE, "LDAP request is NULL? I cannot record anything");
847 + return 1;
850 + nbmod = _v2l_count_attrs (req);
852 + attrs = (LDAPMod **) malloc ((nbmod + 1) * sizeof (LDAPMod *));
854 + if (attrs == NULL)
856 + LOG_ERROR_MEM;
857 + return 0;
860 + /* to wait for the results */
861 + evt_res = (v2l_LdapEvt *) malloc (sizeof (v2l_LdapEvt));
863 + if (evt_res == NULL)
865 + LOG_ERROR_MEM;
866 + free (attrs);
867 + return 0;
870 + for (i = 0; i < nbmod; i++)
872 + attrs[i] = (LDAPMod *) malloc (sizeof (LDAPMod));
874 + if (attrs[i] == NULL)
876 + while (--i >= 0)
878 + free (attrs[i]);
881 + LOG_ERROR_MEM;
882 + free (attrs);
883 + free (evt_res);
884 + return 0;
888 + for (cur_req = req, i = 0; i < nbmod; cur_req = cur_req->next, i++)
890 + memcpy (attrs[i], cur_req->attr, sizeof (LDAPMod));
891 + log_debug (ZONE, "Element \"%s\" (%d) in the LDAP request: %s",
892 + attrs[i]->mod_type, i, attrs[i]->mod_values[0]);
895 + attrs[nbmod] = NULL;
897 + log_debug (ZONE, "LDAP attempting to modify \"%s\" with dn \"%s\"",
898 + curr_conn->user, curr_conn->binddn);
900 + evt_res->ld = curr_conn->ld;
901 + evt_res->rc = _v2l_ldap_modify (curr_conn->binddn, attrs, evt_res);
902 + ret = evt_res->rc == LDAP_SUCCESS;
904 + if (!ret)
906 + log_error (ZONE, "LDAP error attempting to modify user info: %s",
907 + ldap_err2string (evt_res->rc));
909 + else
911 + _v2l_ldap_sync (evt_res);
914 + ldap_msgfree (evt_res->result);
915 + free (evt_res);
917 + for (cur_req = req, i = 0; i < nbmod; i++)
919 + cur_temp = cur_req;
920 + cur_req = cur_req->next;
922 + free (attrs[i]);
923 + free (cur_temp->attr->mod_values[0]);
924 + free (cur_temp->attr->mod_values);
925 + free (cur_temp->attr);
926 + free (cur_temp);
929 + free (attrs);
931 + return ret;
934 +v2l_LdapRequest *
935 +v2l_add_attr_str (v2l_LdapRequest *req, const char *attr, const char *str)
937 + LDAPMod *mod;
939 + mod = (LDAPMod *) malloc (sizeof (LDAPMod));
941 + if (mod == NULL)
943 + return NULL;
946 + mod->mod_op = LDAP_MOD_REPLACE;
947 + mod->mod_type = (char *) attr;
949 + mod->mod_values = (char **) malloc (2 * sizeof (char *));
951 + if (mod->mod_values == NULL)
953 + free (mod);
954 + return NULL;
957 + mod->mod_values[0] = (char *) malloc (strlen (str) + 1);
959 + if (mod->mod_values[0] == NULL)
961 + free (mod->mod_values);
962 + free (mod);
963 + return NULL;
966 + memcpy (mod->mod_values[0], str, strlen (str) + 1);
967 + mod->mod_values[1] = NULL;
969 + return _v2l_add_attr (req, mod);
972 +/* public api ends here */
974 +static v2l_LdapConn *
975 +_v2l_create_conn (char *host, int port, const char *binddn, const char *user,
976 + const char *passwd, int expire)
978 + LDAP *ld;
979 + v2l_LdapConn *ldap_conn;
980 + int version; /* LDAP protocol version */
981 + int rc;
982 + pool poolref;
984 + ld = ldap_init (host, port);
986 + if (ld == NULL)
988 + log_error (ZONE, "Unable to init LDAP");
989 + return NULL;
992 + /* XXX */
993 + version = LDAP_VERSION3;
994 + /***/
996 + ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version);
997 + rc = ldap_simple_bind_s (ld, binddn, passwd);
999 + if (rc != LDAP_SUCCESS)
1001 + log_error (ZONE,
1002 + "LDAP simple bind error : %s", ldap_err2string (rc));
1003 + return NULL;
1006 + poolref = pool_new ();
1008 + if (poolref == NULL)
1010 + LOG_ERROR_MEM;
1011 + ldap_unbind_s (ld);
1012 + return NULL;
1015 + ldap_conn = (v2l_LdapConn *) pmalloc (poolref, sizeof (v2l_LdapConn));
1017 + if (ldap_conn == NULL)
1019 + LOG_ERROR_MEM;
1020 + ldap_unbind_s (ld);
1021 + pool_free(poolref);
1022 + return NULL;
1025 + ldap_conn->poolref = poolref;
1026 + ldap_conn->ld = ld;
1028 + ldap_conn->binddn = (char *) pmalloc (ldap_conn->poolref,
1029 + strlen (binddn) + 1);
1031 + if (ldap_conn->binddn == NULL)
1033 + LOG_ERROR_MEM;
1034 + ldap_unbind_s (ld);
1035 + pool_free(poolref);
1036 + return NULL;
1039 + strcpy (ldap_conn->binddn, binddn);
1041 + ldap_conn->entry = (char *) pmalloc (ldap_conn->poolref, strlen (binddn) + 1);
1043 + if (ldap_conn->entry == NULL)
1045 + LOG_ERROR_MEM;
1046 + ldap_unbind_s (ld);
1047 + pool_free(poolref);
1048 + return NULL;
1051 + strcpy (ldap_conn->entry, binddn);
1052 + strtok (ldap_conn->entry, ", ");
1054 + ldap_conn->user = (char *) pmalloc (ldap_conn->poolref, strlen (user) + 1);
1056 + if (ldap_conn->user == NULL)
1058 + LOG_ERROR_MEM;
1059 + ldap_unbind_s (ld);
1060 + pool_free(poolref);
1061 + return NULL;
1064 + strcpy (ldap_conn->user, user);
1066 + ldap_conn->creation_time = time (NULL); /* timestamp */
1068 + if (expire == 1) /* Add it to V2L_CONN_LIST */
1070 + _v2l_add_conn (ldap_conn);
1073 + return ldap_conn;
1076 +static char *
1077 +_v2l_ldap_get_passwd(v2l_Config *self, const char *user)
1079 + LDAPMessage *e;
1080 + v2l_LdapEvt *evt_res;
1081 + char *data, *filter, **vals, *attrs[2] = {"userPassword", NULL};
1083 + evt_res = (v2l_LdapEvt *) malloc(sizeof(v2l_LdapEvt));
1085 + if (evt_res == NULL)
1087 + LOG_ERROR_MEM;
1088 + return NULL;
1091 + filter = (char *) malloc (strlen (self->uniqattr) + strlen (user) + 2);
1093 + if (filter == NULL)
1095 + LOG_ERROR_MEM;
1096 + free (evt_res);
1097 + return NULL;
1100 + sprintf(filter, "%s=%s", self->uniqattr, user);
1101 + evt_res->ld = self->master_conn->ld;
1103 + evt_res->rc = _v2l_ldap_search (filter, self->suffix, attrs, 0, evt_res);
1104 + free (filter);
1106 + if (evt_res->rc != LDAP_SUCCESS)
1108 + log_error(ZONE,
1109 + "LDAP error attempting to retrieve \"%s\"'s password: %s",
1110 + user, ldap_err2string (evt_res->rc));
1111 + free (evt_res);
1112 + return NULL;
1115 + _v2l_ldap_sync (evt_res);
1116 + data = NULL;
1118 + if (ldap_count_entries(evt_res->ld, evt_res->result) == 1)
1120 + e = ldap_first_entry(evt_res->ld, evt_res->result);
1121 + vals = ldap_get_values(evt_res->ld, e, "userPassword");
1123 + if (vals == NULL)
1125 + log_debug(ZONE, "User has no password!");
1126 + data = (char *) malloc(sizeof(char));
1128 + if (data == NULL)
1130 + LOG_ERROR_MEM;
1131 + ldap_msgfree(evt_res->result);
1132 + free(evt_res);
1133 + return NULL;
1136 + data[0] = 0;
1138 + else
1140 + data = (char *) malloc(sizeof(char) * (strlen(vals[0]) + 1));
1142 + if (data != NULL)
1144 + strcpy(data, vals[0]);
1147 + ldap_value_free(vals);
1150 + ldap_msgfree(evt_res->result);
1153 + free(evt_res);
1154 + return data;
1157 +static int
1158 +_v2l_ldap_modify (char *dn, LDAPMod **attrs, v2l_LdapEvt *evt_res)
1160 + return ldap_modify_ext (evt_res->ld, dn, attrs, NULL, NULL,
1161 + &(evt_res->msgid));
1164 +static int
1165 +_v2l_ldap_search (char *dn, char *suffix, char **attrs, int subtree,
1166 + v2l_LdapEvt *evt_res)
1168 + int scope;
1170 + scope = subtree ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_ONELEVEL;
1172 + return ldap_search_ext (evt_res->ld, suffix, scope,
1173 + dn, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
1174 + &(evt_res->msgid));
1177 +static void
1178 +_v2l_ldap_sync (v2l_LdapEvt *evt_res)
1180 +#ifndef _V2L_JABBER2
1181 + pth_event_t evt;
1183 + evt = pth_event (PTH_EVENT_FUNC, &_v2l_ldap_wait_callback,
1184 + (void *) evt_res, pth_time (V2L_POLL_INTERVAL, 0));
1185 + pth_wait (evt);
1186 +#else
1187 + pthread_t thr;
1188 + int rc;
1190 + rc = pthread_create(&thr, NULL, _v2l_ldap_wait_callback_g, (void *) evt_res);
1192 + if (rc != 0)
1194 + log_error (ZONE, "Thread create failed: %d", rc);
1195 + return;
1198 + pthread_join(thr, NULL);
1199 +#endif
1202 +/*! Count the number of LDAPMod in the structure */
1203 +static int
1204 +_v2l_count_attrs (v2l_LdapRequest *req)
1206 + v2l_LdapRequest *ptr;
1207 + int nbmod;
1209 + for (nbmod = 0, ptr = req; ptr != NULL; ptr = ptr->next, nbmod++);
1211 + return nbmod;
1214 +static v2l_LdapRequest *
1215 +_v2l_add_attr (v2l_LdapRequest *req, LDAPMod *attr)
1217 + if (attr == NULL)
1219 + log_warn (ZONE, "LDAP attribute is NULL? I cannot add anything");
1220 + return NULL;
1223 + if (req == NULL)
1225 + req = (v2l_LdapRequest *) malloc (sizeof (v2l_LdapRequest));
1227 + if (req == NULL)
1229 + LOG_ERROR_MEM;
1230 + return NULL;
1233 + req->attr = attr;
1234 + req->next = NULL;
1236 + else
1238 + v2l_LdapRequest *ptr;
1239 + v2l_LdapRequest *new_req;
1241 + new_req = (v2l_LdapRequest *) malloc (sizeof (v2l_LdapRequest));
1243 + if (new_req == NULL)
1245 + LOG_ERROR_MEM;
1246 + return NULL;
1249 + new_req->attr = attr;
1250 + new_req->next = NULL;
1252 + for (ptr = req; ptr->next != NULL; ptr = ptr->next);
1254 + ptr->next = new_req;
1257 + return req;
1260 +static int
1261 +_v2l_ldap_wait_callback(void *arg)
1263 + v2l_LdapEvt *evt_res = (v2l_LdapEvt *) arg;
1264 + LDAPMessage *result;
1265 + int rc;
1267 + rc = ldap_result (evt_res->ld, evt_res->msgid, 1, NULL, &result);
1269 + if (rc == -1)
1271 + log_error(ZONE, "LDAP result error %s",
1272 + ldap_err2string(rc));
1273 + evt_res->result = NULL;
1274 + evt_res->rc = -1;
1275 + return 1;
1278 + if ((rc == LDAP_RES_ADD)
1279 + || (rc == LDAP_RES_MODIFY)
1280 + || (rc == LDAP_RES_SEARCH_RESULT)
1281 + || (rc == LDAP_RES_SEARCH_ENTRY)
1282 + || (rc == LDAP_RES_DELETE))
1284 + evt_res->result = result;
1285 + evt_res->rc = rc;
1286 + return 1;
1289 + return 0; /* still waiting */
1292 +#ifdef _V2L_JABBER2
1293 +static void *
1294 +_v2l_ldap_wait_callback_g (void *arg)
1296 + while (!_v2l_ldap_wait_callback (arg))
1298 + sleep (V2L_POLL_INTERVAL);
1301 + return NULL;
1303 +#endif
1305 +static void
1306 +_v2l_free_walker (xht h, const char *key, void *val, void *arg)
1308 + _v2l_free_conn (h, key, val);
1311 +static void
1312 +_v2l_free_conn (xht h, const char *user, void *val)
1314 + v2l_LdapConn *temp_conn = (v2l_LdapConn *) val;
1316 + log_debug (ZONE, "Freeing LDAP connection for user \"%s\"", user);
1318 + xhash_zap (h, user);
1319 + ldap_unbind_s (temp_conn->ld);
1320 + pool_free (temp_conn->poolref);
1323 +static void
1324 +_v2l_free_expired_walker (xht h, const char *key, void *val, void *arg)
1326 + v2l_LdapConn *temp_conn = (v2l_LdapConn *) val;
1328 + /* kill connections older than V2L_CONN_LIFETIME */
1329 + if ((time (NULL) - temp_conn->creation_time) > (time_t) V2L_CONN_LIFETIME)
1331 + _v2l_free_conn (h, key, val);
1335 +static void *
1336 +_v2l_purge_conn_callback (void *arg)
1338 + log_debug (ZONE, "Checking connections lifetime");
1340 + while (1)
1342 + /* V2L_CONN_LIST has been freed? */
1343 + if (V2L_CONN_LIST != NULL)
1345 + xhash_walk (V2L_CONN_LIST, _v2l_free_expired_walker, NULL);
1347 +#ifndef _V2L_JABBER2
1348 + pth_sleep (V2L_CONN_LIFETIME);
1349 +#else
1350 + sleep (V2L_CONN_LIFETIME);
1351 +#endif
1354 + return NULL;
1357 +static void
1358 +_v2l_add_conn (v2l_LdapConn *ldap_conn)
1360 +#ifndef _V2L_JABBER2
1361 + pth_attr_t attr;
1362 +#else
1363 + pthread_t thr;
1364 + pthread_attr_t attr;
1365 + int rc;
1366 +#endif
1368 + if (V2L_CONN_LIST == NULL)
1371 + log_debug (ZONE, "V2L_CONN_LIST hashtable is not initialized yet");
1373 + V2L_CONN_LIST = xhash_new (509);
1375 + /* spawn the thread which deletes expired connections */
1376 +#ifndef _V2L_JABBER2
1377 + attr = pth_attr_new ();
1378 + pth_attr_set (attr, PTH_ATTR_JOINABLE, FALSE);
1379 + pth_spawn (attr, _v2l_purge_conn_callback, NULL);
1380 + pth_attr_destroy (attr);
1381 +#else
1382 + pthread_attr_init(&attr);
1383 + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1385 + rc = pthread_create (&thr, &attr, _v2l_purge_conn_callback, NULL);
1386 + pthread_attr_destroy(&attr);
1388 + if (rc != 0)
1390 + log_error (ZONE, "Thread create failed: %d", rc);
1392 +#endif
1395 + xhash_put (V2L_CONN_LIST, ldap_conn->user, (void *) ldap_conn);
1398 +void
1399 +v2l_ldap_for_all_attrs(v2l_AttrValueFunction value_func,
1400 + v2l_AttrMatchFunction match_func, void *pointer, v2l_LdapEvt *evt_res)
1402 + LDAPMessage *current_result;
1403 + BerElement *ber;
1404 + char *current_attr, **vals;
1405 + void *shrdata;
1407 + current_result = ldap_first_entry (evt_res->ld, evt_res->result);
1408 + current_attr = ldap_first_attribute (evt_res->ld, current_result, &ber);
1410 + /* step through each attribute in objectclass */
1411 + for (;
1412 + current_attr != NULL;
1413 + current_attr = ldap_next_attribute (evt_res->ld, current_result, ber))
1416 + if (match_func (current_attr, &shrdata))
1418 + vals = ldap_get_values (evt_res->ld, current_result, current_attr);
1419 + value_func (current_attr, (const char **) vals, pointer, shrdata);
1421 + if (vals != NULL)
1423 + ldap_value_free (vals);
1427 + ldap_memfree (current_attr);
1428 + } /* attributes loop */
1430 + if (ber != NULL)
1432 + ber_free (ber, 0);
1435 + /* don't forget to free the next attribute */
1436 + ldap_memfree (current_attr);
1437 + ldap_msgfree (evt_res->result);
1439 diff -Naurb jabberd-2.1.14.orig/sm/v2l_conn.h jabberd-2.1.14/sm/v2l_conn.h
1440 --- jabberd-2.1.14.orig/sm/v2l_conn.h 1970-01-01 01:00:00.000000000 +0100
1441 +++ jabberd-2.1.14/sm/v2l_conn.h 2007-09-27 01:03:26.000000000 +0200
1442 @@ -0,0 +1,143 @@
1444 + * This program is free software; you can redistribute it and/or modify
1445 + * it under the terms of the GNU General Public License as published by
1446 + * the Free Software Foundation; either version 2 of the License, or
1447 + * (at your option) any later version.
1449 + * This program is distributed in the hope that it will be useful,
1450 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1451 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1452 + * GNU General Public License for more details.
1454 + * You should have received a copy of the GNU General Public License
1455 + * along with this program; if not, write to the Free Software
1456 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1457 + */
1459 +/*! \file v2l_conn.h
1460 + \brief Handling the LDAP directory. Low-level tier.
1463 +#ifndef __V2L_CONN_H
1464 +#define __V2L_CONN_H
1466 +#include <ldap.h>
1467 +#include <time.h>
1469 +#include <v2l_config.h>
1471 +/*! \brief Simple Linked List of connections to LDAP directory */
1472 +typedef struct v2l_LdapConn
1474 + pool poolref;
1475 + LDAP *ld; /*!< LDAP descriptor */
1476 + time_t creation_time; /*!< timestamp */
1477 + char *binddn; /*!< complete dn */
1478 + char *entry; /*!< short dn */
1479 + char *user; /*!< username */
1480 + struct v2l_LdapConn *next;
1481 +} v2l_LdapConn;
1483 +/*! \brief Request (SLL) for LDAP directory */
1484 +typedef struct v2l_LdapRequest
1486 + LDAPMod *attr;
1487 + struct v2l_LdapRequest *next;
1488 +} v2l_LdapRequest;
1490 +/*! \brief LDAP environment.
1491 + Control struct for perform operations on the LDAP directory and retrieve
1492 + results.
1494 +typedef struct v2l_LdapEvt
1496 + LDAP *ld; /*!< LDAP descriptor */
1497 + int msgid; /*!< LDAP message id (see OpenLDAP API docs) */
1498 + int rc; /*!< LDAP error code */
1499 + LDAPMessage *result; /*!< LDAP result (see OpenLDAP API docs) */
1500 +} v2l_LdapEvt;
1502 +/*! \brief Match function type
1503 + Generic attribute matching routine.
1504 + \param attr The attribute.
1505 + \param[out] shrdata Generic deferenced pointer. Shared data with a 'value
1506 + function'
1507 + \sa v2l_AttrValueFunction
1508 + \sa v2l_ldap_for_all_attrs
1509 + \return true if matching, otherwise false.
1511 +typedef int (*v2l_AttrMatchFunction) (const char *attr, void **shrdata);
1513 +/*! \brief Values read function type
1514 + Generic values handling routine.
1515 + \param attr The attribute.
1516 + \param vals Values of attribute.
1517 + \param pointer Generic multipurpose pointer.
1518 + \param shrdata Shared data with 'match function'
1519 + \sa v2l_MatchValueFunction
1520 + \sa v2l_ldap_for_all_attrs
1522 +typedef void (*v2l_AttrValueFunction) (const char *attr, const char **vals,
1523 + void *pointer, void *shrdata);
1525 +/*! \brief Gets a (ephemeral) connection by name. Creates one if doesn't exist.
1526 + \pre self is valid, user is not null and exists.
1527 + \post ephermeral connection for user is open.
1528 + \param self Module config.
1529 + \param user the username
1530 + \return the connection if no error, otherwise NULL.
1532 +extern v2l_LdapConn *v2l_get_conn (v2l_Config *self, const char *user);
1534 +/*! \brief Gets a connection master connection. Creates one if doesn't exist.
1535 + \pre self is valid
1536 + \post master connection is open.
1537 + \param self Module config.
1538 + \return the connection if no error, otherwise NULL.
1540 +extern v2l_LdapConn *v2l_get_master_conn (v2l_Config *self);
1542 +/*! \brief Frees and closes all connections (ephemeral or not)
1543 + If connections doesn't exist does nothing.
1544 + \post self->master_conn closed. Connections list empty.
1546 +extern void v2l_free_allconn ();
1548 +/*! \brief Retrieves an user entry from the LDAP directory
1549 + \note Allocated memory must be freed by the caller.
1550 + \param self Module config
1551 + \param curr_conn user connection.
1552 + \return evt_res LDAP descriptor, control code and result. NULL if error.
1554 +extern v2l_LdapEvt *v2l_ldap_get_entry (v2l_Config *self,
1555 + v2l_LdapConn *curr_conn);
1557 +/*! \brief Executes a list of changes on the LDAP directory.
1558 + \pre req is not NULL
1559 + \param self Module config
1560 + \param curr_conn The user connection.
1561 + \param req list of changes.
1562 + \return 1 if no error, otherwise 0
1564 +extern int v2l_request_record (v2l_Config *self, v2l_LdapConn *curr_conn,
1565 + v2l_LdapRequest *req);
1567 +/*! \brief Adds a new request to the list
1568 + \param req The list of requests.
1569 + \param attr attribute name.
1570 + \param str attribute value.
1571 + \return The list of requests + the last added. The list of request if error.
1573 +extern v2l_LdapRequest *v2l_add_attr_str (v2l_LdapRequest *req,
1574 + const char *attr, const char *str);
1576 +/*! \brief Applies a function to all LDAP object attributes.
1577 + \pre evt_res should be a valid entry (ie. result of a search in directory)
1578 + \param value_func Walker function.
1579 + \param match_func Match function. If returns true we'll call to value_func
1580 + \param pointer Generic multipurpose pointer. It will be passed to value_func
1581 + \param evt_res LDAP descriptor, control code and result.
1583 +extern void v2l_ldap_for_all_attrs (v2l_AttrValueFunction value_func,
1584 + v2l_AttrMatchFunction match_func, void *pointer, v2l_LdapEvt *evt_res);
1585 +#endif
1586 diff -Naurb jabberd-2.1.14.orig/sm/v2l_vcard.c jabberd-2.1.14/sm/v2l_vcard.c
1587 --- jabberd-2.1.14.orig/sm/v2l_vcard.c 1970-01-01 01:00:00.000000000 +0100
1588 +++ jabberd-2.1.14/sm/v2l_vcard.c 2007-09-26 23:46:59.000000000 +0200
1589 @@ -0,0 +1,588 @@
1591 + * This program is free software; you can redistribute it and/or modify
1592 + * it under the terms of the GNU General Public License as published by
1593 + * the Free Software Foundation; either version 2 of the License, or
1594 + * (at your option) any later version.
1596 + * This program is distributed in the hope that it will be useful,
1597 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1598 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1599 + * GNU General Public License for more details.
1601 + * You should have received a copy of the GNU General Public License
1602 + * along with this program; if not, write to the Free Software
1603 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1604 + */
1606 +/*! \file v2l_vcard.c
1607 + \brief XML vCard's to/from LDAP objects translation functions.
1608 + Implementation
1611 +#include <stdlib.h>
1613 +#ifndef _V2L_JABBER2
1614 +#include <jabberd.h>
1615 +#else
1616 +#include "../util/util.h"
1617 +#include <xmlnode.h>
1619 +#define log_warn log_debug
1620 +#define log_error log_debug
1622 +#endif
1623 +#include <v2l_vcard.h>
1625 +#define LOG_ERROR_MEM log_error(ZONE, "Unable to allocate memory")
1627 +/*! \brief vCard template item.
1628 + SLL. All of relations tag<->LDAP attr read from template
1630 +typedef struct v2l_vCardItem
1632 + char *vcard; /*!< tag name */
1633 + char *ldap; /*!< LDAP attribute */
1634 + char *group; /*!< XML parent of the tag */
1635 + struct v2l_vCardItem *next;
1636 +} v2l_vCardItem;
1638 +/*! \brief Gets the translation map.
1639 + If it is not initilized yet, the function reads the template from disk
1640 + and sets the map.
1641 + \param self Module config, if map is initialized can be NULL.
1642 + \return The map, NULL if error.
1644 +static v2l_vCardItem *_v2l_vcard_map (v2l_Config *self);
1646 +/*! \brief Creates the FN tag
1647 + Creates FN tag from GIVEN and FAMILY tags.
1648 + \param vcard The vCard.
1649 + \return 1 if no error, otherwise 0.
1651 +static int _v2l_create_fn (xmlnode vcard);
1653 +/*! \brief Sets sn1 and sn2 from sn
1654 + Hack. IrisPerson has two surnames: first surname and mother's maiden name.
1655 + This function splits sn in two. Should be called when the list of request
1656 + are complete and before program excutes them.
1657 + \param req The SLL of LDAP requests.
1659 +static v2l_LdapRequest *_v2l_set_sn12 (v2l_LdapRequest *req);
1661 +/*! \brief Map function from LDAP to XML vCard
1662 + \param item Info about the tag (name, parent group and attribute associated)
1663 + \param vals array of values for the attribe.
1664 + \param[in,out] res The vCard, output is appended here.
1665 + \return res + new tag or res if error.
1667 +static xmlnode _v2l_ldap2vcard_generic (v2l_vCardItem *item, const char **vals,
1668 + xmlnode res);
1670 +/*! \brief Function for maps PHOTO tag.
1671 + Hack. InetOrgPerson has a jpegphoto attribute so PHOTO/MIMETYPE tag can be
1672 + only "image/jpeg"
1673 + \warning The module doesn't support storing avatars in another format (png)
1675 +static xmlnode _v2l_ldap2vcard_photo (v2l_vCardItem *item, const char **vals,
1676 + xmlnode res);
1678 +/*! \brief Map function from XML Vcard to LDAP
1679 + \param item Info about the tag (name, parent group and attribute associated)
1680 + \param data Thhe vCard.
1681 + \param[in,out] req List of requests, the new request is appended here.
1682 + \return req + new request or req if error.
1684 +static v2l_LdapRequest *_v2l_vcard2ldap_generic (v2l_vCardItem *item,
1685 + xmlnode data, v2l_LdapRequest *req);
1687 +/*! \brief Finds tag linked to attr
1688 + Parses the translation map since 'item' node.
1689 + \param item Where the search starts.
1690 + \param attr The attribute;
1691 + \return node with tag<->attr association or NULL if error or not found.
1693 +static v2l_vCardItem *_v2l_vcard_find_attr (v2l_vCardItem *item,
1694 + const char *attr);
1696 +/*! \brief Is LDAP object attribute linked to any tag?
1697 + Utility function.
1698 + \param attr The attribute.
1699 + \param[out] shrdata Contents the address of any map's node. NULL if no match
1700 + \return true if attr is linked to any tag, otherwise false
1702 +static int _v2l_vcard_attr_match (const char *attr, void **shrdata);
1704 +/*! \brief Function applied to all attrs.
1705 + Utility function, walker function.
1706 + \param attr The attribute.
1707 + \param vals Values of attribute.
1708 + \param pointer Deferenced pointer to vCard.
1709 + \param shrdata Data shared with the match function.
1711 +static void _v2l_vcard_attr_value (const char *attr, const char **vals,
1712 + void *pointer, void *shrdata);
1714 +#if 0
1715 +static v2l_vCardItem *
1716 + _v2l_vcard_find_tag (v2l_vCardItem *item, char *tag);
1717 +#endif
1719 +/*! List of all XML vCard tags supported */
1720 +static const char *_V2L_MAP_VCARD [] = {
1721 + "FN",
1722 + "NICKNAME",
1723 + "URL",
1724 + "TEL/NUMBER",
1725 + "EMAIL/USERID",
1726 + "TITLE",
1727 + "ROLE",
1728 + "BDAY",
1729 + "DESC",
1730 + "N/FAMILY",
1731 + "N/GIVEN",
1732 + "N/MIDDLE",
1733 + "N/PREFIX",
1734 + "N/SUFFIX",
1735 + "ADR/STREET",
1736 + "ADR/POBOX",
1737 + "ADR/EXTADD",
1738 + "ADR/LOCALITY",
1739 + "ADR/REGION",
1740 + "ADR/PCODE",
1741 + "ADR/CTRY",
1742 + "ORG/ORGNAME",
1743 + "ORG/ORGUNIT",
1745 + "TZ",
1746 + "GEO/LAT",
1747 + "GEO/LON",
1748 + "AGENT/EXTVAL",
1749 + "NOTE",
1750 + "REV",
1751 + "SORT-STRING",
1753 + "KEY/TYPE",
1754 + "KEY/CRED",
1756 + "PHOTO/TYPE",
1757 + "PHOTO/BINVAL",
1758 + "PHOTO/EXTVAL",
1760 + "LOGO/TYPE",
1761 + "LOGO/BINVAL",
1762 + "LOGO/EXTVAL",
1764 + "SOUND/PHONETIC",
1765 + "SOUND/BINVAL",
1766 + "SOUND/EXTVAL",
1768 + NULL
1771 +/* public api */
1772 +xmlnode
1773 +v2l_vcard_get (v2l_Config *self, v2l_LdapConn *curr_conn)
1775 + xmlnode vcard;
1776 + v2l_LdapEvt *evt_res;
1778 + if (_v2l_vcard_map (self) == NULL)
1780 + log_error (ZONE, "Unreadable/malformed vCard template!");
1781 + return NULL;
1784 + /* get user info from LDAP */
1785 + evt_res = v2l_ldap_get_entry (self, curr_conn);
1787 + if (evt_res == NULL)
1789 + return NULL;
1792 + /* prepare the XML result */
1793 + vcard = xmlnode_new_tag ("vCard");
1794 + xmlnode_put_attrib (vcard, "xmlns", "vcard-temp");
1796 + v2l_ldap_for_all_attrs (_v2l_vcard_attr_value, _v2l_vcard_attr_match, vcard,
1797 + evt_res);
1799 + free (evt_res);
1800 + _v2l_create_fn (vcard);
1802 + return vcard;
1805 +int
1806 +v2l_vcard_set (v2l_Config *self, v2l_LdapConn *curr_conn, xmlnode data)
1808 + xmlnode node;
1809 + v2l_LdapRequest *ldap_req = NULL;
1810 + v2l_vCardItem *item;
1812 + if (data == NULL)
1814 + log_warn (ZONE, "vCard data is NULL?");
1815 + return 0;
1818 + item = _v2l_vcard_map (self);
1820 + if (item == NULL)
1822 + log_error (ZONE, "Unreadable/Malformed vCard template!");
1823 + return 0;
1826 + do
1828 + if (strcmp (item->vcard, "FN") == 0) /* FIXME: ugly */
1830 + goto is_fn;
1833 + if (item->group != NULL)
1835 + char tag[30];
1837 + sprintf (tag, "%s/%s", item->group, item->vcard);
1838 + node = xmlnode_get_tag (data, tag);
1840 + else
1842 + node = xmlnode_get_tag (data, item->vcard);
1845 + if (node != NULL)
1847 + ldap_req = _v2l_vcard2ldap_generic (item, node, ldap_req);
1849 +is_fn:
1850 + item = item->next;
1851 + } while (item != NULL);
1853 + ldap_req = _v2l_set_sn12 (ldap_req);
1855 + return v2l_request_record (self, curr_conn, ldap_req);
1858 +/* public api ends here */
1860 +static v2l_vCardItem *
1861 +_v2l_vcard_map (v2l_Config *self)
1863 + static v2l_vCardItem *_V2L_TPL = NULL;
1864 + xmlnode tpl, tag;
1865 + char **stag, *tmp, group[10];
1866 + v2l_vCardItem *item;
1868 + if (_V2L_TPL == NULL && self != NULL && self->confpath != NULL)
1870 + tpl = xmlnode_file (self->confpath);
1872 + if (tpl == NULL)
1874 + return NULL;
1877 + for (stag = (char **) _V2L_MAP_VCARD; *stag != NULL; stag++)
1879 + tmp = strchr(*stag, '/');
1881 + if (tmp == NULL)
1883 + group[0] = 0;
1884 + tmp = *stag;
1886 + else
1888 + sprintf(group, "%.*s", tmp - *stag, *stag);
1889 + tmp++;
1892 + tag = xmlnode_get_tag (tpl, *stag);
1894 + if (xmlnode_get_data(tag) != NULL)
1896 + int ntags = 0;
1897 + char find_attr[30];
1899 + do
1901 + v2l_vCardItem *ptr;
1903 + ptr = (v2l_vCardItem *) pmalloc (self->poolref,
1904 + sizeof(v2l_vCardItem));
1906 + ptr->vcard = tmp;
1907 + ptr->ldap = pstrdup (self->poolref, xmlnode_get_data(tag));
1908 + ptr->next = NULL;
1909 + ptr->group = group[0] == 0 ? NULL :
1910 + pstrdup (self->poolref, group);
1912 + if (_V2L_TPL == NULL)
1914 + _V2L_TPL = ptr;
1915 + item = ptr;
1917 + else
1919 + item->next = ptr;
1920 + item = item->next;
1923 + sprintf (find_attr, "%s?v2ln=%d", *stag, ++ntags);
1924 + tag = xmlnode_get_tag (tpl, find_attr);
1925 + } while (tag && xmlnode_get_data (tag) != NULL && ntags < 10);
1926 + }/* xmlnode_get_data(tag) != NULL */
1927 + } /* for loop, all tags in template */
1929 + xmlnode_free (tpl);
1932 + return _V2L_TPL;
1935 +#if 0
1936 +static v2l_vCardItem *
1937 +_v2l_vcard_find_tag (v2l_vCardItem *item, char *tag)
1939 + v2l_vCardItem *res = NULL;
1941 + while (item != NULL)
1943 + if (strcmp (item->vcard, tag) == 0)
1945 + res = item;
1946 + break;
1949 + item = item->next;
1952 + return res;
1954 +#endif
1956 +static v2l_vCardItem *
1957 +_v2l_vcard_find_attr (v2l_vCardItem *item, const char *attr)
1959 + v2l_vCardItem *res = NULL;
1961 + while (item != NULL)
1963 + if (strcmp (item->ldap, attr) == 0)
1965 + res = item;
1966 + break;
1969 + item = item->next;
1972 + return res;
1975 +static int
1976 +_v2l_vcard_attr_match (const char *attr, void **shrdata)
1978 + *shrdata = _v2l_vcard_find_attr (_v2l_vcard_map (NULL), attr);
1980 + return *shrdata != NULL;
1983 +static void
1984 +_v2l_vcard_attr_value (const char *attr, const char **vals, void *pointer,
1985 + void *shrdata)
1987 + xmlnode vcard;
1988 + v2l_vCardItem *match;
1990 + vcard = (xmlnode) pointer;
1991 + match = (v2l_vCardItem *) shrdata;
1993 + if (vals != NULL)
1995 + /* FIXME: ugly */
1996 + if (match->group != NULL && (strcmp (match->group, "PHOTO") == 0))
1998 + _v2l_ldap2vcard_photo (match, vals, vcard);
2000 + else
2002 + _v2l_ldap2vcard_generic (match, vals, vcard);
2007 +static int
2008 +_v2l_create_fn (xmlnode vcard)
2010 + xmlnode n, fn;
2011 + char *family, *given, *fn_str;
2012 + int len;
2014 + fn = xmlnode_insert_tag (vcard, "FN");
2015 + n = xmlnode_get_tag (vcard, "N");
2016 + family = xmlnode_get_tag_data (n, "FAMILY");
2017 + given = xmlnode_get_tag_data (n, "GIVEN");
2019 + len = 0;
2020 + len += (family != NULL) ? strlen (family) : 0;
2021 + len += (given != NULL) ? strlen (given) : 0;
2023 + if (len == 0)
2025 + log_debug (ZONE, "<fn><n>...</n></fn> is empty, returning");
2026 + return 1;
2029 + fn_str = (char *) malloc (sizeof (char) * (len + 2));
2031 + if (fn_str == NULL)
2033 + LOG_ERROR_MEM;
2034 + return 0;
2037 + fn_str[0] = 0;
2039 + if (family != NULL)
2041 + sprintf (fn_str, "%s ", family);
2044 + if (given != NULL)
2046 + strcat (fn_str, given);
2049 + xmlnode_insert_cdata (fn, fn_str, len + 1);
2050 + free (fn_str);
2052 + return 1;
2055 +/* LDAP -> vCard */
2057 +static xmlnode
2058 +_v2l_ldap2vcard_generic (v2l_vCardItem *item, const char **vals, xmlnode res)
2060 + xmlnode node;
2062 + if (item->group != NULL)
2064 + node = xmlnode_get_tag (res, item->group);
2066 + if (node == NULL)
2068 + node = xmlnode_insert_tag(res, item->group);
2071 + else
2073 + node = res;
2076 + node = xmlnode_insert_tag (node, item->vcard);
2077 + xmlnode_insert_cdata (node, vals[0], strlen (vals[0]));
2079 + return res;
2082 +static xmlnode
2083 +_v2l_ldap2vcard_photo (v2l_vCardItem *item, const char **vals, xmlnode res)
2085 + xmlnode mimetype, photo;
2087 + res = _v2l_ldap2vcard_generic (item, vals, res);
2089 + /* FIXME: mimetype is hardcoded */
2090 + photo = xmlnode_get_tag (res, "PHOTO");
2091 + mimetype = xmlnode_insert_tag (photo, "TYPE");
2092 + xmlnode_insert_cdata (mimetype, "image/jpeg", sizeof ("image/jpeg"));
2094 + return res;
2097 +/* vCard -> LDAP */
2099 +static v2l_LdapRequest *
2100 +_v2l_vcard2ldap_generic (v2l_vCardItem *item, xmlnode data,
2101 + v2l_LdapRequest *req)
2103 + const char *str;
2105 + str = xmlnode_get_data (data);
2107 + return str == NULL ? req : v2l_add_attr_str (req, item->ldap, str);
2110 +static v2l_LdapRequest *
2111 +_v2l_set_sn12 (v2l_LdapRequest *req)
2113 + if (req != NULL)
2115 + v2l_LdapRequest *ptr;
2116 + char *sn;
2118 + for (ptr = req, sn = NULL; ptr != NULL; ptr = ptr->next)
2120 + if (strcmp (ptr->attr->mod_type, "sn") == 0)
2122 + sn = ptr->attr->mod_values[0];
2123 + break;
2127 + if (sn != NULL)
2129 + char *sit, *sn1, *sn2;
2131 + for (sit = sn; *sit != ' ' && *sit != 0; sit++);
2133 + sn1 = (char *) malloc (sizeof (char) * (sit - sn + 1));
2135 + if (sn1 == NULL)
2137 + return req;
2140 + strncpy (sn1, sn, sizeof (char) * (sit - sn));
2141 + sn1[sit - sn] = 0;
2142 + ptr = v2l_add_attr_str (req, "sn1", sn1);
2143 + free (sn1);
2145 + if (ptr == NULL)
2147 + return req;
2150 + req = ptr;
2152 + if (sit - sn != strlen (sn))
2154 + sn2 = (char *) malloc (strlen (sit) + 1);
2156 + if (sn2 == NULL)
2158 + LOG_ERROR_MEM;
2159 + return req;
2162 + strcpy (sn2, sit);
2163 + ptr = v2l_add_attr_str (req, "sn2", sn2);
2164 + free (sn2);
2166 + if (ptr == NULL)
2168 + return req;
2171 + req = ptr;
2173 + } /* sn != NULL */
2174 + } /* req != NULL */
2176 + return req;
2178 diff -Naurb jabberd-2.1.14.orig/sm/v2l_vcard.h jabberd-2.1.14/sm/v2l_vcard.h
2179 --- jabberd-2.1.14.orig/sm/v2l_vcard.h 1970-01-01 01:00:00.000000000 +0100
2180 +++ jabberd-2.1.14/sm/v2l_vcard.h 2007-09-26 23:52:13.000000000 +0200
2181 @@ -0,0 +1,41 @@
2183 + * This program is free software; you can redistribute it and/or modify
2184 + * it under the terms of the GNU General Public License as published by
2185 + * the Free Software Foundation; either version 2 of the License, or
2186 + * (at your option) any later version.
2188 + * This program is distributed in the hope that it will be useful,
2189 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2190 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2191 + * GNU General Public License for more details.
2193 + * You should have received a copy of the GNU General Public License
2194 + * along with this program; if not, write to the Free Software
2195 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2196 + */
2198 +/*! \file v2l_vcard.h
2199 + \brief XML vCard's to/from LDAP objects translation functions.
2202 +#ifndef __V2L_VCARD_H
2203 +#define __V2L_VCARD_H
2205 +#include <v2l_conn.h>
2207 +/*! \brief Gets user vCard in xml format
2208 + \param self Module config
2209 + \param curr_conn user connection.
2210 + \return vCard main node, NULL if error.
2212 +extern xmlnode v2l_vcard_get (v2l_Config *self, v2l_LdapConn *curr_conn);
2214 +/*! \brief Writes vCard to user LDAP directory entry.
2215 + \param self Module config
2216 + \param curr_conn user connection.
2217 + \param data the vCard
2218 + \return 1 if no error, otherwise 0
2220 +extern int v2l_vcard_set (v2l_Config *self, v2l_LdapConn *curr_conn,
2221 + xmlnode data);
2222 +#endif
2223 diff -Naurb jabberd-2.1.14.orig/sm/xmlnode.c jabberd-2.1.14/sm/xmlnode.c
2224 --- jabberd-2.1.14.orig/sm/xmlnode.c 1970-01-01 01:00:00.000000000 +0100
2225 +++ jabberd-2.1.14/sm/xmlnode.c 2007-09-25 17:45:15.000000000 +0200
2226 @@ -0,0 +1,1029 @@
2227 +/* --------------------------------------------------------------------------
2229 + * License
2231 + * The contents of this file are subject to the Jabber Open Source License
2232 + * Version 1.0 (the "JOSL"). You may not copy or use this file, in either
2233 + * source code or executable form, except in compliance with the JOSL. You
2234 + * may obtain a copy of the JOSL at http://www.jabber.org/ or at
2235 + * http://www.opensource.org/.
2237 + * Software distributed under the JOSL is distributed on an "AS IS" basis,
2238 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL
2239 + * for the specific language governing rights and limitations under the
2240 + * JOSL.
2242 + * Copyrights
2244 + * Portions created by or assigned to Jabber.com, Inc. are
2245 + * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact
2246 + * information for Jabber.com, Inc. is available at http://www.jabber.com/.
2248 + * Portions Copyright (c) 1998-1999 Jeremie Miller.
2250 + * Acknowledgements
2252 + * Special thanks to the Jabber Open Source Contributors for their
2253 + * suggestions and support of Jabber.
2255 + * Alternatively, the contents of this file may be used under the terms of the
2256 + * GNU General Public License Version 2 or later (the "GPL"), in which case
2257 + * the provisions of the GPL are applicable instead of those above. If you
2258 + * wish to allow use of your version of this file only under the terms of the
2259 + * GPL and not to allow others to use your version of this file under the JOSL,
2260 + * indicate your decision by deleting the provisions above and replace them
2261 + * with the notice and other provisions required by the GPL. If you do not
2262 + * delete the provisions above, a recipient may use your version of this file
2263 + * under either the JOSL or the GPL.
2266 + * --------------------------------------------------------------------------*/
2268 +#include "../util/util.h"
2269 +#include "xmlnode.h"
2271 +#include <sys/types.h>
2272 +#include <sys/stat.h>
2273 +#include <fcntl.h>
2275 +/* Internal routines */
2276 +xmlnode _xmlnode_new(pool p, const char* name, unsigned int type)
2278 + xmlnode result = NULL;
2279 + if (type > NTYPE_LAST)
2280 + return NULL;
2282 + if (type != NTYPE_CDATA && name == NULL)
2283 + return NULL;
2285 + if (p == NULL)
2287 + p = pool_heap(1*1024);
2290 + /* Allocate & zero memory */
2291 + result = (xmlnode)pmalloco(p, sizeof(_xmlnode));
2293 + /* Initialize fields */
2294 + if (type != NTYPE_CDATA)
2295 + result->name = pstrdup(p,name);
2296 + result->type = type;
2297 + result->p = p;
2298 + return result;
2301 +static xmlnode _xmlnode_append_sibling(xmlnode lastsibling, const char* name, unsigned int type)
2303 + xmlnode result;
2305 + result = _xmlnode_new(xmlnode_pool(lastsibling), name, type);
2306 + if (result != NULL)
2308 + /* Setup sibling pointers */
2309 + result->prev = lastsibling;
2310 + lastsibling->next = result;
2312 + return result;
2315 +static xmlnode _xmlnode_insert(xmlnode parent, const char* name, unsigned int type)
2317 + xmlnode result;
2319 + if(parent == NULL || (type != NTYPE_CDATA && name == NULL)) return NULL;
2321 + /* If parent->firstchild is NULL, simply create a new node for the first child */
2322 + if (parent->firstchild == NULL)
2324 + result = _xmlnode_new(parent->p, name, type);
2325 + parent->firstchild = result;
2327 + /* Otherwise, append this to the lastchild */
2328 + else
2330 + result= _xmlnode_append_sibling(parent->lastchild, name, type);
2332 + result->parent = parent;
2333 + parent->lastchild = result;
2334 + return result;
2338 +static xmlnode _xmlnode_search(xmlnode firstsibling, const char* name, unsigned int type)
2340 + xmlnode current;
2342 + /* Walk the sibling list, looking for a NTYPE_TAG xmlnode with
2343 + the specified name */
2344 + current = firstsibling;
2345 + while (current != NULL)
2347 + if ((current->type == type) && (j_strcmp(current->name, name) == 0))
2348 + return current;
2349 + else
2350 + current = current->next;
2352 + return NULL;
2355 +void _xmlnode_merge(xmlnode data)
2357 + xmlnode cur;
2358 + char *merge, *scur;
2359 + int imerge;
2361 + /* get total size of all merged cdata */
2362 + imerge = 0;
2363 + for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next)
2364 + imerge += cur->data_sz;
2366 + /* copy in current data and then spin through all of them and merge */
2367 + scur = merge = pmalloc(data->p,imerge + 1);
2368 + for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next)
2370 + memcpy(scur,cur->data,cur->data_sz);
2371 + scur += cur->data_sz;
2373 + *scur = '\0';
2375 + /* this effectively hides all of the merged-in chunks */
2376 + data->next = cur;
2377 + if(cur == NULL)
2378 + data->parent->lastchild = data;
2379 + else
2380 + cur->prev = data;
2382 + /* reset data */
2383 + data->data = merge;
2384 + data->data_sz = imerge;
2388 +static void _xmlnode_hide_sibling(xmlnode child)
2390 + if(child == NULL)
2391 + return;
2393 + if(child->prev != NULL)
2394 + child->prev->next = child->next;
2395 + if(child->next != NULL)
2396 + child->next->prev = child->prev;
2399 +void _xmlnode_tag2str(spool s, xmlnode node, int flag)
2401 + xmlnode tmp;
2403 + if(flag==0 || flag==1)
2405 + spooler(s,"<",xmlnode_get_name(node),s);
2406 + tmp = xmlnode_get_firstattrib(node);
2407 + while(tmp) {
2408 + spooler(s," ",xmlnode_get_name(tmp),"='",strescape(xmlnode_pool(node),xmlnode_get_data(tmp), strlen(xmlnode_get_data(tmp))),"'",s);
2409 + tmp = xmlnode_get_nextsibling(tmp);
2411 + if(flag==0)
2412 + spool_add(s,"/>");
2413 + else
2414 + spool_add(s,">");
2416 + else
2418 + spooler(s,"</",xmlnode_get_name(node),">",s);
2422 +spool _xmlnode2spool(xmlnode node)
2424 + spool s;
2425 + int level=0,dir=0;
2426 + xmlnode tmp;
2428 + if(!node || xmlnode_get_type(node)!=NTYPE_TAG)
2429 + return NULL;
2431 + s = spool_new(xmlnode_pool(node));
2432 + if(!s) return(NULL);
2434 + while(1)
2436 + if(dir==0)
2438 + if(xmlnode_get_type(node) == NTYPE_TAG)
2440 + if(xmlnode_has_children(node))
2442 + _xmlnode_tag2str(s,node,1);
2443 + node = xmlnode_get_firstchild(node);
2444 + level++;
2445 + continue;
2446 + }else{
2447 + _xmlnode_tag2str(s,node,0);
2449 + }else{
2450 + spool_add(s,strescape(xmlnode_pool(node),xmlnode_get_data(node),strlen(xmlnode_get_data(node))));
2454 + tmp = xmlnode_get_nextsibling(node);
2455 + if(!tmp)
2457 + node = xmlnode_get_parent(node);
2458 + level--;
2459 + if(level>=0) _xmlnode_tag2str(s,node,2);
2460 + if(level<1) break;
2461 + dir = 1;
2462 + }else{
2463 + node = tmp;
2464 + dir = 0;
2468 + return s;
2472 +/* External routines */
2476 + * xmlnode_new_tag -- create a tag node
2477 + * Automatically creates a memory pool for the node.
2479 + * parameters
2480 + * name -- name of the tag
2482 + * returns
2483 + * a pointer to the tag node
2484 + * or NULL if it was unsuccessfull
2485 + */
2486 +xmlnode xmlnode_new_tag(const char* name)
2488 + return _xmlnode_new(NULL, name, NTYPE_TAG);
2493 + * xmlnode_new_tag_pool -- create a tag node within given pool
2495 + * parameters
2496 + * p -- previously created memory pool
2497 + * name -- name of the tag
2499 + * returns
2500 + * a pointer to the tag node
2501 + * or NULL if it was unsuccessfull
2502 + */
2503 +xmlnode xmlnode_new_tag_pool(pool p, const char* name)
2505 + return _xmlnode_new(p, name, NTYPE_TAG);
2510 + * xmlnode_insert_tag -- append a child tag to a tag
2512 + * parameters
2513 + * parent -- pointer to the parent tag
2514 + * name -- name of the child tag
2516 + * returns
2517 + * a pointer to the child tag node
2518 + * or NULL if it was unsuccessfull
2519 + */
2520 +xmlnode xmlnode_insert_tag(xmlnode parent, const char* name)
2522 + return _xmlnode_insert(parent, name, NTYPE_TAG);
2527 + * xmlnode_insert_cdata -- append character data to a tag
2529 + * parameters
2530 + * parent -- parent tag
2531 + * CDATA -- character data
2532 + * size -- size of CDATA
2533 + * or -1 for null-terminated CDATA strings
2535 + * returns
2536 + * a pointer to the child CDATA node
2537 + * or NULL if it was unsuccessfull
2538 + */
2539 +xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size)
2541 + xmlnode result;
2543 + if(CDATA == NULL || parent == NULL)
2544 + return NULL;
2546 + if(size == -1)
2547 + size = strlen(CDATA);
2549 + result = _xmlnode_insert(parent, NULL, NTYPE_CDATA);
2550 + if (result != NULL)
2552 + result->data = (char*)pmalloc(result->p, size + 1);
2553 + memcpy(result->data, CDATA, size);
2554 + result->data[size] = '\0';
2555 + result->data_sz = size;
2558 + return result;
2563 + * xmlnode_get_tag -- find given tag in an xmlnode tree
2565 + * parameters
2566 + * parent -- pointer to the parent tag
2567 + * name -- "name" for the child tag of that name
2568 + * "name/name" for a sub child (recurses)
2569 + * "?attrib" to match the first tag with that attrib defined
2570 + * "?attrib=value" to match the first tag with that attrib and value
2571 + * "=cdata" to match the cdata contents of the child
2572 + * or any combination: "name/name/?attrib", "name=cdata", etc
2574 + * results
2575 + * a pointer to the tag matching search criteria
2576 + * or NULL if search was unsuccessfull
2577 + */
2578 +xmlnode xmlnode_get_tag(xmlnode parent, const char* name)
2580 + char *str, *slash, *qmark, *equals;
2581 + xmlnode step, ret;
2584 + if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL;
2586 + if(strstr(name, "/") == NULL && strstr(name,"?") == NULL && strstr(name, "=") == NULL)
2587 + return _xmlnode_search(parent->firstchild, name, NTYPE_TAG);
2589 + str = strdup(name);
2590 + slash = strstr(str, "/");
2591 + qmark = strstr(str, "?");
2592 + equals = strstr(str, "=");
2594 + if(equals != NULL && (slash == NULL || equals < slash) && (qmark == NULL || equals < qmark))
2595 + { /* of type =cdata */
2597 + *equals = '\0';
2598 + equals++;
2600 + for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
2602 + if(xmlnode_get_type(step) != NTYPE_TAG)
2603 + continue;
2605 + if(*str != '\0')
2606 + if(j_strcmp(xmlnode_get_name(step),str) != 0)
2607 + continue;
2609 + if(j_strcmp(xmlnode_get_data(step),equals) != 0)
2610 + continue;
2612 + break;
2615 + free(str);
2616 + return step;
2620 + if(qmark != NULL && (slash == NULL || qmark < slash))
2621 + { /* of type ?attrib */
2623 + *qmark = '\0';
2624 + qmark++;
2625 + if(equals != NULL)
2627 + *equals = '\0';
2628 + equals++;
2631 + for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
2633 + if(xmlnode_get_type(step) != NTYPE_TAG)
2634 + continue;
2636 + if(*str != '\0')
2637 + if(j_strcmp(xmlnode_get_name(step),str) != 0)
2638 + continue;
2640 + if(xmlnode_get_attrib(step,qmark) == NULL)
2641 + continue;
2643 + if(equals != NULL && j_strcmp(xmlnode_get_attrib(step,qmark),equals) != 0)
2644 + continue;
2646 + break;
2649 + free(str);
2650 + return step;
2654 + *slash = '\0';
2655 + ++slash;
2657 + for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
2659 + if(xmlnode_get_type(step) != NTYPE_TAG) continue;
2661 + if(j_strcmp(xmlnode_get_name(step),str) != 0)
2662 + continue;
2664 + ret = xmlnode_get_tag(step, slash);
2665 + if(ret != NULL)
2667 + free(str);
2668 + return ret;
2672 + free(str);
2673 + return NULL;
2677 +/* return the cdata from any tag */
2678 +char *xmlnode_get_tag_data(xmlnode parent, const char *name)
2680 + xmlnode tag;
2682 + tag = xmlnode_get_tag(parent, name);
2683 + if(tag == NULL) return NULL;
2685 + return xmlnode_get_data(tag);
2689 +void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value)
2691 + xmlnode attrib;
2693 + if(owner == NULL || name == NULL || value == NULL) return;
2695 + /* If there are no existing attributs, allocate a new one to start
2696 + the list */
2697 + if (owner->firstattrib == NULL)
2699 + attrib = _xmlnode_new(owner->p, name, NTYPE_ATTRIB);
2700 + owner->firstattrib = attrib;
2701 + owner->lastattrib = attrib;
2703 + else
2705 + attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
2706 + if(attrib == NULL)
2708 + attrib = _xmlnode_append_sibling(owner->lastattrib, name, NTYPE_ATTRIB);
2709 + owner->lastattrib = attrib;
2712 + /* Update the value of the attribute */
2713 + attrib->data_sz = strlen(value);
2714 + attrib->data = pstrdup(owner->p, value);
2718 +char* xmlnode_get_attrib(xmlnode owner, const char* name)
2720 + xmlnode attrib;
2722 + if (owner != NULL && owner->firstattrib != NULL)
2724 + attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
2725 + if (attrib != NULL)
2726 + return (char*)attrib->data;
2728 + return NULL;
2731 +void xmlnode_put_vattrib(xmlnode owner, const char* name, void *value)
2733 + xmlnode attrib;
2735 + if (owner != NULL)
2737 + attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
2738 + if (attrib == NULL)
2740 + xmlnode_put_attrib(owner, name, "");
2741 + attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
2743 + if (attrib != NULL)
2744 + attrib->firstchild = (xmlnode)value;
2748 +void* xmlnode_get_vattrib(xmlnode owner, const char* name)
2750 + xmlnode attrib;
2752 + if (owner != NULL && owner->firstattrib != NULL)
2754 + attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
2755 + if (attrib != NULL)
2756 + return (void*)attrib->firstchild;
2758 + return NULL;
2761 +xmlnode xmlnode_get_firstattrib(xmlnode parent)
2763 + if (parent != NULL)
2764 + return parent->firstattrib;
2765 + return NULL;
2768 +xmlnode xmlnode_get_firstchild(xmlnode parent)
2770 + if (parent != NULL)
2771 + return parent->firstchild;
2772 + return NULL;
2775 +xmlnode xmlnode_get_lastchild(xmlnode parent)
2777 + if (parent != NULL)
2778 + return parent->lastchild;
2779 + return NULL;
2782 +xmlnode xmlnode_get_nextsibling(xmlnode sibling)
2784 + if (sibling != NULL)
2785 + return sibling->next;
2786 + return NULL;
2789 +xmlnode xmlnode_get_prevsibling(xmlnode sibling)
2791 + if (sibling != NULL)
2792 + return sibling->prev;
2793 + return NULL;
2796 +xmlnode xmlnode_get_parent(xmlnode node)
2798 + if (node != NULL)
2799 + return node->parent;
2800 + return NULL;
2803 +char* xmlnode_get_name(xmlnode node)
2805 + if (node != NULL)
2806 + return node->name;
2807 + return NULL;
2810 +char* xmlnode_get_data(xmlnode node)
2812 + if(xmlnode_get_type(node) == NTYPE_TAG) /* loop till we find a CDATA in the children */
2813 + for(node = xmlnode_get_firstchild(node); node != NULL; node = xmlnode_get_nextsibling(node))
2814 + if(xmlnode_get_type(node) == NTYPE_CDATA) break;
2816 + if(node == NULL) return NULL;
2818 + /* check for a dirty node w/ unassembled cdata chunks */
2819 + if(xmlnode_get_type(node->next) == NTYPE_CDATA)
2820 + _xmlnode_merge(node);
2822 + return node->data;
2825 +int xmlnode_get_datasz(xmlnode node)
2827 + if(xmlnode_get_type(node) != NTYPE_CDATA) return 0;
2829 + /* check for a dirty node w/ unassembled cdata chunks */
2830 + if(xmlnode_get_type(node->next) == NTYPE_CDATA)
2831 + _xmlnode_merge(node);
2832 + return node->data_sz;
2835 +int xmlnode_get_type(xmlnode node)
2837 + if (node != NULL)
2838 + return node->type;
2839 + return NTYPE_UNDEF;
2842 +int xmlnode_has_children(xmlnode node)
2844 + if ((node != NULL) && (node->firstchild != NULL))
2845 + return 1;
2846 + return 0;
2849 +int xmlnode_has_attribs(xmlnode node)
2851 + if ((node != NULL) && (node->firstattrib != NULL))
2852 + return 1;
2853 + return 0;
2856 +pool xmlnode_pool(xmlnode node)
2858 + if (node != NULL)
2859 + return node->p;
2860 + return (pool)NULL;
2863 +void xmlnode_hide(xmlnode child)
2865 + xmlnode parent;
2867 + if(child == NULL || child->parent == NULL)
2868 + return;
2870 + parent = child->parent;
2872 + /* first fix up at the child level */
2873 + _xmlnode_hide_sibling(child);
2875 + /* next fix up at the parent level */
2876 + if(parent->firstchild == child)
2877 + parent->firstchild = child->next;
2878 + if(parent->lastchild == child)
2879 + parent->lastchild = child->prev;
2882 +void xmlnode_hide_attrib(xmlnode parent, const char *name)
2884 + xmlnode attrib;
2886 + if(parent == NULL || parent->firstattrib == NULL || name == NULL)
2887 + return;
2889 + attrib = _xmlnode_search(parent->firstattrib, name, NTYPE_ATTRIB);
2890 + if(attrib == NULL)
2891 + return;
2893 + /* first fix up at the child level */
2894 + _xmlnode_hide_sibling(attrib);
2896 + /* next fix up at the parent level */
2897 + if(parent->firstattrib == attrib)
2898 + parent->firstattrib = attrib->next;
2899 + if(parent->lastattrib == attrib)
2900 + parent->lastattrib = attrib->prev;
2906 + * xmlnode2str -- convert given xmlnode tree into a string
2908 + * parameters
2909 + * node -- pointer to the xmlnode structure
2911 + * results
2912 + * a pointer to the created string
2913 + * or NULL if it was unsuccessfull
2914 + */
2915 +char *xmlnode2str(xmlnode node)
2917 + return spool_print(_xmlnode2spool(node));
2921 + * xmlnode2tstr -- convert given xmlnode tree into a newline terminated string
2923 + * parameters
2924 + * node -- pointer to the xmlnode structure
2926 + * results
2927 + * a pointer to the created string
2928 + * or NULL if it was unsuccessfull
2929 + */
2930 +char* xmlnode2tstr(xmlnode node)
2932 + spool s = _xmlnode2spool(node);
2933 + if (s != NULL)
2934 + spool_add(s, "\n");
2935 + return spool_print(s);
2939 +/* loop through both a and b comparing everything, attribs, cdata, children, etc */
2940 +int xmlnode_cmp(xmlnode a, xmlnode b)
2942 + int ret = 0;
2944 + while(1)
2946 + if(a == NULL && b == NULL)
2947 + return 0;
2949 + if(a == NULL || b == NULL)
2950 + return -1;
2952 + if(xmlnode_get_type(a) != xmlnode_get_type(b))
2953 + return -1;
2955 + switch(xmlnode_get_type(a))
2957 + case NTYPE_ATTRIB:
2958 + ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b));
2959 + if(ret != 0)
2960 + return -1;
2961 + ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b));
2962 + if(ret != 0)
2963 + return -1;
2964 + break;
2965 + case NTYPE_TAG:
2966 + ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b));
2967 + if(ret != 0)
2968 + return -1;
2969 + ret = xmlnode_cmp(xmlnode_get_firstattrib(a), xmlnode_get_firstattrib(b));
2970 + if(ret != 0)
2971 + return -1;
2972 + ret = xmlnode_cmp(xmlnode_get_firstchild(a), xmlnode_get_firstchild(b));
2973 + if(ret != 0)
2974 + return -1;
2975 + break;
2976 + case NTYPE_CDATA:
2977 + ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b));
2978 + if(ret != 0)
2979 + return -1;
2981 + a = xmlnode_get_nextsibling(a);
2982 + b = xmlnode_get_nextsibling(b);
2987 +xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node)
2989 + xmlnode child;
2991 + child = xmlnode_insert_tag(parent, xmlnode_get_name(node));
2992 + if (xmlnode_has_attribs(node))
2993 + xmlnode_insert_node(child, xmlnode_get_firstattrib(node));
2994 + if (xmlnode_has_children(node))
2995 + xmlnode_insert_node(child, xmlnode_get_firstchild(node));
2997 + return child;
3000 +/* places copy of node and node's siblings in parent */
3001 +void xmlnode_insert_node(xmlnode parent, xmlnode node)
3003 + if(node == NULL || parent == NULL)
3004 + return;
3006 + while(node != NULL)
3008 + switch(xmlnode_get_type(node))
3010 + case NTYPE_ATTRIB:
3011 + xmlnode_put_attrib(parent, xmlnode_get_name(node), xmlnode_get_data(node));
3012 + break;
3013 + case NTYPE_TAG:
3014 + xmlnode_insert_tag_node(parent, node);
3015 + break;
3016 + case NTYPE_CDATA:
3017 + xmlnode_insert_cdata(parent, xmlnode_get_data(node), xmlnode_get_datasz(node));
3019 + node = xmlnode_get_nextsibling(node);
3024 +/* produce full duplicate of x with a new pool, x must be a tag! */
3025 +xmlnode xmlnode_dup(xmlnode x)
3027 + xmlnode x2;
3029 + if(x == NULL)
3030 + return NULL;
3032 + x2 = xmlnode_new_tag(xmlnode_get_name(x));
3034 + if (xmlnode_has_attribs(x))
3035 + xmlnode_insert_node(x2, xmlnode_get_firstattrib(x));
3036 + if (xmlnode_has_children(x))
3037 + xmlnode_insert_node(x2, xmlnode_get_firstchild(x));
3039 + return x2;
3042 +xmlnode xmlnode_dup_pool(pool p, xmlnode x)
3044 + xmlnode x2;
3046 + if(x == NULL)
3047 + return NULL;
3049 + x2 = xmlnode_new_tag_pool(p, xmlnode_get_name(x));
3051 + if (xmlnode_has_attribs(x))
3052 + xmlnode_insert_node(x2, xmlnode_get_firstattrib(x));
3053 + if (xmlnode_has_children(x))
3054 + xmlnode_insert_node(x2, xmlnode_get_firstchild(x));
3056 + return x2;
3059 +xmlnode xmlnode_wrap(xmlnode x,const char *wrapper)
3061 + xmlnode wrap;
3062 + if(x==NULL||wrapper==NULL) return NULL;
3063 + wrap=xmlnode_new_tag_pool(xmlnode_pool(x),wrapper);
3064 + if(wrap==NULL) return NULL;
3065 + wrap->firstchild=x;
3066 + wrap->lastchild=x;
3067 + x->parent=wrap;
3068 + return wrap;
3071 +void xmlnode_free(xmlnode node)
3073 + if(node == NULL)
3074 + return;
3076 + pool_free(node->p);
3079 +/***/
3080 +void expat_startElement(void* userdata, const char* name, const char** atts)
3082 + /* get the xmlnode pointed to by the userdata */
3083 + xmlnode *x = userdata;
3084 + xmlnode current = *x;
3086 + if (current == NULL)
3088 + /* allocate a base node */
3089 + current = xmlnode_new_tag(name);
3090 + xmlnode_put_expat_attribs(current, atts);
3091 + *x = current;
3093 + else
3095 + *x = xmlnode_insert_tag(current, name);
3096 + xmlnode_put_expat_attribs(*x, atts);
3100 +void expat_endElement(void* userdata, const char* name)
3102 + xmlnode *x = userdata;
3103 + xmlnode current = *x;
3105 + current->complete = 1;
3106 + current = xmlnode_get_parent(current);
3108 + /* if it's NULL we've hit the top folks, otherwise back up a level */
3109 + if(current != NULL)
3110 + *x = current;
3113 +void expat_charData(void* userdata, const char* s, int len)
3115 + xmlnode *x = userdata;
3116 + xmlnode current = *x;
3118 + xmlnode_insert_cdata(current, s, len);
3122 +xmlnode xmlnode_str(char *str, int len)
3124 + XML_Parser p;
3125 + xmlnode *x, node; /* pointer to an xmlnode */
3127 + if(NULL == str)
3128 + return NULL;
3130 + x = malloc(sizeof(void *));
3132 + *x = NULL; /* pointer to NULL */
3133 + p = XML_ParserCreate(NULL);
3134 + XML_SetUserData(p, x);
3135 + XML_SetElementHandler(p, expat_startElement, expat_endElement);
3136 + XML_SetCharacterDataHandler(p, expat_charData);
3137 + if(!XML_Parse(p, str, len, 1))
3139 + /* jdebug(ZONE,"xmlnode_str_error: %s",(char *)XML_ErrorString(XML_GetErrorCode(p)));*/
3140 + xmlnode_free(*x);
3141 + *x = NULL;
3143 + node = *x;
3144 + free(x);
3145 + XML_ParserFree(p);
3146 + return node; /* return the xmlnode x points to */
3149 +xmlnode xmlnode_file(char *file)
3151 + XML_Parser p;
3152 + xmlnode *x, node; /* pointer to an xmlnode */
3153 + char buf[BUFSIZ];
3154 + int done, fd, len;
3156 + if(NULL == file)
3157 + return NULL;
3159 + fd = open(file,O_RDONLY);
3160 + if(fd < 0)
3161 + return NULL;
3163 + x = malloc(sizeof(void *));
3165 + *x = NULL; /* pointer to NULL */
3166 + p = XML_ParserCreate(NULL);
3167 + XML_SetUserData(p, x);
3168 + XML_SetElementHandler(p, expat_startElement, expat_endElement);
3169 + XML_SetCharacterDataHandler(p, expat_charData);
3170 + do{
3171 + len = read(fd, buf, BUFSIZ);
3172 + done = len < BUFSIZ;
3173 + if(!XML_Parse(p, buf, len, done))
3175 + /* jdebug(ZONE,"xmlnode_file_parseerror: %s",(char *)XML_ErrorString(XML_GetErrorCode(p)));*/
3176 + xmlnode_free(*x);
3177 + *x = NULL;
3178 + done = 1;
3180 + }while(!done);
3182 + node = *x;
3183 + XML_ParserFree(p);
3184 + free(x);
3185 + close(fd);
3186 + return node; /* return the xmlnode x points to */
3189 +char* xmlnode_file_borked(char *file)
3191 + XML_Parser p;
3192 + char buf[BUFSIZ];
3193 + static char err[1024];
3194 + int fd, len, done;
3196 + if(NULL == file)
3197 + return "no file specified";
3199 + fd = open(file,O_RDONLY);
3200 + if(fd < 0)
3201 + return "unable to open file";
3203 + p = XML_ParserCreate(NULL);
3204 + while(1)
3206 + len = read(fd, buf, BUFSIZ);
3207 + done = len < BUFSIZ;
3208 + if(!XML_Parse(p, buf, len, done))
3210 + snprintf(err,1023,"%s at line %d and column %d",XML_ErrorString(XML_GetErrorCode(p)),XML_GetErrorLineNumber(p),XML_GetErrorColumnNumber(p));
3211 + XML_ParserFree(p);
3212 + close(fd);
3213 + return err;
3218 +int xmlnode2file(char *file, xmlnode node)
3220 + char *doc, *ftmp;
3221 + int fd, i;
3223 + if(file == NULL || node == NULL)
3224 + return -1;
3226 + ftmp = spools(xmlnode_pool(node),file,".t.m.p",xmlnode_pool(node));
3227 + fd = open(ftmp, O_CREAT | O_WRONLY | O_TRUNC, 0600);
3228 + if(fd < 0)
3229 + return -1;
3231 + doc = xmlnode2str(node);
3232 + i = write(fd,doc,strlen(doc));
3233 + if(i < 0)
3234 + return -1;
3236 + close(fd);
3238 + if(rename(ftmp,file) < 0)
3240 + unlink(ftmp);
3241 + return -1;
3243 + return 1;
3246 +void xmlnode_put_expat_attribs(xmlnode owner, const char** atts)
3248 + int i = 0;
3249 + if (atts == NULL) return;
3250 + while (atts[i] != '\0')
3252 + xmlnode_put_attrib(owner, atts[i], atts[i+1]);
3253 + i += 2;
3256 diff -Naurb jabberd-2.1.14.orig/sm/xmlnode.h jabberd-2.1.14/sm/xmlnode.h
3257 --- jabberd-2.1.14.orig/sm/xmlnode.h 1970-01-01 01:00:00.000000000 +0100
3258 +++ jabberd-2.1.14/sm/xmlnode.h 2007-08-29 15:54:24.000000000 +0200
3259 @@ -0,0 +1,128 @@
3260 +#ifndef __XMLNODE_H
3261 +#define __XMLNODE_H
3263 +#include "../util/util.h"
3264 +typedef pool_t pool;
3266 +/* --------------------------------------------------------- */
3267 +/* */
3268 +/* xmlnodes - Document Object Model */
3269 +/* */
3270 +/* --------------------------------------------------------- */
3271 +#define NTYPE_TAG 0
3272 +#define NTYPE_ATTRIB 1
3273 +#define NTYPE_CDATA 2
3275 +#define NTYPE_LAST 2
3276 +#define NTYPE_UNDEF -1
3278 +/* --------------------------------------------------------------------------
3279 + * Node structure. Do not use directly! Always use accessor macros
3280 + * and methods!
3281 + * -------------------------------------------------------------------------- */
3282 +typedef struct xmlnode_t
3284 + char* name;
3285 + unsigned short type;
3286 + char* data;
3287 + int data_sz;
3288 + int complete;
3289 + pool p;
3290 + struct xmlnode_t* parent;
3291 + struct xmlnode_t* firstchild;
3292 + struct xmlnode_t* lastchild;
3293 + struct xmlnode_t* prev;
3294 + struct xmlnode_t* next;
3295 + struct xmlnode_t* firstattrib;
3296 + struct xmlnode_t* lastattrib;
3297 +} _xmlnode, *xmlnode;
3299 +/* Node creation routines */
3300 +xmlnode xmlnode_wrap(xmlnode x,const char* wrapper);
3301 +xmlnode xmlnode_new_tag(const char* name);
3302 +xmlnode xmlnode_new_tag_pool(pool p, const char* name);
3303 +xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size);
3304 +xmlnode xmlnode_insert_tag(xmlnode parent, const char* name);
3305 +xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node);
3306 +void xmlnode_insert_node(xmlnode parent, xmlnode node);
3307 +xmlnode xmlnode_str(char *str, int len);
3308 +xmlnode xmlnode_file(char *file);
3309 +char* xmlnode_file_borked(char *file); /* same as _file but returns the parsing error */
3310 +xmlnode xmlnode_dup(xmlnode x); /* duplicate x */
3311 +xmlnode xmlnode_dup_pool(pool p, xmlnode x);
3313 +/* Node Memory Pool */
3314 +pool xmlnode_pool(xmlnode node);
3315 +xmlnode _xmlnode_new(pool p, const char *name, unsigned int type);
3317 +/* Node editing */
3318 +void xmlnode_hide(xmlnode child);
3319 +void xmlnode_hide_attrib(xmlnode parent, const char *name);
3321 +/* Node deletion routine, also frees the node pool! */
3322 +void xmlnode_free(xmlnode node);xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size);
3323 +xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node);
3324 +void xmlnode_insert_node(xmlnode parent, xmlnode node);
3325 +xmlnode xmlnode_str(char *str, int len);
3326 +xmlnode xmlnode_file(char *file);
3327 +char* xmlnode_file_borked(char *file); /* same as _file but returns the parsing error */
3328 +xmlnode xmlnode_dup(xmlnode x); /* duplicate x */
3329 +xmlnode xmlnode_dup_pool(pool p, xmlnode x);
3331 +/* Node Memory Pool */
3332 +pool xmlnode_pool(xmlnode node);
3333 +xmlnode _xmlnode_new(pool p, const char *name, unsigned int type);
3335 +/* Node editing */
3336 +void xmlnode_hide(xmlnode child);
3337 +void xmlnode_hide_attrib(xmlnode parent, const char *name);
3339 +/* Node deletion routine, also frees the node pool! */
3340 +void xmlnode_free(xmlnode node);
3342 +/* Locates a child tag by name and returns it */
3343 +xmlnode xmlnode_get_tag(xmlnode parent, const char* name);
3344 +char* xmlnode_get_tag_data(xmlnode parent, const char* name);
3346 +/* Attribute accessors */
3347 +void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value);
3348 +char* xmlnode_get_attrib(xmlnode owner, const char* name);
3349 +void xmlnode_put_expat_attribs(xmlnode owner, const char** atts);
3351 +/* Bastard am I, but these are fun for internal use ;-) */
3352 +void xmlnode_put_vattrib(xmlnode owner, const char* name, void *value);
3353 +void* xmlnode_get_vattrib(xmlnode owner, const char* name);
3355 +/* Node traversal routines */
3356 +xmlnode xmlnode_get_firstattrib(xmlnode parent);
3357 +xmlnode xmlnode_get_firstchild(xmlnode parent);
3358 +xmlnode xmlnode_get_lastchild(xmlnode parent);
3359 +xmlnode xmlnode_get_nextsibling(xmlnode sibling);
3360 +xmlnode xmlnode_get_prevsibling(xmlnode sibling);
3361 +xmlnode xmlnode_get_parent(xmlnode node);
3363 +/* Node information routines */
3364 +char* xmlnode_get_name(xmlnode node);
3365 +char* xmlnode_get_data(xmlnode node);
3366 +int xmlnode_get_datasz(xmlnode node);
3367 +int xmlnode_get_type(xmlnode node);
3369 +int xmlnode_has_children(xmlnode node);
3370 +int xmlnode_has_attribs(xmlnode node);
3372 +/* Node-to-string translation */
3373 +char* xmlnode2str(xmlnode node);
3375 +/* Node-to-terminated-string translation
3376 + * -- useful for interfacing w/ scripting langs */
3377 +char* xmlnode2tstr(xmlnode node);
3379 +int xmlnode_cmp(xmlnode a, xmlnode b); /* compares a and b for equality */
3381 +int xmlnode2file(char *file, xmlnode node); /* writes node to file */
3383 +/* Expat callbacks */
3384 +void expat_startElement(void* userdata, const char* name, const char** atts);
3385 +void expat_endElement(void* userdata, const char* name);
3386 +void expat_charData(void* userdata, const char* s, int len);
3387 +#endif