mod_template_roster.c [plain text]
#include "sm.h"
typedef struct _template_roster_st {
sm_t sm;
char *filename;
time_t mtime;
xht items;
} *template_roster_t;
union xhashv
{
void **val;
item_t *item_val;
};
static int _template_roster_reload(template_roster_t tr) {
struct stat st;
FILE *f;
long size;
char *buf;
nad_t nad;
int nitems, eitem, ajid, as10n, aname, egroup;
item_t item;
if(stat(tr->filename, &st) < 0) {
log_write(tr->sm->log, LOG_ERR, "couldn't stat roster template %s: %s", tr->filename, strerror(errno));
return 1;
}
if(st.st_mtime <= tr->mtime)
return 0;
tr->mtime = st.st_mtime;
if(tr->items != NULL)
xhash_free(tr->items);
tr->items = xhash_new(101);
f = fopen(tr->filename, "r");
if(f == NULL) {
log_write(tr->sm->log, LOG_ERR, "couldn't open roster template %s: %s", tr->filename, strerror(errno));
return 1;
}
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
buf = (char *) malloc(sizeof(char) * size);
fread(buf, 1, size, f);
if(ferror(f)) {
log_write(tr->sm->log, LOG_ERR, "couldn't read from roster template %s: %s", tr->filename, strerror(errno));
free(buf);
fclose(f);
return 1;
}
fclose(f);
nad = nad_parse(tr->sm->router->nad_cache, buf, size);
if(nad == NULL) {
log_write(tr->sm->log, LOG_ERR, "couldn't parse roster template");
free(buf);
return 1;
}
free(buf);
if(nad->ecur < 2) {
log_write(tr->sm->log, LOG_NOTICE, "roster template has no elements");
}
nitems = 0;
eitem = nad_find_elem(nad, 0, NAD_ENS(nad, 0), "item", 1);
while(eitem >= 0) {
ajid = nad_find_attr(nad, eitem, -1, "jid", NULL);
if(ajid < 0) {
log_write(tr->sm->log, LOG_ERR, "roster template has item with no jid, skipping");
continue;
}
item = (item_t) pmalloco(xhash_pool(tr->items), sizeof(struct item_st));
item->jid = jid_new(tr->sm->pc, NAD_AVAL(nad, ajid), NAD_AVAL_L(nad, ajid));
if(item->jid == NULL) {
log_write(tr->sm->log, LOG_ERR, "roster template has item with invalid jid, skipping");
continue;
}
pool_cleanup(xhash_pool(tr->items), (void (*)(void *)) jid_free, item->jid);
as10n = nad_find_attr(nad, eitem, -1, "subscription", NULL);
if(as10n >= 0) {
if(NAD_AVAL_L(nad, as10n) == 2 && strncmp("to", NAD_AVAL(nad, as10n), 2) == 0)
item->to = 1;
else if(NAD_AVAL_L(nad, as10n) == 4 && strncmp("from", NAD_AVAL(nad, as10n), 4) == 0)
item->from = 1;
else if(NAD_AVAL_L(nad, as10n) == 4 && strncmp("both", NAD_AVAL(nad, as10n), 4) == 0)
item->to = item->from = 1;
}
aname = nad_find_attr(nad, eitem, -1, "name", NULL);
if(aname >= 0)
item->name = pstrdupx(xhash_pool(tr->items), NAD_AVAL(nad, aname), NAD_AVAL_L(nad, aname));
egroup = nad_find_elem(nad, eitem, NAD_ENS(nad, 0), "group", 1);
while(egroup >= 0) {
if(NAD_CDATA_L(nad, egroup) <= 0) {
log_write(tr->sm->log, LOG_ERR, "roster template has zero-length group, skipping");
continue;
}
item->groups = (char **) realloc(item->groups, sizeof(char *) * (item->ngroups + 1));
item->groups[item->ngroups] = pstrdupx(xhash_pool(tr->items), NAD_CDATA(nad, egroup), NAD_CDATA_L(nad, egroup));
item->ngroups++;
egroup = nad_find_elem(nad, egroup, NAD_ENS(nad, 0), "group", 0);
}
if(item->groups != NULL)
pool_cleanup(xhash_pool(tr->items), free, item->groups);
xhash_put(tr->items, jid_full(item->jid), item);
log_debug(ZONE, "loaded roster template item %s, %d groups", jid_full(item->jid), item->ngroups);
nitems++;
eitem = nad_find_elem(nad, eitem, NAD_ENS(nad, 0), "item", 0);
}
log_write(tr->sm->log, LOG_NOTICE, "loaded %d items from roster template", nitems);
return 0;
}
static void _template_roster_save_item(sm_t sm, jid_t jid, 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(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=%i:%s)", strlen(jid_full(item->jid)), jid_full(item->jid));
storage_replace(sm->st, "roster-items", jid_user(jid), filter, os);
os_free(os);
snprintf(filter, 4096, "(jid=%i:%s)", strlen(jid_full(item->jid)), jid_full(item->jid));
if(item->ngroups == 0) {
storage_delete(sm->st, "roster-groups", jid_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(sm->st, "roster-groups", jid_user(jid), filter, os);
os_free(os);
}
static int _template_roster_user_create(mod_instance_t mi, jid_t jid) {
template_roster_t tr = (template_roster_t) mi->mod->private;
item_t item;
union xhashv xhv;
if(_template_roster_reload(tr) != 0)
return 0;
log_debug(ZONE, "populating roster with items from template");
if(xhash_iter_first(tr->items))
do {
xhv.item_val = &item;
xhash_iter_get(tr->items, NULL, xhv.val);
_template_roster_save_item(tr->sm, jid, item);
} while(xhash_iter_next(tr->items));
return 0;
}
static void _template_roster_free(module_t mod) {
template_roster_t tr = (template_roster_t) mod->private;
if(tr->items != NULL)
xhash_free(tr->items);
free(tr);
}
int template_roster_init(mod_instance_t mi, user_t user) {
module_t mod = mi->mod;
char *filename;
template_roster_t tr;
if(mod->init) return 0;
filename = config_get_one(mod->mm->sm->config, "user.template.roster", 0);
if(filename == NULL)
return 0;
tr = (template_roster_t) malloc(sizeof(struct _template_roster_st));
memset(tr, 0, sizeof(struct _template_roster_st));
tr->sm = mod->mm->sm;
tr->filename = filename;
mod->private = tr;
mod->user_create = _template_roster_user_create;
mod->free = _template_roster_free;
return 0;
}