📄 mod_roster.c
字号:
/* * 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.c * @brief roster managment & subscriptions * @author Robert Norris * $Date: 2004/11/13 16:08:33 $ * $Revision: 1.50.2.7 $ *//** free a single roster item */static void _roster_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);}/** free the roster */static void _roster_free(user_t user){ if(user->roster == NULL) return; log_debug(ZONE, "freeing roster for %s", jid_user(user->jid)); xhash_walk(user->roster, _roster_free_walker, NULL); xhash_free(user->roster); user->roster = NULL;}static void _roster_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=%i:%s)", strlen(jid_full(item->jid)), jid_full(item->jid)); storage_replace(user->sm->st, "roster-items", jid_user(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(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);}/** insert a roster item into this pkt, starting at elem */static void _roster_insert_item(pkt_t pkt, item_t item, int elem){ int ns, i; char *sub; ns = nad_add_namespace(pkt->nad, uri_CLIENT, NULL); elem = nad_insert_elem(pkt->nad, elem, ns, "item", NULL); nad_set_attr(pkt->nad, elem, -1, "jid", jid_full(item->jid), 0); if(item->to && item->from) sub = "both"; else if(item->to) sub = "to"; else if(item->from) sub = "from"; else sub = "none"; nad_set_attr(pkt->nad, elem, -1, "subscription", sub, 0); if(item->ask == 1) nad_set_attr(pkt->nad, elem, -1, "ask", "subscribe", 9); else if(item->ask == 2) nad_set_attr(pkt->nad, elem, -1, "ask", "unsubscribe", 11); if(item->name != NULL) nad_set_attr(pkt->nad, elem, -1, "name", item->name, 0); for(i = 0; i < item->ngroups; i++) nad_insert_elem(pkt->nad, elem, NAD_ENS(pkt->nad, elem), "group", item->groups[i]);}/** push this packet to all sessions except the given one */static void _roster_push(user_t user, pkt_t pkt, int mod_index){ sess_t scan; pkt_t push; /* do the push */ for(scan = user->sessions; scan != NULL; scan = scan->next) { /* don't push to us or to anyone who hasn't loaded the roster */ if((int) scan->module_data[mod_index] == 0) continue; push = pkt_dup(pkt, jid_full(scan->jid), NULL); pkt_sess(push, scan); }}static mod_ret_t _roster_in_sess_s10n(mod_instance_t mi, sess_t sess, pkt_t pkt){ module_t mod = mi->mod; item_t item; pkt_t push; int ns, elem; log_debug(ZONE, "got s10n packet"); /* s10ns have to go to someone */ if(pkt->to == NULL) return -stanza_err_BAD_REQUEST; /* add a proper from address (no resource) */ if(pkt->from != NULL) jid_free(pkt->from); pkt->from = jid_new(mod->mm->sm->pc, jid_user(sess->jid), 0); nad_set_attr(pkt->nad, 1, -1, "from", jid_full(pkt->from), 0); /* see if they're already on the roster */ item = xhash_get(sess->user->roster, jid_full(pkt->to)); if(item == NULL) { /* if they're not on the roster, there's no subscription, * so quietly pass it on */ if(pkt->type == pkt_S10N_UN || pkt->type == pkt_S10N_UNED) return mod_PASS; /* make a new one */ item = (item_t) malloc(sizeof(struct item_st)); memset(item, 0, sizeof(struct item_st)); item->jid = jid_dup(pkt->to); /* remember it */ xhash_put(sess->user->roster, jid_full(item->jid), (void *) item); log_debug(ZONE, "made new empty roster item for %s", jid_full(item->jid)); } /* a request */ if(pkt->type == pkt_S10N) item->ask = 1; else if(pkt->type == pkt_S10N_UN) item->ask = 2; /* changing states */ else if(pkt->type == pkt_S10N_ED) { /* they're allowed to see us, send them presence */ item->ask = 0; item->from = 1; pres_roster(sess, item); } else if(pkt->type == pkt_S10N_UNED) { /* they're not allowed to see us anymore */ item->ask = 0; item->from = 0; pres_roster(sess, item); } /* save changes */ _roster_save_item(sess->user, item); /* build a new packet to push out to everyone */ push = pkt_create(sess->user->sm, "iq", "set", NULL, NULL); ns = nad_add_namespace(push->nad, uri_ROSTER, NULL); elem = nad_append_elem(push->nad, ns, "query", 3); _roster_insert_item(push, item, elem); /* tell everyone */ _roster_push(sess->user, push, mod->index); /* everyone knows */ pkt_free(push); /* pass it on */ return mod_PASS;}/** build the iq:roster packet from the hash */static void _roster_get_walker(xht roster, const char *id, void *val, void *arg){ item_t item = (item_t) val; pkt_t pkt = (pkt_t) arg; _roster_insert_item(pkt, item, 2);}static void _roster_set_item(pkt_t pkt, int elem, sess_t sess, mod_instance_t mi){ module_t mod = mi->mod; int attr, ns, i; jid_t jid; item_t item; pkt_t push; char filter[4096]; /* extract the jid */ attr = nad_find_attr(pkt->nad, elem, -1, "jid", NULL); jid = jid_new(pkt->sm->pc, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); if(jid == NULL) { log_debug(ZONE, "jid failed prep check, skipping"); return; } /* check for removals */ if(nad_find_attr(pkt->nad, elem, -1, "subscription", "remove") >= 0) { /* trash the item */ item = xhash_get(sess->user->roster, jid_full(jid)); if(item != NULL) { /* tell them they're unsubscribed */ if(item->from) { log_debug(ZONE, "telling %s that they're unsubscribed", jid_user(item->jid)); pkt_router(pkt_create(sess->user->sm, "presence", "unsubscribed", jid_user(item->jid), jid_user(sess->jid))); } item->from = 0; /* tell them to unsubscribe us */ if(item->to) { log_debug(ZONE, "unsubscribing from %s", jid_user(item->jid)); pkt_router(pkt_create(sess->user->sm, "presence", "unsubscribe", jid_user(item->jid), jid_user(sess->jid))); } item->to = 0; /* send unavailable */ pres_roster(sess, item); /* kill it */ xhash_zap(sess->user->roster, jid_full(jid)); _roster_free_walker(NULL, (const char *) jid_full(jid), (void *) item, NULL); snprintf(filter, 4096, "(jid=%i:%s)", strlen(jid_full(jid)), jid_full(jid)); storage_delete(sess->user->sm->st, "roster-items", jid_user(sess->jid), filter); snprintf(filter, 4096, "(jid=%i:%s)", strlen(jid_full(jid)), jid_full(jid)); storage_delete(sess->user->sm->st, "roster-groups", jid_user(sess->jid), filter); } log_debug(ZONE, "removed %s from roster", jid_full(jid)); /* build a new packet to push out to everyone */ push = pkt_create(sess->user->sm, "iq", "set", NULL, NULL); ns = nad_add_namespace(push->nad, uri_ROSTER, NULL); nad_append_elem(push->nad, ns, "query", 3); elem = nad_append_elem(push->nad, ns, "item", 4); nad_set_attr(push->nad, elem, -1, "jid", jid_full(jid), 0); nad_set_attr(push->nad, elem, -1, "subscription", "remove", 6); /* tell everyone */ _roster_push(sess->user, push, mod->index); /* we're done */ pkt_free(push); jid_free(jid); return; } /* find a pre-existing one */ item = xhash_get(sess->user->roster, jid_full(jid)); if(item == NULL) { /* make a new one */ item = (item_t) malloc(sizeof(struct item_st)); memset(item, 0, sizeof(struct item_st)); /* add the jid */ item->jid = jid; /* add it to the roster */ xhash_put(sess->user->roster, jid_full(item->jid), (void *) item); log_debug(ZONE, "created new roster item %s", jid_full(item->jid)); } else jid_free(jid); /* free the old name */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -