jabberd2
2.2.16
|
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 }