jabberd2  2.7.0
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  /* remember that this resource requested the namespace */
84  if(sess->module_data[mod->index] == NULL) {
85  /* create new hash if necesary */
86  sess->module_data[mod->index] = xhash_new(101);
87  pool_cleanup(sess->p, (void (*))(void *) xhash_free, sess->module_data[mod->index]);
88  }
89  xhash_put(sess->module_data[mod->index], pstrdupx(sess->p, NAD_NURI(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns)), (void *) 1);
90  snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
91  ret = storage_get(sess->user->sm->st, "private", jid_user(sess->jid), filter, &os);
92  switch(ret) {
93  case st_SUCCESS:
94  if(os_iter_first(os)) {
95  o = os_iter_object(os);
96  if(os_object_get_nad(os, o, "xml", &nad)) {
97  result = pkt_new(sess->user->sm, nad_copy(nad));
98  if(result != NULL) {
99  nad_set_attr(result->nad, 1, -1, "type", "result", 6);
100 
101  pkt_id(pkt, result);
102 
103  pkt_sess(result, sess);
104 
105  pkt_free(pkt);
106 
107  os_free(os);
108 
109  return mod_HANDLED;
110  }
111  }
112  }
113 
114  os_free(os);
115 
116  /* drop through */
117  log_debug(ZONE, "storage_get succeeded, but couldn't make packet, faking st_NOTFOUND");
118 
119  case st_NOTFOUND:
120 
121  log_debug(ZONE, "namespace not found, returning");
122 
123  /*
124  * !!! really, we should just return a 404. 1.4 just slaps a
125  * result on the packet and sends it back. hurrah for
126  * legacy namespaces.
127  */
128  nad_set_attr(pkt->nad, 1, -1, "type", "result", 6);
129 
130  pkt_sess(pkt_tofrom(pkt), sess);
131 
132  return mod_HANDLED;
133 
134  case st_FAILED:
136 
137  case st_NOTIMPL:
139  }
140  }
141 
142  os = os_new();
143  o = os_object_new(os);
144 
145  snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
146  os_object_put(o, "ns", filter, os_type_STRING);
147  os_object_put(o, "xml", pkt->nad, os_type_NAD);
148 
149  snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
150 
151  ret = storage_replace(sess->user->sm->st, "private", jid_user(sess->jid), filter, os);
152  os_free(os);
153 
154  switch(ret) {
155  case st_FAILED:
157 
158  case st_NOTIMPL:
160 
161  default:
162  /* create result packet */
163  result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL);
164  pkt_id(pkt, result);
165  /* and flush it to the session */
166  pkt_sess(result, sess);
167  /* push it to all resources that read this xmlns item */
168  snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns));
169  for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) {
170  /* skip our resource and those that didn't read any private-storage */
171  if(sscan == sess || sscan->module_data[mod->index] == NULL)
172  continue;
173 
174  /* check whether namespace was read */
175  if(xhash_get(sscan->module_data[mod->index], filter)) {
176  result = pkt_dup(pkt, jid_full(sscan->jid), NULL);
177  if(result->from != NULL) {
178  jid_free(result->from);
179  result->from = NULL;
180  nad_set_attr(result->nad, 1, -1, "from", NULL, 0);
181  }
182  pkt_id_new(result);
183  pkt_sess(result, sscan);
184  }
185  }
186  /* finally free the packet */
187  pkt_free(pkt);
188  return mod_HANDLED;
189  }
190 
191  /* we never get here */
192  return 0;
193 }
194 
196  log_debug(ZONE, "deleting private xml storage for %s", jid_user(jid));
197 
198  storage_delete(mi->sm->st, "private", jid_user(jid), NULL);
199 }
200 
201 static void _iq_private_free(module_t mod) {
204 }
205 
206 DLLEXPORT int module_init(mod_instance_t mi, const char *arg) {
207  module_t mod = mi->mod;
208 
209  if (mod->init) return 0;
210 
213  mod->free = _iq_private_free;
214 
217 
218  return 0;
219 }
user_t user
user this session belongs to
Definition: sm.h:256
pkt_type_t type
packet type
Definition: sm.h:138
int sm_register_ns(sm_t sm, const char *uri)
register a new global ns
Definition: sm.c:324
jid_t jid
session jid (user@host/res)
Definition: sm.h:258
struct nad_elem_st * elems
Definition: nad.h:95
Definition: nad.h:93
data structures and prototypes for the session manager
#define uri_PRIVATE
void sm_unregister_ns(sm_t sm, const char *uri)
unregister a global ns
Definition: sm.c:338
void xhash_free(xht h)
Definition: xhash.c:241
static void _iq_private_user_delete(mod_instance_t mi, jid_t jid)
const char * jid_user(jid_t jid)
expand and return the user
Definition: jid.c:338
DLLEXPORT int module_init(mod_instance_t mi, const char *arg)
const char * jid_full(jid_t jid)
expand and return the full
Definition: jid.c:346
pkt_t pkt_tofrom(pkt_t pkt)
swap a packet&#39;s to and from attributes
Definition: pkt.c:57
single instance of a module in a chain
Definition: sm.h:446
void nad_set_attr(nad_t nad, unsigned int elem, int ns, const char *name, const char *val, int vallen)
create, update, or zap any matching attr on this elem
Definition: nad.c:407
int init
number of times the module intialiser has been called
Definition: sm.h:416
info/query (set)
Definition: sm.h:107
void ** module_data
per-session module data
Definition: sm.h:274
#define stanza_err_FEATURE_NOT_IMPLEMENTED
Definition: util.h:369
sm_t sm
sm context
Definition: sm.h:237
pkt_t pkt_dup(pkt_t pkt, const char *to, const char *from)
duplicate pkt, replacing addresses
Definition: pkt.c:84
void pkt_id_new(pkt_t pkt)
create an id value for new iq packets
Definition: pkt.c:364
nad_t nad_copy(nad_t nad)
copy a nad
Definition: nad.c:147
int index
module index.
Definition: sm.h:408
pool_t p
memory pool this session is allocated off
Definition: sm.h:254
mm_t mm
module manager
Definition: sm.h:404
#define DLLEXPORT
Definition: c2s.h:47
sess_t next
next session (in a list of sessions)
Definition: sm.h:276
pkt_t pkt_new(sm_t sm, nad_t nad)
Definition: pkt.c:113
void pool_cleanup(pool_t p, pool_cleanup_t f, void *arg)
public cleanup utils, insert in a way that they are run FIFO, before mem frees
Definition: pool.c:251
sm_t sm
sm context
Definition: sm.h:366
mod_ret_t(* in_sess)(mod_instance_t mi, sess_t sess, pkt_t pkt)
in-sess handler
Definition: sm.h:423
unsigned int depth
Definition: nad.h:77
sess_t sessions
list of action sessions
Definition: sm.h:243
module_t mod
module that this is an instance of
Definition: sm.h:449
jid_t from
packet addressing (not used for routing)
Definition: sm.h:140
void feature_unregister(sm_t sm, const char *feature)
unregister feature
Definition: feature.c:45
packet summary data wrapper
Definition: sm.h:129
char * pstrdupx(pool_t p, const char *src, int len)
use given size
Definition: pool.c:205
#define NAD_NURI_L(N, NS)
Definition: nad.h:192
storage_t st
storage subsystem
Definition: sm.h:211
nad_t nad
nad of the entire packet
Definition: sm.h:146
void jid_free(jid_t jid)
free a jid
Definition: jid.c:286
void xhash_put(xht h, const char *key, void *val)
Definition: xhash.c:163
#define stanza_err_BAD_REQUEST
Definition: util.h:367
char * domain
Definition: jid.h:45
Definition: jid.h:42
int ecur
Definition: nad.h:105
void pkt_id(pkt_t src, pkt_t dest)
convenience - copy the packet id from src to dest
Definition: pkt.c:353
void pkt_free(pkt_t pkt)
Definition: pkt.c:315
#define log_debug(...)
Definition: log.h:65
void feature_register(sm_t sm, const char *feature)
register a feature
Definition: feature.c:37
info/query (get)
Definition: sm.h:106
packet was unhandled, should be passed to the next module
Definition: sm.h:340
int ns
iq sub-namespace
Definition: sm.h:142
static void _iq_private_free(module_t mod)
packet was handled (and freed)
Definition: sm.h:339
There is one instance of this struct per user who is logged in to this c2s instance.
Definition: c2s.h:74
int jid_compare_user(jid_t a, jid_t b)
compare the user portion of two jids
Definition: jid.c:354
int nad_find_elem(nad_t nad, unsigned int elem, int ns, const char *name, int depth)
locate the next elem at a given depth with an optional matching name
Definition: nad.c:206
void(* user_delete)(mod_instance_t mi, jid_t jid)
user-delete handler
Definition: sm.h:438
static int ns_PRIVATE
jid_t to
Definition: sm.h:140
void * xhash_get(xht h, const char *key)
Definition: xhash.c:184
#define ZONE
Definition: mio_impl.h:76
#define NAD_NURI(N, NS)
Definition: nad.h:191
static mod_ret_t _iq_private_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt)
void(* free)(module_t mod)
called when module is freed
Definition: sm.h:442
xht xhash_new(int prime)
Definition: xhash.c:96
data for a single module
Definition: sm.h:403
pkt_t pkt_create(sm_t sm, const char *elem, const char *type, const char *to, const char *from)
Definition: pkt.c:328
mod_ret_t
module return values
Definition: sm.h:338
sm_t sm
sm context
Definition: sm.h:447
#define stanza_err_INTERNAL_SERVER_ERROR
Definition: util.h:372
void pkt_sess(pkt_t pkt, sess_t sess)
Definition: pkt.c:459
#define NAD_ENS(N, E)
Definition: nad.h:196
int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix)
find a namespace in scope
Definition: nad.c:292