jabberd2  2.2.16
util/xdata.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002-2003 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 /* xdata, whee! */
00022 
00023 #include "util.h"
00024 
00026 xdata_t xdata_new(xdata_type_t type, char *title, char *instructions) {
00027     pool_t p;
00028     xdata_t xd;
00029 
00030     assert((int) type);
00031 
00032     p = pool_new();
00033 
00034     xd = pmalloco(p, sizeof(struct _xdata_st));
00035 
00036     xd->p = p;
00037 
00038     xd->type = type;
00039 
00040     if(title != NULL) xd->title = pstrdup(xd->p, title);
00041     if(instructions != NULL) xd->instructions = pstrdup(xd->p, instructions);
00042 
00043     log_debug(ZONE, "created new xd; title=%s, instructions=%s", title, instructions);
00044 
00045     return xd;
00046 }
00047 
00049 xdata_field_t xdata_field_new(xdata_t xd, xdata_field_type_t type, char *var, char *label, char *desc, int required) {
00050     xdata_field_t xdf;
00051 
00052     assert((int) (xd != NULL));
00053     assert((int) type);
00054     assert((int) (var != NULL));
00055 
00056     xdf = pmalloco(xd->p, sizeof(struct _xdata_field_st));
00057 
00058     xdf->p = xd->p;
00059 
00060     xdf->type = type;
00061 
00062     xdf->var = pstrdup(xdf->p, var);
00063 
00064     if(label != NULL) xdf->label = pstrdup(xdf->p, label);
00065     if(desc != NULL) xdf->desc = pstrdup(xdf->p, desc);
00066 
00067     xdf->required = required;
00068 
00069     return xdf;
00070 }
00071 
00073 xdata_item_t xdata_item_new(xdata_t xd) {
00074     xdata_item_t xdi;
00075 
00076     assert((int) (xd != NULL));
00077 
00078     xdi = pmalloco(xd->p, sizeof(struct _xdata_item_st));
00079 
00080     xdi->p = xd->p;
00081 
00082     return xdi;
00083 }
00084 
00086 void xdata_add_field(xdata_t xd, xdata_field_t xdf) {
00087     assert((int) (xd != NULL));
00088     assert((int) (xdf != NULL));
00089 
00090     if(xd->fields == NULL)
00091         xd->fields = xd->flast = xdf;
00092     else {
00093         xd->flast->next = xdf;
00094         xd->flast = xdf;
00095     }
00096 }
00097 
00098 void xdata_add_rfield(xdata_t xd, xdata_field_t xdf) {
00099     assert((int) (xd != NULL));
00100     assert((int) (xdf != NULL));
00101 
00102     if(xd->rfields == NULL)
00103         xd->rfields = xd->rflast = xdf;
00104     else {
00105         xd->rflast->next = xdf;
00106         xd->rflast = xdf;
00107     }
00108 }
00109 
00110 void xdata_add_field_item(xdata_item_t xdi, xdata_field_t xdf) {
00111     assert((int) (xdi != NULL));
00112     assert((int) (xdf != NULL));
00113 
00114     if(xdi->fields == NULL)
00115         xdi->fields = xdi->flast = xdf;
00116     else {
00117         xdi->flast->next = xdf;
00118         xdi->flast = xdf;
00119     }
00120 }
00121 
00123 void xdata_add_item(xdata_t xd, xdata_item_t xdi) {
00124     assert((int) (xd != NULL));
00125     assert((int) (xdi != NULL));
00126 
00127     if(xd->items == NULL)
00128         xd->items = xd->ilast = xdi;
00129     else {
00130         xd->ilast->next = xdi;
00131         xd->ilast = xdi;
00132     }
00133 }
00134 
00136 static void xdata_option_new(xdata_field_t xdf, char *value, int lvalue, char *label, int llabel) {
00137     xdata_option_t xdo;
00138 
00139     assert((int) (xdf != NULL));
00140     assert((int) (value != NULL));
00141 
00142     xdo = pmalloco(xdf->p, sizeof(struct _xdata_option_st));
00143 
00144     xdo->p = xdf->p;
00145 
00146     if(lvalue <= 0) lvalue = strlen(value);
00147     xdo->value = pstrdupx(xdo->p, value, lvalue);
00148 
00149     if(label != NULL) {
00150         if(llabel <= 0) llabel = strlen(label);
00151         xdo->label = pstrdupx(xdo->p, label, llabel);
00152     }
00153 
00154     xdf->olast->next = xdo;
00155     xdf->olast = xdo;
00156     if(xdf->options == NULL) xdf->options = xdo;
00157 }
00158 
00160 void xdata_add_value(xdata_field_t xdf, char *value, int vlen) {
00161     int first = 0;
00162 
00163     assert((int) (xdf != NULL));
00164     assert((int) (value != NULL));
00165 
00166     if(vlen <= 0) vlen = strlen(value);
00167 
00168     if(xdf->values == NULL)
00169         first = 1;
00170 
00171     xdf->values = (char **) realloc(xdf->values, sizeof(char *) * (xdf->nvalues + 1));
00172     xdf->values[xdf->nvalues] = pstrdupx(xdf->p, value, vlen);
00173     xdf->nvalues++;
00174 
00175     if(first)
00176         pool_cleanup(xdf->p, free, xdf->values);
00177 }
00178 
00180 static xdata_field_t _xdata_field_parse(xdata_t xd, nad_t nad, int root) {
00181     xdata_field_t xdf;
00182     int attr, elem, eval;
00183 
00184     xdf = pmalloco(xd->p, sizeof(struct _xdata_field_st));
00185 
00186     xdf->p = xd->p;
00187 
00188     attr = nad_find_attr(nad, root, -1, "var", NULL);
00189     if(attr >= 0)
00190         xdf->var = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
00191 
00192     attr = nad_find_attr(nad, root, -1, "label", NULL);
00193     if(attr >= 0)
00194         xdf->label = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
00195 
00196     attr = nad_find_attr(nad, root, -1, "desc", NULL);
00197     if(attr >= 0)
00198         xdf->desc = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
00199 
00200     if(nad_find_elem(nad, root, NAD_ENS(nad, root), "required", 1) >= 0)
00201         xdf->required = 1;
00202 
00203     attr = nad_find_attr(nad, root, -1, "type", NULL);
00204     if(attr >= 0) {
00205         if(NAD_AVAL_L(nad, attr) == 7 && strncmp("boolean", NAD_AVAL(nad, attr), 7) == 0)
00206             xdf->type = xd_field_BOOLEAN;
00207         else if(NAD_AVAL_L(nad, attr) == 5 && strncmp("fixed", NAD_AVAL(nad, attr), 5) == 0)
00208             xdf->type = xd_field_FIXED;
00209         else if(NAD_AVAL_L(nad, attr) == 6 && strncmp("hidden", NAD_AVAL(nad, attr), 6) == 0)
00210             xdf->type = xd_field_HIDDEN;
00211         else if(NAD_AVAL_L(nad, attr) == 9 && strncmp("jid-multi", NAD_AVAL(nad, attr), 9) == 0)
00212             xdf->type = xd_field_JID_MULTI;
00213         else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("jid-single", NAD_AVAL(nad, attr), 10) == 0)
00214             xdf->type = xd_field_JID_SINGLE;
00215         else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("list-multi", NAD_AVAL(nad, attr), 10) == 0)
00216             xdf->type = xd_field_LIST_MULTI;
00217         else if(NAD_AVAL_L(nad, attr) == 11 && strncmp("list-single", NAD_AVAL(nad, attr), 11) == 0)
00218             xdf->type = xd_field_LIST_SINGLE;
00219         else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("text-multi", NAD_AVAL(nad, attr), 10) == 0)
00220             xdf->type = xd_field_TEXT_MULTI;
00221         else if(NAD_AVAL_L(nad, attr) == 12 && strncmp("text-private", NAD_AVAL(nad, attr), 12) == 0)
00222             xdf->type = xd_field_TEXT_PRIVATE;
00223         else if(NAD_AVAL_L(nad, attr) == 11 && strncmp("text-single", NAD_AVAL(nad, attr), 11) == 0)
00224             xdf->type = xd_field_TEXT_SINGLE;
00225         else {
00226             log_debug(ZONE, "unknown field type '%.*s'", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));
00227             return NULL;
00228         }
00229     }
00230 
00231     elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "value", 1);
00232     while(elem >= 0) {
00233         if(NAD_CDATA_L(nad, elem) <= 0) {
00234             log_debug(ZONE, "value element requires cdata");
00235             return NULL;
00236         }
00237 
00238         xdata_add_value(xdf, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem));
00239 
00240         elem = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "value", 0);
00241     }
00242 
00243     elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "options", 1);
00244     while(elem >= 0) {
00245         eval = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "value", 1);
00246         if(eval < 0) {
00247             log_debug(ZONE, "option requires value subelement");
00248             return NULL;
00249         }
00250 
00251         if(NAD_CDATA_L(nad, eval) <= 0) {
00252             log_debug(ZONE, "value element requires cdata");
00253             return NULL;
00254         }
00255 
00256         attr = nad_find_attr(nad, elem, -1, "label", NULL);
00257         if(attr < 0)
00258             xdata_option_new(xdf, NAD_CDATA(nad, eval), NAD_CDATA_L(nad, eval), NAD_AVAL(nad, eval), NAD_AVAL_L(nad, eval));
00259         else
00260             xdata_option_new(xdf, NAD_CDATA(nad, eval), NAD_CDATA_L(nad, eval), NULL, 0);
00261 
00262         elem = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "options", 0);
00263     }
00264 
00265     return xdf;
00266 }
00267 
00269 xdata_t xdata_parse(nad_t nad, int root) {
00270     xdata_t xd;
00271     int atype, elem, field;
00272     xdata_field_t xdf;
00273 
00274     assert((int) (nad != NULL));
00275     assert((int) (root >= 0));
00276 
00277     log_debug(ZONE, "building xd from nad");
00278 
00279     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') {
00280         log_debug(ZONE, "elem %d does not exist, or is not {x:data}x", root);
00281         return NULL;
00282     }
00283 
00284     atype = nad_find_attr(nad, root, -1, "type", NULL);
00285     if(atype < 0) {
00286         log_debug(ZONE, "no type attribute");
00287         return NULL;
00288     }
00289 
00290     if(NAD_AVAL_L(nad, atype) == 4 && strncmp("form", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
00291         xd = xdata_new(xd_type_FORM, NULL, NULL);
00292     else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("result", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
00293         xd = xdata_new(xd_type_RESULT, NULL, NULL);
00294     else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("submit", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
00295         xd = xdata_new(xd_type_SUBMIT, NULL, NULL);
00296     else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("cancel", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
00297         xd = xdata_new(xd_type_CANCEL, NULL, NULL);
00298     else {
00299         log_debug(ZONE, "unknown xd type %.*s", NAD_AVAL_L(nad, atype), NAD_AVAL(nad, atype));
00300         return NULL;
00301     }
00302 
00303     elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "title", 1);
00304     if(elem < 0 || NAD_CDATA_L(nad, elem) <= 0) {
00305         log_debug(ZONE, "no cdata on x/title element");
00306         pool_free(xd->p);
00307         return NULL;
00308     }
00309 
00310     xd->title = pmalloco(xd->p, sizeof(char) * (NAD_CDATA_L(nad, elem) + 1));
00311     strncpy(xd->title, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem));
00312 
00313     elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "instructions", 1);
00314     if(elem < 0 || NAD_CDATA_L(nad, elem) <= 0) {
00315         log_debug(ZONE, "no cdata on x/instructions element");
00316         pool_free(xd->p);
00317         return NULL;
00318     }
00319 
00320     xd->instructions = pstrdupx(xd->p, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem));
00321 
00322     switch(xd->type) {
00323         case xd_type_FORM:
00324         case xd_type_SUBMIT:
00325             /* form and submit just have fields, one level */
00326             field = nad_find_elem(nad, root, NAD_ENS(nad, root), "field", 1);
00327             while(field >= 0) {
00328                 xdf = _xdata_field_parse(xd, nad, field);
00329                 if(xdf == NULL) {
00330                     log_debug(ZONE, "field parse failed");
00331                     pool_free(xd->p);
00332                     return NULL;
00333                 }
00334 
00335                 xdata_add_field(xd, xdf);
00336 
00337                 field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0);
00338             }
00339 
00340             break;
00341 
00342         case xd_type_RESULT:
00343             /* result has reported and item */
00344             elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "reported", 1);
00345             if(elem >= 0) {
00346                 field = nad_find_elem(nad, elem, NAD_ENS(nad, root), "field", 1);
00347                 while(field >= 0) {
00348                     xdf = _xdata_field_parse(xd, nad, field);
00349                     if(xdf == NULL) {
00350                         log_debug(ZONE, "field parse failed");
00351                         pool_free(xd->p);
00352                         return NULL;
00353                     }
00354 
00355                     xdata_add_field(xd, xdf);
00356 
00357                     field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0);
00358                 }
00359             }
00360 
00361             elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "item", 1);
00362             if(elem >= 0) {
00363                 field = nad_find_elem(nad, elem, NAD_ENS(nad, root), "field", 1);
00364                 while(field >= 0) {
00365                     xdf = _xdata_field_parse(xd, nad, field);
00366                     if(xdf == NULL) {
00367                         log_debug(ZONE, "field parse failed");
00368                         pool_free(xd->p);
00369                         return NULL;
00370                     }
00371 
00372                     xdata_add_field(xd, xdf);
00373 
00374                     field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0);
00375                 }
00376             }
00377 
00378             break;
00379 
00380         case xd_type_CANCEL:
00381             /* nothing to do with cancel, its all based on context */
00382             break;
00383 
00384         case xd_type_NONE:
00385             break;
00386     }
00387 
00388     return xd;
00389 }