📄 mod_disco.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_disco.c * @brief service discovery * @author Robert Norris * $Date: 2003/11/30 22:02:25 $ * $Revision: 1.28 $ *//** holder for a single service */typedef struct service_st *service_t;struct service_st { jid_t jid; char name[257]; char category[257]; char type[257]; xht features;};/** all the current disco data */typedef struct disco_st *disco_t;struct disco_st { /** identity */ char *category; char *type; char *name; /** compatibility */ int agents; int browse; /** the lists */ xht dyn; xht stat; /** unified list */ xht un; /** cached result packets */ pkt_t disco_info_result; pkt_t disco_items_result; pkt_t agents_result; pkt_t browse_result;};/** put val into arg */static void _disco_unify_walker(xht list, const char *key, void *val, void *arg) { service_t svc = (service_t) val; xht dest = (xht) arg; /* if its already there, skip this one */ if(xhash_get(dest, jid_full(svc->jid)) != NULL) return; log_debug(ZONE, "unify: %s", jid_full(svc->jid)); xhash_put(dest, jid_full(svc->jid), (void *) svc);}/** unify the contest of dyn and stat */static void _disco_unify_lists(disco_t d) { log_debug(ZONE, "unifying lists"); if(d->un != NULL) xhash_free(d->un); d->un = xhash_new(101); /* dynamic overrieds static */ xhash_walk(d->dyn, _disco_unify_walker, (void *) d->un); xhash_walk(d->stat, _disco_unify_walker, (void *) d->un);}/** build a disco items result, known services */static pkt_t _disco_items_result(module_t mod, disco_t d) { pkt_t pkt; int ns; service_t svc; pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); ns = nad_add_namespace(pkt->nad, uri_DISCO_ITEMS, NULL); nad_append_elem(pkt->nad, ns, "query", 2); if(xhash_iter_first(d->un)) do { xhash_iter_get(d->un, NULL, (void **) &svc); nad_append_elem(pkt->nad, ns, "item", 3); nad_append_attr(pkt->nad, -1, "jid", jid_full(svc->jid)); if(svc->name[0] != '\0') nad_append_attr(pkt->nad, -1, "name", svc->name); } while(xhash_iter_next(d->un)); return pkt;}/** build a disco info result */static pkt_t _disco_info_result(module_t mod, disco_t d) { pkt_t pkt; int ns; const char *key; pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); ns = nad_add_namespace(pkt->nad, uri_DISCO_INFO, NULL); nad_append_elem(pkt->nad, ns, "query", 2); /* identity */ nad_append_elem(pkt->nad, ns, "identity", 3); nad_append_attr(pkt->nad, -1, "category", d->category); nad_append_attr(pkt->nad, -1, "type", d->type); nad_append_attr(pkt->nad, -1, "name", d->name); /* fill in our features */ if(xhash_iter_first(mod->mm->sm->features)) do { xhash_iter_get(mod->mm->sm->features, &key, NULL); nad_append_elem(pkt->nad, ns, "feature", 3); nad_append_attr(pkt->nad, -1, "var", (char *) key); } while(xhash_iter_next(mod->mm->sm->features)); return pkt;}/** build an agents result */static pkt_t _disco_agents_result(module_t mod, disco_t d) { pkt_t pkt; int ns; const char *key; service_t svc; pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); ns = nad_add_namespace(pkt->nad, uri_AGENTS, NULL); nad_append_elem(pkt->nad, ns, "query", 2); /* fill in the items */ if(xhash_iter_first(d->un)) do { xhash_iter_get(d->un, &key, (void **) &svc); nad_append_elem(pkt->nad, ns, "agent", 3); nad_append_attr(pkt->nad, -1, "jid", jid_full(svc->jid)); if(svc->name[0] != '\0') { nad_append_elem(pkt->nad, ns, "name", 4); nad_append_cdata(pkt->nad, svc->name, strlen(svc->name), 5); } nad_append_elem(pkt->nad, ns, "service", 4); nad_append_cdata(pkt->nad, svc->type, strlen(svc->type), 5); /* map features to the old agent flags */ if(xhash_get(svc->features, uri_REGISTER) != NULL) nad_append_elem(pkt->nad, ns, "register", 4); if(xhash_get(svc->features, uri_SEARCH) != NULL) nad_append_elem(pkt->nad, ns, "search", 4); if(xhash_get(svc->features, uri_GATEWAY) != NULL) nad_append_elem(pkt->nad, ns, "transport", 4); /* conference gets special treatment */ if(strcmp(svc->category, "conference") == 0) nad_append_elem(pkt->nad, ns, "groupchat", 4); } while(xhash_iter_next(d->un)); return pkt;}/** build a browse result */static pkt_t _disco_browse_result(module_t mod, disco_t d) { pkt_t pkt; int ns; const char *key; service_t svc; pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); ns = nad_add_namespace(pkt->nad, uri_BROWSE, NULL); nad_append_elem(pkt->nad, ns, "service", 2); nad_append_attr(pkt->nad, -1, "jid", mod->mm->sm->id); nad_append_attr(pkt->nad, -1, "type", "jabber"); /* fill in our features */ if(xhash_iter_first(mod->mm->sm->features)) do { xhash_iter_get(mod->mm->sm->features, &key, NULL); /* hackishly seperate generic features from namespaces */ if(!((strlen(key) >= 7 && (strncmp(key, "jabber:", 7) == 0 || strncmp(key, "http://", 7) == 0)) || strcmp(key, "vcard-temp") == 0)) continue; nad_append_elem(pkt->nad, ns, "ns", 3); nad_append_cdata(pkt->nad, (char *) key, strlen(key), 4); } while(xhash_iter_next(mod->mm->sm->features)); /* fill in the items */ if(xhash_iter_first(d->un)) do { xhash_iter_get(d->un, NULL, (void **) &svc); if(strcmp(svc->category, "gateway") == 0) nad_append_elem(pkt->nad, ns, "service", 3); else nad_append_elem(pkt->nad, ns, svc->category, 3); nad_append_attr(pkt->nad, -1, "jid", jid_full(svc->jid)); if(svc->name[0] != '\0') nad_append_attr(pkt->nad, -1, "name", svc->name); nad_append_attr(pkt->nad, -1, "type", svc->type); /* service features */ if(xhash_iter_first(svc->features)) do { xhash_iter_get(svc->features, &key, NULL); /* hackishly seperate generic features from namespaces */ if(!((strlen(key) >= 7 && (strncmp(key, "jabber:", 7) == 0 || strncmp(key, "http://", 7) == 0)) || strcmp(key, "vcard-temp") == 0)) continue; nad_append_elem(pkt->nad, ns, "ns", 4); nad_append_cdata(pkt->nad, (char *) key, strlen(key), 5); } while(xhash_iter_next(svc->features)); } while(xhash_iter_next(d->un)); return pkt;}/** generate cached result packets */static void _disco_generate_packets(module_t mod, disco_t d) { log_debug(ZONE, "regenerating packets"); if(d->disco_items_result != NULL) pkt_free(d->disco_items_result); d->disco_items_result = _disco_items_result(mod, d); if(d->disco_info_result != NULL) pkt_free(d->disco_info_result); d->disco_info_result = _disco_info_result(mod, d); if(d->agents) { if(d->agents_result != NULL) pkt_free(d->agents_result); d->agents_result = _disco_agents_result(mod, d); } if(d->browse) { if(d->browse_result != NULL) pkt_free(d->browse_result); d->browse_result = _disco_browse_result(mod, d); }}/** catch responses and populate the table */static mod_ret_t _disco_pkt_sm_populate(mod_instance_t mi, pkt_t pkt){ module_t mod = mi->mod; disco_t d = (disco_t) mod->private; int ns, qelem, elem, attr; service_t svc; /* it has to come from the service itself - don't want any old user messing with the table */ if(pkt->from->node[0] != '\0' || pkt->from->resource[0] != '\0') { log_debug(ZONE, "disco response from %s, not allowed", jid_full(pkt->from)); return -stanza_err_NOT_ALLOWED; } ns = nad_find_scoped_namespace(pkt->nad, uri_DISCO_INFO, NULL); qelem = nad_find_elem(pkt->nad, 1, ns, "query", 1); elem = nad_find_elem(pkt->nad, qelem, ns, "identity", 1); if(elem < 0) return -stanza_err_BAD_REQUEST; /* see if we already have this service */ svc = xhash_get(d->dyn, jid_full(pkt->from)); if(svc == NULL) { /* make a new one */ svc = (service_t) malloc(sizeof(struct service_st)); memset(svc, 0, sizeof(struct service_st)); svc->jid = jid_dup(pkt->from); svc->features = xhash_new(9); /* link it in */ xhash_put(d->dyn, jid_full(svc->jid), (void *) svc); /* unify */ _disco_unify_lists(d); } /* fill in the name */ attr = nad_find_attr(pkt->nad, elem, -1, "name", NULL); if(attr < 0) svc->name[0] = '\0'; else snprintf(svc->name, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); /* category and type */ attr = nad_find_attr(pkt->nad, elem, -1, "category", NULL); if(attr >= 0) snprintf(svc->category, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); else strcpy(svc->category, "unknown"); attr = nad_find_attr(pkt->nad, elem, -1, "type", NULL); if(attr >= 0) snprintf(svc->type, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); else strcpy(svc->type, "unknown"); /* features */ elem = nad_find_elem(pkt->nad, qelem, -1, "feature", 1); while(elem >= 0) { attr = nad_find_attr(pkt->nad, elem, -1, "var", NULL); if(attr < 0) { elem = nad_find_elem(pkt->nad, elem, -1, "feature", 0); continue; } xhash_put(svc->features, pstrdupx(xhash_pool(svc->features), NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)), (void *) 1); elem = nad_find_elem(pkt->nad, elem, -1, "feature", 0); } /* regenerate packets */ _disco_generate_packets(mod, d); pkt_free(pkt); return mod_HANDLED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -