#include "jsm.h"
#define NS_XGROUPS "jabber:xdb:groups"
#define NS_XINFO "jabber:xdb:groups:info"
#define GROUP_GET(mi,gid) (gt = (grouptab) xhash_get(mi->groups,gid)) ? gt : mod_groups_tab_add(mi,gid)
typedef struct
{
pool p;
xdbcache xc;
xht groups;
xht config;
char *inst;
} *mod_groups_i, _mod_groups_i;
typedef struct
{
xht to;
xht from;
} *grouptab, _grouptab;
xmlnode mod_groups_get_info(mod_groups_i mi, pool p, char *host, char *gid)
{
xmlnode info, xinfo, cur;
jid id;
if (gid == NULL) return NULL;
log_debug("mod_groups","Getting info %s",gid);
id = jid_new(p,host);
jid_set(id,gid,JID_RESOURCE);
xinfo = xdb_get(mi->xc,id,NS_XINFO);
info = xmlnode_get_tag((xmlnode) xhash_get(mi->config,gid),"info");
if (info != NULL)
info = xmlnode_dup(info);
else
return xinfo;
for (cur = xmlnode_get_firstchild(xinfo); cur != NULL; cur = xmlnode_get_nextsibling(cur))
if (xmlnode_get_tag(info,xmlnode_get_name(cur)) == NULL)
xmlnode_insert_node(info,cur);
xmlnode_free(xinfo);
return info;
}
xmlnode mod_groups_get_users(mod_groups_i mi, pool p, char *host, char *gid)
{
xmlnode group, users;
jid id;
if (gid == NULL) return NULL;
log_debug("mod_groups","getting users %s",gid);
group = (xmlnode) xhash_get(mi->config,gid);
if (group != NULL && (users = xmlnode_get_tag(group,"users")) != NULL)
return xmlnode_dup(users);
log_debug("mod_groups","%d %d",group != NULL,users!= NULL);
id = jid_new(p,host);
jid_set(id,gid,JID_RESOURCE);
return xdb_get(mi->xc,id,NS_XGROUPS);
}
void mod_groups_top_walk(xht h, const char *gid, void *val, void *arg)
{
if (strchr(gid,'/') == NULL)
{
xmlnode result = (xmlnode) arg;
xmlnode group, info;
pool p;
p = xmlnode_pool(result);
xmlnode_hide(xmlnode_get_tag(result,spools(p,"group?id=",gid,p)));
info = mod_groups_get_info((mod_groups_i) xmlnode_get_vattrib(result,"mi"),p,xmlnode_get_attrib(result,"host"),(char *) gid);
group = xmlnode_insert_tag(result,"group");
xmlnode_put_attrib(group,"name",xmlnode_get_tag_data(info,"name"));
xmlnode_put_attrib(group,"id",gid);
xmlnode_free(info);
}
}
xmlnode mod_groups_get_top(mod_groups_i mi, pool p, char *host)
{
xmlnode result;
result = xdb_get(mi->xc,jid_new(p,host),NS_XGROUPS);
if (result == NULL)
result = xmlnode_new_tag("query");
xmlnode_put_vattrib(result,"mi",(void *) mi);
xmlnode_put_attrib(result,"host",host);
xhash_walk(mi->config,mod_groups_top_walk,(void *) result);
xmlnode_hide_attrib(result,"mi");
xmlnode_hide_attrib(result,"host");
return result;
}
void mod_groups_current_walk(xht h, const char *gid, void *val, void *arg)
{
xmlnode info;
info = xmlnode_get_tag((xmlnode) val,"info");
if (xmlnode_get_tag(info,"require") != NULL)
{
xmlnode result = (xmlnode) arg;
xmlnode group;
pool p;
log_debug("mod_groups","required group %s",gid);
p = xmlnode_pool(result);
group = xmlnode_get_tag(result,spools(p,"?id=",gid,p));
if (group == NULL)
{
group = xmlnode_insert_tag(result,"group");
xmlnode_put_attrib(group,"id",gid);
if (xmlnode_get_tag(xmlnode_get_tag(info,"users"),xmlnode_get_attrib(result,"jid")) != NULL)
xmlnode_put_attrib(group,"type","both");
}
else
xmlnode_put_attrib(group,"type","both");
}
}
xmlnode mod_groups_get_current(mod_groups_i mi, jid id)
{
xmlnode result;
pool p;
id = jid_user(id);
result = xdb_get(mi->xc,id,NS_XGROUPS);
if (result == NULL)
result = xmlnode_new_tag("query");
p = xmlnode_pool(result);
xmlnode_put_attrib(result,"jid",spools(p,"?jid=",jid_full(id),p));
xhash_walk(mi->config,mod_groups_current_walk,(void *) result);
xmlnode_hide_attrib(result,"jid");
return result;
}
grouptab mod_groups_tab_add(mod_groups_i mi, char *gid)
{
grouptab gt;
log_debug("mod_groups","new group entry %s",gid);
gt = pmalloco(mi->p,sizeof(_grouptab));
gt->to = xhash_new(509);
gt->from = xhash_new(509);
xhash_put(mi->groups,pstrdup(mi->p,gid),gt);
return gt;
}
void mod_groups_presence_to_walk(xht h, const char *key, void *val, void *arg)
{
session from;
from = js_session_primary((udata) val);
if (from != NULL)
js_session_to((session) arg,jpacket_new(xmlnode_dup(from->presence)));
}
void mod_groups_presence_to(session s, grouptab gt)
{
xhash_put(gt->to,jid_full(s->u->id),(void *) s->u);
xhash_walk(gt->from,mod_groups_presence_to_walk,(void *) s);
}
void mod_groups_presence_from_walk(xht h, const char *key, void *val, void *arg)
{
xmlnode x = (xmlnode) arg;
udata u = (udata) val;
session s;
s = xmlnode_get_vattrib(x,"s");
if (s->u != u)
{
xmlnode pres;
log_debug("mod_groups","delivering presence to %s",jid_full(u->id));
pres = xmlnode_dup(x);
xmlnode_put_attrib(pres,"to",jid_full(u->id));
xmlnode_hide_attrib(pres,"s");
js_session_from(s,jpacket_new(pres));
}
}
void mod_groups_presence_from(session s, grouptab gt, xmlnode pres)
{
udata u = s->u;
log_debug("mod_groups","brodcasting");
if (xhash_get(gt->from,jid_full(u->id)) == NULL)
xhash_put(gt->from,jid_full(u->id),u);
xmlnode_hide_attrib(pres,"to");
xmlnode_put_vattrib(pres,"s",s);
xhash_walk(gt->to,mod_groups_presence_from_walk,(void *) pres);
xmlnode_hide_attrib(pres,"s");
}
void mod_groups_roster_insert(udata u, xmlnode roster, xmlnode group, char *gn, int add)
{
xmlnode item, cur, q;
char *id, *user;
user = jid_full(u->id);
q = xmlnode_get_tag(roster,"query");
for (cur = xmlnode_get_firstchild(group); cur != NULL; cur = xmlnode_get_nextsibling(cur))
{
id = xmlnode_get_attrib(cur,"jid");
if (id == NULL || strcmp(id,user) == 0)
continue;
item = xmlnode_insert_tag(q,"item");
xmlnode_put_attrib(item,"jid",id);
xmlnode_put_attrib(item,"subscription",add ? "to":"remove");
xmlnode_put_attrib(item,"name",xmlnode_get_attrib(cur,"name"));
xmlnode_insert_cdata(xmlnode_insert_tag(item,"group"),gn,-1);
}
xmlnode_free(group);
}
void mod_groups_roster_push(session s, xmlnode roster, int all)
{
session cur;
if (all)
{
for(cur = s->u->sessions; cur != NULL; cur = cur->next)
if(cur->roster)
js_session_to(cur,jpacket_new(cur->next ? xmlnode_dup(roster):roster));
}
else
js_session_to(s,jpacket_new(roster));
}
void mod_groups_update_walk(xht h, const char *key, void *val, void *arg)
{
xmlnode packet = (xmlnode) arg;
udata u = (udata) val;
mod_groups_roster_push(js_session_primary(u),xmlnode_dup(packet),1);
}
void mod_groups_update_rosters(grouptab gt, jid uid, char *un, char *gn, int add)
{
xmlnode packet, item, q;
packet = xmlnode_new_tag("iq");
xmlnode_put_attrib(packet, "type", "set");
q = xmlnode_insert_tag(packet, "query");
xmlnode_put_attrib(q,"xmlns",NS_ROSTER);
item = xmlnode_insert_tag(q,"item");
xmlnode_put_attrib(item,"jid",jid_full(uid));
xmlnode_put_attrib(item,"name",un);
xmlnode_put_attrib(item,"subscription",add ? "to" : "remove");
xmlnode_insert_cdata(xmlnode_insert_tag(item,"group"),gn,-1);
xhash_walk(gt->to,mod_groups_update_walk,(void *) packet);
xmlnode_free(packet);
}
int mod_groups_xdb_add(mod_groups_i mi, pool p, jid uid, char *un, char *gid, char *gn, int both)
{
xmlnode groups, user, group;
jid xid;
xid = jid_new(p,uid->server);
jid_set(xid,gid,JID_RESOURCE);
user = xmlnode_new_tag("user");
xmlnode_put_attrib(user,"jid",jid_full(uid));
xmlnode_put_attrib(user,"name",un);
if(both && xdb_act(mi->xc,xid,NS_XGROUPS,"insert",spools(p,"?jid=",jid_full(uid),p),user))
{
log_debug(ZONE,"Failed to insert user");
xmlnode_free(user);
return 1;
}
xmlnode_free(user);
groups = mod_groups_get_current(mi,uid);
if (groups == NULL)
{
groups = xmlnode_new_tag("query");
xmlnode_put_attrib(groups,"xmlns",NS_XGROUPS);
}
group = xmlnode_get_tag(groups,spools(p,"?id=",gid,p));
if (group == NULL)
{
group = xmlnode_insert_tag(groups,"group");
xmlnode_put_attrib(group,"id",gid);
}
else if (j_strcmp(xmlnode_get_attrib(group,"type"),"both") == 0 && both)
{
xmlnode_free(groups);
return 0;
}
else if (both == 0)
{
xmlnode_free(groups);
return 0;
}
if (both)
xmlnode_put_attrib(group,"type","both");
xdb_set(mi->xc,uid,NS_XGROUPS,groups);
xmlnode_free(groups);
return 0;
}
int mod_groups_xdb_remove(mod_groups_i mi, pool p, jid uid, char *host, char *gid)
{
xmlnode groups, group, info;
jid xid;
xid = jid_new(p,uid->server);
jid_set(xid,gid,JID_RESOURCE);
if(xdb_act(mi->xc,xid,NS_XGROUPS,"insert",spools(p,"?jid=",jid_full(uid),p),NULL))
{
log_debug(ZONE,"Failed to remove user");
return 1;
}
info = mod_groups_get_info(mi, p, host, gid);
if (xmlnode_get_tag(info,"require") != NULL)
return 0;
groups = mod_groups_get_current(mi,uid);
if (groups == NULL)
{
groups = xmlnode_new_tag("query");
xmlnode_put_attrib(groups,"xmlns",NS_XGROUPS);
}
group = xmlnode_get_tag(groups,spools(p,"?id=",gid,p));
if (group == NULL)
{
xmlnode_free(groups);
return 0;
}
xmlnode_hide(group);
xdb_set(mi->xc,uid,NS_XGROUPS,groups);
xmlnode_free(groups);
return 0;
}
void mod_groups_register_set(mod_groups_i mi, mapi m)
{
jpacket jp = m->packet;
pool p = jp->p;
grouptab gt;
xmlnode info, roster, users;
jid uid;
char *gid, *host, *key, *un, *gn;
int add, both;
key = xmlnode_get_tag_data(jp->iq,"key");
gid = strchr(pstrdup(p,jp->to->resource),'/') + 1;
if (gid == NULL || key == NULL || jutil_regkey(key,jid_full(jp->from)) == NULL)
{
js_bounce(m->si,jp->x,TERROR_NOTACCEPTABLE);
return;
}
host = jp->from->server;
info = mod_groups_get_info(mi,p,host,gid);
if (info == NULL)
{
js_bounce(m->si,jp->x,TERROR_NOTFOUND);
return;
}
uid = jid_user(jp->from);
un = xmlnode_get_tag_data(jp->iq,"name");
gn = xmlnode_get_tag_data(info,"name");
add = (xmlnode_get_tag(jp->iq, "remove") == NULL);
both = (xmlnode_get_tag(info,"static") == NULL);
if (add)
{
log_debug("mod_groups","register GID %s",gid);
if (mod_groups_xdb_add(mi,p,uid,un ? un : jid_full(uid),gid,gn,both))
{
js_bounce(m->si,jp->x,TERROR_UNAVAIL);
xmlnode_free(info);
return;
}
}
else
{
log_debug("mod_groups","unregister GID %s",gid);
if (mod_groups_xdb_remove(mi,p,uid,host,gid))
{
js_bounce(m->si,jp->x,TERROR_UNAVAIL);
xmlnode_free(info);
return;
}
}
gt = GROUP_GET(mi,gid);
if (add || xmlnode_get_tag(info,"require") == NULL)
{
users = mod_groups_get_users(mi,p,host,gid);
if (users != NULL)
{
roster = jutil_iqnew(JPACKET__SET,NS_ROSTER);
mod_groups_roster_insert(m->user,roster,users,gn,add);
mod_groups_roster_push(m->s,roster,add);
}
}
if (both)
mod_groups_update_rosters(gt,uid,un,gn,add);
if (add && both)
{
mod_groups_presence_from(m->s,gt,m->s->presence);
mod_groups_presence_to(m->s,gt);
}
jutil_iqresult(jp->x);
jpacket_reset(jp);
js_session_to(m->s,jp);
xmlnode_free(info);
}
void mod_groups_register_get(mod_groups_i mi, mapi m)
{
jpacket jp = m->packet;
xmlnode q;
char *gid, *name = "";
xmlnode members, user;
jid uid = m->user->id;
gid = strchr(pstrdup(jp->p, jp->to->resource),'/');
if (gid != NULL && ++gid != NULL)
{
jutil_iqresult(jp->x);
q = xmlnode_insert_tag(jp->x,"query");
xmlnode_put_attrib(q,"xmlns",NS_REGISTER);
members = mod_groups_get_users(mi,jp->p,jp->from->server,gid);
user = xmlnode_get_tag(members,spools(jp->p,"?jid=",uid->full,jp->p));
if (user)
{
name = xmlnode_get_attrib(user, "name");
xmlnode_insert_tag(q,"registered");
}
xmlnode_free(members);
xmlnode_insert_cdata(xmlnode_insert_tag(q,"name"),name,-1);
xmlnode_insert_cdata(xmlnode_insert_tag(q,"key"),jutil_regkey(NULL,jid_full(jp->from)),-1);
xmlnode_insert_cdata(xmlnode_insert_tag(q,"instructions"),mi->inst,-1);
jpacket_reset(jp);
js_session_to(m->s,jp);
}
else
js_bounce(m->si,jp->x,TERROR_NOTACCEPTABLE);
}
void mod_groups_browse_set(mod_groups_i mi, mapi m)
{
jpacket jp = m->packet;
pool p = jp->p;
grouptab gt;
xmlnode info, user;
jid uid;
char *gid, *gn, *un, *host, *action;
int add;
log_debug(ZONE,"Setting");
gid = strchr(jp->to->resource,'/');
if (gid == NULL || ++gid == NULL)
{
js_bounce(m->si,jp->x,TERROR_NOTACCEPTABLE);
return;
}
user = xmlnode_get_tag(jp->iq,"user");
uid = jid_new(p,xmlnode_get_attrib(user,"jid"));
un = xmlnode_get_attrib(user,"name");
action = xmlnode_get_attrib(user, "action");
add = ( ( action == NULL ) || j_strcmp(action, "remove") );
if (uid == NULL || un == NULL)
{
js_bounce(m->si,jp->x,TERROR_NOTACCEPTABLE);
return;
}
info = mod_groups_get_info(mi,p,jp->to->server,gid);
if (info == NULL || xmlnode_get_tag(info,spools(p,"edit/user=",jid_full(jp->from),p)) == NULL)
{
js_bounce(m->si,jp->x,TERROR_NOTALLOWED);
return;
}
gn = xmlnode_get_tag_data(info,"name");
if ( add )
{
log_debug("mod_groups", "Adding");
if (mod_groups_xdb_add(mi,p,uid,un,gid,gn,1))
{
js_bounce(m->si,jp->x,TERROR_UNAVAIL);
xmlnode_free(info);
return;
}
}
else
{
log_debug("mod_groups", "Removing");
host = jp->from->server;
if (mod_groups_xdb_remove(mi,p,uid,host,gid))
{
js_bounce(m->si,jp->x,TERROR_UNAVAIL);
xmlnode_free(info);
return;
}
}
gt = GROUP_GET(mi,gid);
mod_groups_update_rosters(gt,uid,un,gn,add);
xmlnode_free(info);
jutil_iqresult(jp->x);
jpacket_reset(jp);
js_session_to(m->s,jp);
}
void mod_groups_browse_result(pool p, jpacket jp, xmlnode group, char *host, char *gn)
{
xmlnode q, cur, tag;
char *id, *name;
q = xmlnode_insert_tag(jutil_iqresult(jp->x),"item");
xmlnode_put_attrib(q,"xmlns",NS_BROWSE);
xmlnode_put_attrib(q,"jid",jid_full(jp->to));
xmlnode_put_attrib(q,"name",gn ? gn : "Toplevel groups");
for (cur = xmlnode_get_firstchild(group); cur != NULL; cur = xmlnode_get_nextsibling(cur))
{
if (xmlnode_get_type(cur) != NTYPE_TAG) continue;
name = xmlnode_get_name(cur);
if (j_strcmp(name,"group") == 0)
{
tag = xmlnode_insert_tag(q,"item");
xmlnode_put_attrib(tag,"name",xmlnode_get_attrib(cur,"name"));
id = spools(p,host,"/groups/",xmlnode_get_attrib(cur,"id"),p);
xmlnode_put_attrib(tag,"jid",id);
}
else if (j_strcmp(name,"user") == 0)
{
xmlnode_insert_node(q,cur);
}
}
}
void mod_groups_browse_get(mod_groups_i mi, mapi m)
{
jpacket jp = m->packet;
xmlnode group;
pool p = jp->p;
xmlnode info = NULL;
char *gid, *gn, *host = jp->to->server;
log_debug("mod_groups","Browse request");
gid = strchr(jp->to->resource,'/');
if (gid != NULL && ++gid != NULL)
{
group = mod_groups_get_users(mi,p,host,gid);
info = mod_groups_get_info(mi,p,host,gid);
gn = xmlnode_get_tag_data(info,"name");
}
else
{
group = mod_groups_get_top(mi,p,host);
gn = NULL;
}
if (group == NULL && gn == NULL)
{
js_bounce(m->si,jp->x,TERROR_NOTFOUND);
return;
}
if (group)
{
mod_groups_browse_result(p,jp,group,host,gn);
xmlnode_free(group);
}
else
{
xmlnode q;
q = xmlnode_insert_tag(jutil_iqresult(jp->x),"item");
xmlnode_put_attrib(q,"xmlns",NS_BROWSE);
xmlnode_put_attrib(q,"jid",jid_full(jp->to));
xmlnode_put_attrib(q,"name",gn);
}
jpacket_reset(jp);
if (gid)
{
xmlnode_insert_cdata(xmlnode_insert_tag(jp->iq,"ns"),NS_REGISTER,-1);
xmlnode_free(info);
}
js_session_to(m->s,jp);
}
void mod_groups_roster(mod_groups_i mi, mapi m)
{
xmlnode groups, users, cur, roster;
pool p;
udata u = m->user;
char *gid, *host = m->user->id->server;
if ((groups = mod_groups_get_current(mi,u->id)) == NULL)
return;
p = xmlnode_pool(groups);
roster = jutil_iqnew(JPACKET__SET,NS_ROSTER);
for (cur = xmlnode_get_firstchild(groups); cur != NULL; cur = xmlnode_get_nextsibling(cur))
{
if (xmlnode_get_type(cur) != NTYPE_TAG) continue;
gid = xmlnode_get_attrib(cur,"id");
users = mod_groups_get_users(mi,p,host,gid);
if (users != NULL)
{
xmlnode info;
char *gn;
info = mod_groups_get_info(mi,p,host,gid);
gn = xmlnode_get_tag_data(info,"name");
mod_groups_roster_insert(u,roster,users,gn ? gn : gid,1);
xmlnode_free(info);
}
else
log_debug("mod_groups","Failed to get users for group");
}
mod_groups_roster_push(m->s,roster,0);
xmlnode_free(groups);
}
mreturn mod_groups_iq(mod_groups_i mi, mapi m)
{
char *ns, *res;
int type;
ns = xmlnode_get_attrib(m->packet->iq,"xmlns");
type = jpacket_subtype(m->packet);
if (j_strcmp(ns,NS_ROSTER) == 0)
{
if (jpacket_subtype(m->packet) == JPACKET__GET)
{
log_debug("mod_groups","Roster request");
mod_groups_roster(mi,m);
}
return M_PASS;
}
res = m->packet->to ? m->packet->to->resource : NULL;
if (res && strncmp(res,"groups",6) == 0 && (strlen(res) == 6 || res[6] == '/'))
{
if (j_strcmp(ns,NS_BROWSE) == 0)
{
log_debug("mod_groups","Browse request");
if (type == JPACKET__GET)
mod_groups_browse_get(mi,m);
else if (type == JPACKET__SET)
mod_groups_browse_set(mi,m);
else
xmlnode_free(m->packet->x);
}
else if (j_strcmp(ns,NS_REGISTER) == 0)
{
log_debug("mod_groups","Register request");
if (type == JPACKET__GET)
mod_groups_register_get(mi,m);
else if (type == JPACKET__SET)
mod_groups_register_set(mi,m);
else
xmlnode_free(m->packet->x);
}
else
js_bounce(m->si,m->packet->x,TERROR_NOTALLOWED);
return M_HANDLED;
}
return M_PASS;
}
void mod_groups_presence(mod_groups_i mi, mapi m)
{
grouptab gt;
session s = m->s;
udata u = m->user;
xmlnode groups, cur;
if ((groups = mod_groups_get_current(mi,u->id)) == NULL)
return;
log_debug("mod_groups","Getting groups for %s",jid_full(u->id));
for (cur = xmlnode_get_firstchild(groups); cur != NULL; cur = xmlnode_get_nextsibling(cur))
{
char *gid;
if ((gid = xmlnode_get_attrib(cur,"id")) == NULL) continue;
gt = GROUP_GET(mi,gid);
if(j_strcmp(xmlnode_get_attrib(cur,"type"),"both") == 0)
mod_groups_presence_from(s,gt,m->packet->x);
if (js_session_primary(m->user) || m->s->priority < 0)
mod_groups_presence_to(s,gt);
}
xmlnode_free(groups);
}
mreturn mod_groups_out(mapi m, void *arg)
{
mod_groups_i mi = (mod_groups_i) arg;
if (m->packet->type == JPACKET_PRESENCE)
{
if (m->packet->to == NULL) mod_groups_presence(mi,m);
return M_PASS;
}
else if (m->packet->type == JPACKET_IQ)
return mod_groups_iq(mi,m);
return M_IGNORE;
}
mreturn mod_groups_end(mapi m, void *arg)
{
mod_groups_i mi = (mod_groups_i) arg;
xmlnode groups, cur;
udata u = m->user;
jid id = u->id;
grouptab gt;
if (js_session_primary(u) != NULL || (groups = mod_groups_get_current(mi,id)) == NULL)
return M_PASS;
log_debug("mod_groups","removing user from table");
for (cur = xmlnode_get_firstchild(groups); cur != NULL; cur = xmlnode_get_nextsibling(cur))
{
gt = (grouptab) xhash_get(mi->groups,xmlnode_get_attrib(cur,"id"));
if (gt == NULL) continue;
if(j_strcmp(xmlnode_get_attrib(cur,"type"),"both") == 0)
xhash_zap(gt->from,jid_full(id));
xhash_zap(gt->to,jid_full(id));
}
xmlnode_free(groups);
return M_PASS;
}
mreturn mod_groups_session(mapi m, void *arg)
{
js_mapi_session(es_OUT,m->s,mod_groups_out,arg);
js_mapi_session(es_END,m->s,mod_groups_end,arg);
return M_PASS;
}
void mod_groups_message_walk(xht h, const char *key, void *val, void *arg)
{
xmlnode m = (xmlnode) arg;
udata u = (udata) val;
m = xmlnode_dup(m);
xmlnode_put_attrib(m,"to",jid_full(u->id));
js_deliver(u->si,jpacket_new(m));
}
void mod_groups_message_online(mod_groups_i mi, xmlnode msg, char *gid)
{
grouptab gt;
log_debug("mod_groups","broadcast message to '%s'",gid);
gt = (grouptab) xhash_get(mi->groups,gid);
if (gt != NULL)
{
xmlnode_put_attrib(msg,"from",xmlnode_get_attrib(msg,"to"));
xmlnode_hide_attrib(msg,"to");
xhash_walk(gt->from,mod_groups_message_walk,(void *) msg);
}
xmlnode_free(msg);
}
mreturn mod_groups_message(mapi m, void *arg)
{
mod_groups_i mi = (mod_groups_i) arg;
xmlnode info;
jpacket jp = m->packet;
char *gid;
if(jp->type != JPACKET_MESSAGE) return M_IGNORE;
if(jp->to == NULL || j_strncmp(jp->to->resource,"groups/",7) != 0) return M_PASS;
if(xmlnode_get_tag(jp->x,"x?xmlns=" NS_DELAY) != NULL)
{
xmlnode_free(jp->x);
return M_HANDLED;
}
gid = strchr(jp->to->resource,'/');
if (gid == NULL || ++gid == NULL)
{
js_bounce(m->si,jp->x,TERROR_NOTACCEPTABLE);
return M_HANDLED;
}
info = mod_groups_get_info(mi,jp->p,jp->to->server,gid);
if (info == NULL)
{
js_bounce(m->si,jp->x,TERROR_NOTFOUND);
return M_HANDLED;
}
if (xmlnode_get_tag(info,spools(jp->p,"write/user=",jid_full(jp->from),jp->p)) != NULL)
mod_groups_message_online(mi,jp->x,gid);
else
js_bounce(m->si,jp->x,TERROR_NOTALLOWED);
xmlnode_free(info);
return M_HANDLED;
}
void mod_groups_destroy(xht h, const char *key, void *val, void *arg)
{
grouptab gt = (grouptab) val;
xhash_free(gt->to);
xhash_free(gt->from);
}
mreturn mod_groups_shutdown(mapi m, void *arg)
{
mod_groups_i mi = (mod_groups_i) arg;
xhash_walk(mi->groups,mod_groups_destroy,NULL);
xhash_free(mi->groups);
xhash_free(mi->config);
pool_free(mi->p);
return M_PASS;
}
void mod_groups(jsmi si)
{
pool p;
mod_groups_i mi;
xmlnode cur, config;
char *gid, *id = si->i->id;
log_debug("mod_groups","initing");
p = pool_new();
mi = pmalloco(p,sizeof(_mod_groups_i));
mi->p = p;
mi->groups = xhash_new(67);
mi->xc = si->xc;
config = js_config(si,"groups");
mi->inst = xmlnode_get_tag_data(config,"instructions");
if (mi->inst == NULL)
mi->inst = pstrdup(p,"This will add the group to your roster");
if (config != NULL)
{
mi->config = xhash_new(67);
for (cur = xmlnode_get_firstchild(config); cur != NULL; cur = xmlnode_get_nextsibling(cur))
{
if (j_strcmp(xmlnode_get_name(cur),"group") != 0) continue;
gid = xmlnode_get_attrib(cur,"id");
if (gid == NULL)
{
log_error(id,"mod_groups: Error loading, no id attribute on group");
pool_free(p);
return;
}
else if (xhash_get(mi->config,gid) != NULL)
{
log_error(si->i->id,"mod_groups: Error loading, group '%s' configured twice",gid);
pool_free(p);
return;
}
if (xmlnode_get_tag(cur,"info") || xmlnode_get_tag(cur,"users"))
xhash_put(mi->config,pstrdup(p,gid),cur);
}
}
js_mapi_register(si,e_SERVER,mod_groups_message,(void *) mi);
js_mapi_register(si,e_SESSION,mod_groups_session,(void *) mi);
js_mapi_register(si,e_SHUTDOWN,mod_groups_shutdown,(void *) mi);
}