jabberd2  2.2.17
mod_iq_private.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "sm.h"
22 
30 #define uri_PRIVATE "jabber:iq:private"
31 static int ns_PRIVATE = 0;
32 
34  module_t mod = mi->mod;
35  int ns, elem, target, targetns;
36  st_ret_t ret;
37  char filter[4096];
38  os_t os;
39  os_object_t o;
40  nad_t nad;
41  pkt_t result;
42  sess_t sscan;
43 
44  /* only handle private sets and gets */
45  if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_PRIVATE)
46  return mod_PASS;
47 
48  /* we're only interested in no to, to our host, or to us */
49  if(pkt->to != NULL && jid_compare_user(sess->jid, pkt->to) != 0 && strcmp(sess->jid->domain, jid_user(pkt->to)) != 0)
50  return mod_PASS;
51 
52  ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVATE, NULL);
53  elem = nad_find_elem(pkt->nad, 1, ns, "query", 1);
54 
55  /* find the first child */
56  target = elem + 1;
57  while(target < pkt->nad->ecur)
58  {
59  if(pkt->nad->elems[target].depth > pkt->nad->elems[elem].depth)
60  break;
61 
62  target++;
63  }
64 
65  /* not found, so we're done */
66  if(target == pkt->nad->ecur)
67  return -stanza_err_BAD_REQUEST;
68 
69  /* find the target namespace */
70  targetns = NAD_ENS(pkt->nad, target);
71 
72  /* gotta have a namespace */
73  if(targetns < 0)
74  {
75  log_debug(ZONE, "no namespace specified");
76  return -stanza_err_BAD_REQUEST;
77  }
78 
79  log_debug(ZONE, "processing private request for %.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
80 
81  /* get */
82  if(pkt->type == pkt_IQ) {
83 #ifdef ENABLE_EXPERIMENTAL
84  /* remember that this resource requested the namespace */
85  if(sess->module_data[mod->index] == NULL) {
86  /* create new hash if necesary */
87  sess->module_data[mod->index] = xhash_new(101);
88  pool_cleanup(sess->p, (void (*))(void *) xhash_free, sess->module_data[mod->index]);
89  }
90  xhash_put(sess->module_data[mod->index], pstrdupx(sess->p, NAD_NURI(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns)), (void *) 1);
91 #endif
92  snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
93  ret = storage_get(sess->user->sm->st, "private", jid_user(sess->jid), filter, &os);
94  switch(ret) {
95  case st_SUCCESS:
96  if(os_iter_first(os)) {
97  o = os_iter_object(os);
98  if(os_object_get_nad(os, o, "xml", &nad)) {
99  result = pkt_new(sess->user->sm, nad_copy(nad));
100  if(result != NULL) {
101  nad_set_attr(result->nad, 1, -1, "type", "result", 6);
102 
103  pkt_id(pkt, result);
104 
105  pkt_sess(result, sess);
106 
107  pkt_free(pkt);
108 
109  os_free(os);
110 
111  return mod_HANDLED;
112  }
113  }
114  }
115 
116  os_free(os);
117 
118  /* drop through */
119  log_debug(ZONE, "storage_get succeeded, but couldn't make packet, faking st_NOTFOUND");
120 
121  case st_NOTFOUND:
122 
123  log_debug(ZONE, "namespace not found, returning");
124 
125  /*
126  * !!! really, we should just return a 404. 1.4 just slaps a
127  * result on the packet and sends it back. hurrah for
128  * legacy namespaces.
129  */
130  nad_set_attr(pkt->nad, 1, -1, "type", "result", 6);
131 
132  pkt_sess(pkt_tofrom(pkt), sess);
133 
134  return mod_HANDLED;
135 
136  case st_FAILED:
138 
139  case st_NOTIMPL:
141  }
142  }
143 
144  os = os_new();
145  o = os_object_new(os);
146 
147  snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
148  os_object_put(o, "ns", filter, os_type_STRING);
149  os_object_put(o, "xml", pkt->nad, os_type_NAD);
150 
151  snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
152 
153  ret = storage_replace(sess->user->sm->st, "private", jid_user(sess->jid), filter, os);
154  os_free(os);
155 
156  switch(ret) {
157  case st_FAILED:
159 
160  case st_NOTIMPL:
162 
163  default:
164  /* create result packet */
165  result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL);
166  pkt_id(pkt, result);
167  /* and flush it to the session */
168  pkt_sess(result, sess);
169 #ifdef ENABLE_EXPERIMENTAL
170  /* push it to all resources that read this xmlns item */
171  snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
172  for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) {
173  /* skip our resource and those that didn't read any private-storage */
174  if(sscan == sess || sscan->module_data[mod->index] == NULL)
175  continue;
176 
177  /* check whether namespace was read */
178  if(xhash_get(sscan->module_data[mod->index], filter)) {
179  result = pkt_dup(pkt, jid_full(sscan->jid), NULL);
180  if(result->from != NULL) {
181  jid_free(result->from);
182  nad_set_attr(result->nad, 1, -1, "from", NULL, 0);
183  }
184  pkt_id_new(result);
185  pkt_sess(result, sscan);
186  }
187  }
188 #endif
189  /* finally free the packet */
190  pkt_free(pkt);
191  return mod_HANDLED;
192  }
193 
194  /* we never get here */
195  return 0;
196 }
197 
199  log_debug(ZONE, "deleting private xml storage for %s", jid_user(jid));
200 
201  storage_delete(mi->sm->st, "private", jid_user(jid), NULL);
202 }
203 
204 static void _iq_private_free(module_t mod) {
207 }
208 
210  module_t mod = mi->mod;
211 
212  if (mod->init) return 0;
213 
216  mod->free = _iq_private_free;
217 
220 
221  return 0;
222 }