jabberd2  2.3.2
xdata.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002-2003 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 /* xdata, whee! */
22 
23 #include "util.h"
24 
26 xdata_t xdata_new(xdata_type_t type, const char *title, const char *instructions) {
27  pool_t p;
28  xdata_t xd;
29 
30  assert((int) type);
31 
32  p = pool_new();
33 
34  xd = pmalloco(p, sizeof(struct _xdata_st));
35 
36  xd->p = p;
37 
38  xd->type = type;
39 
40  if(title != NULL) xd->title = pstrdup(xd->p, title);
41  if(instructions != NULL) xd->instructions = pstrdup(xd->p, instructions);
42 
43  log_debug(ZONE, "created new xd; title=%s, instructions=%s", title, instructions);
44 
45  return xd;
46 }
47 
49 xdata_field_t xdata_field_new(xdata_t xd, xdata_field_type_t type, const char *var, const char *label, const char *desc, int required) {
50  xdata_field_t xdf;
51 
52  assert((int) (xd != NULL));
53  assert((int) type);
54  assert((int) (var != NULL));
55 
56  xdf = pmalloco(xd->p, sizeof(struct _xdata_field_st));
57 
58  xdf->p = xd->p;
59 
60  xdf->type = type;
61 
62  xdf->var = pstrdup(xdf->p, var);
63 
64  if(label != NULL) xdf->label = pstrdup(xdf->p, label);
65  if(desc != NULL) xdf->desc = pstrdup(xdf->p, desc);
66 
67  xdf->required = required;
68 
69  return xdf;
70 }
71 
74  xdata_item_t xdi;
75 
76  assert((int) (xd != NULL));
77 
78  xdi = pmalloco(xd->p, sizeof(struct _xdata_item_st));
79 
80  xdi->p = xd->p;
81 
82  return xdi;
83 }
84 
87  assert((int) (xd != NULL));
88  assert((int) (xdf != NULL));
89 
90  if(xd->fields == NULL)
91  xd->fields = xd->flast = xdf;
92  else {
93  xd->flast->next = xdf;
94  xd->flast = xdf;
95  }
96 }
97 
99  assert((int) (xd != NULL));
100  assert((int) (xdf != NULL));
101 
102  if(xd->rfields == NULL)
103  xd->rfields = xd->rflast = xdf;
104  else {
105  xd->rflast->next = xdf;
106  xd->rflast = xdf;
107  }
108 }
109 
111  assert((int) (xdi != NULL));
112  assert((int) (xdf != NULL));
113 
114  if(xdi->fields == NULL)
115  xdi->fields = xdi->flast = xdf;
116  else {
117  xdi->flast->next = xdf;
118  xdi->flast = xdf;
119  }
120 }
121 
124  assert((int) (xd != NULL));
125  assert((int) (xdi != NULL));
126 
127  if(xd->items == NULL)
128  xd->items = xd->ilast = xdi;
129  else {
130  xd->ilast->next = xdi;
131  xd->ilast = xdi;
132  }
133 }
134 
136 static void xdata_option_new(xdata_field_t xdf, const char *value, int lvalue, const char *label, int llabel) {
137  xdata_option_t xdo;
138 
139  assert((int) (xdf != NULL));
140  assert((int) (value != NULL));
141 
142  xdo = pmalloco(xdf->p, sizeof(struct _xdata_option_st));
143 
144  xdo->p = xdf->p;
145 
146  if(lvalue <= 0) lvalue = strlen(value);
147  xdo->value = pstrdupx(xdo->p, value, lvalue);
148 
149  if(label != NULL) {
150  if(llabel <= 0) llabel = strlen(label);
151  xdo->label = pstrdupx(xdo->p, label, llabel);
152  }
153 
154  xdf->olast->next = xdo;
155  xdf->olast = xdo;
156  if(xdf->options == NULL) xdf->options = xdo;
157 }
158 
160 void xdata_add_value(xdata_field_t xdf, const char *value, int vlen) {
161  int first = 0;
162 
163  assert((int) (xdf != NULL));
164  assert((int) (value != NULL));
165 
166  if(vlen <= 0) vlen = strlen(value);
167 
168  if(xdf->values == NULL)
169  first = 1;
170 
171  xdf->values = (char **) realloc(xdf->values, sizeof(char *) * (xdf->nvalues + 1));
172  xdf->values[xdf->nvalues] = pstrdupx(xdf->p, value, vlen);
173  xdf->nvalues++;
174 
175  if(first)
176  pool_cleanup(xdf->p, free, xdf->values);
177 }
178 
180 static xdata_field_t _xdata_field_parse(xdata_t xd, nad_t nad, int root) {
181  xdata_field_t xdf;
182  int attr, elem, eval;
183 
184  xdf = pmalloco(xd->p, sizeof(struct _xdata_field_st));
185 
186  xdf->p = xd->p;
187 
188  attr = nad_find_attr(nad, root, -1, "var", NULL);
189  if(attr >= 0)
190  xdf->var = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
191 
192  attr = nad_find_attr(nad, root, -1, "label", NULL);
193  if(attr >= 0)
194  xdf->label = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
195 
196  attr = nad_find_attr(nad, root, -1, "desc", NULL);
197  if(attr >= 0)
198  xdf->desc = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
199 
200  if(nad_find_elem(nad, root, NAD_ENS(nad, root), "required", 1) >= 0)
201  xdf->required = 1;
202 
203  attr = nad_find_attr(nad, root, -1, "type", NULL);
204  if(attr >= 0) {
205  if(NAD_AVAL_L(nad, attr) == 7 && strncmp("boolean", NAD_AVAL(nad, attr), 7) == 0)
206  xdf->type = xd_field_BOOLEAN;
207  else if(NAD_AVAL_L(nad, attr) == 5 && strncmp("fixed", NAD_AVAL(nad, attr), 5) == 0)
208  xdf->type = xd_field_FIXED;
209  else if(NAD_AVAL_L(nad, attr) == 6 && strncmp("hidden", NAD_AVAL(nad, attr), 6) == 0)
210  xdf->type = xd_field_HIDDEN;
211  else if(NAD_AVAL_L(nad, attr) == 9 && strncmp("jid-multi", NAD_AVAL(nad, attr), 9) == 0)
212  xdf->type = xd_field_JID_MULTI;
213  else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("jid-single", NAD_AVAL(nad, attr), 10) == 0)
214  xdf->type = xd_field_JID_SINGLE;
215  else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("list-multi", NAD_AVAL(nad, attr), 10) == 0)
216  xdf->type = xd_field_LIST_MULTI;
217  else if(NAD_AVAL_L(nad, attr) == 11 && strncmp("list-single", NAD_AVAL(nad, attr), 11) == 0)
218  xdf->type = xd_field_LIST_SINGLE;
219  else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("text-multi", NAD_AVAL(nad, attr), 10) == 0)
220  xdf->type = xd_field_TEXT_MULTI;
221  else if(NAD_AVAL_L(nad, attr) == 12 && strncmp("text-private", NAD_AVAL(nad, attr), 12) == 0)
223  else if(NAD_AVAL_L(nad, attr) == 11 && strncmp("text-single", NAD_AVAL(nad, attr), 11) == 0)
224  xdf->type = xd_field_TEXT_SINGLE;
225  else {
226  log_debug(ZONE, "unknown field type '%.*s'", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));
227  return NULL;
228  }
229  }
230 
231  elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "value", 1);
232  while(elem >= 0) {
233  if(NAD_CDATA_L(nad, elem) <= 0) {
234  log_debug(ZONE, "value element requires cdata");
235  return NULL;
236  }
237 
238  xdata_add_value(xdf, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem));
239 
240  elem = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "value", 0);
241  }
242 
243  elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "options", 1);
244  while(elem >= 0) {
245  eval = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "value", 1);
246  if(eval < 0) {
247  log_debug(ZONE, "option requires value subelement");
248  return NULL;
249  }
250 
251  if(NAD_CDATA_L(nad, eval) <= 0) {
252  log_debug(ZONE, "value element requires cdata");
253  return NULL;
254  }
255 
256  attr = nad_find_attr(nad, elem, -1, "label", NULL);
257  if(attr < 0)
258  xdata_option_new(xdf, NAD_CDATA(nad, eval), NAD_CDATA_L(nad, eval), NAD_AVAL(nad, eval), NAD_AVAL_L(nad, eval));
259  else
260  xdata_option_new(xdf, NAD_CDATA(nad, eval), NAD_CDATA_L(nad, eval), NULL, 0);
261 
262  elem = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "options", 0);
263  }
264 
265  return xdf;
266 }
267 
269 xdata_t xdata_parse(nad_t nad, int root) {
270  xdata_t xd;
271  int atype, elem, field;
272  xdata_field_t xdf;
273 
274  assert((int) (nad != NULL));
275  assert((int) (root >= 0));
276 
277  log_debug(ZONE, "building xd from nad");
278 
279  if(root >= nad->ecur || NAD_NURI_L(nad, NAD_ENS(nad, root)) != strlen(uri_XDATA) || strncmp(uri_XDATA, NAD_NURI(nad, NAD_ENS(nad, root)), strlen(uri_XDATA) != 0) || NAD_ENAME_L(nad, root) != 1 || (NAD_ENAME(nad, root))[0] != 'x') {
280  log_debug(ZONE, "elem %d does not exist, or is not {x:data}x", root);
281  return NULL;
282  }
283 
284  atype = nad_find_attr(nad, root, -1, "type", NULL);
285  if(atype < 0) {
286  log_debug(ZONE, "no type attribute");
287  return NULL;
288  }
289 
290  if(NAD_AVAL_L(nad, atype) == 4 && strncmp("form", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
291  xd = xdata_new(xd_type_FORM, NULL, NULL);
292  else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("result", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
293  xd = xdata_new(xd_type_RESULT, NULL, NULL);
294  else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("submit", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
295  xd = xdata_new(xd_type_SUBMIT, NULL, NULL);
296  else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("cancel", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
297  xd = xdata_new(xd_type_CANCEL, NULL, NULL);
298  else {
299  log_debug(ZONE, "unknown xd type %.*s", NAD_AVAL_L(nad, atype), NAD_AVAL(nad, atype));
300  return NULL;
301  }
302 
303  elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "title", 1);
304  if(elem < 0 || NAD_CDATA_L(nad, elem) <= 0) {
305  log_debug(ZONE, "no cdata on x/title element");
306  pool_free(xd->p);
307  return NULL;
308  }
309 
310  xd->title = pmalloco(xd->p, sizeof(char) * (NAD_CDATA_L(nad, elem) + 1));
311  strncpy(xd->title, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem));
312 
313  elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "instructions", 1);
314  if(elem < 0 || NAD_CDATA_L(nad, elem) <= 0) {
315  log_debug(ZONE, "no cdata on x/instructions element");
316  pool_free(xd->p);
317  return NULL;
318  }
319 
320  xd->instructions = pstrdupx(xd->p, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem));
321 
322  switch(xd->type) {
323  case xd_type_FORM:
324  case xd_type_SUBMIT:
325  /* form and submit just have fields, one level */
326  field = nad_find_elem(nad, root, NAD_ENS(nad, root), "field", 1);
327  while(field >= 0) {
328  xdf = _xdata_field_parse(xd, nad, field);
329  if(xdf == NULL) {
330  log_debug(ZONE, "field parse failed");
331  pool_free(xd->p);
332  return NULL;
333  }
334 
335  xdata_add_field(xd, xdf);
336 
337  field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0);
338  }
339 
340  break;
341 
342  case xd_type_RESULT:
343  /* result has reported and item */
344  elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "reported", 1);
345  if(elem >= 0) {
346  field = nad_find_elem(nad, elem, NAD_ENS(nad, root), "field", 1);
347  while(field >= 0) {
348  xdf = _xdata_field_parse(xd, nad, field);
349  if(xdf == NULL) {
350  log_debug(ZONE, "field parse failed");
351  pool_free(xd->p);
352  return NULL;
353  }
354 
355  xdata_add_field(xd, xdf);
356 
357  field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0);
358  }
359  }
360 
361  elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "item", 1);
362  if(elem >= 0) {
363  field = nad_find_elem(nad, elem, NAD_ENS(nad, root), "field", 1);
364  while(field >= 0) {
365  xdf = _xdata_field_parse(xd, nad, field);
366  if(xdf == NULL) {
367  log_debug(ZONE, "field parse failed");
368  pool_free(xd->p);
369  return NULL;
370  }
371 
372  xdata_add_field(xd, xdf);
373 
374  field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0);
375  }
376  }
377 
378  break;
379 
380  case xd_type_CANCEL:
381  /* nothing to do with cancel, its all based on context */
382  break;
383 
384  case xd_type_NONE:
385  break;
386  }
387 
388  return xd;
389 }
xdata_type_t
Definition: xdata.h:33
Definition: nad.h:93
char * value
Definition: xdata.h:94
void pool_free(pool_t p)
Definition: pool.c:226
char * var
Definition: xdata.h:74
xdata_item_t ilast
Definition: xdata.h:52
#define NAD_CDATA_L(N, E)
Definition: nad.h:186
int nvalues
Definition: xdata.h:83
xdata_item_t items
Definition: xdata.h:52
xdata_type_t type
Definition: xdata.h:44
int nad_find_elem(nad_t nad, 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:204
char * label
Definition: xdata.h:76
void xdata_add_value(xdata_field_t xdf, const char *value, int vlen)
value insertion
Definition: xdata.c:160
xdata_field_t rfields
Definition: xdata.h:50
pool_t p
Definition: xdata.h:42
#define NAD_ENAME(N, E)
Definition: nad.h:183
#define pool_new()
Definition: pool.h:97
pool_t p
Definition: xdata.h:70
xdata_field_t fields
Definition: xdata.h:49
char * instructions
Definition: xdata.h:47
xdata_field_t rflast
Definition: xdata.h:50
pool_t p
Definition: xdata.h:100
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
xdata_t xdata_new(xdata_type_t type, const char *title, const char *instructions)
creation
Definition: xdata.c:26
xdata_field_t fields
Definition: xdata.h:102
xdata_option_t options
Definition: xdata.h:85
void * pmalloco(pool_t p, int size)
easy safety utility (for creating blank mem for structs, etc)
Definition: pool.c:183
#define NAD_ENAME_L(N, E)
Definition: nad.h:184
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
xdata_item_t xdata_item_new(xdata_t xd)
new item
Definition: xdata.c:73
void xdata_add_rfield(xdata_t xd, xdata_field_t xdf)
Definition: xdata.c:98
int ecur
Definition: nad.h:105
#define uri_XDATA
Definition: uri.h:54
#define NAD_AVAL_L(N, A)
Definition: nad.h:190
xdata_field_t flast
Definition: xdata.h:49
#define log_debug(...)
Definition: log.h:65
xdata_option_t olast
Definition: xdata.h:85
xdata_field_t xdata_field_new(xdata_t xd, xdata_field_type_t type, const char *var, const char *label, const char *desc, int required)
new field
Definition: xdata.c:49
#define NAD_AVAL(N, A)
Definition: nad.h:189
xdata_field_t next
Definition: xdata.h:87
xdata_option_t next
Definition: xdata.h:96
xdata_item_t next
Definition: xdata.h:104
static xdata_field_t _xdata_field_parse(xdata_t xd, nad_t nad, int root)
rip out a field
Definition: xdata.c:180
void xdata_add_field(xdata_t xd, xdata_field_t xdf)
field insertion
Definition: xdata.c:86
int required
Definition: xdata.h:80
char * label
Definition: xdata.h:93
xdata_field_type_t type
Definition: xdata.h:72
static void xdata_option_new(xdata_field_t xdf, const char *value, int lvalue, const char *label, int llabel)
option insertion
Definition: xdata.c:136
xdata_field_t flast
Definition: xdata.h:102
char ** values
Definition: xdata.h:82
char * pstrdup(pool_t p, const char *src)
XXX efficient: move this to const char * and then loop throug the existing heaps to see if src is wit...
Definition: pool.c:191
#define NAD_CDATA(N, E)
Definition: nad.h:185
#define ZONE
Definition: mio_impl.h:76
#define NAD_NURI(N, NS)
Definition: nad.h:191
xdata_t xdata_parse(nad_t nad, int root)
parse a nad and build
Definition: xdata.c:269
int nad_find_attr(nad_t nad, int elem, int ns, const char *name, const char *val)
get a matching attr on this elem, both name and optional val
Definition: nad.c:235
pool - base node for a pool.
Definition: pool.h:80
char * desc
Definition: xdata.h:78
char * title
Definition: xdata.h:46
#define NAD_ENS(N, E)
Definition: nad.h:196
void xdata_add_item(xdata_t xd, xdata_item_t xdi)
item insertion
Definition: xdata.c:123
void xdata_add_field_item(xdata_item_t xdi, xdata_field_t xdf)
Definition: xdata.c:110
pool_t p
Definition: xdata.h:91
xdata_field_type_t
Definition: xdata.h:55