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