jabberd2  2.2.16
sm/mod_iq_private.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00021 #include "sm.h"
00022 
00030 #define uri_PRIVATE    "jabber:iq:private"
00031 static int ns_PRIVATE = 0;
00032 
00033 static mod_ret_t _iq_private_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) {
00034     module_t mod = mi->mod;
00035     int ns, elem, target, targetns;
00036     st_ret_t ret;
00037     char filter[4096];
00038     os_t os;
00039     os_object_t o;
00040     nad_t nad;
00041     pkt_t result;
00042     sess_t sscan;
00043 
00044     /* only handle private sets and gets */
00045     if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_PRIVATE)
00046         return mod_PASS;
00047 
00048     /* we're only interested in no to, to our host, or to us */
00049     if(pkt->to != NULL && jid_compare_user(sess->jid, pkt->to) != 0 && strcmp(sess->jid->domain, jid_user(pkt->to)) != 0)
00050         return mod_PASS;
00051 
00052     ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVATE, NULL);
00053     elem = nad_find_elem(pkt->nad, 1, ns, "query", 1);
00054 
00055     /* find the first child */
00056     target = elem + 1;
00057     while(target < pkt->nad->ecur)
00058     {
00059         if(pkt->nad->elems[target].depth > pkt->nad->elems[elem].depth)
00060             break;
00061 
00062         target++;
00063     }
00064 
00065     /* not found, so we're done */
00066     if(target == pkt->nad->ecur)
00067         return -stanza_err_BAD_REQUEST;
00068 
00069     /* find the target namespace */
00070     targetns = NAD_ENS(pkt->nad, target);
00071 
00072     /* gotta have a namespace */
00073     if(targetns < 0)
00074     {
00075         log_debug(ZONE, "no namespace specified");
00076         return -stanza_err_BAD_REQUEST;
00077     }
00078 
00079     log_debug(ZONE, "processing private request for %.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
00080 
00081     /* get */
00082     if(pkt->type == pkt_IQ) {
00083 #ifdef ENABLE_EXPERIMENTAL
00084         /* remember that this resource requested the namespace */
00085         if(sess->module_data[mod->index] == NULL) {
00086             /* create new hash if necesary */
00087             sess->module_data[mod->index] = xhash_new(101);
00088             pool_cleanup(sess->p, (void (*))(void *) xhash_free, sess->module_data[mod->index]);
00089         }
00090         xhash_put(sess->module_data[mod->index], pstrdupx(sess->p, NAD_NURI(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns)), (void *) 1);
00091 #endif
00092         snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
00093         ret = storage_get(sess->user->sm->st, "private", jid_user(sess->jid), filter, &os);
00094         switch(ret) {
00095             case st_SUCCESS:
00096                 if(os_iter_first(os)) {
00097                     o = os_iter_object(os);
00098                     if(os_object_get_nad(os, o, "xml", &nad)) {
00099                         result = pkt_new(sess->user->sm, nad_copy(nad));
00100                         if(result != NULL) {
00101                             nad_set_attr(result->nad, 1, -1, "type", "result", 6);
00102 
00103                             pkt_id(pkt, result);
00104 
00105                             pkt_sess(result, sess);
00106 
00107                             pkt_free(pkt);
00108 
00109                             os_free(os);
00110                 
00111                             return mod_HANDLED;
00112                         }
00113                     }
00114                 }
00115 
00116                 os_free(os);
00117 
00118                 /* drop through */
00119                 log_debug(ZONE, "storage_get succeeded, but couldn't make packet, faking st_NOTFOUND");
00120 
00121             case st_NOTFOUND:
00122 
00123                 log_debug(ZONE, "namespace not found, returning");
00124 
00125                 /*
00126                  * !!! really, we should just return a 404. 1.4 just slaps a
00127                  *     result on the packet and sends it back. hurrah for
00128                  *     legacy namespaces.
00129                  */
00130                 nad_set_attr(pkt->nad, 1, -1, "type", "result", 6);
00131 
00132                 pkt_sess(pkt_tofrom(pkt), sess);
00133                 
00134                 return mod_HANDLED;
00135 
00136             case st_FAILED:
00137                 return -stanza_err_INTERNAL_SERVER_ERROR;
00138 
00139             case st_NOTIMPL:
00140                 return -stanza_err_FEATURE_NOT_IMPLEMENTED;
00141         }
00142     }
00143 
00144     os = os_new();
00145     o = os_object_new(os);
00146 
00147     snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
00148     os_object_put(o, "ns", filter, os_type_STRING);
00149     os_object_put(o, "xml", pkt->nad, os_type_NAD);
00150 
00151     snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
00152 
00153     ret = storage_replace(sess->user->sm->st, "private", jid_user(sess->jid), filter, os);
00154     os_free(os);
00155 
00156     switch(ret) {
00157         case st_FAILED:
00158             return -stanza_err_INTERNAL_SERVER_ERROR;
00159 
00160         case st_NOTIMPL:
00161             return -stanza_err_FEATURE_NOT_IMPLEMENTED;
00162 
00163         default:
00164             /* create result packet */
00165             result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL);
00166             pkt_id(pkt, result);
00167             /* and flush it to the session */
00168             pkt_sess(result, sess);
00169 #ifdef ENABLE_EXPERIMENTAL
00170             /* push it to all resources that read this xmlns item */
00171             snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
00172             for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) {
00173                 /* skip our resource and those that didn't read any private-storage */
00174                 if(sscan == sess || sscan->module_data[mod->index] == NULL)
00175                     continue;
00176 
00177                 /* check whether namespace was read */
00178                 if(xhash_get(sscan->module_data[mod->index], filter)) {
00179                     result = pkt_dup(pkt, jid_full(sscan->jid), NULL);
00180                     if(result->from != NULL) {
00181                         jid_free(result->from);
00182                         nad_set_attr(result->nad, 1, -1, "from", NULL, 0);
00183                     }
00184                     pkt_id_new(result);
00185                     pkt_sess(result, sscan);
00186                 }
00187             }
00188 #endif
00189             /* finally free the packet */
00190             pkt_free(pkt);
00191             return mod_HANDLED;
00192     }
00193 
00194     /* we never get here */
00195     return 0;
00196 }
00197 
00198 static void _iq_private_user_delete(mod_instance_t mi, jid_t jid) {
00199     log_debug(ZONE, "deleting private xml storage for %s", jid_user(jid));
00200 
00201     storage_delete(mi->sm->st, "private", jid_user(jid), NULL);
00202 }
00203 
00204 static void _iq_private_free(module_t mod) {
00205      sm_unregister_ns(mod->mm->sm, uri_PRIVATE);
00206      feature_unregister(mod->mm->sm, uri_PRIVATE);
00207 }
00208 
00209 DLLEXPORT int module_init(mod_instance_t mi, char *arg) {
00210     module_t mod = mi->mod;
00211 
00212     if (mod->init) return 0;
00213 
00214     mod->in_sess = _iq_private_in_sess;
00215     mod->user_delete = _iq_private_user_delete;
00216     mod->free = _iq_private_free;
00217 
00218     ns_PRIVATE = sm_register_ns(mod->mm->sm, uri_PRIVATE);
00219     feature_register(mod->mm->sm, uri_PRIVATE);
00220 
00221     return 0;
00222 }