jabberd2
2.2.16
|
00001 /* 00002 * jabberd - Jabber Open Source Server 00003 * Copyright (c) 2002 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 #include "util.h" 00022 #include "expat.h" 00023 00025 config_t config_new(void) 00026 { 00027 config_t c; 00028 00029 c = (config_t) calloc(1, sizeof(struct config_st)); 00030 00031 c->hash = xhash_new(501); 00032 00033 return c; 00034 } 00035 00036 struct build_data 00037 { 00038 nad_t nad; 00039 int depth; 00040 }; 00041 00042 static void _config_startElement(void *arg, const char *name, const char **atts) 00043 { 00044 struct build_data *bd = (struct build_data *) arg; 00045 int i = 0; 00046 00047 nad_append_elem(bd->nad, -1, (char *) name, bd->depth); 00048 while(atts[i] != NULL) 00049 { 00050 nad_append_attr(bd->nad, -1, (char *) atts[i], (char *) atts[i + 1]); 00051 i += 2; 00052 } 00053 00054 bd->depth++; 00055 } 00056 00057 static void _config_endElement(void *arg, const char *name) 00058 { 00059 struct build_data *bd = (struct build_data *) arg; 00060 00061 bd->depth--; 00062 } 00063 00064 static void _config_charData(void *arg, const char *str, int len) 00065 { 00066 struct build_data *bd = (struct build_data *) arg; 00067 00068 nad_append_cdata(bd->nad, (char *) str, len, bd->depth); 00069 } 00070 00071 static char *_config_expandx(config_t c, const char *value, int l); 00072 00074 int config_load(config_t c, const char *file) 00075 { 00076 return config_load_with_id(c, file, 0); 00077 } 00078 00080 int config_load_with_id(config_t c, const char *file, const char *id) 00081 { 00082 struct build_data bd; 00083 FILE *f; 00084 XML_Parser p; 00085 int done, len, end, i, j, attr; 00086 char buf[1024], *next; 00087 struct nad_elem_st **path; 00088 config_elem_t elem; 00089 int rv = 0; 00090 00091 /* open the file */ 00092 f = fopen(file, "r"); 00093 if(f == NULL) 00094 { 00095 fprintf(stderr, "config_load: couldn't open %s for reading: %s\n", file, strerror(errno)); 00096 return 1; 00097 } 00098 00099 /* new parser */ 00100 p = XML_ParserCreate(NULL); 00101 if(p == NULL) 00102 { 00103 fprintf(stderr, "config_load: couldn't allocate XML parser\n"); 00104 fclose(f); 00105 return 1; 00106 } 00107 00108 /* nice new nad to parse it into */ 00109 bd.nad = nad_new(); 00110 bd.depth = 0; 00111 00112 /* setup the parser */ 00113 XML_SetUserData(p, (void *) &bd); 00114 XML_SetElementHandler(p, _config_startElement, _config_endElement); 00115 XML_SetCharacterDataHandler(p, _config_charData); 00116 00117 for(;;) 00118 { 00119 /* read that file */ 00120 len = fread(buf, 1, 1024, f); 00121 if(ferror(f)) 00122 { 00123 fprintf(stderr, "config_load: read error: %s\n", strerror(errno)); 00124 XML_ParserFree(p); 00125 fclose(f); 00126 nad_free(bd.nad); 00127 return 1; 00128 } 00129 done = feof(f); 00130 00131 /* parse it */ 00132 if(!XML_Parse(p, buf, len, done)) 00133 { 00134 fprintf(stderr, "config_load: parse error at line %llu: %s\n", (unsigned long long) XML_GetCurrentLineNumber(p), XML_ErrorString(XML_GetErrorCode(p))); 00135 XML_ParserFree(p); 00136 fclose(f); 00137 nad_free(bd.nad); 00138 return 1; 00139 } 00140 00141 if(done) 00142 break; 00143 } 00144 00145 /* done reading */ 00146 XML_ParserFree(p); 00147 fclose(f); 00148 00149 // Put id if specified 00150 if (id) { 00151 elem = pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st)); 00152 xhash_put(c->hash, pstrdup(xhash_pool(c->hash), "id"), elem); 00153 elem->values = calloc(1, sizeof(char *)); 00154 elem->values[0] = pstrdup(xhash_pool(c->hash), id); 00155 elem->nvalues = 1; 00156 } 00157 00158 /* now, turn the nad into a config hash */ 00159 path = NULL; 00160 len = 0, end = 0; 00161 /* start at 1, so we skip the root element */ 00162 for(i = 1; i < bd.nad->ecur && rv == 0; i++) 00163 { 00164 /* make sure we have enough room to add this element to our path */ 00165 if(end <= bd.nad->elems[i].depth) 00166 { 00167 end = bd.nad->elems[i].depth + 1; 00168 path = (struct nad_elem_st **) realloc((void *) path, sizeof(struct nad_elem_st *) * end); 00169 } 00170 00171 /* save this path element */ 00172 path[bd.nad->elems[i].depth] = &bd.nad->elems[i]; 00173 len = bd.nad->elems[i].depth + 1; 00174 00175 /* construct the key from the current path */ 00176 next = buf; 00177 for(j = 1; j < len; j++) 00178 { 00179 strncpy(next, bd.nad->cdata + path[j]->iname, path[j]->lname); 00180 next = next + path[j]->lname; 00181 *next = '.'; 00182 next++; 00183 } 00184 next--; 00185 *next = '\0'; 00186 00187 /* find the config element for this key */ 00188 elem = xhash_get(c->hash, buf); 00189 if(elem == NULL) 00190 { 00191 /* haven't seen it before, so create it */ 00192 elem = pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st)); 00193 xhash_put(c->hash, pstrdup(xhash_pool(c->hash), buf), elem); 00194 } 00195 00196 /* make room for this value .. can't easily realloc off a pool, so 00197 * we do it this way and let _config_reaper clean up */ 00198 elem->values = realloc((void *) elem->values, sizeof(char *) * (elem->nvalues + 1)); 00199 00200 /* and copy it in */ 00201 if(NAD_CDATA_L(bd.nad, i) > 0) { 00202 // Expand values 00203 00204 const char *val = _config_expandx(c, NAD_CDATA(bd.nad, i), NAD_CDATA_L(bd.nad, i)); 00205 00206 if (!val) { 00207 rv = 1; 00208 break; 00209 } 00210 // Make a copy 00211 elem->values[elem->nvalues] = val; 00212 } else { 00213 elem->values[elem->nvalues] = "1"; 00214 } 00215 00216 /* make room for the attribute lists */ 00217 elem->attrs = realloc((void *) elem->attrs, sizeof(char **) * (elem->nvalues + 1)); 00218 elem->attrs[elem->nvalues] = NULL; 00219 00220 /* count the attributes */ 00221 for(attr = bd.nad->elems[i].attr, j = 0; attr >= 0; attr = bd.nad->attrs[attr].next, j++); 00222 00223 /* make space */ 00224 elem->attrs[elem->nvalues] = pmalloc(xhash_pool(c->hash), sizeof(char *) * (j * 2 + 2)); 00225 00226 /* if we have some */ 00227 if(j > 0) 00228 { 00229 /* copy them in */ 00230 j = 0; 00231 attr = bd.nad->elems[i].attr; 00232 while(attr >= 0) 00233 { 00234 elem->attrs[elem->nvalues][j] = pstrdupx(xhash_pool(c->hash), NAD_ANAME(bd.nad, attr), NAD_ANAME_L(bd.nad, attr)); 00235 elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr)); 00236 00237 /* 00238 * pstrdupx(blob, 0) returns NULL - which means that later 00239 * there's no way of telling whether an attribute is defined 00240 * as empty, or just not defined. This fixes that by creating 00241 * an empty string for attributes which are defined empty 00242 */ 00243 if (NAD_AVAL_L(bd.nad, attr)==0) { 00244 elem->attrs[elem->nvalues][j + 1] = pstrdup(xhash_pool(c->hash), ""); 00245 } else { 00246 elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr)); 00247 } 00248 j += 2; 00249 attr = bd.nad->attrs[attr].next; 00250 } 00251 } 00252 00253 /* do this and we can use j_attr */ 00254 elem->attrs[elem->nvalues][j] = NULL; 00255 elem->attrs[elem->nvalues][j + 1] = NULL; 00256 00257 elem->nvalues++; 00258 } 00259 00260 if(path != NULL) 00261 free(path); 00262 00263 if(c->nad != NULL) 00264 nad_free(c->nad); 00265 c->nad = bd.nad; 00266 00267 return rv; 00268 } 00269 00271 config_elem_t config_get(config_t c, const char *key) 00272 { 00273 return xhash_get(c->hash, key); 00274 } 00275 00277 const char *config_get_one(config_t c, const char* key, int num) 00278 { 00279 config_elem_t elem = xhash_get(c->hash, key); 00280 00281 if(elem == NULL) 00282 return NULL; 00283 00284 if(num >= elem->nvalues) 00285 return NULL; 00286 00287 return elem->values[num]; 00288 } 00289 00291 const char *config_get_one_default(config_t c, const char *key, int num, const char *default_value) 00292 { 00293 const char *rv = config_get_one(c, key, num); 00294 00295 if (!rv) 00296 rv = default_value; 00297 00298 return rv; 00299 }; 00300 00301 00303 int config_count(config_t c, const char *key) 00304 { 00305 config_elem_t elem = xhash_get(c->hash, key); 00306 00307 if(elem == NULL) 00308 return 0; 00309 00310 return elem->nvalues; 00311 } 00312 00314 char *config_get_attr(config_t c, const char *key, int num, const char *attr) 00315 { 00316 config_elem_t elem = xhash_get(c->hash, key); 00317 00318 if(num >= elem->nvalues || elem->attrs == NULL || elem->attrs[num] == NULL) 00319 return NULL; 00320 00321 return j_attr((const char **) elem->attrs[num], attr); 00322 } 00323 00325 static void _config_reaper(const char *key, int keylen, void *val, void *arg) 00326 { 00327 config_elem_t elem = (config_elem_t) val; 00328 00329 free(elem->values); 00330 free(elem->attrs); 00331 } 00332 00333 char *config_expand(config_t c, const char *value) 00334 { 00335 return _config_expandx(c, value, strlen(value)); 00336 } 00337 00338 static char *_config_expandx(config_t c, const char *value, int l) 00339 { 00340 #ifdef CONFIGEXPAND_GUARDED 00341 static char guard[] = "deadbeaf"; 00342 #endif 00343 00344 // fprintf(stderr, "config_expand: Expanding '%s'\n", value); 00345 char *s = strndup(value, l); 00346 00347 char *var_start, *var_end; 00348 00349 while (var_start = strstr(s, "${")) { 00350 // fprintf(stderr, "config_expand: processing '%s'\n", s); 00351 var_end = strstr(var_start + 2, "}"); 00352 00353 if (var_end) { 00354 char *tail = var_end + 1; 00355 char *var = var_start + 2; 00356 *var_end = 0; 00357 00358 // fprintf(stderr, "config_expand: Var '%s', tail is '%s'\n", var, tail); 00359 00360 const char *var_value = config_get_one(c, var, 0); 00361 00362 if (var_value) { 00363 int len = (var_start - s) + strlen(tail) + strlen(var_value) + 1; 00364 00365 #ifdef CONFIGEXPAND_GUARDED 00366 len += sizeof(guard); 00367 #endif 00368 char *expanded_str = calloc(len, 1); 00369 00370 #ifdef CONFIGEXPAND_GUARDED 00371 char *p_guard = expanded_str + len - sizeof(guard); 00372 strncpy(p_guard, guard, sizeof(guard)); 00373 #endif 00374 00375 char *p = expanded_str; 00376 strncpy(expanded_str, s, var_start - s); 00377 p += var_start - s; 00378 00379 strcpy(p, var_value); 00380 p += strlen(var_value); 00381 00382 strcpy(p, tail); 00383 00384 free(s); 00385 s = expanded_str; 00386 } else { 00387 fprintf(stderr, "config_expand: Have no '%s' defined\n", var); 00388 free(s); 00389 s = 0; 00390 break; 00391 } 00392 } else { 00393 fprintf(stderr, "config_expand: } missmatch\n"); 00394 free(s); 00395 s = 0; 00396 break; 00397 } 00398 } 00399 00400 if (s) { 00401 char *retval = pstrdup(xhash_pool(c->hash), s); 00402 free(s); 00403 return retval; 00404 } else { 00405 return 0; 00406 } 00407 } 00408 00410 void config_free(config_t c) 00411 { 00412 xhash_walk(c->hash, _config_reaper, NULL); 00413 00414 xhash_free(c->hash); 00415 00416 nad_free(c->nad); 00417 00418 free(c); 00419 }