More sophisticated selection of the user jid in Vcard2Ldap. Minor fixes.
[vcard2ldap.git] / patch / patch-v2l-jabberd-2.1.14.diff
blob90fdc1c0495c365fe02943f49dcd3cda61bce46c
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-10-05 11:02:41.000000000 +0200
306 @@ -0,0 +1,178 @@
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 +/* public api */
350 +int
351 +v2l_config_init (v2l_Config *self, T_CONF cfgroot)
353 + T_CONF conn_base;
354 + const char *portstr;
356 + if (!cfgroot)
358 + log_error (ZONE, "xdb_v2l configuration not present");
359 + return 0;
362 +#ifndef _V2L_JABBER2
363 + /* Have a look in the XML configuration data for connection information. */
364 + conn_base = xmlnode_get_tag (cfgroot, "connection");
366 + if (conn_base == NULL)
368 + log_error (ZONE,"<connection> tag is not present");
369 + return 0;
371 +#else
372 + conn_base = cfgroot;
373 +#endif
375 + self->host = _v2l_config_get_tag (conn_base, "host");
377 + if (self->host == NULL)
379 + log_error (ZONE, "LDAP server is not specified");
380 + return 0;
383 + portstr = _v2l_config_get_tag (conn_base, "port");
384 + self->port = portstr != NULL ? atoi (portstr) : LDAP_PORT;
386 + self->suffix = _v2l_config_get_tag (conn_base, "suffix");
388 + if (self->suffix == NULL)
390 + log_error (ZONE, "LDAP suffix is not specified");
391 + return 0;
394 + self->filter = _v2l_config_get_tag (conn_base, "filter");
396 + if (self->filter == NULL)
398 + log_error (ZONE, "LDAP search filter is not specified");
399 + return 0;
402 + self->binddn = _v2l_config_get_tag (conn_base, "binddn");
404 + if (self->binddn == NULL)
406 + log_error (ZONE, "LDAP jabber admin dn is not specified");
407 + return 0;
410 + self->bindpw = _v2l_config_get_tag (conn_base, "bindpw");
412 + if (self->bindpw == NULL)
414 + log_error (ZONE,
415 + "LDAP jabber admin password is not specified");
416 + return 0;
419 + self->confpath = _v2l_config_get_tag (conn_base, "tpl");
421 + if (self->confpath == NULL)
423 + log_error (ZONE,
424 + "Path to vCard <->LDAP is not specified");
425 + return 0;
428 + self->poolref = pool_new ();
430 + if (self->poolref == NULL)
432 + log_error (ZONE, "Cannot create pool");
433 + return 0;
436 + /* Get a handle to an LDAP connection. */
437 + log_debug (ZONE, "LDAP server: %s / port : %d", self->host, self->port);
439 + self->master_conn = v2l_get_master_conn (self);
441 + if (self->master_conn == NULL)
443 + log_error (ZONE,
444 + "Unable to create the LDAP main connection");
445 + return 0;
448 + return 1;
451 +void
452 +v2l_config_shutdown (v2l_Config *self)
454 + if (self != NULL && self->master_conn != NULL)
456 + v2l_free_allconn ();
457 + ldap_unbind_s (self->master_conn->ld);
458 + pool_free (self->master_conn->poolref);
459 + pool_free (self->poolref);
463 +/* public api ends here */
465 +static char *
466 +_v2l_config_get_tag (T_CONF conn_base, const char *tag)
468 +#ifndef _V2L_JABBER2
469 + xmlnode tmp;
471 + tmp = xmlnode_get_tag (conn_base, tag);
473 + if (tmp == NULL)
475 + return NULL;
478 + return (char *) xmlnode_get_data (xmlnode_get_firstchild (tmp));
479 +#else
480 + char str[32] = "v2l.";
482 + return config_get_one (conn_base, strncat (str, tag, 27), 0);
483 +#endif
485 diff -Naurb jabberd-2.1.14.orig/sm/v2l_config.h jabberd-2.1.14/sm/v2l_config.h
486 --- jabberd-2.1.14.orig/sm/v2l_config.h 1970-01-01 01:00:00.000000000 +0100
487 +++ jabberd-2.1.14/sm/v2l_config.h 2007-10-04 20:40:38.000000000 +0200
488 @@ -0,0 +1,73 @@
490 + * This program is free software; you can redistribute it and/or modify
491 + * it under the terms of the GNU General Public License as published by
492 + * the Free Software Foundation; either version 2 of the License, or
493 + * (at your option) any later version.
495 + * This program is distributed in the hope that it will be useful,
496 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
497 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
498 + * GNU General Public License for more details.
500 + * You should have received a copy of the GNU General Public License
501 + * along with this program; if not, write to the Free Software
502 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
503 + */
505 +/*! \file v2l_config.h
506 + \brief Config handling functions.
509 +#ifndef __V2L_CONFIG_H
510 +#define __V2L_CONFIG_H
512 +/*! Forward declaration */
513 +typedef struct v2l_LdapConn* v2l_LdapConnPtr;
515 +/*! The username associated with the master connection */
516 +#define V2L_ADMIN "jabberadmin"
518 +/*! \brief Type of the jabberd global config.
519 + 'xmlnode' for jabberd14, 'config_t' por jabberd2
521 +#ifdef _V2L_JABBER2
522 +#define T_CONF config_t
523 +#else
524 +#define T_CONF xmlnode
525 +#endif
527 +/*! \brief VCard2LDAP configuration.
528 + Shared config for the module API.
530 +typedef struct v2l_Config
532 +#ifndef _V2L_JABBER2
533 + xmlnode config; /*! reference to config file (jabber14) */
534 +#endif
535 + pool poolref;
536 + v2l_LdapConnPtr master_conn; /*! root connection to LDAP */
537 + char *host; /*!< LDAP hostname */
538 + int port; /*!< LDAP port */
539 + char *suffix; /*!< LDAP root dn */
540 + char *binddn; /*!< dn used for "master" connections */
541 + char *bindpw; /*!< pw used for "master" connections */
542 + char *filter; /*!< LDAP search filter */
543 + char *confpath; /*!< path to the translation template */
544 +} v2l_Config;
546 +/*! \brief Reads global config and initialize module config.
547 + \pre jabberd config exists and it's valid.
548 + \post all fields of self are set.
549 + \param self Module config.
550 + \param cfgroot Global config. T_CONF type.
551 + \return 1 if no error, otherwise returns 0.
553 +extern int v2l_config_init (v2l_Config *self, T_CONF cfgroot);
555 +/*! \brief Shutdown function, closes all connections and frees mempools.
556 + \pre self != NULL and self->master_conn is open.
557 + \post self->master_conn closed, all pools freeds.
558 + \param self Module config.
560 +extern void v2l_config_shutdown (v2l_Config *self);
561 +#endif
562 diff -Naurb jabberd-2.1.14.orig/sm/v2l_conn.c jabberd-2.1.14/sm/v2l_conn.c
563 --- jabberd-2.1.14.orig/sm/v2l_conn.c 1970-01-01 01:00:00.000000000 +0100
564 +++ jabberd-2.1.14/sm/v2l_conn.c 2007-10-05 11:50:31.000000000 +0200
565 @@ -0,0 +1,916 @@
567 + * This program is free software; you can redistribute it and/or modify
568 + * it under the terms of the GNU General Public License as published by
569 + * the Free Software Foundation; either version 2 of the License, or
570 + * (at your option) any later version.
572 + * This program is distributed in the hope that it will be useful,
573 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
574 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
575 + * GNU General Public License for more details.
577 + * You should have received a copy of the GNU General Public License
578 + * along with this program; if not, write to the Free Software
579 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
580 + */
582 +/*! \file v2l_conn.c
583 + \brief Handling the LDAP directory. Implementation
586 +#include <stdlib.h>
588 +#ifndef _V2L_JABBER2
589 +#include <jabberd.h>
590 +#else
591 +#include <pthread.h>
592 +#include "../util/util.h"
594 +#define log_warn log_debug
595 +#define log_error log_debug
596 +typedef pool_t pool;
597 +#endif
599 +#include <v2l_conn.h>
601 +/*! \brief Lifetime of an ephemeral connection, in seconds
602 + The recall connections thread period.
604 +#define V2L_CONN_LIFETIME 30
606 +/*! How often thread checks for LDAP results, in seconds */
607 +#define V2L_POLL_INTERVAL 1
609 +#define LOG_ERROR_MEM log_error (ZONE, "Unable to allocate memory")
611 +/*! Global hashtable of all currently active LDAP connections */
612 +static xht V2L_CONN_LIST = NULL;
614 +/*! \brief Creates new LDAP connection
615 + \param host LDAP hostname.
616 + \param port LDAP port.
617 + \param binddn Bind DN.
618 + \param user User name.
619 + \param passwd User password.
620 + \param expire Boolean, ephemeral connection?
621 + \return LDAP connectior or NULL if error.
623 +static v2l_LdapConn *_v2l_create_conn (char *host, int port, const char *binddn,
624 + const char *user, const char *passwd, int expire);
626 +/*! \brief Gets user credentials
627 + Retrieves user password and common name from LDAP directory using master
628 + connection.
629 + \note Allocated memory (*passwd and *cn) must be freed by the caller.
630 + \param self Module config.
631 + \param user User name.
632 + \param[out] passwd User password.
633 + \param[out] cn Common Name.
634 + \pre self is valid, user is not NULL
635 + \return 1 if no error, otherwise 0.
637 +static int _v2l_ldap_get_credentials (v2l_Config *self, const char *user,
638 + char **passwd, char **cn);
640 +/*! \brief Closes and frees a connection.
641 + Utility function, common code for two hash walker functions.
642 + \param h Jabberd hash. Hash table "username"->connection.
643 + \param user User name.
644 + \param val deference pointer to connection.
645 + \sa _v2l_free_walker
646 + \sa _v2l_free_expired_walker
648 +static void _v2l_free_conn (xht h, const char *user, void *val);
650 +/*! \brief Gets the number or attributes in a LDAP request.
651 + \param[in,out] req The SLL of LDAP requests.
652 + \return number of attributes, 0 if req is NULL.
654 +static int _v2l_count_attrs (v2l_LdapRequest *req);
656 +/*! \brief Modifies an entry in the LDAP directory
657 + Utility function.
658 + \param dn Entry bind DN
659 + \param attrs List of attributes changed.
660 + \param[in,out] evt_res Control and info parameter.
661 + \return LDAP error code.
663 +static int _v2l_ldap_modify (char *dn, LDAPMod **attrs, v2l_LdapEvt *evt_res);
665 +/*! \brief Searchs and retrieves an entry from the LDAP directory
666 + Utility function.
667 + \param dn Entry bind DN.
668 + \param suffix LDAP suffix
669 + \param[out] attrs Entry attributes.
670 + \param subtree boolean. Search in a one level or in entire subtree?
671 + \param[in,out] evt_res Control and info parameter.
672 + \return LDAP error code.
674 +static int _v2l_ldap_search (char *dn, char *suffix, char **attrs, int subtree,
675 + v2l_LdapEvt *evt_res);
677 +/*! \brief Builds and returns the search filter
678 + \note Allocated memory must be freed by the caller.
679 + \param self Module config.
680 + \param user User name.
681 + \sa _v2l_ldap_search
682 + \return The filter or NULL if error.
684 +static char *_v2l_ldap_filter (v2l_Config *self, const char *user);
686 +/*! \brief Waits for LDAP results.
687 + Operations on the directory are asynchronous. This is a sync wait function.
688 + \param[in,out] evt_res Control and info parameter.
690 +static void _v2l_ldap_sync (v2l_LdapEvt *evt_res);
692 +/*! \brief Adds LDAP attr to request.
693 + Utility function, hides OpenLDAP API to upper level.
694 + \pre Attribute is not NULL.
695 + \param[in,out] req The SLL of LDAP requests. If NULL new list is returned.
696 + \param attr The attr, LDAPMod pointer.
697 + \return The list of requests + the last added. The list of request if error.
699 +static v2l_LdapRequest *_v2l_add_attr (v2l_LdapRequest *req, LDAPMod *attr);
701 +/*! \brief Adds a conn to the global list.
702 + If list is empty, initializes it and starts the thread who recalls expired
703 + connections.
704 + \param ldap_conn New connection.
706 +static void _v2l_add_conn (v2l_LdapConn *ldap_conn);
708 +/*! \brief Frees connection unconditionally.
709 + Utility function. Hash walker function.
710 + See jabberd API for details.
712 +static void _v2l_free_walker (xht h, const char *key, void *val,
713 + void *arg);
715 +/*! \brief Frees connections when its slice time expired (periodic thread)
716 + \dot
717 + digraph G {
718 + rankdir = LR
719 + node [shape = ellipse, fontname = Helvetica fontsize = 12]
720 + {node[style = filled, fontsize = 16, bgcolor = grey] sleep}
721 + {node[shape = circle, label = delete] free}
722 + {node[label = "expired?" ] is_expired}
723 + {node[label = "conn left?" ] any_conn}
724 + sleep -> sleep
725 + sleep -> any_conn [label = "wake!"]
726 + any_conn -> sleep [label = no]
727 + any_conn -> is_expired [label = yes]
728 + is_expired -> free [label = yes]
729 + is_expired -> any_conn [label = no]
730 + free -> any_conn
732 + \enddot
733 + \param arg Unused.
735 +static void *_v2l_purge_conn_callback (void *arg);
737 +/*! \brief Frees expired connections.
738 + Utility function. Hash walker function.
739 + See jabberd API for details.
741 +static void _v2l_free_expired_walker (xht h, const char *key, void *val,
742 + void *arg);
744 +/*! A thread for active wait for LDAP results */
745 +static int _v2l_ldap_wait_callback (void *arg);
747 +#ifdef _V2L_JABBER2
748 +static void *_v2l_ldap_wait_callback_g (void *arg);
749 +#endif
751 +/* public api */
753 +v2l_LdapConn *
754 +v2l_get_conn (v2l_Config *self, const char *user)
756 + v2l_LdapConn *user_conn;
758 + user_conn = (v2l_LdapConn *) xhash_get (V2L_CONN_LIST, user);
760 + if (user_conn == NULL)
762 + char *passwd, *cn, *binddn;
764 + /* Get the user password for connecting him to LDAP server */
765 + if (_v2l_ldap_get_credentials (self, user, &passwd, &cn) == 0)
767 + log_error (ZONE, "User \"%s\" not found in the directory", user);
768 + return NULL;
771 + binddn = (char *) malloc (strlen (self->suffix) + strlen (cn) + 4);
773 + if (binddn == NULL)
775 + LOG_ERROR_MEM;
776 + free (passwd);
777 + free (cn);
778 + return NULL;
781 + sprintf (binddn, "cn=%s,%s", cn, self->suffix);
783 + log_debug (ZONE, "Attempting to connect with DN: %s", binddn);
785 + user_conn = _v2l_create_conn (self->host, self->port, binddn, user,
786 + passwd, 1);
788 + free (passwd);
789 + free (cn);
790 + free (binddn);
792 + } /* user_conn == NULL */
794 + return user_conn;
797 +v2l_LdapConn *
798 +v2l_get_master_conn (v2l_Config *self)
800 + return _v2l_create_conn (self->host, self->port, self->binddn, V2L_ADMIN,
801 + self->bindpw, 0);
804 +void
805 +v2l_free_allconn ()
807 + xhash_walk (V2L_CONN_LIST, _v2l_free_walker, NULL);
808 + xhash_free (V2L_CONN_LIST);
811 +v2l_LdapEvt *
812 +v2l_ldap_get_entry (v2l_Config *self, v2l_LdapConn *curr_conn)
814 + v2l_LdapEvt *evt_res;
815 + int rc;
817 + evt_res = (v2l_LdapEvt *) malloc (sizeof (v2l_LdapEvt));
819 + if (evt_res == NULL)
821 + LOG_ERROR_MEM;
822 + return NULL;
825 + evt_res->ld = curr_conn->ld;
827 + rc = _v2l_ldap_search (curr_conn->entry, self->suffix, NULL, 1, evt_res);
829 + if (rc != LDAP_SUCCESS)
831 + log_error (ZONE, "LDAP error attempting to retrieve user info: %s",
832 + ldap_err2string (rc));
833 + free (evt_res);
834 + return NULL;
837 + _v2l_ldap_sync (evt_res);
839 + if (ldap_count_entries (evt_res->ld, evt_res->result) != 1)
841 + log_warn (ZONE, "Multiple users with the same dn?");
842 + free (evt_res);
843 + return NULL;
846 + return evt_res;
849 +int
850 +v2l_request_record (v2l_Config *self, v2l_LdapConn *curr_conn,
851 + v2l_LdapRequest *req)
853 + LDAPMod **attrs;
854 + int i, nbmod, ret;
855 + v2l_LdapRequest *cur_req;
856 + v2l_LdapEvt *evt_res;
858 + if (req == NULL)
860 + log_warn (ZONE, "LDAP request is NULL? I cannot record anything");
861 + return 1;
864 + nbmod = _v2l_count_attrs (req);
866 + attrs = (LDAPMod **) malloc ((nbmod + 1) * sizeof (LDAPMod *));
868 + if (attrs == NULL)
870 + LOG_ERROR_MEM;
871 + return 0;
874 + /* to wait for the results */
875 + evt_res = (v2l_LdapEvt *) malloc (sizeof (v2l_LdapEvt));
877 + if (evt_res == NULL)
879 + LOG_ERROR_MEM;
880 + free (attrs);
881 + return 0;
884 + for (i = 0; i < nbmod; i++)
886 + attrs[i] = (LDAPMod *) malloc (sizeof (LDAPMod));
888 + if (attrs[i] == NULL)
890 + while (--i >= 0)
892 + free (attrs[i]);
895 + LOG_ERROR_MEM;
896 + free (attrs);
897 + free (evt_res);
898 + return 0;
902 + for (cur_req = req, i = 0; i < nbmod; cur_req = cur_req->next, i++)
904 + memcpy (attrs[i], cur_req->attr, sizeof (LDAPMod));
905 + log_debug (ZONE, "Element \"%s\" (%d) in the LDAP request: %s",
906 + attrs[i]->mod_type, i, attrs[i]->mod_values[0]);
909 + attrs[nbmod] = NULL;
911 + log_debug (ZONE, "LDAP attempting to modify \"%s\" with dn \"%s\"",
912 + curr_conn->user, curr_conn->binddn);
914 + evt_res->ld = curr_conn->ld;
915 + evt_res->rc = _v2l_ldap_modify (curr_conn->binddn, attrs, evt_res);
916 + ret = evt_res->rc == LDAP_SUCCESS;
918 + if (!ret)
920 + log_error (ZONE, "LDAP error attempting to modify user info: %s",
921 + ldap_err2string (evt_res->rc));
923 + else
925 + _v2l_ldap_sync (evt_res);
928 + ldap_msgfree (evt_res->result);
929 + free (evt_res);
931 + for (cur_req = req, i = 0; i < nbmod; cur_req = cur_req->next, i++)
933 + free (attrs[i]);
934 + free (cur_req->attr->mod_values[0]);
935 + free (cur_req->attr->mod_values);
936 + free (cur_req->attr);
937 + free (cur_req);
940 + free (attrs);
942 + return ret;
945 +v2l_LdapRequest *
946 +v2l_add_attr_str (v2l_LdapRequest *req, const char *attr, const char *str)
948 + LDAPMod *mod;
950 + mod = (LDAPMod *) malloc (sizeof (LDAPMod));
952 + if (mod == NULL)
954 + return NULL;
957 + mod->mod_op = LDAP_MOD_REPLACE;
958 + mod->mod_type = (char *) attr;
960 + mod->mod_values = (char **) malloc (2 * sizeof (char *));
962 + if (mod->mod_values == NULL)
964 + free (mod);
965 + return NULL;
968 + mod->mod_values[0] = (char *) malloc (strlen (str) + 1);
970 + if (mod->mod_values[0] == NULL)
972 + free (mod->mod_values);
973 + free (mod);
974 + return NULL;
977 + memcpy (mod->mod_values[0], str, strlen (str) + 1);
978 + mod->mod_values[1] = NULL;
980 + return _v2l_add_attr (req, mod);
983 +void
984 +v2l_ldap_for_all_attrs (v2l_AttrValueFunction value_func,
985 + v2l_AttrMatchFunction match_func, void *pointer, v2l_LdapEvt *evt_res)
987 + LDAPMessage *current_result;
988 + BerElement *ber;
989 + char *current_attr, **vals;
990 + void *shrdata;
992 + current_result = ldap_first_entry (evt_res->ld, evt_res->result);
993 + current_attr = ldap_first_attribute (evt_res->ld, current_result, &ber);
995 + /* step through each attribute in objectclass */
996 + for (;
997 + current_attr != NULL;
998 + current_attr = ldap_next_attribute (evt_res->ld, current_result, ber))
1001 + if (match_func (current_attr, &shrdata))
1003 + vals = ldap_get_values (evt_res->ld, current_result, current_attr);
1004 + value_func (current_attr, (const char **) vals, pointer, shrdata);
1006 + if (vals != NULL)
1008 + ldap_value_free (vals);
1012 + ldap_memfree (current_attr);
1013 + } /* attributes loop */
1015 + if (ber != NULL)
1017 + ber_free (ber, 0);
1020 + /* don't forget to free the next attribute */
1021 + ldap_memfree (current_attr);
1022 + ldap_msgfree (evt_res->result);
1025 +/* public api ends here */
1027 +static v2l_LdapConn *
1028 +_v2l_create_conn (char *host, int port, const char *binddn, const char *user,
1029 + const char *passwd, int expire)
1031 + LDAP *ld;
1032 + v2l_LdapConn *ldap_conn;
1033 + int version; /* LDAP protocol version */
1034 + int rc;
1035 + pool poolref;
1037 + ld = ldap_init (host, port);
1039 + if (ld == NULL)
1041 + log_error (ZONE, "Unable to init LDAP");
1042 + return NULL;
1045 + /* XXX */
1046 + version = LDAP_VERSION3;
1047 + /***/
1049 + ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version);
1050 + rc = ldap_simple_bind_s (ld, binddn, passwd);
1052 + if (rc != LDAP_SUCCESS)
1054 + log_error (ZONE,
1055 + "LDAP simple bind error : %s", ldap_err2string (rc));
1056 + return NULL;
1059 + poolref = pool_new ();
1061 + if (poolref == NULL)
1063 + LOG_ERROR_MEM;
1064 + ldap_unbind_s (ld);
1065 + return NULL;
1068 + ldap_conn = (v2l_LdapConn *) pmalloc (poolref, sizeof (v2l_LdapConn));
1070 + if (ldap_conn == NULL)
1072 + LOG_ERROR_MEM;
1073 + ldap_unbind_s (ld);
1074 + pool_free (poolref);
1075 + return NULL;
1078 + ldap_conn->poolref = poolref;
1079 + ldap_conn->ld = ld;
1081 + ldap_conn->binddn = (char *) pmalloc (ldap_conn->poolref,
1082 + strlen (binddn) + 1);
1084 + if (ldap_conn->binddn == NULL)
1086 + LOG_ERROR_MEM;
1087 + ldap_unbind_s (ld);
1088 + pool_free (poolref);
1089 + return NULL;
1092 + strcpy (ldap_conn->binddn, binddn);
1094 + ldap_conn->entry = (char *) pmalloc (ldap_conn->poolref, strlen (binddn) + 1);
1096 + if (ldap_conn->entry == NULL)
1098 + LOG_ERROR_MEM;
1099 + ldap_unbind_s (ld);
1100 + pool_free (poolref);
1101 + return NULL;
1104 + strcpy (ldap_conn->entry, binddn);
1105 + strtok (ldap_conn->entry, ", ");
1107 + ldap_conn->user = (char *) pmalloc (ldap_conn->poolref, strlen (user) + 1);
1109 + if (ldap_conn->user == NULL)
1111 + LOG_ERROR_MEM;
1112 + ldap_unbind_s (ld);
1113 + pool_free (poolref);
1114 + return NULL;
1117 + strcpy (ldap_conn->user, user);
1119 + ldap_conn->creation_time = time (NULL); /* timestamp */
1121 + if (expire == 1) /* Add it to V2L_CONN_LIST */
1123 + _v2l_add_conn (ldap_conn);
1126 + return ldap_conn;
1129 +static char *
1130 +_v2l_ldap_filter (v2l_Config *self, const char *user)
1132 + char *filter;
1134 + if (self->filter == NULL || user == NULL)
1136 + log_error (ZONE, "Attempt to make a NULL filter");
1137 + return NULL;
1140 + filter = (char *) malloc (strlen (self->filter) + strlen (user));
1142 + if (filter == NULL)
1144 + LOG_ERROR_MEM;
1145 + return NULL;
1148 + sprintf (filter, self->filter, user);
1150 + return filter;
1153 +static int
1154 +_v2l_ldap_get_credentials (v2l_Config *self, const char *user, char **passwd,
1155 + char **cn)
1157 + LDAPMessage *e;
1158 + v2l_LdapEvt *evt_res;
1159 + char *filter, **vpw, **vcn;
1160 + char *attrs[3] = {"userPassword", "cn", NULL};
1162 + evt_res = (v2l_LdapEvt *) malloc (sizeof (v2l_LdapEvt));
1164 + if (evt_res == NULL)
1166 + LOG_ERROR_MEM;
1167 + return 0;
1170 + filter = _v2l_ldap_filter (self, user);
1172 + evt_res->ld = self->master_conn->ld;
1173 + evt_res->rc = _v2l_ldap_search (filter, self->suffix, attrs, 0, evt_res);
1175 + free (filter);
1177 + if (evt_res->rc != LDAP_SUCCESS)
1179 + log_error (ZONE,
1180 + "LDAP error attempting to retrieve \"%s\"'s password: %s",
1181 + user, ldap_err2string (evt_res->rc));
1182 + free (evt_res);
1183 + return 0;
1186 + _v2l_ldap_sync (evt_res);
1188 + *passwd = NULL;
1189 + *cn = NULL;
1191 + if (ldap_count_entries (evt_res->ld, evt_res->result) == 1)
1193 + e = ldap_first_entry (evt_res->ld, evt_res->result);
1195 + vpw = ldap_get_values (evt_res->ld, e, "userPassword");
1197 + if (vpw == NULL)
1199 + log_debug (ZONE, "User has no password!");
1200 + ldap_msgfree (evt_res->result);
1201 + free (evt_res);
1202 + return 0;
1205 + vcn = ldap_get_values (evt_res->ld, e, "cn");
1207 + if (vcn == NULL)
1209 + log_debug (ZONE, "LDAP general failure!!");
1210 + ldap_value_free (vpw);
1211 + ldap_msgfree (evt_res->result);
1212 + free (evt_res);
1213 + return 0;
1216 + *passwd = (char *) malloc (strlen (vpw[0]) + 1);
1218 + if (*passwd == NULL)
1220 + LOG_ERROR_MEM;
1221 + ldap_value_free (vpw);
1222 + ldap_value_free (vcn);
1223 + ldap_msgfree (evt_res->result);
1224 + free (evt_res);
1225 + return 0;
1228 + strcpy (*passwd, vpw[0]);
1229 + ldap_value_free (vpw);
1231 + *cn = (char *) malloc (strlen (vcn[0]) + 1);
1233 + if (*cn == NULL)
1235 + LOG_ERROR_MEM;
1236 + free (*passwd);
1237 + ldap_value_free (vpw);
1238 + ldap_value_free (vcn);
1239 + ldap_msgfree (evt_res->result);
1240 + free (evt_res);
1241 + return 0;
1244 + strcpy (*cn, vcn[0]);
1245 + ldap_value_free (vcn);
1248 + ldap_msgfree (evt_res->result);
1249 + free (evt_res);
1251 + return *passwd != NULL && *cn != NULL;
1254 +static int
1255 +_v2l_ldap_modify (char *dn, LDAPMod **attrs, v2l_LdapEvt *evt_res)
1257 + return ldap_modify_ext (evt_res->ld, dn, attrs, NULL, NULL,
1258 + &(evt_res->msgid));
1261 +static int
1262 +_v2l_ldap_search (char *dn, char *suffix, char **attrs, int subtree,
1263 + v2l_LdapEvt *evt_res)
1265 + int scope;
1267 + scope = subtree ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_ONELEVEL;
1269 + return ldap_search_ext (evt_res->ld, suffix, scope,
1270 + dn, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
1271 + &(evt_res->msgid));
1274 +static void
1275 +_v2l_ldap_sync (v2l_LdapEvt *evt_res)
1277 +#ifndef _V2L_JABBER2
1278 + pth_event_t evt;
1280 + evt = pth_event (PTH_EVENT_FUNC, &_v2l_ldap_wait_callback,
1281 + (void *) evt_res, pth_time (V2L_POLL_INTERVAL, 0));
1282 + pth_wait (evt);
1283 +#else
1284 + pthread_t thr;
1285 + int rc;
1287 + rc = pthread_create (&thr, NULL, _v2l_ldap_wait_callback_g, (void *) evt_res);
1289 + if (rc != 0)
1291 + log_error (ZONE, "Thread create failed: %d", rc);
1292 + return;
1295 + pthread_join (thr, NULL);
1296 +#endif
1299 +/*! Count the number of LDAPMod in the structure */
1300 +static int
1301 +_v2l_count_attrs (v2l_LdapRequest *req)
1303 + int nbmod;
1305 + for (nbmod = 0; req != NULL; req = req->next, nbmod++);
1307 + return nbmod;
1310 +static v2l_LdapRequest *
1311 +_v2l_add_attr (v2l_LdapRequest *req, LDAPMod *attr)
1313 + v2l_LdapRequest *new_req, *ptr;
1315 + if (attr == NULL)
1317 + log_warn (ZONE, "LDAP attribute is NULL? I cannot add anything");
1318 + return NULL;
1321 + new_req = (v2l_LdapRequest *) malloc (sizeof (v2l_LdapRequest));
1323 + if (new_req == NULL)
1325 + LOG_ERROR_MEM;
1326 + return NULL;
1329 + new_req->attr = attr;
1330 + new_req->next = NULL;
1332 + if (req == NULL)
1334 + req = new_req;
1336 + else
1338 + for (ptr = req; ptr->next != NULL; ptr = ptr->next);
1339 + ptr->next = new_req;
1342 + return req;
1345 +static int
1346 +_v2l_ldap_wait_callback (void *arg)
1348 + v2l_LdapEvt *evt_res = (v2l_LdapEvt *) arg;
1349 + LDAPMessage *result;
1350 + int rc;
1352 + rc = ldap_result (evt_res->ld, evt_res->msgid, 1, NULL, &result);
1354 + if (rc == -1)
1356 + log_error (ZONE, "LDAP result error %s",
1357 + ldap_err2string (rc));
1358 + evt_res->result = NULL;
1359 + evt_res->rc = -1;
1360 + return 1;
1363 + if ((rc == LDAP_RES_ADD)
1364 + || (rc == LDAP_RES_MODIFY)
1365 + || (rc == LDAP_RES_SEARCH_RESULT)
1366 + || (rc == LDAP_RES_SEARCH_ENTRY)
1367 + || (rc == LDAP_RES_DELETE))
1369 + evt_res->result = result;
1370 + evt_res->rc = rc;
1371 + return 1;
1374 + return 0; /* still waiting */
1377 +#ifdef _V2L_JABBER2
1378 +static void *
1379 +_v2l_ldap_wait_callback_g (void *arg)
1381 + while (!_v2l_ldap_wait_callback (arg))
1383 + sleep (V2L_POLL_INTERVAL);
1386 + return NULL;
1388 +#endif
1390 +static void
1391 +_v2l_free_walker (xht h, const char *key, void *val, void *arg)
1393 + _v2l_free_conn (h, key, val);
1396 +static void
1397 +_v2l_free_conn (xht h, const char *user, void *val)
1399 + v2l_LdapConn *temp_conn = (v2l_LdapConn *) val;
1401 + log_debug (ZONE, "Freeing LDAP connection for user \"%s\"", user);
1403 + xhash_zap (h, user);
1404 + ldap_unbind_s (temp_conn->ld);
1405 + pool_free (temp_conn->poolref);
1408 +static void
1409 +_v2l_free_expired_walker (xht h, const char *key, void *val, void *arg)
1411 + v2l_LdapConn *temp_conn = (v2l_LdapConn *) val;
1413 + /* kill connections older than V2L_CONN_LIFETIME */
1414 + if ((time (NULL) - temp_conn->creation_time) > (time_t) V2L_CONN_LIFETIME)
1416 + _v2l_free_conn (h, key, val);
1420 +static void *
1421 +_v2l_purge_conn_callback (void *arg)
1423 + log_debug (ZONE, "Checking connections lifetime");
1425 + while (1)
1427 + /* V2L_CONN_LIST has been freed? */
1428 + if (V2L_CONN_LIST != NULL)
1430 + xhash_walk (V2L_CONN_LIST, _v2l_free_expired_walker, NULL);
1432 +#ifndef _V2L_JABBER2
1433 + pth_sleep (V2L_CONN_LIFETIME);
1434 +#else
1435 + sleep (V2L_CONN_LIFETIME);
1436 +#endif
1439 + return NULL;
1442 +static void
1443 +_v2l_add_conn (v2l_LdapConn *ldap_conn)
1445 +#ifndef _V2L_JABBER2
1446 + pth_attr_t attr;
1447 +#else
1448 + pthread_t thr;
1449 + pthread_attr_t attr;
1450 + int rc;
1451 +#endif
1453 + if (V2L_CONN_LIST == NULL)
1456 + log_debug (ZONE, "V2L_CONN_LIST hashtable is not initialized yet");
1458 + V2L_CONN_LIST = xhash_new (509);
1460 + /* spawn the thread which deletes expired connections */
1461 +#ifndef _V2L_JABBER2
1462 + attr = pth_attr_new ();
1463 + pth_attr_set (attr, PTH_ATTR_JOINABLE, FALSE);
1464 + pth_spawn (attr, _v2l_purge_conn_callback, NULL);
1465 + pth_attr_destroy (attr);
1466 +#else
1467 + pthread_attr_init (&attr);
1468 + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
1470 + rc = pthread_create (&thr, &attr, _v2l_purge_conn_callback, NULL);
1471 + pthread_attr_destroy (&attr);
1473 + if (rc != 0)
1475 + log_error (ZONE, "Thread create failed: %d", rc);
1477 +#endif
1480 + xhash_put (V2L_CONN_LIST, ldap_conn->user, (void *) ldap_conn);
1482 diff -Naurb jabberd-2.1.14.orig/sm/v2l_conn.h jabberd-2.1.14/sm/v2l_conn.h
1483 --- jabberd-2.1.14.orig/sm/v2l_conn.h 1970-01-01 01:00:00.000000000 +0100
1484 +++ jabberd-2.1.14/sm/v2l_conn.h 2007-10-05 12:06:20.000000000 +0200
1485 @@ -0,0 +1,146 @@
1487 + * This program is free software; you can redistribute it and/or modify
1488 + * it under the terms of the GNU General Public License as published by
1489 + * the Free Software Foundation; either version 2 of the License, or
1490 + * (at your option) any later version.
1492 + * This program is distributed in the hope that it will be useful,
1493 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1494 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1495 + * GNU General Public License for more details.
1497 + * You should have received a copy of the GNU General Public License
1498 + * along with this program; if not, write to the Free Software
1499 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1500 + */
1502 +/*! \file v2l_conn.h
1503 + \brief Handling the LDAP directory. Low-level tier.
1506 +#ifndef __V2L_CONN_H
1507 +#define __V2L_CONN_H
1509 +#include <ldap.h>
1510 +#include <time.h>
1512 +#include <v2l_config.h>
1514 +/*! \brief Simple Linked List of connections to LDAP directory */
1515 +typedef struct v2l_LdapConn
1517 + pool poolref;
1518 + LDAP *ld; /*!< LDAP descriptor */
1519 + time_t creation_time; /*!< timestamp */
1520 + char *binddn; /*!< complete dn */
1521 + char *entry; /*!< short dn */
1522 + char *user; /*!< username */
1523 + struct v2l_LdapConn *next;
1524 +} v2l_LdapConn;
1526 +/*! \brief Request (SLL) for LDAP directory */
1527 +typedef struct v2l_LdapRequest
1529 + LDAPMod *attr;
1530 + struct v2l_LdapRequest *next;
1531 +} v2l_LdapRequest;
1533 +/*! \brief LDAP environment.
1534 + Control struct for perform operations on the LDAP directory and retrieve
1535 + results.
1537 +typedef struct v2l_LdapEvt
1539 + LDAP *ld; /*!< LDAP descriptor */
1540 + int msgid; /*!< LDAP message id (see OpenLDAP API docs) */
1541 + int rc; /*!< LDAP error code */
1542 + LDAPMessage *result; /*!< LDAP result (see OpenLDAP API docs) */
1543 +} v2l_LdapEvt;
1545 +/*! \brief Match function type
1546 + Generic attribute matching routine.
1547 + \param attr The attribute.
1548 + \param[out] shrdata Generic deferenced pointer. Shared data with a 'value
1549 + function'
1550 + \sa v2l_AttrValueFunction
1551 + \sa v2l_ldap_for_all_attrs
1552 + \return true if matching, otherwise false.
1554 +typedef int (*v2l_AttrMatchFunction) (const char *attr, void **shrdata);
1556 +/*! \brief Values read function type
1557 + Generic values handling routine.
1558 + \param attr The attribute.
1559 + \param vals Values of attribute.
1560 + \param pointer Generic multipurpose pointer.
1561 + \param shrdata Shared data with 'match function'
1562 + \sa v2l_MatchValueFunction
1563 + \sa v2l_ldap_for_all_attrs
1565 +typedef void (*v2l_AttrValueFunction) (const char *attr, const char **vals,
1566 + void *pointer, void *shrdata);
1568 +/*! \brief Gets a (ephemeral) connection by name. Creates one if doesn't exist.
1569 + \warning The name defined by V2L_ADMIN is reserved for master conn.
1570 + \pre self is valid, user is not null and exists.
1571 + \post ephermeral connection for user is open.
1572 + \param self Module config.
1573 + \param user the username
1574 + \sa V2L_ADMIN
1575 + \sa v2l_get_master_conn
1576 + \return the connection if no error, otherwise NULL.
1578 +extern v2l_LdapConn *v2l_get_conn (v2l_Config *self, const char *user);
1580 +/*! \brief Gets a connection master connection. Creates one if doesn't exist.
1581 + \pre self is valid
1582 + \post master connection is open.
1583 + \param self Module config.
1584 + \return the connection if no error, otherwise NULL.
1586 +extern v2l_LdapConn *v2l_get_master_conn (v2l_Config *self);
1588 +/*! \brief Frees and closes all connections (ephemeral or not)
1589 + If connections doesn't exist does nothing.
1590 + \post self->master_conn closed. Connections list empty.
1592 +extern void v2l_free_allconn ();
1594 +/*! \brief Retrieves an user entry from the LDAP directory
1595 + \note Allocated memory must be freed by the caller.
1596 + \param self Module config
1597 + \param curr_conn user connection.
1598 + \return evt_res LDAP descriptor, control code and result. NULL if error.
1600 +extern v2l_LdapEvt *v2l_ldap_get_entry (v2l_Config *self,
1601 + v2l_LdapConn *curr_conn);
1603 +/*! \brief Executes a list of changes on the LDAP directory.
1604 + \pre req is not NULL
1605 + \param self Module config
1606 + \param curr_conn The user connection.
1607 + \param req list of changes.
1608 + \return 1 if no error, otherwise 0
1610 +extern int v2l_request_record (v2l_Config *self, v2l_LdapConn *curr_conn,
1611 + v2l_LdapRequest *req);
1613 +/*! \brief Adds a new request to the list
1614 + \param req The list of requests.
1615 + \param attr attribute name.
1616 + \param str attribute value.
1617 + \return The list of requests + the last added. The list of request if error.
1619 +extern v2l_LdapRequest *v2l_add_attr_str (v2l_LdapRequest *req,
1620 + const char *attr, const char *str);
1622 +/*! \brief Applies a function to all LDAP object attributes.
1623 + \pre evt_res should be a valid entry (ie. result of a search in directory)
1624 + \param value_func Walker function.
1625 + \param match_func Match function. If returns true we'll call to value_func
1626 + \param pointer Generic multipurpose pointer. It will be passed to value_func
1627 + \param evt_res LDAP descriptor, control code and result.
1629 +extern void v2l_ldap_for_all_attrs (v2l_AttrValueFunction value_func,
1630 + v2l_AttrMatchFunction match_func, void *pointer, v2l_LdapEvt *evt_res);
1631 +#endif
1632 diff -Naurb jabberd-2.1.14.orig/sm/v2l_vcard.c jabberd-2.1.14/sm/v2l_vcard.c
1633 --- jabberd-2.1.14.orig/sm/v2l_vcard.c 1970-01-01 01:00:00.000000000 +0100
1634 +++ jabberd-2.1.14/sm/v2l_vcard.c 2007-10-05 11:03:01.000000000 +0200
1635 @@ -0,0 +1,589 @@
1637 + * This program is free software; you can redistribute it and/or modify
1638 + * it under the terms of the GNU General Public License as published by
1639 + * the Free Software Foundation; either version 2 of the License, or
1640 + * (at your option) any later version.
1642 + * This program is distributed in the hope that it will be useful,
1643 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1644 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1645 + * GNU General Public License for more details.
1647 + * You should have received a copy of the GNU General Public License
1648 + * along with this program; if not, write to the Free Software
1649 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1650 + */
1652 +/*! \file v2l_vcard.c
1653 + \brief XML vCard's to/from LDAP objects translation functions.
1654 + Implementation
1657 +#include <stdlib.h>
1659 +#ifndef _V2L_JABBER2
1660 +#include <jabberd.h>
1661 +#else
1662 +#include "../util/util.h"
1663 +#include <xmlnode.h>
1665 +#define log_warn log_debug
1666 +#define log_error log_debug
1668 +#endif
1669 +#include <v2l_vcard.h>
1671 +#define LOG_ERROR_MEM log_error (ZONE, "Unable to allocate memory")
1673 +/*! \brief vCard template item.
1674 + SLL. All of relations tag<->LDAP attr read from template
1676 +typedef struct v2l_vCardItem
1678 + char *vcard; /*!< tag name */
1679 + char *ldap; /*!< LDAP attribute */
1680 + char *group; /*!< XML parent of the tag */
1681 + struct v2l_vCardItem *next;
1682 +} v2l_vCardItem;
1684 +/*! \brief Gets the translation map.
1685 + If it is not initilized yet, the function reads the template from disk
1686 + and sets the map.
1687 + \param self Module config, if map is initialized can be NULL.
1688 + \return The map, NULL if error.
1690 +static v2l_vCardItem *_v2l_vcard_map (v2l_Config *self);
1692 +/*! \brief Creates the FN tag
1693 + Creates FN tag from GIVEN and FAMILY tags.
1694 + \param vcard The vCard.
1695 + \return 1 if no error, otherwise 0.
1697 +static int _v2l_create_fn (xmlnode vcard);
1699 +/*! \brief Sets sn1 and sn2 from sn
1700 + Hack. IrisPerson has two surnames: first surname and mother's maiden name.
1701 + This function splits sn in two. Should be called when the list of request
1702 + are complete and before program excutes them.
1703 + \param req The SLL of LDAP requests.
1705 +static v2l_LdapRequest *_v2l_set_sn12 (v2l_LdapRequest *req);
1707 +/*! \brief Map function from LDAP to XML vCard
1708 + \param item Info about the tag (name, parent group and attribute associated)
1709 + \param vals array of values for the attribe.
1710 + \param[in,out] res The vCard, output is appended here.
1711 + \return res + new tag or res if error.
1713 +static xmlnode _v2l_ldap2vcard_generic (v2l_vCardItem *item, const char **vals,
1714 + xmlnode res);
1716 +/*! \brief Function for maps PHOTO tag.
1717 + Hack. InetOrgPerson has a jpegphoto attribute so PHOTO/MIMETYPE tag can be
1718 + only "image/jpeg"
1719 + \warning The module doesn't support storing avatars in another format (png)
1721 +static xmlnode _v2l_ldap2vcard_photo (v2l_vCardItem *item, const char **vals,
1722 + xmlnode res);
1724 +/*! \brief Map function from XML Vcard to LDAP
1725 + \param item Info about the tag (name, parent group and attribute associated)
1726 + \param data Thhe vCard.
1727 + \param[in,out] req List of requests, the new request is appended here.
1728 + \return req + new request or req if error.
1730 +static v2l_LdapRequest *_v2l_vcard2ldap_generic (v2l_vCardItem *item,
1731 + xmlnode data, v2l_LdapRequest *req);
1733 +/*! \brief Finds tag linked to attr
1734 + Parses the translation map since 'item' node.
1735 + \param item Where the search starts.
1736 + \param attr The attribute;
1737 + \return node with tag<->attr association or NULL if error or not found.
1739 +static v2l_vCardItem *_v2l_vcard_find_attr (v2l_vCardItem *item,
1740 + const char *attr);
1742 +/*! \brief Is LDAP object attribute linked to any tag?
1743 + Utility function.
1744 + \param attr The attribute.
1745 + \param[out] shrdata Contents the address of any map's node. NULL if no match
1746 + \return true if attr is linked to any tag, otherwise false
1748 +static int _v2l_vcard_attr_match (const char *attr, void **shrdata);
1750 +/*! \brief Function applied to all attrs.
1751 + Utility function, walker function.
1752 + \param attr The attribute.
1753 + \param vals Values of attribute.
1754 + \param pointer Deferenced pointer to vCard.
1755 + \param shrdata Data shared with the match function.
1757 +static void _v2l_vcard_attr_value (const char *attr, const char **vals,
1758 + void *pointer, void *shrdata);
1760 +#if 0
1761 +static v2l_vCardItem *
1762 + _v2l_vcard_find_tag (v2l_vCardItem *item, char *tag);
1763 +#endif
1765 +/*! List of all XML vCard tags supported */
1766 +static const char *_V2L_MAP_VCARD [] = {
1767 + "FN",
1768 + "NICKNAME",
1769 + "URL",
1770 + "TEL/NUMBER",
1771 + "EMAIL/USERID",
1772 + "TITLE",
1773 + "ROLE",
1774 + "BDAY",
1775 + "DESC",
1776 + "N/FAMILY",
1777 + "N/GIVEN",
1778 + "N/MIDDLE",
1779 + "N/PREFIX",
1780 + "N/SUFFIX",
1781 + "ADR/STREET",
1782 + "ADR/POBOX",
1783 + "ADR/EXTADD",
1784 + "ADR/LOCALITY",
1785 + "ADR/REGION",
1786 + "ADR/PCODE",
1787 + "ADR/CTRY",
1788 + "ORG/ORGNAME",
1789 + "ORG/ORGUNIT",
1791 + "TZ",
1792 + "GEO/LAT",
1793 + "GEO/LON",
1794 + "AGENT/EXTVAL",
1795 + "NOTE",
1796 + "REV",
1797 + "SORT-STRING",
1799 + "KEY/TYPE",
1800 + "KEY/CRED",
1802 + "PHOTO/TYPE",
1803 + "PHOTO/BINVAL",
1804 + "PHOTO/EXTVAL",
1806 + "LOGO/TYPE",
1807 + "LOGO/BINVAL",
1808 + "LOGO/EXTVAL",
1810 + "SOUND/PHONETIC",
1811 + "SOUND/BINVAL",
1812 + "SOUND/EXTVAL",
1814 + NULL
1817 +/* public api */
1819 +xmlnode
1820 +v2l_vcard_get (v2l_Config *self, v2l_LdapConn *curr_conn)
1822 + xmlnode vcard;
1823 + v2l_LdapEvt *evt_res;
1825 + if (_v2l_vcard_map (self) == NULL)
1827 + log_error (ZONE, "Unreadable/malformed vCard template!");
1828 + return NULL;
1831 + /* get user info from LDAP */
1832 + evt_res = v2l_ldap_get_entry (self, curr_conn);
1834 + if (evt_res == NULL)
1836 + return NULL;
1839 + /* prepare the XML result */
1840 + vcard = xmlnode_new_tag ("vCard");
1841 + xmlnode_put_attrib (vcard, "xmlns", "vcard-temp");
1843 + v2l_ldap_for_all_attrs (_v2l_vcard_attr_value, _v2l_vcard_attr_match, vcard,
1844 + evt_res);
1846 + free (evt_res);
1847 + _v2l_create_fn (vcard);
1849 + return vcard;
1852 +int
1853 +v2l_vcard_set (v2l_Config *self, v2l_LdapConn *curr_conn, xmlnode data)
1855 + xmlnode node;
1856 + v2l_LdapRequest *ldap_req = NULL;
1857 + v2l_vCardItem *item;
1859 + if (data == NULL)
1861 + log_warn (ZONE, "vCard data is NULL?");
1862 + return 0;
1865 + item = _v2l_vcard_map (self);
1867 + if (item == NULL)
1869 + log_error (ZONE, "Unreadable/Malformed vCard template!");
1870 + return 0;
1873 + do
1875 + if (strcmp (item->vcard, "FN") == 0) /* FIXME: ugly */
1877 + goto is_fn;
1880 + if (item->group != NULL)
1882 + char tag[30];
1884 + sprintf (tag, "%s/%s", item->group, item->vcard);
1885 + node = xmlnode_get_tag (data, tag);
1887 + else
1889 + node = xmlnode_get_tag (data, item->vcard);
1892 + if (node != NULL)
1894 + ldap_req = _v2l_vcard2ldap_generic (item, node, ldap_req);
1896 +is_fn:
1897 + item = item->next;
1898 + } while (item != NULL);
1900 + ldap_req = _v2l_set_sn12 (ldap_req);
1902 + return v2l_request_record (self, curr_conn, ldap_req);
1905 +/* public api ends here */
1907 +static v2l_vCardItem *
1908 +_v2l_vcard_map (v2l_Config *self)
1910 + static v2l_vCardItem *_V2L_TPL = NULL;
1911 + xmlnode tpl, tag;
1912 + char **stag, *tmp, group[10];
1913 + v2l_vCardItem *item;
1915 + if (_V2L_TPL == NULL && self != NULL && self->confpath != NULL)
1917 + tpl = xmlnode_file (self->confpath);
1919 + if (tpl == NULL)
1921 + return NULL;
1924 + for (stag = (char **) _V2L_MAP_VCARD; *stag != NULL; stag++)
1926 + tmp = strchr (*stag, '/');
1928 + if (tmp == NULL)
1930 + group[0] = 0;
1931 + tmp = *stag;
1933 + else
1935 + sprintf (group, "%.*s", tmp - *stag, *stag);
1936 + tmp++;
1939 + tag = xmlnode_get_tag (tpl, *stag);
1941 + if (xmlnode_get_data (tag) != NULL)
1943 + int ntags = 0;
1944 + char find_attr[30];
1946 + do
1948 + v2l_vCardItem *ptr;
1950 + ptr = (v2l_vCardItem *) pmalloc (self->poolref,
1951 + sizeof (v2l_vCardItem));
1953 + ptr->vcard = tmp;
1954 + ptr->ldap = pstrdup (self->poolref, xmlnode_get_data (tag));
1955 + ptr->next = NULL;
1956 + ptr->group = group[0] == 0 ? NULL :
1957 + pstrdup (self->poolref, group);
1959 + if (_V2L_TPL == NULL)
1961 + _V2L_TPL = ptr;
1962 + item = ptr;
1964 + else
1966 + item->next = ptr;
1967 + item = item->next;
1970 + sprintf (find_attr, "%s?v2ln=%d", *stag, ++ntags);
1971 + tag = xmlnode_get_tag (tpl, find_attr);
1972 + } while (tag && xmlnode_get_data (tag) != NULL && ntags < 10);
1973 + }/* xmlnode_get_data (tag) != NULL */
1974 + } /* for loop, all tags in template */
1976 + xmlnode_free (tpl);
1979 + return _V2L_TPL;
1982 +#if 0
1983 +static v2l_vCardItem *
1984 +_v2l_vcard_find_tag (v2l_vCardItem *item, char *tag)
1986 + v2l_vCardItem *res = NULL;
1988 + while (item != NULL)
1990 + if (strcmp (item->vcard, tag) == 0)
1992 + res = item;
1993 + break;
1996 + item = item->next;
1999 + return res;
2001 +#endif
2003 +static v2l_vCardItem *
2004 +_v2l_vcard_find_attr (v2l_vCardItem *item, const char *attr)
2006 + v2l_vCardItem *res = NULL;
2008 + while (item != NULL)
2010 + if (strcmp (item->ldap, attr) == 0)
2012 + res = item;
2013 + break;
2016 + item = item->next;
2019 + return res;
2022 +static int
2023 +_v2l_vcard_attr_match (const char *attr, void **shrdata)
2025 + *shrdata = _v2l_vcard_find_attr (_v2l_vcard_map (NULL), attr);
2027 + return *shrdata != NULL;
2030 +static void
2031 +_v2l_vcard_attr_value (const char *attr, const char **vals, void *pointer,
2032 + void *shrdata)
2034 + xmlnode vcard;
2035 + v2l_vCardItem *match;
2037 + vcard = (xmlnode) pointer;
2038 + match = (v2l_vCardItem *) shrdata;
2040 + if (vals != NULL)
2042 + /* FIXME: ugly */
2043 + if (match->group != NULL && (strcmp (match->group, "PHOTO") == 0))
2045 + _v2l_ldap2vcard_photo (match, vals, vcard);
2047 + else
2049 + _v2l_ldap2vcard_generic (match, vals, vcard);
2054 +static int
2055 +_v2l_create_fn (xmlnode vcard)
2057 + xmlnode n, fn;
2058 + char *family, *given, *fn_str;
2059 + int len;
2061 + fn = xmlnode_insert_tag (vcard, "FN");
2062 + n = xmlnode_get_tag (vcard, "N");
2063 + family = xmlnode_get_tag_data (n, "FAMILY");
2064 + given = xmlnode_get_tag_data (n, "GIVEN");
2066 + len = 0;
2067 + len += (family != NULL) ? strlen (family) : 0;
2068 + len += (given != NULL) ? strlen (given) : 0;
2070 + if (len == 0)
2072 + log_debug (ZONE, "<fn><n>...</n></fn> is empty, returning");
2073 + return 1;
2076 + fn_str = (char *) malloc (sizeof (char) * (len + 2));
2078 + if (fn_str == NULL)
2080 + LOG_ERROR_MEM;
2081 + return 0;
2084 + fn_str[0] = 0;
2086 + if (family != NULL)
2088 + sprintf (fn_str, "%s ", family);
2091 + if (given != NULL)
2093 + strcat (fn_str, given);
2096 + xmlnode_insert_cdata (fn, fn_str, len + 1);
2097 + free (fn_str);
2099 + return 1;
2102 +/* LDAP -> vCard */
2104 +static xmlnode
2105 +_v2l_ldap2vcard_generic (v2l_vCardItem *item, const char **vals, xmlnode res)
2107 + xmlnode node;
2109 + if (item->group != NULL)
2111 + node = xmlnode_get_tag (res, item->group);
2113 + if (node == NULL)
2115 + node = xmlnode_insert_tag (res, item->group);
2118 + else
2120 + node = res;
2123 + node = xmlnode_insert_tag (node, item->vcard);
2124 + xmlnode_insert_cdata (node, vals[0], strlen (vals[0]));
2126 + return res;
2129 +static xmlnode
2130 +_v2l_ldap2vcard_photo (v2l_vCardItem *item, const char **vals, xmlnode res)
2132 + xmlnode mimetype, photo;
2134 + res = _v2l_ldap2vcard_generic (item, vals, res);
2136 + /* FIXME: mimetype is hardcoded */
2137 + photo = xmlnode_get_tag (res, "PHOTO");
2138 + mimetype = xmlnode_insert_tag (photo, "TYPE");
2139 + xmlnode_insert_cdata (mimetype, "image/jpeg", sizeof ("image/jpeg"));
2141 + return res;
2144 +/* vCard -> LDAP */
2146 +static v2l_LdapRequest *
2147 +_v2l_vcard2ldap_generic (v2l_vCardItem *item, xmlnode data,
2148 + v2l_LdapRequest *req)
2150 + const char *str;
2152 + str = xmlnode_get_data (data);
2154 + return str == NULL ? req : v2l_add_attr_str (req, item->ldap, str);
2157 +static v2l_LdapRequest *
2158 +_v2l_set_sn12 (v2l_LdapRequest *req)
2160 + if (req != NULL)
2162 + v2l_LdapRequest *ptr;
2163 + char *sn;
2165 + for (ptr = req, sn = NULL; ptr != NULL; ptr = ptr->next)
2167 + if (strcmp (ptr->attr->mod_type, "sn") == 0)
2169 + sn = ptr->attr->mod_values[0];
2170 + break;
2174 + if (sn != NULL)
2176 + char *sit, *sn1, *sn2;
2178 + for (sit = sn; *sit != ' ' && *sit != 0; sit++);
2180 + sn1 = (char *) malloc (sizeof (char) * (sit - sn + 1));
2182 + if (sn1 == NULL)
2184 + return req;
2187 + strncpy (sn1, sn, sizeof (char) * (sit - sn));
2188 + sn1[sit - sn] = 0;
2189 + ptr = v2l_add_attr_str (req, "sn1", sn1);
2190 + free (sn1);
2192 + if (ptr == NULL)
2194 + return req;
2197 + req = ptr;
2199 + if (sit - sn != strlen (sn))
2201 + sn2 = (char *) malloc (strlen (sit) + 1);
2203 + if (sn2 == NULL)
2205 + LOG_ERROR_MEM;
2206 + return req;
2209 + strcpy (sn2, sit);
2210 + ptr = v2l_add_attr_str (req, "sn2", sn2);
2211 + free (sn2);
2213 + if (ptr == NULL)
2215 + return req;
2218 + req = ptr;
2220 + } /* sn != NULL */
2221 + } /* req != NULL */
2223 + return req;
2225 diff -Naurb jabberd-2.1.14.orig/sm/v2l_vcard.h jabberd-2.1.14/sm/v2l_vcard.h
2226 --- jabberd-2.1.14.orig/sm/v2l_vcard.h 1970-01-01 01:00:00.000000000 +0100
2227 +++ jabberd-2.1.14/sm/v2l_vcard.h 2007-09-26 23:52:13.000000000 +0200
2228 @@ -0,0 +1,41 @@
2230 + * This program is free software; you can redistribute it and/or modify
2231 + * it under the terms of the GNU General Public License as published by
2232 + * the Free Software Foundation; either version 2 of the License, or
2233 + * (at your option) any later version.
2235 + * This program is distributed in the hope that it will be useful,
2236 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2237 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2238 + * GNU General Public License for more details.
2240 + * You should have received a copy of the GNU General Public License
2241 + * along with this program; if not, write to the Free Software
2242 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2243 + */
2245 +/*! \file v2l_vcard.h
2246 + \brief XML vCard's to/from LDAP objects translation functions.
2249 +#ifndef __V2L_VCARD_H
2250 +#define __V2L_VCARD_H
2252 +#include <v2l_conn.h>
2254 +/*! \brief Gets user vCard in xml format
2255 + \param self Module config
2256 + \param curr_conn user connection.
2257 + \return vCard main node, NULL if error.
2259 +extern xmlnode v2l_vcard_get (v2l_Config *self, v2l_LdapConn *curr_conn);
2261 +/*! \brief Writes vCard to user LDAP directory entry.
2262 + \param self Module config
2263 + \param curr_conn user connection.
2264 + \param data the vCard
2265 + \return 1 if no error, otherwise 0
2267 +extern int v2l_vcard_set (v2l_Config *self, v2l_LdapConn *curr_conn,
2268 + xmlnode data);
2269 +#endif
2270 diff -Naurb jabberd-2.1.14.orig/sm/xmlnode.c jabberd-2.1.14/sm/xmlnode.c
2271 --- jabberd-2.1.14.orig/sm/xmlnode.c 1970-01-01 01:00:00.000000000 +0100
2272 +++ jabberd-2.1.14/sm/xmlnode.c 2007-09-25 17:45:15.000000000 +0200
2273 @@ -0,0 +1,1029 @@
2274 +/* --------------------------------------------------------------------------
2276 + * License
2278 + * The contents of this file are subject to the Jabber Open Source License
2279 + * Version 1.0 (the "JOSL"). You may not copy or use this file, in either
2280 + * source code or executable form, except in compliance with the JOSL. You
2281 + * may obtain a copy of the JOSL at http://www.jabber.org/ or at
2282 + * http://www.opensource.org/.
2284 + * Software distributed under the JOSL is distributed on an "AS IS" basis,
2285 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL
2286 + * for the specific language governing rights and limitations under the
2287 + * JOSL.
2289 + * Copyrights
2291 + * Portions created by or assigned to Jabber.com, Inc. are
2292 + * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact
2293 + * information for Jabber.com, Inc. is available at http://www.jabber.com/.
2295 + * Portions Copyright (c) 1998-1999 Jeremie Miller.
2297 + * Acknowledgements
2299 + * Special thanks to the Jabber Open Source Contributors for their
2300 + * suggestions and support of Jabber.
2302 + * Alternatively, the contents of this file may be used under the terms of the
2303 + * GNU General Public License Version 2 or later (the "GPL"), in which case
2304 + * the provisions of the GPL are applicable instead of those above. If you
2305 + * wish to allow use of your version of this file only under the terms of the
2306 + * GPL and not to allow others to use your version of this file under the JOSL,
2307 + * indicate your decision by deleting the provisions above and replace them
2308 + * with the notice and other provisions required by the GPL. If you do not
2309 + * delete the provisions above, a recipient may use your version of this file
2310 + * under either the JOSL or the GPL.
2313 + * --------------------------------------------------------------------------*/
2315 +#include "../util/util.h"
2316 +#include "xmlnode.h"
2318 +#include <sys/types.h>
2319 +#include <sys/stat.h>
2320 +#include <fcntl.h>
2322 +/* Internal routines */
2323 +xmlnode _xmlnode_new(pool p, const char* name, unsigned int type)
2325 + xmlnode result = NULL;
2326 + if (type > NTYPE_LAST)
2327 + return NULL;
2329 + if (type != NTYPE_CDATA && name == NULL)
2330 + return NULL;
2332 + if (p == NULL)
2334 + p = pool_heap(1*1024);
2337 + /* Allocate & zero memory */
2338 + result = (xmlnode)pmalloco(p, sizeof(_xmlnode));
2340 + /* Initialize fields */
2341 + if (type != NTYPE_CDATA)
2342 + result->name = pstrdup(p,name);
2343 + result->type = type;
2344 + result->p = p;
2345 + return result;
2348 +static xmlnode _xmlnode_append_sibling(xmlnode lastsibling, const char* name, unsigned int type)
2350 + xmlnode result;
2352 + result = _xmlnode_new(xmlnode_pool(lastsibling), name, type);
2353 + if (result != NULL)
2355 + /* Setup sibling pointers */
2356 + result->prev = lastsibling;
2357 + lastsibling->next = result;
2359 + return result;
2362 +static xmlnode _xmlnode_insert(xmlnode parent, const char* name, unsigned int type)
2364 + xmlnode result;
2366 + if(parent == NULL || (type != NTYPE_CDATA && name == NULL)) return NULL;
2368 + /* If parent->firstchild is NULL, simply create a new node for the first child */
2369 + if (parent->firstchild == NULL)
2371 + result = _xmlnode_new(parent->p, name, type);
2372 + parent->firstchild = result;
2374 + /* Otherwise, append this to the lastchild */
2375 + else
2377 + result= _xmlnode_append_sibling(parent->lastchild, name, type);
2379 + result->parent = parent;
2380 + parent->lastchild = result;
2381 + return result;
2385 +static xmlnode _xmlnode_search(xmlnode firstsibling, const char* name, unsigned int type)
2387 + xmlnode current;
2389 + /* Walk the sibling list, looking for a NTYPE_TAG xmlnode with
2390 + the specified name */
2391 + current = firstsibling;
2392 + while (current != NULL)
2394 + if ((current->type == type) && (j_strcmp(current->name, name) == 0))
2395 + return current;
2396 + else
2397 + current = current->next;
2399 + return NULL;
2402 +void _xmlnode_merge(xmlnode data)
2404 + xmlnode cur;
2405 + char *merge, *scur;
2406 + int imerge;
2408 + /* get total size of all merged cdata */
2409 + imerge = 0;
2410 + for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next)
2411 + imerge += cur->data_sz;
2413 + /* copy in current data and then spin through all of them and merge */
2414 + scur = merge = pmalloc(data->p,imerge + 1);
2415 + for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next)
2417 + memcpy(scur,cur->data,cur->data_sz);
2418 + scur += cur->data_sz;
2420 + *scur = '\0';
2422 + /* this effectively hides all of the merged-in chunks */
2423 + data->next = cur;
2424 + if(cur == NULL)
2425 + data->parent->lastchild = data;
2426 + else
2427 + cur->prev = data;
2429 + /* reset data */
2430 + data->data = merge;
2431 + data->data_sz = imerge;
2435 +static void _xmlnode_hide_sibling(xmlnode child)
2437 + if(child == NULL)
2438 + return;
2440 + if(child->prev != NULL)
2441 + child->prev->next = child->next;
2442 + if(child->next != NULL)
2443 + child->next->prev = child->prev;
2446 +void _xmlnode_tag2str(spool s, xmlnode node, int flag)
2448 + xmlnode tmp;
2450 + if(flag==0 || flag==1)
2452 + spooler(s,"<",xmlnode_get_name(node),s);
2453 + tmp = xmlnode_get_firstattrib(node);
2454 + while(tmp) {
2455 + spooler(s," ",xmlnode_get_name(tmp),"='",strescape(xmlnode_pool(node),xmlnode_get_data(tmp), strlen(xmlnode_get_data(tmp))),"'",s);
2456 + tmp = xmlnode_get_nextsibling(tmp);
2458 + if(flag==0)
2459 + spool_add(s,"/>");
2460 + else
2461 + spool_add(s,">");
2463 + else
2465 + spooler(s,"</",xmlnode_get_name(node),">",s);
2469 +spool _xmlnode2spool(xmlnode node)
2471 + spool s;
2472 + int level=0,dir=0;
2473 + xmlnode tmp;
2475 + if(!node || xmlnode_get_type(node)!=NTYPE_TAG)
2476 + return NULL;
2478 + s = spool_new(xmlnode_pool(node));
2479 + if(!s) return(NULL);
2481 + while(1)
2483 + if(dir==0)
2485 + if(xmlnode_get_type(node) == NTYPE_TAG)
2487 + if(xmlnode_has_children(node))
2489 + _xmlnode_tag2str(s,node,1);
2490 + node = xmlnode_get_firstchild(node);
2491 + level++;
2492 + continue;
2493 + }else{
2494 + _xmlnode_tag2str(s,node,0);
2496 + }else{
2497 + spool_add(s,strescape(xmlnode_pool(node),xmlnode_get_data(node),strlen(xmlnode_get_data(node))));
2501 + tmp = xmlnode_get_nextsibling(node);
2502 + if(!tmp)
2504 + node = xmlnode_get_parent(node);
2505 + level--;
2506 + if(level>=0) _xmlnode_tag2str(s,node,2);
2507 + if(level<1) break;
2508 + dir = 1;
2509 + }else{
2510 + node = tmp;
2511 + dir = 0;
2515 + return s;
2519 +/* External routines */
2523 + * xmlnode_new_tag -- create a tag node
2524 + * Automatically creates a memory pool for the node.
2526 + * parameters
2527 + * name -- name of the tag
2529 + * returns
2530 + * a pointer to the tag node
2531 + * or NULL if it was unsuccessfull
2532 + */
2533 +xmlnode xmlnode_new_tag(const char* name)
2535 + return _xmlnode_new(NULL, name, NTYPE_TAG);
2540 + * xmlnode_new_tag_pool -- create a tag node within given pool
2542 + * parameters
2543 + * p -- previously created memory pool
2544 + * name -- name of the tag
2546 + * returns
2547 + * a pointer to the tag node
2548 + * or NULL if it was unsuccessfull
2549 + */
2550 +xmlnode xmlnode_new_tag_pool(pool p, const char* name)
2552 + return _xmlnode_new(p, name, NTYPE_TAG);
2557 + * xmlnode_insert_tag -- append a child tag to a tag
2559 + * parameters
2560 + * parent -- pointer to the parent tag
2561 + * name -- name of the child tag
2563 + * returns
2564 + * a pointer to the child tag node
2565 + * or NULL if it was unsuccessfull
2566 + */
2567 +xmlnode xmlnode_insert_tag(xmlnode parent, const char* name)
2569 + return _xmlnode_insert(parent, name, NTYPE_TAG);
2574 + * xmlnode_insert_cdata -- append character data to a tag
2576 + * parameters
2577 + * parent -- parent tag
2578 + * CDATA -- character data
2579 + * size -- size of CDATA
2580 + * or -1 for null-terminated CDATA strings
2582 + * returns
2583 + * a pointer to the child CDATA node
2584 + * or NULL if it was unsuccessfull
2585 + */
2586 +xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size)
2588 + xmlnode result;
2590 + if(CDATA == NULL || parent == NULL)
2591 + return NULL;
2593 + if(size == -1)
2594 + size = strlen(CDATA);
2596 + result = _xmlnode_insert(parent, NULL, NTYPE_CDATA);
2597 + if (result != NULL)
2599 + result->data = (char*)pmalloc(result->p, size + 1);
2600 + memcpy(result->data, CDATA, size);
2601 + result->data[size] = '\0';
2602 + result->data_sz = size;
2605 + return result;
2610 + * xmlnode_get_tag -- find given tag in an xmlnode tree
2612 + * parameters
2613 + * parent -- pointer to the parent tag
2614 + * name -- "name" for the child tag of that name
2615 + * "name/name" for a sub child (recurses)
2616 + * "?attrib" to match the first tag with that attrib defined
2617 + * "?attrib=value" to match the first tag with that attrib and value
2618 + * "=cdata" to match the cdata contents of the child
2619 + * or any combination: "name/name/?attrib", "name=cdata", etc
2621 + * results
2622 + * a pointer to the tag matching search criteria
2623 + * or NULL if search was unsuccessfull
2624 + */
2625 +xmlnode xmlnode_get_tag(xmlnode parent, const char* name)
2627 + char *str, *slash, *qmark, *equals;
2628 + xmlnode step, ret;
2631 + if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL;
2633 + if(strstr(name, "/") == NULL && strstr(name,"?") == NULL && strstr(name, "=") == NULL)
2634 + return _xmlnode_search(parent->firstchild, name, NTYPE_TAG);
2636 + str = strdup(name);
2637 + slash = strstr(str, "/");
2638 + qmark = strstr(str, "?");
2639 + equals = strstr(str, "=");
2641 + if(equals != NULL && (slash == NULL || equals < slash) && (qmark == NULL || equals < qmark))
2642 + { /* of type =cdata */
2644 + *equals = '\0';
2645 + equals++;
2647 + for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
2649 + if(xmlnode_get_type(step) != NTYPE_TAG)
2650 + continue;
2652 + if(*str != '\0')
2653 + if(j_strcmp(xmlnode_get_name(step),str) != 0)
2654 + continue;
2656 + if(j_strcmp(xmlnode_get_data(step),equals) != 0)
2657 + continue;
2659 + break;
2662 + free(str);
2663 + return step;
2667 + if(qmark != NULL && (slash == NULL || qmark < slash))
2668 + { /* of type ?attrib */
2670 + *qmark = '\0';
2671 + qmark++;
2672 + if(equals != NULL)
2674 + *equals = '\0';
2675 + equals++;
2678 + for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
2680 + if(xmlnode_get_type(step) != NTYPE_TAG)
2681 + continue;
2683 + if(*str != '\0')
2684 + if(j_strcmp(xmlnode_get_name(step),str) != 0)
2685 + continue;
2687 + if(xmlnode_get_attrib(step,qmark) == NULL)
2688 + continue;
2690 + if(equals != NULL && j_strcmp(xmlnode_get_attrib(step,qmark),equals) != 0)
2691 + continue;
2693 + break;
2696 + free(str);
2697 + return step;
2701 + *slash = '\0';
2702 + ++slash;
2704 + for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
2706 + if(xmlnode_get_type(step) != NTYPE_TAG) continue;
2708 + if(j_strcmp(xmlnode_get_name(step),str) != 0)
2709 + continue;
2711 + ret = xmlnode_get_tag(step, slash);
2712 + if(ret != NULL)
2714 + free(str);
2715 + return ret;
2719 + free(str);
2720 + return NULL;
2724 +/* return the cdata from any tag */
2725 +char *xmlnode_get_tag_data(xmlnode parent, const char *name)
2727 + xmlnode tag;
2729 + tag = xmlnode_get_tag(parent, name);
2730 + if(tag == NULL) return NULL;
2732 + return xmlnode_get_data(tag);
2736 +void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value)
2738 + xmlnode attrib;
2740 + if(owner == NULL || name == NULL || value == NULL) return;
2742 + /* If there are no existing attributs, allocate a new one to start
2743 + the list */
2744 + if (owner->firstattrib == NULL)
2746 + attrib = _xmlnode_new(owner->p, name, NTYPE_ATTRIB);
2747 + owner->firstattrib = attrib;
2748 + owner->lastattrib = attrib;
2750 + else
2752 + attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
2753 + if(attrib == NULL)
2755 + attrib = _xmlnode_append_sibling(owner->lastattrib, name, NTYPE_ATTRIB);
2756 + owner->lastattrib = attrib;
2759 + /* Update the value of the attribute */
2760 + attrib->data_sz = strlen(value);
2761 + attrib->data = pstrdup(owner->p, value);
2765 +char* xmlnode_get_attrib(xmlnode owner, const char* name)
2767 + xmlnode attrib;
2769 + if (owner != NULL && owner->firstattrib != NULL)
2771 + attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
2772 + if (attrib != NULL)
2773 + return (char*)attrib->data;
2775 + return NULL;
2778 +void xmlnode_put_vattrib(xmlnode owner, const char* name, void *value)
2780 + xmlnode attrib;
2782 + if (owner != NULL)
2784 + attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
2785 + if (attrib == NULL)
2787 + xmlnode_put_attrib(owner, name, "");
2788 + attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
2790 + if (attrib != NULL)
2791 + attrib->firstchild = (xmlnode)value;
2795 +void* xmlnode_get_vattrib(xmlnode owner, const char* name)
2797 + xmlnode attrib;
2799 + if (owner != NULL && owner->firstattrib != NULL)
2801 + attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
2802 + if (attrib != NULL)
2803 + return (void*)attrib->firstchild;
2805 + return NULL;
2808 +xmlnode xmlnode_get_firstattrib(xmlnode parent)
2810 + if (parent != NULL)
2811 + return parent->firstattrib;
2812 + return NULL;
2815 +xmlnode xmlnode_get_firstchild(xmlnode parent)
2817 + if (parent != NULL)
2818 + return parent->firstchild;
2819 + return NULL;
2822 +xmlnode xmlnode_get_lastchild(xmlnode parent)
2824 + if (parent != NULL)
2825 + return parent->lastchild;
2826 + return NULL;
2829 +xmlnode xmlnode_get_nextsibling(xmlnode sibling)
2831 + if (sibling != NULL)
2832 + return sibling->next;
2833 + return NULL;
2836 +xmlnode xmlnode_get_prevsibling(xmlnode sibling)
2838 + if (sibling != NULL)
2839 + return sibling->prev;
2840 + return NULL;
2843 +xmlnode xmlnode_get_parent(xmlnode node)
2845 + if (node != NULL)
2846 + return node->parent;
2847 + return NULL;
2850 +char* xmlnode_get_name(xmlnode node)
2852 + if (node != NULL)
2853 + return node->name;
2854 + return NULL;
2857 +char* xmlnode_get_data(xmlnode node)
2859 + if(xmlnode_get_type(node) == NTYPE_TAG) /* loop till we find a CDATA in the children */
2860 + for(node = xmlnode_get_firstchild(node); node != NULL; node = xmlnode_get_nextsibling(node))
2861 + if(xmlnode_get_type(node) == NTYPE_CDATA) break;
2863 + if(node == NULL) return NULL;
2865 + /* check for a dirty node w/ unassembled cdata chunks */
2866 + if(xmlnode_get_type(node->next) == NTYPE_CDATA)
2867 + _xmlnode_merge(node);
2869 + return node->data;
2872 +int xmlnode_get_datasz(xmlnode node)
2874 + if(xmlnode_get_type(node) != NTYPE_CDATA) return 0;
2876 + /* check for a dirty node w/ unassembled cdata chunks */
2877 + if(xmlnode_get_type(node->next) == NTYPE_CDATA)
2878 + _xmlnode_merge(node);
2879 + return node->data_sz;
2882 +int xmlnode_get_type(xmlnode node)
2884 + if (node != NULL)
2885 + return node->type;
2886 + return NTYPE_UNDEF;
2889 +int xmlnode_has_children(xmlnode node)
2891 + if ((node != NULL) && (node->firstchild != NULL))
2892 + return 1;
2893 + return 0;
2896 +int xmlnode_has_attribs(xmlnode node)
2898 + if ((node != NULL) && (node->firstattrib != NULL))
2899 + return 1;
2900 + return 0;
2903 +pool xmlnode_pool(xmlnode node)
2905 + if (node != NULL)
2906 + return node->p;
2907 + return (pool)NULL;
2910 +void xmlnode_hide(xmlnode child)
2912 + xmlnode parent;
2914 + if(child == NULL || child->parent == NULL)
2915 + return;
2917 + parent = child->parent;
2919 + /* first fix up at the child level */
2920 + _xmlnode_hide_sibling(child);
2922 + /* next fix up at the parent level */
2923 + if(parent->firstchild == child)
2924 + parent->firstchild = child->next;
2925 + if(parent->lastchild == child)
2926 + parent->lastchild = child->prev;
2929 +void xmlnode_hide_attrib(xmlnode parent, const char *name)
2931 + xmlnode attrib;
2933 + if(parent == NULL || parent->firstattrib == NULL || name == NULL)
2934 + return;
2936 + attrib = _xmlnode_search(parent->firstattrib, name, NTYPE_ATTRIB);
2937 + if(attrib == NULL)
2938 + return;
2940 + /* first fix up at the child level */
2941 + _xmlnode_hide_sibling(attrib);
2943 + /* next fix up at the parent level */
2944 + if(parent->firstattrib == attrib)
2945 + parent->firstattrib = attrib->next;
2946 + if(parent->lastattrib == attrib)
2947 + parent->lastattrib = attrib->prev;
2953 + * xmlnode2str -- convert given xmlnode tree into a string
2955 + * parameters
2956 + * node -- pointer to the xmlnode structure
2958 + * results
2959 + * a pointer to the created string
2960 + * or NULL if it was unsuccessfull
2961 + */
2962 +char *xmlnode2str(xmlnode node)
2964 + return spool_print(_xmlnode2spool(node));
2968 + * xmlnode2tstr -- convert given xmlnode tree into a newline terminated string
2970 + * parameters
2971 + * node -- pointer to the xmlnode structure
2973 + * results
2974 + * a pointer to the created string
2975 + * or NULL if it was unsuccessfull
2976 + */
2977 +char* xmlnode2tstr(xmlnode node)
2979 + spool s = _xmlnode2spool(node);
2980 + if (s != NULL)
2981 + spool_add(s, "\n");
2982 + return spool_print(s);
2986 +/* loop through both a and b comparing everything, attribs, cdata, children, etc */
2987 +int xmlnode_cmp(xmlnode a, xmlnode b)
2989 + int ret = 0;
2991 + while(1)
2993 + if(a == NULL && b == NULL)
2994 + return 0;
2996 + if(a == NULL || b == NULL)
2997 + return -1;
2999 + if(xmlnode_get_type(a) != xmlnode_get_type(b))
3000 + return -1;
3002 + switch(xmlnode_get_type(a))
3004 + case NTYPE_ATTRIB:
3005 + ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b));
3006 + if(ret != 0)
3007 + return -1;
3008 + ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b));
3009 + if(ret != 0)
3010 + return -1;
3011 + break;
3012 + case NTYPE_TAG:
3013 + ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b));
3014 + if(ret != 0)
3015 + return -1;
3016 + ret = xmlnode_cmp(xmlnode_get_firstattrib(a), xmlnode_get_firstattrib(b));
3017 + if(ret != 0)
3018 + return -1;
3019 + ret = xmlnode_cmp(xmlnode_get_firstchild(a), xmlnode_get_firstchild(b));
3020 + if(ret != 0)
3021 + return -1;
3022 + break;
3023 + case NTYPE_CDATA:
3024 + ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b));
3025 + if(ret != 0)
3026 + return -1;
3028 + a = xmlnode_get_nextsibling(a);
3029 + b = xmlnode_get_nextsibling(b);
3034 +xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node)
3036 + xmlnode child;
3038 + child = xmlnode_insert_tag(parent, xmlnode_get_name(node));
3039 + if (xmlnode_has_attribs(node))
3040 + xmlnode_insert_node(child, xmlnode_get_firstattrib(node));
3041 + if (xmlnode_has_children(node))
3042 + xmlnode_insert_node(child, xmlnode_get_firstchild(node));
3044 + return child;
3047 +/* places copy of node and node's siblings in parent */
3048 +void xmlnode_insert_node(xmlnode parent, xmlnode node)
3050 + if(node == NULL || parent == NULL)
3051 + return;
3053 + while(node != NULL)
3055 + switch(xmlnode_get_type(node))
3057 + case NTYPE_ATTRIB:
3058 + xmlnode_put_attrib(parent, xmlnode_get_name(node), xmlnode_get_data(node));
3059 + break;
3060 + case NTYPE_TAG:
3061 + xmlnode_insert_tag_node(parent, node);
3062 + break;
3063 + case NTYPE_CDATA:
3064 + xmlnode_insert_cdata(parent, xmlnode_get_data(node), xmlnode_get_datasz(node));
3066 + node = xmlnode_get_nextsibling(node);
3071 +/* produce full duplicate of x with a new pool, x must be a tag! */
3072 +xmlnode xmlnode_dup(xmlnode x)
3074 + xmlnode x2;
3076 + if(x == NULL)
3077 + return NULL;
3079 + x2 = xmlnode_new_tag(xmlnode_get_name(x));
3081 + if (xmlnode_has_attribs(x))
3082 + xmlnode_insert_node(x2, xmlnode_get_firstattrib(x));
3083 + if (xmlnode_has_children(x))
3084 + xmlnode_insert_node(x2, xmlnode_get_firstchild(x));
3086 + return x2;
3089 +xmlnode xmlnode_dup_pool(pool p, xmlnode x)
3091 + xmlnode x2;
3093 + if(x == NULL)
3094 + return NULL;
3096 + x2 = xmlnode_new_tag_pool(p, xmlnode_get_name(x));
3098 + if (xmlnode_has_attribs(x))
3099 + xmlnode_insert_node(x2, xmlnode_get_firstattrib(x));
3100 + if (xmlnode_has_children(x))
3101 + xmlnode_insert_node(x2, xmlnode_get_firstchild(x));
3103 + return x2;
3106 +xmlnode xmlnode_wrap(xmlnode x,const char *wrapper)
3108 + xmlnode wrap;
3109 + if(x==NULL||wrapper==NULL) return NULL;
3110 + wrap=xmlnode_new_tag_pool(xmlnode_pool(x),wrapper);
3111 + if(wrap==NULL) return NULL;
3112 + wrap->firstchild=x;
3113 + wrap->lastchild=x;
3114 + x->parent=wrap;
3115 + return wrap;
3118 +void xmlnode_free(xmlnode node)
3120 + if(node == NULL)
3121 + return;
3123 + pool_free(node->p);
3126 +/***/
3127 +void expat_startElement(void* userdata, const char* name, const char** atts)
3129 + /* get the xmlnode pointed to by the userdata */
3130 + xmlnode *x = userdata;
3131 + xmlnode current = *x;
3133 + if (current == NULL)
3135 + /* allocate a base node */
3136 + current = xmlnode_new_tag(name);
3137 + xmlnode_put_expat_attribs(current, atts);
3138 + *x = current;
3140 + else
3142 + *x = xmlnode_insert_tag(current, name);
3143 + xmlnode_put_expat_attribs(*x, atts);
3147 +void expat_endElement(void* userdata, const char* name)
3149 + xmlnode *x = userdata;
3150 + xmlnode current = *x;
3152 + current->complete = 1;
3153 + current = xmlnode_get_parent(current);
3155 + /* if it's NULL we've hit the top folks, otherwise back up a level */
3156 + if(current != NULL)
3157 + *x = current;
3160 +void expat_charData(void* userdata, const char* s, int len)
3162 + xmlnode *x = userdata;
3163 + xmlnode current = *x;
3165 + xmlnode_insert_cdata(current, s, len);
3169 +xmlnode xmlnode_str(char *str, int len)
3171 + XML_Parser p;
3172 + xmlnode *x, node; /* pointer to an xmlnode */
3174 + if(NULL == str)
3175 + return NULL;
3177 + x = malloc(sizeof(void *));
3179 + *x = NULL; /* pointer to NULL */
3180 + p = XML_ParserCreate(NULL);
3181 + XML_SetUserData(p, x);
3182 + XML_SetElementHandler(p, expat_startElement, expat_endElement);
3183 + XML_SetCharacterDataHandler(p, expat_charData);
3184 + if(!XML_Parse(p, str, len, 1))
3186 + /* jdebug(ZONE,"xmlnode_str_error: %s",(char *)XML_ErrorString(XML_GetErrorCode(p)));*/
3187 + xmlnode_free(*x);
3188 + *x = NULL;
3190 + node = *x;
3191 + free(x);
3192 + XML_ParserFree(p);
3193 + return node; /* return the xmlnode x points to */
3196 +xmlnode xmlnode_file(char *file)
3198 + XML_Parser p;
3199 + xmlnode *x, node; /* pointer to an xmlnode */
3200 + char buf[BUFSIZ];
3201 + int done, fd, len;
3203 + if(NULL == file)
3204 + return NULL;
3206 + fd = open(file,O_RDONLY);
3207 + if(fd < 0)
3208 + return NULL;
3210 + x = malloc(sizeof(void *));
3212 + *x = NULL; /* pointer to NULL */
3213 + p = XML_ParserCreate(NULL);
3214 + XML_SetUserData(p, x);
3215 + XML_SetElementHandler(p, expat_startElement, expat_endElement);
3216 + XML_SetCharacterDataHandler(p, expat_charData);
3217 + do{
3218 + len = read(fd, buf, BUFSIZ);
3219 + done = len < BUFSIZ;
3220 + if(!XML_Parse(p, buf, len, done))
3222 + /* jdebug(ZONE,"xmlnode_file_parseerror: %s",(char *)XML_ErrorString(XML_GetErrorCode(p)));*/
3223 + xmlnode_free(*x);
3224 + *x = NULL;
3225 + done = 1;
3227 + }while(!done);
3229 + node = *x;
3230 + XML_ParserFree(p);
3231 + free(x);
3232 + close(fd);
3233 + return node; /* return the xmlnode x points to */
3236 +char* xmlnode_file_borked(char *file)
3238 + XML_Parser p;
3239 + char buf[BUFSIZ];
3240 + static char err[1024];
3241 + int fd, len, done;
3243 + if(NULL == file)
3244 + return "no file specified";
3246 + fd = open(file,O_RDONLY);
3247 + if(fd < 0)
3248 + return "unable to open file";
3250 + p = XML_ParserCreate(NULL);
3251 + while(1)
3253 + len = read(fd, buf, BUFSIZ);
3254 + done = len < BUFSIZ;
3255 + if(!XML_Parse(p, buf, len, done))
3257 + snprintf(err,1023,"%s at line %d and column %d",XML_ErrorString(XML_GetErrorCode(p)),XML_GetErrorLineNumber(p),XML_GetErrorColumnNumber(p));
3258 + XML_ParserFree(p);
3259 + close(fd);
3260 + return err;
3265 +int xmlnode2file(char *file, xmlnode node)
3267 + char *doc, *ftmp;
3268 + int fd, i;
3270 + if(file == NULL || node == NULL)
3271 + return -1;
3273 + ftmp = spools(xmlnode_pool(node),file,".t.m.p",xmlnode_pool(node));
3274 + fd = open(ftmp, O_CREAT | O_WRONLY | O_TRUNC, 0600);
3275 + if(fd < 0)
3276 + return -1;
3278 + doc = xmlnode2str(node);
3279 + i = write(fd,doc,strlen(doc));
3280 + if(i < 0)
3281 + return -1;
3283 + close(fd);
3285 + if(rename(ftmp,file) < 0)
3287 + unlink(ftmp);
3288 + return -1;
3290 + return 1;
3293 +void xmlnode_put_expat_attribs(xmlnode owner, const char** atts)
3295 + int i = 0;
3296 + if (atts == NULL) return;
3297 + while (atts[i] != '\0')
3299 + xmlnode_put_attrib(owner, atts[i], atts[i+1]);
3300 + i += 2;
3303 diff -Naurb jabberd-2.1.14.orig/sm/xmlnode.h jabberd-2.1.14/sm/xmlnode.h
3304 --- jabberd-2.1.14.orig/sm/xmlnode.h 1970-01-01 01:00:00.000000000 +0100
3305 +++ jabberd-2.1.14/sm/xmlnode.h 2007-08-29 15:54:24.000000000 +0200
3306 @@ -0,0 +1,128 @@
3307 +#ifndef __XMLNODE_H
3308 +#define __XMLNODE_H
3310 +#include "../util/util.h"
3311 +typedef pool_t pool;
3313 +/* --------------------------------------------------------- */
3314 +/* */
3315 +/* xmlnodes - Document Object Model */
3316 +/* */
3317 +/* --------------------------------------------------------- */
3318 +#define NTYPE_TAG 0
3319 +#define NTYPE_ATTRIB 1
3320 +#define NTYPE_CDATA 2
3322 +#define NTYPE_LAST 2
3323 +#define NTYPE_UNDEF -1
3325 +/* --------------------------------------------------------------------------
3326 + * Node structure. Do not use directly! Always use accessor macros
3327 + * and methods!
3328 + * -------------------------------------------------------------------------- */
3329 +typedef struct xmlnode_t
3331 + char* name;
3332 + unsigned short type;
3333 + char* data;
3334 + int data_sz;
3335 + int complete;
3336 + pool p;
3337 + struct xmlnode_t* parent;
3338 + struct xmlnode_t* firstchild;
3339 + struct xmlnode_t* lastchild;
3340 + struct xmlnode_t* prev;
3341 + struct xmlnode_t* next;
3342 + struct xmlnode_t* firstattrib;
3343 + struct xmlnode_t* lastattrib;
3344 +} _xmlnode, *xmlnode;
3346 +/* Node creation routines */
3347 +xmlnode xmlnode_wrap(xmlnode x,const char* wrapper);
3348 +xmlnode xmlnode_new_tag(const char* name);
3349 +xmlnode xmlnode_new_tag_pool(pool p, const char* name);
3350 +xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size);
3351 +xmlnode xmlnode_insert_tag(xmlnode parent, const char* name);
3352 +xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node);
3353 +void xmlnode_insert_node(xmlnode parent, xmlnode node);
3354 +xmlnode xmlnode_str(char *str, int len);
3355 +xmlnode xmlnode_file(char *file);
3356 +char* xmlnode_file_borked(char *file); /* same as _file but returns the parsing error */
3357 +xmlnode xmlnode_dup(xmlnode x); /* duplicate x */
3358 +xmlnode xmlnode_dup_pool(pool p, xmlnode x);
3360 +/* Node Memory Pool */
3361 +pool xmlnode_pool(xmlnode node);
3362 +xmlnode _xmlnode_new(pool p, const char *name, unsigned int type);
3364 +/* Node editing */
3365 +void xmlnode_hide(xmlnode child);
3366 +void xmlnode_hide_attrib(xmlnode parent, const char *name);
3368 +/* Node deletion routine, also frees the node pool! */
3369 +void xmlnode_free(xmlnode node);xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size);
3370 +xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node);
3371 +void xmlnode_insert_node(xmlnode parent, xmlnode node);
3372 +xmlnode xmlnode_str(char *str, int len);
3373 +xmlnode xmlnode_file(char *file);
3374 +char* xmlnode_file_borked(char *file); /* same as _file but returns the parsing error */
3375 +xmlnode xmlnode_dup(xmlnode x); /* duplicate x */
3376 +xmlnode xmlnode_dup_pool(pool p, xmlnode x);
3378 +/* Node Memory Pool */
3379 +pool xmlnode_pool(xmlnode node);
3380 +xmlnode _xmlnode_new(pool p, const char *name, unsigned int type);
3382 +/* Node editing */
3383 +void xmlnode_hide(xmlnode child);
3384 +void xmlnode_hide_attrib(xmlnode parent, const char *name);
3386 +/* Node deletion routine, also frees the node pool! */
3387 +void xmlnode_free(xmlnode node);
3389 +/* Locates a child tag by name and returns it */
3390 +xmlnode xmlnode_get_tag(xmlnode parent, const char* name);
3391 +char* xmlnode_get_tag_data(xmlnode parent, const char* name);
3393 +/* Attribute accessors */
3394 +void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value);
3395 +char* xmlnode_get_attrib(xmlnode owner, const char* name);
3396 +void xmlnode_put_expat_attribs(xmlnode owner, const char** atts);
3398 +/* Bastard am I, but these are fun for internal use ;-) */
3399 +void xmlnode_put_vattrib(xmlnode owner, const char* name, void *value);
3400 +void* xmlnode_get_vattrib(xmlnode owner, const char* name);
3402 +/* Node traversal routines */
3403 +xmlnode xmlnode_get_firstattrib(xmlnode parent);
3404 +xmlnode xmlnode_get_firstchild(xmlnode parent);
3405 +xmlnode xmlnode_get_lastchild(xmlnode parent);
3406 +xmlnode xmlnode_get_nextsibling(xmlnode sibling);
3407 +xmlnode xmlnode_get_prevsibling(xmlnode sibling);
3408 +xmlnode xmlnode_get_parent(xmlnode node);
3410 +/* Node information routines */
3411 +char* xmlnode_get_name(xmlnode node);
3412 +char* xmlnode_get_data(xmlnode node);
3413 +int xmlnode_get_datasz(xmlnode node);
3414 +int xmlnode_get_type(xmlnode node);
3416 +int xmlnode_has_children(xmlnode node);
3417 +int xmlnode_has_attribs(xmlnode node);
3419 +/* Node-to-string translation */
3420 +char* xmlnode2str(xmlnode node);
3422 +/* Node-to-terminated-string translation
3423 + * -- useful for interfacing w/ scripting langs */
3424 +char* xmlnode2tstr(xmlnode node);
3426 +int xmlnode_cmp(xmlnode a, xmlnode b); /* compares a and b for equality */
3428 +int xmlnode2file(char *file, xmlnode node); /* writes node to file */
3430 +/* Expat callbacks */
3431 +void expat_startElement(void* userdata, const char* name, const char** atts);
3432 +void expat_endElement(void* userdata, const char* name);
3433 +void expat_charData(void* userdata, const char* s, int len);
3434 +#endif