📄 mod_groups.c
字号:
/* -------------------------------------------------------------------------- * * License * * The contents of this file are subject to the Jabber Open Source License * Version 1.0 (the "License"). You may not copy or use this file, in either * source code or executable form, except in compliance with the License. You * may obtain a copy of the License at http://www.jabber.com/license/ or at * http://www.opensource.org/. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Copyrights * * Portions created by or assigned to Jabber.com, Inc. are * Copyright (c) 1999-2000 Jabber.com, Inc. All Rights Reserved. Contact * information for Jabber.com, Inc. is available at http://www.jabber.com/. * * Portions Copyright (c) 1998-1999 Schuyler Heath. * (c) 2001 Philip Anderson. * * Acknowledgements * * Special thanks to the Jabber Open Source Contributors for their * suggestions and support of Jabber. * * --------------------------------------------------------------------------*/#include "jsm.h"/** * @file mod_groups.c * @brief handle roster groups (optional module, not enabled by default) */#define NS_XGROUPS "jabber:xdb:groups" /**< namespace to store groups in xdb */#define NS_XINFO "jabber:xdb:groups:info" /**< info about the group, name, edit/write perms, etc... *//** * get a grouptab from the mi->groups hash or add a new one if it does not already exist */#define GROUP_GET(mi,gid) (gt = (grouptab) xhash_get(mi->groups,gid)) ? gt : mod_groups_tab_add(mi,gid)/** module configuration */typedef struct { pool p; /**< used memory pool */ xdbcache xc; /**< xdbcache used for xdb queries */ xht groups; xht config; /**< hash of group specfic config: contains xmlnode instances */ char *inst; /**< register instructions */} *mod_groups_i, _mod_groups_i;/** data for a single group */typedef struct { xht to; xht from;} *grouptab, _grouptab;/** * get the information/configuration of a group * * @param mi the module internal data * @param p memory pool to use for processing * @param host server hostname of this group * @param gid group ID * @return information xmlnode, either from xdb or the static configuration (prefered) */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_debug2(ZONE, LOGT_DELIVER, "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) /* config overrides */ xmlnode_insert_node(info,cur); xmlnode_free(xinfo); return info;}/** * get the users that are member of a group * * @param mi the mod_groups_i struct containing module instance data * @param p the memory pool to use * @param host the host of the group * @param gid the group id for which to get the users * @return xmlnode containing the users */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_debug2(ZONE, LOGT_DELIVER, "getting users %s",gid); /* check config for specfic group before xdb */ group = (xmlnode) xhash_get(mi->config,gid); if (group != NULL && (users = xmlnode_get_tag(group,"users")) != NULL) return xmlnode_dup(users); log_debug2(ZONE, LOGT_DELIVER, "%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);}/** * xhash_walker() function used by mod_groups_get_top() to iterate over the groups * * @param h xht that contains the groups (unused/ignored) * @param gid the group id * @param val the group definition * @param arg xmlnode where to store the result */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); /* config overrides xdb */ xmlnode_hide(xmlnode_get_tag(result,spools(p,"group?id=",gid,p))); /* bah, vattrib hack */ 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); }}/** * returns toplevel groups * * @param mi the mod_groups_i struct containing module instance data * @param p the memory pool to use * @param host the host for which the result is generated * @return list of the toplevel groups */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); /* insert toplevel groups from config */ xhash_walk(mi->config,mod_groups_top_walk,(void *) result); xmlnode_hide_attrib(result,"mi"); xmlnode_hide_attrib(result,"host"); return result;}/** * inserts required groups into result * * xhash_walker() function used by mod_groups_get_current() to iterate over the groups * * @param h the xht containing the groups * @param gid the group id * @param val the group definition (xmlnode) * @param arg xmlnode where to put the result to */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_debug2(ZONE, LOGT_DELIVER, "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); /* remember the jid attrib is "?jid=<jid>" */ 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"); } }}/** * get the list of groups a user is currently a member of * * @param mi the mod_groups_i struct containing the module instance data * @param id for which user to get the list of groups * @return list of groups */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;}/** * create a new grouptab entry and add to the groups hash * * @param mi the mod_groups_i struct containing module instance data * @param gid the group id * @return the newly created grouptab entry */grouptab mod_groups_tab_add(mod_groups_i mi, char *gid) { grouptab gt; log_debug2(ZONE, LOGT_DELIVER, "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;}/** * xhash_walker() function used by mod_groups_presence_to() to iterate over the users * * @param h the xht that contains the users (unused/ignored) * @param kay the user (unused/ignored) * @param val the udata struct of the user * @param arg the session for which to send the presence */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)));}/** * send presence to a session from the group members * * @param s the session for which to send the presence * @param gt the grouptab to which users the presence should be sent */void mod_groups_presence_to(session s, grouptab gt) { xhash_put(gt->to,jid_full(s->u->id),(void *) s->u); /* we don't care if it replaces the old entry */ xhash_walk(gt->from,mod_groups_presence_to_walk,(void *) s);}/** * xhash_walker() function used by mod_groups_presence_from() to iterate over all users * * @param h the xht containing the users (unused/ignored) * @param key the user (unused/ignored) * @param val the udata struct of the user * @param arg the presence to send */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_debug2(ZONE, LOGT_DELIVER, "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)); }}/** * send presence from a session to online members of a group * * @param s which sessions presence should be sent * @param gt the grouptab for this group * @param pres the presence to send */void mod_groups_presence_from(session s, grouptab gt, xmlnode pres) { udata u = s->u; log_debug2(ZONE, LOGT_DELIVER, "brodcasting"); if (xhash_get(gt->from,jid_full(u->id)) == NULL) xhash_put(gt->from,jid_full(u->id),u); /* send our presence to online users subscribed to this group */ 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");}/** * insert the users of a group as items to the roster xmlnode * * @param u the user for which the roster is created (which roster item to leave out) * @param roster where to add the items to * @param group which group's members should be added * @param gn the group name * @param add add items or remove them */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"); /* loop through each item in the group */ 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) /* don't push ourselves */ continue; /* add them to the roster */ 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);}/** * push updated roster to all sessions or a specfic session * * @param s one session of the user * @param roster the roster to be pushed * @param all if 0 the roster is pushed only to the given session, else it is pushed to all sessions of the user */void mod_groups_roster_push(session s, xmlnode roster, int all) { session cur; if (all) { /* send a copy to all session that have a roster */ 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)); }}/** * xhash_walker() function used by mod_groups_update_roster() to iterate over all users of a group * * @param h the xht containing the users (unused/ignored) * @param key the user (unused/ignored) * @param val the udata struct of the user * @param arg the packet to send */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);}/** * updates every members roster with the new user * * @param gt grouptab struct for the relevant group * @param uid the new user * @param un the user's name * @param gn the group's name * @param add if the user is added or removed
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -