diff -Naur config.h.in config.h.in
--- config.h.in 2004-06-24 18:55:19.000000000 -0400
+++ config.h.in 2005-06-30 09:54:27.000000000 -0400
@@ -420,6 +420,9 @@
/* Define to 1 if you want to use Berkeley DB for auth/reg/storage. */
#undef STORAGE_DB
+/* Define to 1 if you want to use LDAP for vCard storage. */
+#undef STORAGE_LDAPVCARD
+
/* Define to 1 if you want to use the filesystem for storage. */
#undef STORAGE_FS
diff -Naur configure configure
--- configure 2004-06-24 18:53:57.000000000 -0400
+++ configure 2005-06-30 10:18:46.000000000 -0400
@@ -21076,6 +21076,7 @@
cat >>confdefs.h <<\_ACEOF
#define STORAGE_LDAP 1
+#define STORAGE_LDAPVCARD 1
_ACEOF
fi
diff -Naur configure.in configure.in
--- configure.in 2004-06-24 18:50:26.000000000 -0400
+++ configure.in 2005-06-30 09:54:27.000000000 -0400
@@ -260,6 +260,7 @@
AC_MSG_ERROR([OpenLDAP client libraries >= 2.1.0 not found])
else
AC_DEFINE(STORAGE_LDAP,1,[Define to 1 if you want to use OpenLDAP for auth/reg.])
+ AC_DEFINE(STORAGE_LDAPVCARD,1,[Define to 1 if you want to use OpenLDAP for storage.])
fi
fi
diff -Naur etc/sm.xml.dist.in etc/sm.xml.dist.in
--- etc/sm.xml.dist.in 2004-04-01 23:32:31.000000000 -0500
+++ etc/sm.xml.dist.in 2005-06-30 10:09:40.000000000 -0400
@@ -74,6 +74,46 @@
+
+
+
+
+
+
+ ldap://localhost/ ldaps://ldap.example.com/
+
+
+
+
+
+ uid
+
+ inetOrgPerson
+
+ departmentNumber
+
+ jabberPublishedItem
+
+
+ o=Example Corp.
+
+
@@ -274,6 +314,7 @@
active
roster
+ roster-publish
privacy
disco-publish
vacation
@@ -373,6 +414,50 @@
+
+
+
+
+
+
+
+
+
+
+
diff -Naur sm/Makefile.am sm/Makefile.am
--- sm/Makefile.am 2004-04-07 08:14:47.000000000 -0400
+++ sm/Makefile.am 2005-06-30 09:54:27.000000000 -0400
@@ -16,6 +16,7 @@
user.c \
storage.c \
storage_db.c \
+ storage_ldapvcard.c \
storage_fs.c \
storage_mysql.c \
storage_pgsql.c \
@@ -30,6 +31,7 @@
mod_presence.c \
mod_privacy.c \
mod_roster.c \
+ mod_roster_publish.c \
mod_session.c \
mod_vacation.c \
mod_validate.c \
diff -Naur sm/Makefile.in sm/Makefile.in
--- sm/Makefile.in 2004-06-24 18:56:14.000000000 -0400
+++ sm/Makefile.in 2005-06-30 09:54:27.000000000 -0400
@@ -109,6 +109,7 @@
user.c \
storage.c \
storage_db.c \
+ storage_ldapvcard.c \
storage_fs.c \
storage_mysql.c \
storage_pgsql.c \
@@ -123,6 +124,7 @@
mod_presence.c \
mod_privacy.c \
mod_roster.c \
+ mod_roster_publish.c \
mod_session.c \
mod_vacation.c \
mod_validate.c \
@@ -151,13 +153,13 @@
am_sm_OBJECTS = aci.$(OBJEXT) dispatch.$(OBJEXT) feature.$(OBJEXT) \
main.$(OBJEXT) mm.$(OBJEXT) object.$(OBJEXT) pkt.$(OBJEXT) \
pres.$(OBJEXT) sess.$(OBJEXT) sm.$(OBJEXT) user.$(OBJEXT) \
- storage.$(OBJEXT) storage_db.$(OBJEXT) storage_fs.$(OBJEXT) \
+ storage.$(OBJEXT) storage_db.$(OBJEXT) storage_ldapvcard.$(OBJEXT) storage_fs.$(OBJEXT) \
storage_mysql.$(OBJEXT) storage_pgsql.$(OBJEXT) \
mod_active.$(OBJEXT) mod_announce.$(OBJEXT) \
mod_deliver.$(OBJEXT) mod_disco.$(OBJEXT) \
mod_disco_publish.$(OBJEXT) mod_echo.$(OBJEXT) \
mod_help.$(OBJEXT) mod_offline.$(OBJEXT) mod_presence.$(OBJEXT) \
- mod_privacy.$(OBJEXT) mod_roster.$(OBJEXT) \
+ mod_privacy.$(OBJEXT) mod_roster.$(OBJEXT) mod_roster_publish.$(OBJEXT) \
mod_session.$(OBJEXT) mod_vacation.$(OBJEXT) \
mod_validate.$(OBJEXT) mod_iq_last.$(OBJEXT) \
mod_iq_private.$(OBJEXT) mod_iq_time.$(OBJEXT) \
@@ -194,6 +196,7 @@
@AMDEP_TRUE@ ./$(DEPDIR)/mod_presence.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mod_privacy.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mod_roster.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/mod_roster_publish.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mod_session.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mod_template_roster.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mod_vacation.Po \
@@ -201,6 +204,7 @@
@AMDEP_TRUE@ ./$(DEPDIR)/pkt.Po ./$(DEPDIR)/pres.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/sess.Po ./$(DEPDIR)/sm.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/storage.Po ./$(DEPDIR)/storage_db.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/storage.Po ./$(DEPDIR)/storage_ldapvcard.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/storage_fs.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/storage_mysql.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/storage_pgsql.Po ./$(DEPDIR)/user.Po
@@ -287,6 +291,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_presence.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_privacy.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_roster.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_roster_publish.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_session.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_template_roster.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_vacation.Po@am__quote@
@@ -298,6 +303,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage_db.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage_ldapvcard.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage_fs.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage_mysql.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage_pgsql.Po@am__quote@
diff -Naur sm/mm.c sm/mm.c
--- sm/mm.c 2004-05-31 17:31:05.000000000 -0400
+++ sm/mm.c 2005-06-30 09:54:27.000000000 -0400
@@ -44,6 +44,7 @@
extern int presence_init(mod_instance_t);
extern int privacy_init(mod_instance_t);
extern int roster_init(mod_instance_t);
+extern int roster_publish_init(mod_instance_t);
extern int session_init(mod_instance_t);
extern int vacation_init(mod_instance_t);
extern int validate_init(mod_instance_t);
@@ -66,6 +67,7 @@
"presence",
"privacy",
"roster",
+ "roster-publish",
"session",
"vacation",
"validate",
@@ -90,6 +92,7 @@
presence_init,
privacy_init,
roster_init,
+ roster_publish_init,
session_init,
vacation_init,
validate_init,
diff -Naur sm/mod_roster.c sm/mod_roster.c
--- sm/mod_roster.c 2004-05-31 17:31:05.000000000 -0400
+++ sm/mod_roster.c 2005-06-30 09:54:27.000000000 -0400
@@ -593,6 +593,16 @@
log_debug(ZONE, "loading roster for %s", jid_user(user->jid));
+ if( user->sm->sess_pending_jid ) {
+ if( jid_compare_full(user->jid,user->sm->sess_pending_jid) != 0 ) {
+ log_debug(ZONE,"roster: will not load, session opened for (%s) but not (%s)",jid_user(user->sm->sess_pending_jid),jid_user(user->jid));
+ return 0;
+ }
+ } else {
+ log_debug(ZONE,"roster: will not load, sess_pending_jid is not defined");
+ return 0;
+ }
+
user->roster = xhash_new(101);
/* pull all the items */
diff -Naur sm/mod_roster_publish.c sm/mod_roster_publish.c
--- sm/mod_roster_publish.c 1969-12-31 19:00:00.000000000 -0500
+++ sm/mod_roster_publish.c 2005-06-30 09:54:27.000000000 -0400
@@ -0,0 +1,327 @@
+/*
+ * jabberd - Jabber Open Source Server
+ * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
+ * Ryan Eatmon, Robert Norris
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
+ */
+
+#include "sm.h"
+
+/** @file sm/mod_roster_publish.c
+ * @brief roster publishing
+ * @author Nikita Smirnov
+ */
+
+typedef struct _roster_publish_st {
+ int publish, forcegroups, fixsubs;
+ char *groupprefix, *groupsuffix, *removedomain;
+ int groupprefixlen, groupsuffixlen;
+} *roster_publish_t;
+
+/** free a single roster item */
+static void _roster_publish_free_walker(xht roster, const char *key, void *val, void *arg)
+{
+ item_t item = (item_t) val;
+ int i;
+
+ jid_free(item->jid);
+
+ if(item->name != NULL)
+ free(item->name);
+
+ for(i = 0; i < item->ngroups; i++)
+ free(item->groups[i]);
+ free(item->groups);
+
+ free(item);
+}
+
+static void _roster_publish_save_item(user_t user, item_t item) {
+ os_t os;
+ os_object_t o;
+ char filter[4096];
+ int i;
+
+ log_debug(ZONE, "saving roster item %s for %s", jid_full(item->jid), jid_user(user->jid));
+
+ os = os_new();
+ o = os_object_new(os);
+
+ os_object_put(o, "jid", jid_full(item->jid), os_type_STRING);
+
+ if(item->name != NULL)
+ os_object_put(o, "name", item->name, os_type_STRING);
+
+ os_object_put(o, "to", &item->to, os_type_BOOLEAN);
+ os_object_put(o, "from", &item->from, os_type_BOOLEAN);
+ os_object_put(o, "ask", &item->ask, os_type_INTEGER);
+
+ snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid));
+
+ storage_replace(user->sm->st, "roster-items", jid_user(user->jid), filter, os);
+
+ os_free(os);
+
+ snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid));
+
+ if(item->ngroups == 0) {
+ storage_delete(user->sm->st, "roster-groups", jid_user(user->jid), filter);
+ return;
+ }
+
+ os = os_new();
+
+ for(i = 0; i < item->ngroups; i++) {
+ o = os_object_new(os);
+
+ os_object_put(o, "jid", jid_full(item->jid), os_type_STRING);
+ os_object_put(o, "group", item->groups[i], os_type_STRING);
+ }
+
+ storage_replace(user->sm->st, "roster-groups", jid_user(user->jid), filter, os);
+
+ os_free(os);
+}
+
+/** publish the roster from the database */
+static int _roster_publish_user_load(mod_instance_t mi, user_t user) {
+ roster_publish_t roster_publish = (roster_publish_t) mi->mod->private;
+ os_t os, os_active;
+ os_object_t o;
+ os_type_t ot;
+ char *str, *group, filter[4096];
+ int i,j,gpos,found,delete,checksm,userinsm,tmp_to,tmp_from;
+ user_t usersm;
+ item_t item;
+ jid_t jid;
+
+ /* update roster to match published roster */
+ if( roster_publish->publish && user->sm->sess_pending_jid ) {
+ /* free if necessary */
+ if(user->roster == NULL) {
+ log_write(user->sm->log, LOG_NOTICE, "roster_publish: no roster for %s",jid_user(user->jid));
+ return 0;
+ }
+ if( jid_compare_full(user->jid,user->sm->sess_pending_jid) == 0 ) {
+//log_write(user->sm->log, LOG_NOTICE, "publishing roster for %s",jid_user(user->jid));
+ /* get published roster */
+ if( storage_get(user->sm->st, "published-roster", NULL, NULL, &os) == st_SUCCESS ) {
+ if(os_iter_first(os)) {
+ /* iterate on published roster */
+ jid = NULL;
+ do {
+ o = os_iter_object(os);
+ if(os_object_get(o, "jid", (void **) &str, &ot)) {
+ if( strcmp(str,jid_user(user->jid)) == 0 ) {
+ /* not adding self */
+ continue; /* do { } while( os_iter_next ) */
+ }
+ /* check that published item exists in sm database */
+ checksm=0;
+ if( jid ) jid_free(jid);
+ jid = jid_new(user->sm->pc, str, strlen(str));
+ if( roster_publish->removedomain ) {
+ if( strcmp(jid->domain,roster_publish->removedomain) == 0 ) {
+ checksm = 1;
+ }
+ }
+ if( checksm ) {
+ /* is this a hack? but i whant to know - the user activated in sm or no? */
+ if(storage_get(user->sm->st, "active", jid_user(jid), NULL, &os_active) == st_SUCCESS
+ && os_iter_first(os_active)) {
+ os_free(os_active);
+ userinsm = 1;
+ } else {
+ userinsm = 0;
+ }
+ }
+ item = xhash_get(user->roster,jid_user(jid));
+ if( item == NULL ) {
+ /* user has no this jid in his roster */
+ /* if we checking sm database and user is not in it, not adding */
+ if( checksm && !userinsm ) {
+ log_debug(ZONE, "published user %s has no record in sm, not adding", jid_user(jid));
+ continue; /* do { } while( os_iter_next ) */
+ }
+ log_debug(ZONE, "user has no %s in roster, adding", jid_user(jid));
+ item = (item_t) malloc(sizeof(struct item_st));
+ memset(item, 0, sizeof(struct item_st));
+
+ item->jid = jid_new(mi->mod->mm->sm->pc, jid_user(jid), 0);
+ if(item->jid == NULL) {
+ log_debug(ZONE, "eek! invalid jid %s, skipping it", jid_user(jid));
+ /* nvs: is it needed? */
+ free(item);
+ /* nvs: is it needed? */
+ } else {
+ if(os_object_get(o, "name", (void **) &str, &ot))
+ item->name = strdup(str);
+
+ os_object_get(o, "to", (void **) &item->to, &ot);
+ os_object_get(o, "from", (void **) &item->from, &ot);
+ os_object_get(o, "ask", (void **) &item->ask, &ot);
+
+ os_object_get(o, "group", (void **) &str, &ot);
+ item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups + 1));
+ item->groups[item->ngroups] = strdup(str);
+ item->ngroups++;
+
+ log_debug(ZONE, "adding %s to roster from template (to %d from %d ask %d name %s)", jid_full(item->jid), item->to, item->from, item->ask, item->name);
+
+ /* its good */
+ xhash_put(user->roster, jid_full(item->jid), (void *) item);
+ _roster_publish_save_item(user,item);
+ }
+ }
+ else /* if( item == NULL ) else ... : user has this jid in his roster */
+ {
+ /* if we checking sm database and user is not in it, remove it from roster */
+ if( checksm && !userinsm ) {
+ log_debug(ZONE, "published user %s has no record in sm, deleting from roster", jid_user(jid));
+
+ snprintf(filter, 4096, "(jid=%s)", jid_full(jid));
+ storage_delete(user->sm->st, "roster-items", jid_user(user->jid), filter);
+ snprintf(filter, 4096, "(jid=%s)", jid_full(jid));
+ storage_delete(user->sm->st, "roster-groups", jid_user(user->jid), filter);
+
+ xhash_zap(user->roster, jid_full(jid));
+ _roster_publish_free_walker(NULL, (const char *) jid_full(jid), (void *) item, NULL);
+ continue; /* do { } while( os_iter_next ) */
+ }
+ if( roster_publish->fixsubs ) {
+ /* check subscriptions and correct if needed */
+ os_object_get(o, "to", (void **) &tmp_to, &ot);
+ os_object_get(o, "from", (void **) &tmp_from, &ot);
+ if( item->to != tmp_to || item->from != tmp_from ) {
+ item->to = tmp_to;
+ item->from = tmp_from;
+ log_debug(ZONE, "fixsubs in roster %s, item %s",jid_user(user->jid),jid_user(item->jid));
+ xhash_put(user->roster, jid_full(item->jid), (void *) item);
+ _roster_publish_save_item(user,item);
+ }
+ }
+ if( roster_publish->forcegroups ) {
+ /* item already in roster, check groups if needed */
+ os_object_get(o, "group", (void **) &group, &ot);
+ /* find published roster item's group in user's roster */
+ found = 0;
+ if( group ) {
+ for(i = 0; i < item->ngroups; i++) {
+ if( strcmp(item->groups[i],group) == 0 ) {
+ found = 1;
+ /* do not break loop, give groups that matches
+ * prefix and suffix to be deleted
+ */
+ } else {
+ /* check if user's roster group matches
+ * prefix or suffix given in config
+ * and delete such groups (and thus they will be replaced)
+ */
+ delete = 0;
+ if( roster_publish->groupprefix ) {
+ if( strncmp(item->groups[i],roster_publish->groupprefix,roster_publish->groupprefixlen) == 0 ) {
+ delete = 1;
+ }
+ }
+ if( !delete && roster_publish->groupsuffix ) {
+ gpos=strlen(item->groups[i])-roster_publish->groupsuffixlen;
+ if( gpos > 0 ) {
+ if( strcmp(item->groups[i]+gpos,roster_publish->groupsuffix) == 0 ) {
+ delete = 1;
+ }
+ }
+ }
+ /* remove group from roster item */
+ if( delete ) {
+ free(item->groups[i]);
+ for(j = i; j < item->ngroups-1; j++) {
+ item->groups[j]=item->groups[j+1];
+ }
+ item->ngroups--;
+ item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups));
+ }
+ }
+ } /* for(i... */
+ } /* if( group ) */
+ if( !found ) {
+ log_debug(ZONE, "adding group %s to item %s for user %s",group,jid_user(item->jid),jid_user(user->jid));
+ item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups + 1));
+ item->groups[item->ngroups] = strdup(group);
+ item->ngroups++;
+ /* replace item */
+ xhash_put(user->roster, jid_full(item->jid), (void *) item);
+ _roster_publish_save_item(user,item);
+ }
+ } /* else if( roster_publish->forcegroups ) */
+ } /* end of if if( item == NULL ) */
+ } /* if( os_object_get(...) */
+ } while(os_iter_next(os));
+ if( jid ) jid_free(jid);
+ }
+ os_free(os);
+ } else {
+ log_debug(ZONE,"cannot read published roster");
+ }
+ }
+//log_write(user->sm->log, LOG_ERR, "roster_publish: publisheded roster for %s",jid_user(user->jid));
+ }
+ return 0;
+}
+
+static void _roster_publish_free(module_t mod) {
+ roster_publish_t roster_publish = (roster_publish_t) mod->private;
+
+ free(roster_publish);
+}
+
+int roster_publish_init(mod_instance_t mi, char *arg) {
+ log_debug(ZONE,"roster_publish_init called");
+
+ module_t mod = mi->mod;
+ roster_publish_t roster_publish;
+
+ if(mod->init) return 0;
+
+ roster_publish = (roster_publish_t) malloc(sizeof(struct _roster_publish_st));
+ memset(roster_publish, 0, sizeof(struct _roster_publish_st));
+
+ if( config_get_one(mod->mm->sm->config, "user.template.publish", 0) ) {
+ log_debug(ZONE,"publish template is set");
+ roster_publish->publish = 1;
+ roster_publish->removedomain = config_get_one(mod->mm->sm->config, "user.template.publish.check-remove-domain", 0);
+ roster_publish->fixsubs = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.fix-subscriptions", 0), 0);
+ if( config_get_one(mod->mm->sm->config, "user.template.publish.force-groups", 0) ) {
+ roster_publish->forcegroups = 1;
+ if( roster_publish->groupprefix = config_get_one(mod->mm->sm->config, "user.template.publish.force-groups.prefix", 0) ) {
+ roster_publish->groupprefixlen = strlen(roster_publish->groupprefix);
+ }
+ if( roster_publish->groupsuffix = config_get_one(mod->mm->sm->config, "user.template.publish.force-groups.suffix", 0) ) {
+ roster_publish->groupsuffixlen = strlen(roster_publish->groupsuffix);
+ }
+ } else {
+ roster_publish->forcegroups = 0;
+ }
+ } else {
+ log_debug(ZONE,"publish template is NOT set");
+ roster_publish->publish = 0;
+ }
+ mod->private = roster_publish;
+
+ mod->user_load = _roster_publish_user_load;
+ mod->free = _roster_publish_free;
+
+ return 0;
+}
diff -Naur sm/sess.c sm/sess.c
--- sm/sess.c 2004-05-31 17:31:05.000000000 -0400
+++ sm/sess.c 2005-06-30 09:54:27.000000000 -0400
@@ -105,8 +105,13 @@
log_debug(ZONE, "session requested for %s", jid_full(jid));
/* get user data for this guy */
+
+ sm->sess_pending_jid = jid;
+
user = user_load(sm, jid);
+ sm->sess_pending_jid = NULL;
+
/* unknown user */
if(user == NULL) {
if(config_get(sm->config, "user.auto-create") == NULL) {
@@ -119,7 +124,12 @@
if(user_create(sm, jid) != 0)
return NULL;
+ sm->sess_pending_jid = jid;
+
user = user_load(sm, jid);
+
+ sm->sess_pending_jid = NULL;
+
if(user == NULL) {
log_write(sm->log, LOG_NOTICE, "couldn't load user, can't start session: jid=%s", jid_full(jid));
return NULL;
diff -Naur sm/sm.h sm/sm.h
--- sm/sm.h 2004-05-31 17:31:05.000000000 -0400
+++ sm/sm.h 2005-06-30 09:54:27.000000000 -0400
@@ -187,6 +187,8 @@
xht users; /**< pointers to currently loaded users (key is user@@domain) */
+ jid_t sess_pending_jid; /**< jid for which session is created (set before user_load in sess.c and unset after user_load) */
+
xht sessions; /**< pointers to all connected sessions (key is random sm id) */
xht xmlns; /**< index of common namespaces (for iq sub-namespace in pkt_t) */
diff -Naur sm/storage.c sm/storage.c
--- sm/storage.c 2004-05-31 17:31:05.000000000 -0400
+++ sm/storage.c 2005-06-30 09:54:27.000000000 -0400
@@ -36,6 +36,9 @@
#ifdef STORAGE_DB
extern st_ret_t st_db_init(st_driver_t);
#endif
+#ifdef STORAGE_LDAPVCARD
+extern st_ret_t st_ldapvcard_init(st_driver_t);
+#endif
#ifdef STORAGE_FS
extern st_ret_t st_fs_init(st_driver_t);
#endif
@@ -50,6 +53,9 @@
#ifdef STORAGE_DB
"db",
#endif
+#ifdef STORAGE_LDAPVCARD
+ "ldapvcard",
+#endif
#ifdef STORAGE_FS
"fs",
#endif
@@ -66,6 +72,9 @@
#ifdef STORAGE_DB
st_db_init,
#endif
+#ifdef STORAGE_LDAPVCARD
+ st_ldapvcard_init,
+#endif
#ifdef STORAGE_FS
st_fs_init,
#endif
diff -Naur sm/storage_ldapvcard.c sm/storage_ldapvcard.c
--- sm/storage_ldapvcard.c 1969-12-31 19:00:00.000000000 -0500
+++ sm/storage_ldapvcard.c 2005-06-30 09:56:02.000000000 -0400
@@ -0,0 +1,373 @@
+/*
+ * jabberd - Jabber Open Source Server
+ * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
+ * Ryan Eatmon, Robert Norris
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
+ */
+
+/*
+ * Written by Nikita Smirnov in 2004
+ * on basis of authreg_ldap.c and storage_fs.c
+ */
+
+#include "sm.h"
+
+#ifdef STORAGE_LDAPVCARD
+
+#include
+
+/** internal structure, holds our data */
+typedef struct drvdata_st {
+ LDAP *ld;
+ char *uri;
+ char *srvid;
+ char *binddn;
+ char *bindpw;
+ char *basedn;
+
+ char *objectclass;
+ char *uidattr;
+ char *pwattr;
+ char *groupattr; // group for published-roster
+ char *publishedattr; // cat we publish it?
+} *drvdata_t;
+
+typedef struct {
+ char *ldapentry, *vcardentry;
+ os_type_t ot;
+} ldapvcard_entry_st;
+
+ldapvcard_entry_st ldapvcard_entry[] =
+{
+ {"displayName","fn",os_type_STRING},
+ {"cn","nickname",os_type_STRING},
+ {"labeledURI","url",os_type_STRING},
+ {"telephoneNumber","tel",os_type_STRING},
+ {"mail","email",os_type_STRING},
+ {"title","title",os_type_STRING},
+// {"","role",os_type_STRING},
+// {"","bday",os_type_STRING},
+ {"description","desc",os_type_STRING},
+ {"givenName","n-given",os_type_STRING},
+ {"sn","n-family",os_type_STRING},
+ {"st","adr-street",os_type_STRING},
+ {"l","adr-locality",os_type_STRING},
+// {"","adr-region",os_type_STRING},
+ {"postalCode","adr-pcode",os_type_STRING},
+ {"c","adr-country",os_type_STRING},
+ {"o","org-orgname",os_type_STRING},
+ {"ou","org-orgunit",os_type_STRING},
+ {NULL,NULL,0}
+};
+
+/** utility function to get ld_errno */
+static int _st_ldapvcard_get_lderrno(LDAP *ld)
+{
+ int ld_errno;
+ ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
+ return ld_errno;
+}
+
+/** connect to the ldap host */
+static int _st_ldapvcard_connect(st_driver_t drv)
+{
+ drvdata_t data = (drvdata_t) drv->private;
+ int ldapversion = LDAP_VERSION3;
+ int rc;
+
+ if(data->ld != NULL)
+ ldap_unbind_s(data->ld);
+
+ rc = ldap_initialize( &(data->ld), data->uri);
+ if( rc != LDAP_SUCCESS )
+ {
+ log_write(drv->st->sm->log, LOG_ERR, "ldap: ldap_initialize failed (uri=%s): %s", data->uri, ldap_err2string(rc));
+ return 1;
+ }
+
+ if (ldap_set_option(data->ld, LDAP_OPT_PROTOCOL_VERSION, &ldapversion) != LDAP_SUCCESS)
+ {
+ log_write(drv->st->sm->log, LOG_ERR, "ldap: couldn't set v3 protocol");
+ return 1;
+ }
+ if (ldap_set_option(data->ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON) != LDAP_SUCCESS)
+ {
+ log_write(drv->st->sm->log, LOG_ERR, "ldap: couldn't set LDAP_OPT_REFERRALS");
+ }
+
+ return 0;
+}
+
+/** unbind and clear variables */
+static int _st_ldapvcard_unbind(st_driver_t drv) {
+ drvdata_t data = (drvdata_t) drv->private;
+ ldap_unbind_s(data->ld);
+ data->ld = NULL;
+ return 0;
+}
+
+/** connect to ldap and bind as data->binddn */
+static int _st_ldapvcard_connect_bind(st_driver_t drv) {
+ drvdata_t data = (drvdata_t) drv->private;
+
+ if(data->ld != NULL ) {
+ return 0;
+ }
+
+ if( _st_ldapvcard_connect(drv) ) {
+ return 1;
+ }
+ if(ldap_simple_bind_s(data->ld, data->binddn, data->bindpw))
+ {
+ log_write(drv->st->sm->log, LOG_ERR, "ldap: bind as %s failed: %s", data->binddn, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld)));
+ _st_ldapvcard_unbind(drv);
+ return 1;
+ }
+ return 0;
+}
+
+static st_ret_t _st_ldapvcard_add_type(st_driver_t drv, char *type) {
+ if( strncmp(type,"vcard",6) != 0 && strncmp(type,"published-roster",17) ) {
+ log_write(drv->st->sm->log, LOG_ERR, "ldap: only vcard and published-roster types supperted for now");
+ return st_FAILED;
+ } else {
+ return st_SUCCESS;
+ }
+
+ return st_SUCCESS;
+}
+
+static st_ret_t _st_ldapvcard_get(st_driver_t drv, char *type, char *owner, char *filter, os_t *os) {
+ drvdata_t data = (drvdata_t) drv->private;
+ os_object_t o;
+ char ldapfilter[1024], *no_attrs[] = { NULL }, **vals;
+ LDAPMessage *result, *entry;
+ ldapvcard_entry_st le;
+ int i,ival;
+ char jid[2048], group[1024], name[2048]; // name is cn[1024] + ' ' + initials[1024]
+
+ if( _st_ldapvcard_connect_bind(drv) ) {
+ return st_FAILED;
+ }
+
+ if( strncmp(type,"vcard",6) == 0 ) {
+ /* The owner will be uid@server, so we need to strip it back to uid to search for it in LDAP */
+ /* This method means your uid can't contain "@" */
+ char *atpos;
+ atpos = strtok(owner,"@");
+
+ snprintf(ldapfilter, 1024, "(&(objectClass=%s)(%s=%s))", data->objectclass, data->uidattr, atpos);
+ if(ldap_search_s(data->ld, data->basedn, LDAP_SCOPE_SUBTREE, ldapfilter, no_attrs, 0, &result))
+ {
+ log_write(drv->st->sm->log, LOG_ERR, "ldap: search %s failed: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld)));
+ _st_ldapvcard_unbind(drv);
+ return st_FAILED;
+ }
+
+ entry = ldap_first_entry(data->ld, result);
+ if(entry == NULL)
+ {
+ ldap_msgfree(result);
+ return st_FAILED;
+ }
+
+ *os = os_new();
+
+ o = os_object_new(*os);
+
+ i = 0;
+ le = ldapvcard_entry[i];
+ while( le.ldapentry != NULL ) {
+ vals=ldap_get_values(data->ld,entry,le.ldapentry);
+ if( ldap_count_values(vals) > 0 ) {
+ switch(le.ot) {
+ case os_type_BOOLEAN:
+ case os_type_INTEGER:
+ ival=atoi(vals[0]);
+ os_object_put(o, le.vcardentry, &ival, le.ot);
+ break;
+ case os_type_STRING:
+ os_object_put(o, le.vcardentry, vals[0], le.ot);
+ break;
+
+ }
+ }
+ ldap_value_free(vals);
+ le = ldapvcard_entry[++i];
+ }
+ ldap_msgfree(result);
+ } else if( strncmp(type,"published-roster",17) == 0 ) {
+ /* snprintf(ldapfilter, 1024, "(&(&(%s=*)(!(%s=0)))(objectClass=%s)(%s=*))", data->publishedattr, data->publishedattr, data->objectclass, data->uidattr); */
+ snprintf(ldapfilter, 1024, "(&(objectClass=%s)(%s=*))", data->objectclass, data->uidattr);
+ if(ldap_search_s(data->ld, data->basedn, LDAP_SCOPE_SUBTREE, ldapfilter, no_attrs, 0, &result))
+ {
+ log_write(drv->st->sm->log, LOG_ERR, "ldap: search %s failed: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld)));
+ _st_ldapvcard_unbind(drv);
+ return st_FAILED;
+ }
+
+ entry = ldap_first_entry(data->ld, result);
+ if(entry == NULL)
+ {
+ ldap_msgfree(result);
+ return st_FAILED;
+ }
+
+ *os = os_new();
+
+ do {
+ vals = ldap_get_values(data->ld,entry,data->groupattr);
+ if( ldap_count_values(vals) <= 0 ) {
+ ldap_value_free(vals);
+ continue;
+ }
+ strncpy(group,vals[0],sizeof(group)-1); group[sizeof(group)-1]='\0';
+ ldap_value_free(vals);
+
+ vals = ldap_get_values(data->ld,entry,data->uidattr);
+ if( ldap_count_values(vals) <= 0 ) {
+ ldap_value_free(vals);
+ free(group);
+ continue;
+ }
+ strncpy(jid,vals[0],sizeof(jid)-1); jid[sizeof(jid)-1]='\0';
+ ldap_value_free(vals);
+
+ vals = ldap_get_values(data->ld,entry,"cn");
+ if( ldap_count_values(vals) <= 0 ) {
+ ldap_value_free(vals);
+ vals = ldap_get_values(data->ld,entry,"displayName");
+ if( ldap_count_values(vals) <= 0 ) {
+ strncpy(name,jid,sizeof(name)-1); name[sizeof(name)-1]='\0';
+ } else {
+ strncpy(name,vals[0],sizeof(name)-1); name[sizeof(name)-1]='\0';
+ }
+ } else {
+ strncpy(name,vals[0],1023); name[1023]='\0';
+ ldap_value_free(vals);
+ vals = ldap_get_values(data->ld,entry,"initials");
+ if( ldap_count_values(vals) > 0 ) {
+ strcat(name," ");
+ strncat(name,vals[0],1023);
+ }
+ }
+ ldap_value_free(vals);
+
+ /* We're using LDAP for authentication based on uid, so the user's jid will always be */
+ /* uid@servername. So, append @servername onto jid before we store it in the roster. */
+ strcat(jid,"@");
+ strcat(jid,data->srvid);
+
+ o = os_object_new(*os);
+ os_object_put(o,"jid",jid,os_type_STRING);
+ os_object_put(o,"group",group,os_type_STRING);
+ os_object_put(o,"name",name,os_type_STRING);
+ ival=1;
+ os_object_put(o,"to",&ival,os_type_INTEGER);
+ os_object_put(o,"from",&ival,os_type_INTEGER);
+ ival=0;
+ os_object_put(o,"ask",&ival,os_type_INTEGER);
+ } while( entry = ldap_next_entry(data->ld, entry) );
+ ldap_msgfree(result);
+ } else {
+ log_write(drv->st->sm->log, LOG_ERR, "ldap: unknown storage type: '%s'", type);
+ return st_FAILED;
+ }
+
+ return st_SUCCESS;
+}
+
+static st_ret_t _st_ldapvcard_put(st_driver_t drv, char *type, char *owner, os_t os) {
+ return st_FAILED;
+}
+static st_ret_t _st_ldapvcard_delete(st_driver_t drv, char *type, char *owner, char *filter) {
+ return st_SUCCESS;
+}
+static st_ret_t _st_ldapvcard_replace(st_driver_t drv, char *type, char *owner, char *filter, os_t os) {
+ return st_FAILED;
+}
+
+static void _st_ldapvcard_free(st_driver_t drv) {
+ drvdata_t data = (drvdata_t) drv->private;
+ if( data->ld ) {
+ _st_ldapvcard_unbind(drv);
+ }
+ free(data);
+}
+
+st_ret_t st_ldapvcard_init(st_driver_t drv) {
+ drvdata_t data;
+ char *uri, *basedn, *serverid;
+
+ log_write(drv->st->sm->log, LOG_NOTICE, "ldap: initializing");
+
+ uri = config_get_one(drv->st->sm->config, "storage.ldapvcard.uri", 0);
+ if(uri == NULL) {
+ log_write(drv->st->sm->log, LOG_ERR, "ldap: no uri specified in config file");
+ return st_FAILED;
+ }
+
+ serverid = config_get_one(drv->st->sm->config, "id", 0);
+ if(serverid == NULL) {
+ log_write(drv->st->sm->log, LOG_ERR, "ldap: no server id specified in config file");
+ return st_FAILED;
+ }
+
+ basedn = config_get_one(drv->st->sm->config, "storage.ldapvcard.basedn", 0);
+ if(basedn == NULL) {
+ log_write(drv->st->sm->log, LOG_ERR, "ldap: no basedns specified in config file");
+ return st_FAILED;
+ }
+ data = (drvdata_t) malloc(sizeof(struct drvdata_st));
+ memset(data, 0, sizeof(struct drvdata_st));
+
+ drv->private = (void *) data;
+
+ data->uri = uri;
+ data->basedn = basedn;
+ data->srvid = serverid;
+
+ data->binddn = config_get_one(drv->st->sm->config, "storage.ldapvcard.binddn", 0);
+ if(data->binddn != NULL)
+ data->bindpw = config_get_one(drv->st->sm->config, "storage.ldapvcard.bindpw", 0);
+
+ data->uidattr = config_get_one(drv->st->sm->config, "storage.ldapvcard.uidattr", 0);
+ if(data->uidattr == NULL)
+ data->uidattr = "uid";
+
+ data->groupattr = config_get_one(drv->st->sm->config, "storage.ldapvcard.groupattr", 0);
+ if(data->groupattr == NULL)
+ data->groupattr = "jabberPublishedGroup";
+
+ data->publishedattr = config_get_one(drv->st->sm->config, "storage.ldapvcard.publishedattr", 0);
+ if(data->publishedattr == NULL)
+ data->publishedattr = "jabberPublishedItem";
+
+ data->objectclass = config_get_one(drv->st->sm->config, "storage.ldapvcard.objectclass", 0);
+ if(data->objectclass == NULL)
+ data->objectclass = "jabberUser";
+
+ drv->add_type = _st_ldapvcard_add_type;
+ drv->put = _st_ldapvcard_put;
+ drv->get = _st_ldapvcard_get;
+ drv->delete = _st_ldapvcard_delete;
+ drv->replace = _st_ldapvcard_replace;
+ drv->free = _st_ldapvcard_free;
+
+ return st_SUCCESS;
+}
+
+#endif