1 /*
2   LibRCC - module handling XML configuration
3 
4   Copyright (C) 2005-2008 Suren A. Chilingaryan <csa@dside.dyndns.org>
5 
6   This library is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License version 2.1 or later
8   as published by the Free Software Foundation.
9 
10   This library is distributed in the hope that it will be useful, but WITHOUT
11   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
13   for more details.
14 
15   You should have received a copy of the GNU Lesser General Public License
16   along with this program; if not, write to the Free Software Foundation, Inc.,
17   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <errno.h>
23 
24 #include <string.h>
25 #ifdef HAVE_STRINGS_H
26 # include <strings.h>
27 #endif /* HAVE_STRINGS_H */
28 
29 #include "../config.h"
30 
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif /* HAVE_UNISTD_H */
34 
35 #ifdef HAVE_FCNTL_H
36 # include <fcntl.h>
37 #endif /* HAVE_FCNTL_H */
38 
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
41 #endif /* HAVE_SYS_TYPES_H */
42 
43 #ifdef HAVE_SYS_STAT_H
44 # include <sys/stat.h>
45 #endif /* HAVE_SYS_STAT_H */
46 
47 #ifdef HAVE_SYS_FILE_H
48 # include <sys/file.h>
49 #endif /* HAVE_SYS_FILE_H */
50 
51 #include <libxml/parser.h>
52 #include <libxml/tree.h>
53 #include <libxml/xpath.h>
54 
55 #include "internal.h"
56 #include "rccconfig.h"
57 #include "plugin.h"
58 #include "rcchome.h"
59 
60 #define MAX_HOME_CHARS 96
61 #define XPATH_LANGUAGE "//Language[@name]"
62 
63 static xmlDocPtr xmlctx = NULL;
64 
rccGetConfiguration()65 rcc_config rccGetConfiguration() {
66     return (rcc_config)xmlctx;
67 }
68 
rccXmlGetText(xmlNodePtr node)69 static const char *rccXmlGetText(xmlNodePtr node) {
70     if ((node)&&(node->children)&&(node->children->type == XML_TEXT_NODE)&&(node->children->content)) return (const char*)node->children->content;
71     return NULL;
72 }
73 
rccXmlInit(int LoadConfiguration)74 int rccXmlInit(int LoadConfiguration) {
75     FILE *f;
76     char config[MAX_HOME_CHARS + 32];
77 
78     xmlXPathContextPtr xpathctx = NULL;
79     xmlXPathObjectPtr obj = NULL;
80     xmlNodeSetPtr node_set;
81     unsigned long i, nnodes;
82     xmlNodePtr enode, cnode, pnode, node;
83     xmlAttrPtr attr;
84     const char *lang, *engine_name;
85     unsigned int pos, lpos, epos, cpos;
86     const char *alias, *parent;
87     unsigned int j, apos, rpos;
88 
89     rcc_engine *engine;
90 
91     xmlInitParser();
92     xmlInitCharEncodingHandlers();
93     xmlKeepBlanksDefault(0);
94 
95     if (LoadConfiguration) {
96 	if (strlen(rcc_home_dir)>MAX_HOME_CHARS) config[0] = 0;
97 	else {
98 	    sprintf(config, "%s/.rcc/rcc.xml", rcc_home_dir);
99 	    f = fopen(config, "r");
100 	    if (f) fclose(f);
101 	    else config[0] = 0;
102 	}
103 	if (!config[0]) {
104 	    strcpy(config, "/etc/rcc.xml");
105 	    f = fopen(config, "r");
106     	    if (f) fclose(f);
107 	    else config[0] = 0;
108 	}
109     } else config[0] = 0;
110 
111 
112     for (apos=0;rcc_default_aliases[apos].alias;apos++);
113 
114 	// Load Extra Languages
115     if (config[0]) {
116 	xmlctx = xmlReadFile(config, NULL, 0);
117 	if (!xmlctx) goto clear;
118 
119 	xpathctx = xmlXPathNewContext(xmlctx);
120 	if (!xpathctx) goto clear;
121 
122 	obj = xmlXPathEvalExpression((xmlChar*)XPATH_LANGUAGE, xpathctx);
123 	if (!obj) goto clear;
124 
125 	node_set = obj->nodesetval;
126 	if (!node_set) goto clear;
127 
128 	for (lpos = 0; rcc_default_languages[lpos].sn; lpos++);
129 
130 	nnodes = node_set->nodeNr;
131         for (i=0;i<nnodes;i++) {
132 	    pnode = node_set->nodeTab[i];
133 	    attr = xmlHasProp(pnode, (xmlChar*)"name");
134 	    lang = (const char*)attr->children->content;
135 
136 	    if ((!lang)||(!lang[0])) continue;
137 
138 	    pos = rccDefaultGetLanguageByName(lang);
139 	    if (!pos) continue;
140 	    if (pos == (rcc_language_id)-1) {
141 		for (rpos=0;rcc_default_relations[rpos].lang;rpos++);
142 		if (rpos < RCC_MAX_RELATIONS) {
143 			rcc_default_relations[rpos].parent = rcc_english_language_sn;
144 			rcc_default_relations[rpos++].lang = lang;
145 			rcc_default_relations[rpos].parent = NULL;
146 			rcc_default_relations[rpos].lang = NULL;
147 		}
148 
149 		pos = lpos;
150 	    }
151 	    else if (pos == RCC_MAX_LANGUAGES) continue;
152 
153 	    for (epos = 1, cpos = 1,node=pnode->children;node;node=node->next) {
154 	    	if (node->type != XML_ELEMENT_NODE) continue;
155 		if (!xmlStrcmp(node->name, (xmlChar*)"Charsets")) {
156 		    for (cnode=node->children;cnode;cnode=cnode->next) {
157 			if (cnode->type != XML_ELEMENT_NODE) continue;
158 			if ((!xmlStrcmp(cnode->name, (xmlChar*)"Charset"))&&(rccXmlGetText(cnode))&&(cpos<RCC_MAX_CHARSETS)) {
159 			        rcc_default_languages[pos].charsets[cpos++] = rccXmlGetText(cnode);
160 			}
161 		    }
162 		}
163 		else if (!xmlStrcmp(node->name, (xmlChar*)"Engines")) {
164 		    for (enode=node->children;enode;enode=enode->next) {
165 			if (enode->type != XML_ELEMENT_NODE) continue;
166 			if ((!xmlStrcmp(enode->name, (xmlChar*)"Engine"))&&(epos<RCC_MAX_ENGINES)) {
167 				engine_name = rccXmlGetText(enode);
168 				if (!engine_name) continue;
169 				engine = rccPluginEngineGetInfo(engine_name, lang);
170 				if (!engine) continue;
171 
172 				rcc_default_languages[pos].engines[epos++] = engine;
173 			}
174 		    }
175 		}
176 		else if (!xmlStrcmp(node->name, (xmlChar*)"Aliases")) {
177 		    for (enode=node->children;enode;enode=enode->next) {
178 			if (enode->type != XML_ELEMENT_NODE) continue;
179 			if ((!xmlStrcmp(enode->name, (xmlChar*)"Alias"))&&(apos<RCC_MAX_ALIASES)) {
180 			    alias = rccXmlGetText(enode);
181 			    if (!alias) continue;
182 			    for (j=0;j<apos;j++)
183 				if (!strcasecmp(alias, rcc_default_aliases[j].alias)) break;
184 			    if (j<apos) {
185 				rcc_default_aliases[j].lang = lang;
186 			    } else {
187 				rcc_default_aliases[apos].alias = alias;
188 				rcc_default_aliases[apos++].lang = lang;
189 				rcc_default_aliases[apos].alias = NULL;
190 				rcc_default_aliases[apos].lang = NULL;
191 			    }
192 			}
193 		    }
194 		}
195 		else if (!xmlStrcmp(node->name, (xmlChar*)"Relations")) {
196 		    rpos = rccDefaultDropLanguageRelations(lang);
197 		    for (enode=node->children;enode;enode=enode->next) {
198 			if (enode->type != XML_ELEMENT_NODE) continue;
199 			if ((!xmlStrcmp(enode->name, (xmlChar*)"Parrent"))&&(rpos<RCC_MAX_RELATIONS)) {
200 			    parent = rccXmlGetText(enode);
201 			    if (!parent) continue;
202 			    rcc_default_relations[rpos].parent = parent;
203 			    rcc_default_relations[rpos++].lang = lang;
204 			    rcc_default_relations[rpos].parent = NULL;
205 			    rcc_default_relations[rpos].lang = NULL;
206 			}
207 		    }
208 		}
209 	    }
210 
211 	    if ((cpos > 1)||(epos > 1)) {
212 		rcc_default_languages[pos].sn = lang;
213 	        rcc_default_languages[pos].charsets[0] = rcc_default_charset;
214 		if (cpos > 1) rcc_default_languages[pos].charsets[cpos] = NULL;
215 		else {
216 		    rcc_default_languages[pos].charsets[1] = rcc_utf8_charset;
217 		    rcc_default_languages[pos].charsets[2] = NULL;
218 		}
219 		rcc_default_languages[pos].engines[0] = &rcc_default_engine;
220 		rcc_default_languages[pos].engines[epos] = NULL;
221 
222 		if (pos == lpos) rcc_default_languages[++lpos].sn = NULL;
223 	    }
224 	}
225 
226 clear:
227 	if (xmlctx) {
228 	    if (xpathctx) {
229 		xmlXPathFreeContext(xpathctx);
230 		if (obj) {
231 		    xmlXPathFreeObject(obj);
232 		}
233 	    }
234 	}
235     }
236 
237     return 0;
238 }
239 
rccXmlFree()240 void rccXmlFree() {
241     if (xmlctx) {
242 	xmlFreeDoc(xmlctx);
243 	xmlctx = NULL;
244     }
245 
246     xmlCleanupCharEncodingHandlers();
247     xmlCleanupParser();
248 }
249 
250 
rccNodeFind(xmlXPathContextPtr xpathctx,const char * request,...)251 static xmlNodePtr rccNodeFind(xmlXPathContextPtr xpathctx, const char *request, ...) {
252     xmlXPathObjectPtr obj;
253     xmlNodeSetPtr node_set;
254     xmlNodePtr res = NULL;
255 
256     unsigned int i, args = 0;
257     unsigned int size = 64;
258     va_list ap;
259     char *req;
260 
261     if (!xpathctx) return NULL;
262 
263     for (req = strstr(request, "%s"); req; req = strstr(req + 1, "%s")) args++;
264 
265     if (args) {
266 	va_start(ap, request);
267 	for (i=0;i<args;i++) {
268 	    req = va_arg(ap, char*);
269 	    size += strlen(req);
270 	}
271 	va_end(ap);
272 
273 	req = (char*)malloc(size*sizeof(char));
274 	if (!req) return NULL;
275 
276 	va_start(ap, request);
277 	vsprintf(req,request,ap);
278 	va_end(ap);
279     } else req = (char*)request;
280 
281     obj = xmlXPathEvalExpression((xmlChar*)req, xpathctx);
282     if (obj) {
283 	node_set = obj->nodesetval;
284 	if ((node_set)&&(node_set->nodeNr > 0)) {
285 	    res = node_set->nodeTab[0];
286 	}
287 	xmlXPathFreeObject(obj);
288     }
289 
290     if (args) free(req);
291 
292     return res;
293 }
294 
295 #define XPATH_SELECTED "/Config"
296 #define XPATH_SELECTED_LANGUAGE "/Config/Language"
297 #define XPATH_SELECTED_OPTIONS "/Config/Options"
298 #define XPATH_SELECTED_OPTION "/Config/Options/Option[@name=\"%s\"]"
299 
300 #define XPATH_SELECTED_LANGS "/Config/Languages"
301 #define XPATH_SELECTED_LANG "/Config/Languages/Language[@name=\"%s\"]"
302 #define XPATH_SELECTED_ENGINE "/Config/Languages/Language[@name=\"%s\"]/Engine"
303 #define XPATH_SELECTED_CLASSES "/Config/Languages/Language[@name=\"%s\"]/Classes"
304 #define XPATH_SELECTED_CLASS "/Config/Languages/Language[@name=\"%s\"]/Classes/Class[@name=\"%s\"]"
305 
rccSave(rcc_context ctx,const char * name)306 int rccSave(rcc_context ctx, const char *name) {
307     int fd;
308     char *config;
309     struct stat st;
310 
311     unsigned int i, j, size;
312 
313     rcc_language_ptr *languages;
314     rcc_language_ptr language;
315     rcc_language_config cfg;
316     rcc_class_ptr *classes;
317     rcc_class_ptr cl;
318 
319     xmlXPathContextPtr xpathctx = NULL;
320     xmlDocPtr doc = NULL;
321     xmlNodePtr pnode, lnode, onode, llnode, cnode, enode, node;
322     unsigned char oflag = 0, llflag = 0, cflag;
323     rcc_option_description *odesc;
324     rcc_option_value ovalue;
325     const char *oname, *ovname;
326     char value[16];
327 
328     int memsize;
329     xmlChar *mem;
330 
331     if (!ctx) {
332 	if (rcc_default_ctx) ctx = rcc_default_ctx;
333 	else return -1;
334     }
335 
336     if ((!name)||(!strcmp(name, "rcc"))||(strlen(rcc_home_dir)<3)) name = "default";
337 
338     size = strlen(rcc_home_dir) + strlen(name) + 32;
339     config = (char*)malloc(size*sizeof(char));
340     if (!config) return -1;
341 
342     sprintf(config,"%s/.rcc/",rcc_home_dir);
343     mkdir(config, 00755);
344 
345     sprintf(config,"%s/.rcc/%s.xml",rcc_home_dir,name);
346     fd = open(config, O_CREAT|O_RDWR,00644);
347     if (fd == -1) goto clear;
348 
349 #if defined(HAVE_FLOCK)
350     flock(fd, LOCK_EX);
351 #elif defined(HAVE_LOCKF)
352     lockf(fd, F_LOCK, 1);
353 #endif
354 
355     if ((!fstat(fd, &st))&&(st.st_size)) {
356 	doc = xmlReadFd(fd, config, NULL, 0);
357     }
358 
359     if (!doc) {
360 	doc = xmlNewDoc((xmlChar*)"1.0");
361 	if (!doc) goto clear;
362 	pnode = NULL;
363     } else {
364 	xpathctx = xmlXPathNewContext(doc);
365 	pnode = rccNodeFind(xpathctx, XPATH_SELECTED);
366     }
367 
368     if (pnode) {
369 	lnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANGUAGE);
370 	onode = rccNodeFind(xpathctx, XPATH_SELECTED_OPTIONS);
371 	llnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANGS);
372     } else {
373 	pnode = xmlNewChild((xmlNodePtr)doc, NULL, (xmlChar*)"Config", NULL);
374 	lnode = NULL;
375 	onode = NULL;
376 	llnode = NULL;
377     }
378 
379     if (lnode) xmlNodeSetContent(lnode, (xmlChar*)rccGetSelectedLanguageName(ctx));
380     else lnode = xmlNewChild(pnode,NULL, (xmlChar*)"Language", (xmlChar*)rccGetSelectedLanguageName(ctx));
381 
382     if (onode) oflag = 1;
383     else onode = xmlNewChild(pnode, NULL, (xmlChar*)"Options", NULL);
384 
385     for (i=0;i<RCC_MAX_OPTIONS;i++) {
386 	odesc = rccGetOptionDescription(i);
387 	if (!odesc) continue;
388 
389 	oname = rccOptionDescriptionGetName(odesc);
390 	if (!oname) continue;
391 
392 
393 	if (oflag) node = rccNodeFind(xpathctx, XPATH_SELECTED_OPTION, oname);
394 	else node = NULL;
395 
396 	if (rccOptionIsDefault(ctx, (rcc_option)i)) strcpy(value, rcc_option_nonconfigured);
397 	else {
398 	    ovalue = rccGetOption(ctx, (rcc_option)i);
399 	    ovname = rccOptionDescriptionGetValueName(odesc, ovalue);
400 	    if (ovname) strcpy(value, ovname);
401 	    else sprintf(value, "%i", ovalue);
402 	}
403 
404 	if (node) xmlNodeSetContent(node, (xmlChar*)value);
405 	else {
406 	    node = xmlNewChild(onode, NULL, (xmlChar*)"Option", (xmlChar*)value);
407 	    xmlSetProp(node, (xmlChar*)"name", (xmlChar*)oname);
408 	}
409     }
410 
411     if (llnode) llflag = 1;
412     else llnode = xmlNewChild(pnode, NULL, (xmlChar*)"Languages", NULL);
413 
414     languages = ctx->languages;
415     classes = ctx->classes;
416     for (i=1;languages[i];i++) {
417 	language = languages[i];
418 	cfg = rccCheckConfig(ctx, (rcc_language_id)i);
419 	if ((!cfg)||(!cfg->configured)) continue;
420 
421 	if (llflag) lnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANG, language->sn);
422 	else lnode = NULL;
423 
424 	if (lnode) {
425 	    enode = rccNodeFind(xpathctx, XPATH_SELECTED_ENGINE, language->sn);
426 	    cnode = rccNodeFind(xpathctx, XPATH_SELECTED_CLASSES, language->sn);
427 	} else {
428 	    lnode = xmlNewChild(llnode, NULL, (xmlChar*)"Language", NULL);
429 	    xmlSetProp(lnode, (xmlChar*)"name", (xmlChar*)language->sn);
430 	    enode = NULL;
431 	    cnode = NULL;
432 	}
433 
434 	if (enode) xmlNodeSetContent(enode, (xmlChar*)rccConfigGetSelectedEngineName(cfg));
435 	else xmlNewChild(lnode, NULL, (xmlChar*)"Engine", (xmlChar*)rccConfigGetSelectedEngineName(cfg));
436 
437 	if (cnode) cflag = 1;
438 	else {
439 	    cnode = xmlNewChild(lnode, NULL, (xmlChar*)"Classes", NULL);
440 	    cflag = 0;
441 	}
442 
443 	for (j=0;classes[j];j++) {
444 	    cl = classes[j];
445 	    if (cl->flags&RCC_CLASS_FLAG_SKIP_SAVELOAD) continue;
446 
447 	    if (cflag) node = rccNodeFind(xpathctx, XPATH_SELECTED_CLASS, language->sn, cl->name);
448 	    else node = NULL;
449 
450 	    if (node) xmlNodeSetContent(node, (xmlChar*)rccConfigGetSelectedCharsetName(cfg, (rcc_class_id)j));
451 	    else {
452 		node = xmlNewChild(cnode, NULL, (xmlChar*)"Class", (xmlChar*)rccConfigGetSelectedCharsetName(cfg, (rcc_class_id)j));
453 		xmlSetProp(node, (xmlChar*)"name", (xmlChar*)cl->name);
454 	    }
455 	}
456     }
457 
458     xmlDocDumpFormatMemory(doc,&mem,&memsize,1);
459 
460     if (ftruncate(fd, 0) < 0)
461         goto clear;
462 
463     if (lseek(fd, SEEK_SET, 0))
464         goto clear;
465 
466     if (mem) {
467         ssize_t ret = write(fd, mem, memsize);
468             // Retry once on signals
469         if ((ret < 0)&&(errno = EINTR))
470             ret = write(fd, mem, memsize);
471 	free(mem);
472     }
473 
474 clear:
475     if (config) {
476 	if (fd != -1) {
477 	    if (doc) {
478 		if (xpathctx) {
479 		    xmlXPathFreeContext(xpathctx);
480 		}
481 		xmlFreeDoc(doc);
482 	    }
483 
484 #ifdef HAVE_FSYNC
485 	    fsync(fd);
486 #endif /* HAVE_FSYNC */
487 
488 #if defined(HAVE_FLOCK)
489     	    flock(fd, LOCK_UN);
490 #elif defined(HAVE_LOCKF)
491 	    lockf(fd, F_ULOCK, 1);
492 #endif
493 
494 	    close(fd);
495 	}
496 	free(config);
497     }
498 
499     return 0;
500 }
501 
rccLoad(rcc_context ctx,const char * name)502 int rccLoad(rcc_context ctx, const char *name) {
503     int err;
504 
505     int fd, sysfd;
506     char *config;
507     struct stat st;
508 
509     unsigned int i, j, size;
510     const char *tmp;
511 
512     rcc_option_description *odesc;
513     rcc_option_value ovalue;
514     const char *oname;
515 
516     rcc_language_config cfg;
517     rcc_language_ptr *languages;
518     rcc_language_ptr language;
519     rcc_class_ptr *classes;
520     rcc_class_ptr cl;
521 
522     xmlXPathContextPtr xpathctx = NULL, sysxpathctx = NULL, curxpathctx;
523     xmlDocPtr doc = NULL, sysdoc = NULL;
524     xmlNodePtr node, lnode;
525 
526     if (!ctx) {
527 	if (rcc_default_ctx) ctx = rcc_default_ctx;
528 	else return -1;
529     }
530 
531     if ((!name)||(!strcmp(name, "rcc"))||(strlen(rcc_home_dir)<3)) name = "default";
532 
533     size = strlen(rcc_home_dir) + strlen(name) + 32;
534     config = (char*)malloc(size*sizeof(char));
535     if (!config) return -1;
536 
537     sprintf(config,"%s/.rcc/%s.xml",rcc_home_dir,name);
538     fd = open(config, O_RDONLY);
539 
540     sprintf(config, "/etc/rcc/%s.xml",name);
541     sysfd = open(config, O_RDONLY);
542 
543     free(config);
544 
545     if (fd != -1) {
546 #if defined(HAVE_FLOCK)
547 	flock(fd, LOCK_EX);
548 #elif defined(HAVE_LOCKF)
549 	lockf(fd, F_LOCK, 1);
550 #endif
551 
552 	if ((!fstat(fd, &st))&&(st.st_size)) {
553 	    doc = xmlReadFd(fd, name, NULL, 0);
554 	}
555 
556 #if defined(HAVE_FLOCK)
557 	flock(fd, LOCK_UN);
558 #elif defined(HAVE_LOCKF)
559 	lockf(fd, F_ULOCK, 1);
560 #endif
561 
562 	close(fd);
563 
564 	if (doc) {
565 	    xpathctx = xmlXPathNewContext(doc);
566 	    if (!xpathctx) {
567 		xmlFreeDoc(doc);
568 		doc = NULL;
569 	    }
570 	}
571     }
572 
573     if (sysfd != -1) {
574 #if defined(HAVE_FLOCK)
575 	flock(sysfd, LOCK_EX);
576 #elif defined(HAVE_LOCKF)
577 	lockf(sysfd, F_LOCK, 1);
578 #endif
579 
580 	if ((!fstat(sysfd, &st))&&(st.st_size)) {
581 	    sysdoc = xmlReadFd(sysfd, name, NULL, 0);
582 	}
583 
584 #if defined(HAVE_FLOCK)
585 	flock(sysfd, LOCK_UN);
586 #elif defined(HAVE_LOCKF)
587 	lockf(sysfd, F_ULOCK, 1);
588 #endif
589 
590 	close(sysfd);
591 
592 	if (sysdoc) {
593 	    sysxpathctx = xmlXPathNewContext(sysdoc);
594 	    if (!sysxpathctx) {
595 		xmlFreeDoc(sysdoc);
596 		sysdoc = NULL;
597 	    }
598 	}
599     }
600 
601     if ((!doc)&&(!sysdoc)) goto clear;
602 
603     node = rccNodeFind(xpathctx, XPATH_SELECTED_LANGUAGE);
604     if (!node) node = rccNodeFind(sysxpathctx, XPATH_SELECTED_LANGUAGE);
605     if (node) {
606 	tmp = rccXmlGetText(node);
607 	if (tmp) err = rccSetLanguageByName(ctx, tmp);
608 	else err = -1;
609     } else err = -1;
610     if (err) rccSetLanguage(ctx, 0);
611 
612     for (i=0;i<RCC_MAX_OPTIONS;i++) {
613 	odesc = rccGetOptionDescription(i);
614 	if (!odesc) continue;
615 
616 	oname = rccOptionDescriptionGetName(odesc);
617 	if (!oname) continue;
618 
619 	node = rccNodeFind(xpathctx, XPATH_SELECTED_OPTION, oname);
620 	if (!node) node = rccNodeFind(sysxpathctx, XPATH_SELECTED_OPTION, oname);
621 	if (node) {
622 	    tmp = rccXmlGetText(node);
623 	    if ((tmp)&&(strcasecmp(tmp,rcc_option_nonconfigured))) {
624 		ovalue = rccOptionDescriptionGetValueByName(odesc, tmp);
625 		if (ovalue == (rcc_option_value)-1) ovalue = (rcc_option_value)atoi(tmp);
626 		 err = rccSetOption(ctx, (rcc_option)i, ovalue);
627 	    } else err = -1;
628 	} else err = -1;
629 	if (err) rccOptionSetDefault(ctx, (rcc_option)i);
630     }
631 
632 
633     languages = ctx->languages;
634     classes = ctx->classes;
635     for (i=1;languages[i];i++) {
636 	language = languages[i];
637 
638 	lnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANG, language->sn);
639 	if (lnode) curxpathctx = xpathctx;
640 	else {
641 	    lnode = rccNodeFind(sysxpathctx, XPATH_SELECTED_LANG, language->sn);
642 	    if (lnode) curxpathctx = sysxpathctx;
643 	    else continue;
644 	}
645 
646 	cfg = rccGetConfig(ctx, (rcc_language_id)i);
647 	if (!cfg) continue;
648 
649 	node = rccNodeFind(curxpathctx, XPATH_SELECTED_ENGINE, language->sn);
650 	if (node) {
651 	    tmp = rccXmlGetText(node);
652 	    if (tmp) err = rccConfigSetEngineByName(cfg, tmp);
653 	    else err = -1;
654 	} else err = -1;
655 	if (err) rccConfigSetEngineByName(cfg, NULL);
656 
657 	for (j=0;classes[j];j++) {
658 	    cl = classes[j];
659 	    if (cl->flags&RCC_CLASS_FLAG_SKIP_SAVELOAD) continue;
660 
661 	    node = rccNodeFind(curxpathctx, XPATH_SELECTED_CLASS, language->sn, cl->name);
662 	    if (node) {
663 		tmp = rccXmlGetText(node);
664 		if (tmp) err = rccConfigSetCharsetByName(cfg, (rcc_class_id)j, tmp);
665 		else err = -1;
666 	    } else err = -1;
667 	    if (err) rccConfigSetCharset(cfg, (rcc_class_id)j, 0);
668 	}
669     }
670 
671 clear:
672 
673     if (sysdoc) {
674 	if (sysxpathctx) {
675 	    xmlXPathFreeContext(sysxpathctx);
676 	}
677 	xmlFreeDoc(sysdoc);
678     }
679     if (doc) {
680 	if (xpathctx) {
681 	    xmlXPathFreeContext(xpathctx);
682 	}
683 	xmlFreeDoc(doc);
684     }
685 
686     if ((!ctx->current_language)&&(rccGetOption(ctx, RCC_OPTION_CONFIGURED_LANGUAGES_ONLY))) {
687 	ctx->current_config = rccGetCurrentConfig(ctx);
688     	ctx->configure = 1;
689     }
690 
691     return 0;
692 }
693