Check the return value from pth_spawn().
[pwmd.git] / src / xml.c
blob264eed914c768e0ac844721b74b633a183c0e38c
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2009 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <ctype.h>
28 #include <glib.h>
29 #include <gcrypt.h>
30 #include <libxml/xmlwriter.h>
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
36 #include "pwmd_error.h"
37 #include "misc.h"
38 #include "xml.h"
40 void log_write(const gchar *fmt, ...);
41 static xmlNodePtr find_element(xmlNodePtr node, gchar *element, xmlNodePtr stop);
42 static xmlChar *node_has_attribute(xmlNodePtr n, xmlChar *attr);
45 * 'element' must be allocated.
47 gboolean is_literal_element(gchar **element)
49 gchar *p;
51 if (!element || !*element)
52 return FALSE;
54 if (*(*element) == '!') {
55 gchar *c;
57 for (p = *element, c = p+1; *c; c++)
58 *p++ = *c;
60 *p = 0;
61 return TRUE;
64 return FALSE;
68 * Fails if 'element' begins with punctuation or digit or contains whitespace.
70 * I'm not sure about using g_unichar_isspace() rather than isspace()?
72 gboolean valid_xml_element(xmlChar *element)
74 gunichar c;
75 glong len;
76 gchar *p = (gchar *)element;
78 if (!element || !*element)
79 return FALSE;
81 if (*p == '!')
82 p++;
84 len = g_utf8_strlen(p, -1) - 1;
85 c = g_utf8_get_char(p++);
87 if (g_unichar_ispunct(c) == TRUE || g_unichar_isdigit(c) == TRUE ||
88 g_unichar_isspace(c) == TRUE)
89 return FALSE;
91 while (*p && len--) {
92 c = g_utf8_get_char(p++);
94 if (g_unichar_isspace(c))
95 return FALSE;
98 return TRUE;
101 gboolean valid_element_path(gchar **path, gboolean has_value)
103 gchar **p;
105 for (p = path; *p; p++) {
107 * An empty element is valid and don't check the syntax of the
108 * content.
110 if (has_value == TRUE && (!*(p+1) || !*p[0]))
111 break;
113 if (valid_xml_element((xmlChar *)*p) == FALSE)
114 return FALSE;
117 return TRUE;
120 gpg_error_t new_account(xmlDocPtr doc, gchar *name)
122 xmlNodePtr root = xmlDocGetRootElement(doc);
123 xmlAttrPtr a;
124 xmlNodePtr n;
125 gchar *p = name;
127 if (!p || !root)
128 return EPWMD_LIBXML_ERROR;
130 if (*p == '!')
131 p++;
133 n = xmlNewNode(NULL, (xmlChar *)"root");
134 n = xmlAddChild(root, n);
135 a = xmlNewProp(n, (xmlChar *)"name", (xmlChar *)p);
136 return 0;
139 xmlDocPtr create_dtd(xmlDocPtr doc)
141 xmlNodePtr n = NULL;
142 xmlTextWriterPtr wr;
143 gboolean is_new = TRUE;
144 gboolean newnew = FALSE;
146 if (doc) {
147 n = xmlDocGetRootElement(doc);
148 is_new = FALSE;
151 if (n)
152 wr = xmlNewTextWriterTree(doc, n, 0);
153 else {
154 if (doc)
155 xmlFreeDoc(doc);
157 wr = xmlNewTextWriterDoc(&doc, 0);
158 is_new = TRUE;
159 newnew = TRUE;
162 if (!wr)
163 return NULL;
165 if (xmlTextWriterStartDTD(wr, (xmlChar *)"pwmd", NULL, NULL) == -1)
166 goto fail;
168 if (xmlTextWriterWriteDTDElement(wr, (xmlChar *)"pwmd",
169 (xmlChar *)"(root)") == -1)
170 goto fail;
172 xmlTextWriterEndDTDElement(wr);
174 if (xmlTextWriterWriteDTDAttlist(wr, (xmlChar *)"root",
175 (xmlChar *)"name CDATA #REQUIRED") == -1)
176 goto fail;
178 xmlTextWriterEndDTDAttlist(wr);
179 xmlTextWriterEndDTD(wr);
181 if (is_new) {
182 xmlTextWriterStartElement(wr, (xmlChar *)"pwmd");
183 xmlTextWriterEndElement(wr);
186 xmlTextWriterEndDocument(wr);
187 xmlFreeTextWriter(wr);
188 return doc;
190 fail:
191 xmlTextWriterEndDocument(wr);
192 xmlFreeTextWriter(wr);
194 if (newnew)
195 xmlFreeDoc(doc);
196 return NULL;
199 xmlChar *new_document()
201 xmlChar *xml;
202 gint len;
203 xmlDocPtr doc = create_dtd(NULL);
205 if (!doc)
206 return NULL;
208 xmlDocDumpMemory(doc, &xml, &len);
209 xmlFreeDoc(doc);
210 return xml;
214 * Lists root account element names. If there's a target attribute both
215 * literal and non-literal element names will be added.
217 gpg_error_t list_accounts(xmlDocPtr doc, GString **result)
219 xmlNodePtr n = NULL;
220 GSList *list = NULL;
221 gint total, i;
222 GString *string;
223 gpg_error_t rc = 0;
225 n = xmlDocGetRootElement(doc);
227 if (!n || !n->children)
228 return EPWMD_EMPTY_ELEMENT;
230 for (n = n->children; n; n = n->next) {
231 xmlAttrPtr a;
232 xmlChar *val, *target;
233 GSList *tlist;
234 gchar *tmp;
236 if (n->type != XML_ELEMENT_NODE)
237 continue;
239 a = xmlHasProp(n, (xmlChar *)"name");
241 if (!a || !a->children->content)
242 continue;
244 val = xmlNodeGetContent(a->children);
246 if (!val) {
247 rc = gpg_error_from_errno(ENOMEM);
248 goto fail;
251 tmp = g_strdup_printf("!%s", (gchar *)val);
253 if (!tmp) {
254 xmlFree(val);
255 rc = gpg_error_from_errno(ENOMEM);
256 goto fail;
259 tlist = g_slist_append(list, tmp);
261 if (!tlist) {
262 xmlFree(val);
263 rc = gpg_error_from_errno(ENOMEM);
264 goto fail;
267 list = tlist;
268 target = node_has_attribute(n, (xmlChar *)"target");
270 if (target) {
271 gchar *t = g_strdup((gchar *)val);
273 if (!t) {
274 xmlFree(val);
275 xmlFree(target);
276 rc = gpg_error_from_errno(ENOMEM);
277 goto fail;
280 tlist = g_slist_append(list, t);
282 if (!tlist) {
283 g_free(t);
284 xmlFree(target);
285 rc = gpg_error_from_errno(ENOMEM);
286 goto fail;
289 list = tlist;
292 xmlFree(val);
293 xmlFree(target);
296 total = g_slist_length(list);
298 if (!total)
299 return EPWMD_EMPTY_ELEMENT;
301 string = g_string_new(NULL);
303 if (!string) {
304 rc = gpg_error_from_errno(ENOMEM);
305 goto fail;
308 for (i = 0; i < total; i++) {
309 gchar *val = g_slist_nth_data(list, i);
311 g_string_append_printf(string, "%s\n", val);
314 string = g_string_truncate(string, string->len - 1);
315 *result = string;
317 fail:
318 total = g_slist_length(list);
320 for (i = 0; i < total; i++)
321 g_free(g_slist_nth_data(list, i));
323 g_slist_free(list);
324 return rc;
327 // FIXME return a gboolean in case of memory allocation failure
328 gchar **split_input_line(gchar *str, gchar *delim, gint n)
330 if (!str || !*str)
331 return NULL;
333 return g_strsplit(str, delim, n);
337 * Prevents a sibling element past the current element path with the same
338 * element name.
340 static xmlNodePtr find_stop_node(xmlNodePtr node)
342 xmlNodePtr n;
344 for (n = node->parent->children; n; n = n->next) {
345 if (n == node)
346 return n->next;
349 return NULL;
353 * Alot like create_elements_cb() but doesn't use the last element of 'req' as
354 * content but as an element.
356 xmlNodePtr create_target_elements_cb(xmlNodePtr node, gchar **path,
357 gpg_error_t *rc, void *data)
359 gint i;
360 char **req = path;
362 if (xmlStrEqual(node->name, (xmlChar *)*req))
363 req++;
365 for (i = 0; req[i]; i++) {
366 xmlNodePtr n;
368 if ((n = find_element(node, req[i], find_stop_node(node))) == NULL ||
369 (n && n->parent == node->parent)) {
370 is_literal_element(&req[i]);
371 n = xmlNewNode(NULL, (xmlChar *)req[i]);
373 if (!n) {
374 *rc = gpg_error_from_errno(ENOMEM);
375 return NULL;
378 node = xmlAddChild(node, n);
380 if (!node) {
381 *rc = gpg_error_from_errno(ENOMEM);
382 return NULL;
385 else
386 node = n;
389 return node;
392 xmlNodePtr find_text_node(xmlNodePtr node)
394 xmlNodePtr n = node;
396 if (n && n->type == XML_TEXT_NODE)
397 return n;
399 for (n = node; n; n = n->next) {
400 if (n->type == XML_TEXT_NODE)
401 return n;
404 return NULL;
407 xmlNodePtr create_elements_cb(xmlNodePtr node, gchar **elements,
408 gpg_error_t *rc, void *data)
410 gint i;
411 gchar **req = elements;
413 if (node->type == XML_TEXT_NODE)
414 node = node->parent;
416 if (node->name && xmlStrEqual(node->name, (xmlChar *)*req))
417 req++;
419 for (i = 0; req[i]; i++) {
420 xmlNodePtr n;
422 if (req[i+1]) {
424 * Strip the first '!' if needed. If there's another, it's an
425 * rc. The syntax has already been checked before calling this
426 * function.
428 is_literal_element(&req[i]);
432 * The value of the element tree.
434 if (!req[i+1]) {
435 n = find_text_node(node->children);
437 if (!n)
438 /* Use AddContent here to prevent overwriting any children. */
439 xmlNodeAddContent(node, (xmlChar *)req[i]);
440 else if (n && !*req[i])
441 xmlNodeSetContent(n, NULL);
442 else
443 xmlNodeSetContent(n, (xmlChar *)req[i]);
445 break;
448 n = find_element(node, req[i], find_stop_node(node));
451 * If the found element has the same parent as the current element,
452 * they are siblings and the new element needs to be created as a
453 * child of the current element (node).
455 if (n && n->parent == node->parent)
456 n = NULL;
458 if (!n) {
459 n = xmlNewNode(NULL, (xmlChar *)req[i]);
461 if (!n) {
462 *rc = gpg_error_from_errno(ENOMEM);
463 return NULL;
466 node = xmlAddChild(node, n);
468 if (!node) {
469 *rc = gpg_error_from_errno(ENOMEM);
470 return NULL;
473 else
474 node = n;
477 return node;
480 xmlNodePtr find_account(xmlDocPtr doc, gchar ***req, gpg_error_t *rc,
481 gboolean *target, gint recursion_depth)
483 xmlNodePtr n = xmlDocGetRootElement(doc);
484 gint depth = 0;
485 gchar *account = g_strdup(*req[0]);
486 gboolean literal = is_literal_element(&account);
488 if (!account) {
489 *rc = gpg_error_from_errno(ENOMEM);
490 return NULL;
493 *rc = 0;
494 recursion_depth++;
496 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth) {
497 xmlChar *t = xmlGetNodePath(n);
499 log_write("%s: %s", pwmd_strerror(EPWMD_LOOP), t);
500 xmlFree(t);
501 *rc = EPWMD_LOOP;
502 return NULL;
505 while (n) {
506 if (n->type == XML_ELEMENT_NODE) {
507 if (depth == 0 && xmlStrEqual(n->name, (xmlChar *)"pwmd")) {
508 n = n->children;
509 depth++;
510 continue;
513 if (depth == 1 && xmlStrEqual(n->name, (xmlChar *)"root")) {
514 xmlChar *content = node_has_attribute(n, (xmlChar *)"name");
516 if (!content)
517 continue;
519 if (xmlStrEqual(content, (xmlChar *)account)) {
520 gchar **nreq, **tmp = NULL;
522 if (literal == TRUE) {
523 xmlFree(content);
524 g_free(account);
525 return n;
528 xmlFree(content);
529 content = node_has_attribute(n, (xmlChar *)"target");
531 if (!content) {
532 g_free(account);
533 return n;
536 if (strchr((gchar *)content, '\t')) {
537 nreq = split_input_line((gchar *)content, "\t", 0);
538 xmlFree(content);
540 #if 0
542 * FIXME ENOMEM
544 if (!nreq) {
545 *rc = gpg_error_from_errno(ENOMEM);
546 return NULL;
548 #endif
550 tmp = *req;
551 tmp = strvcatv(nreq, tmp+1);
552 g_strfreev(nreq);
554 if (!tmp) {
555 *rc = gpg_error_from_errno(ENOMEM);
556 return NULL;
559 g_strfreev(*req);
560 *req = tmp;
562 else {
563 if (strv_printf(&tmp, "%s", content) == FALSE) {
564 xmlFree(content);
565 *rc = gpg_error_from_errno(ENOMEM);
566 return NULL;
569 xmlFree(content);
570 nreq = *req;
571 nreq = strvcatv(tmp, nreq+1);
572 g_strfreev(tmp);
574 if (!nreq) {
575 *rc = gpg_error_from_errno(ENOMEM);
576 return NULL;
579 g_strfreev(*req);
580 *req = nreq;
583 if (target)
584 *target = TRUE;
586 g_free(account);
587 n = find_account(doc, req, rc, target, recursion_depth);
588 return n;
593 n = n->next;
596 g_free(account);
597 *rc = EPWMD_ELEMENT_NOT_FOUND;
598 return NULL;
601 static xmlNodePtr find_element(xmlNodePtr node, gchar *element, xmlNodePtr stop)
603 xmlNodePtr n;
605 if (!node || !element)
606 return NULL;
608 for (n = node; n; n = n->next) {
609 if (n->type != XML_ELEMENT_NODE)
610 continue;
612 if (n == stop)
613 break;
615 if (xmlStrEqual(n->name, (xmlChar *)element))
616 return n;
619 return NULL;
622 static xmlChar *node_has_attribute(xmlNodePtr n, xmlChar *attr)
624 xmlAttrPtr a = xmlHasProp(n, attr);
626 if (!a)
627 return NULL;
629 if (!a->children || !a->children->content)
630 return NULL;
632 return xmlGetProp(n, attr);
635 static gboolean element_to_literal(gchar **element)
637 gchar *p = g_strdup_printf("!%s", *element);
639 if (!p)
640 return FALSE;
642 g_free(*element);
643 *element = p;
644 return TRUE;
647 xmlNodePtr find_elements(xmlDocPtr doc, xmlNodePtr node,
648 gchar **req, gpg_error_t *rc, gboolean *target,
649 xmlNodePtr (*found_fn)(xmlNodePtr, gchar **, gpg_error_t *, gchar **, void *),
650 xmlNodePtr (*not_found_fn)(xmlNodePtr, gchar **, gpg_error_t *, void *),
651 gboolean is_list_command, gint recursion_depth, void *data)
653 xmlNodePtr n, last, last_node;
654 gchar **p;
655 gint found = 0;
657 *rc = 0;
658 recursion_depth++;
660 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth) {
661 xmlChar *t = xmlGetNodePath(node);
663 log_write("%s: %s", pwmd_strerror(EPWMD_LOOP), t);
664 xmlFree(t);
665 recursion_depth--;
666 *rc = EPWMD_LOOP;
667 return NULL;
670 for (last_node = last = n = node, p = req; *p; p++) {
671 xmlNodePtr tmp;
672 gchar *t = g_strdup(*p);
673 gboolean literal;
675 if (!t) {
676 *rc = gpg_error_from_errno(ENOMEM);
677 return NULL;
680 literal = is_literal_element(&t);
681 n = find_element(last, t, NULL);
682 g_free(t);
684 if (!n) {
685 if (not_found_fn)
686 return not_found_fn(found ? last_node : last_node->parent, p, rc, data);
688 *rc = EPWMD_ELEMENT_NOT_FOUND;
689 return NULL;
692 last = n->children;
693 last_node = n;
694 found = 1;
696 if (literal == FALSE) {
697 xmlChar *content = node_has_attribute(n, (xmlChar *)"target");
698 gchar **nreq = NULL, **nnreq;
700 if (!content) {
701 if (is_list_command == TRUE) {
702 if (element_to_literal(&(*p)) == FALSE) {
703 *rc = gpg_error_from_errno(ENOMEM);
704 return NULL;
708 continue;
711 if (strchr((gchar *)content, '\t') != NULL) {
712 if ((nreq = split_input_line((gchar *)content, "\t", 0)) == NULL) {
713 xmlFree(content);
714 *rc = EPWMD_INVALID_ELEMENT;
715 return NULL;
718 else {
719 if ((nreq = split_input_line((gchar *)content, " ", 0)) == NULL) {
720 xmlFree(content);
721 *rc = EPWMD_INVALID_ELEMENT;
722 return NULL;
726 xmlFree(content);
727 tmp = find_account(doc, &nreq, rc, target, 0);
729 if (!tmp) {
730 g_strfreev(nreq);
731 return NULL;
734 if (found_fn) {
735 found_fn(tmp, nreq, rc, p+1, data);
737 if (*rc) {
738 g_strfreev(nreq);
739 return NULL;
743 nnreq = strvcatv(nreq+1, p+1);
744 g_strfreev(nreq);
746 // FIXME ENOMEM
747 if (!nnreq || !*nnreq) {
748 if (nnreq)
749 g_strfreev(nnreq);
751 return tmp;
754 if (target)
755 *target = TRUE;
757 n = find_elements(doc, tmp->children, nnreq, rc, NULL, found_fn,
758 not_found_fn, is_list_command, recursion_depth, data);
760 if (*(p+1)) {
761 gchar **zz = p+1, **qq = nnreq;
763 if (g_strv_length(nnreq) > g_strv_length(p+1))
764 qq = nnreq+1;
766 for (; *qq && *zz; zz++) {
767 g_free(*zz);
768 *zz = g_strdup(*qq++);
770 if (!*zz) {
771 *rc = gpg_error_from_errno(ENOMEM);
772 n = NULL;
773 break;
778 g_strfreev(nnreq);
779 return n;
783 return n;
786 static gboolean update_element_list(struct element_list_s *elements)
788 gchar *line;
789 GSList *l;
791 if (!elements || !elements->elements)
792 return TRUE;
794 line = g_strjoinv("\t", elements->elements);
796 if (!line)
797 return FALSE;
799 g_strfreev(elements->elements);
800 elements->elements = NULL;
801 l = g_slist_append(elements->list, line);
803 if (!l)
804 return FALSE;
806 elements->list = l;
807 return TRUE;
810 static gpg_error_t path_list_recurse(xmlDocPtr doc, xmlNodePtr node,
811 struct element_list_s *elements)
813 gpg_error_t rc = 0;
814 xmlNodePtr n;
816 for (n = node; n; n = n->next) {
817 xmlChar *target = NULL;
819 if (n->type != XML_ELEMENT_NODE)
820 goto children;
822 if (strv_printf(&elements->elements, "%s\t!%s", elements->prefix, n->name) == FALSE)
823 return gpg_err_code_from_errno(ENOMEM);
825 if (update_element_list(elements) == FALSE)
826 return gpg_err_code_from_errno(ENOMEM);
828 target = node_has_attribute(n, (xmlChar *)"target");
830 if (target) {
831 gchar *tmp;
832 gchar *save = elements->prefix;
833 gboolean r = elements->resolving;
835 elements->depth++;
837 if (max_recursion_depth >= 1 && elements->depth > max_recursion_depth) {
838 xmlChar *t = xmlGetNodePath(n);
839 log_write("%s: %s", pwmd_strerror(EPWMD_LOOP), t);
840 xmlFree(t);
841 xmlFree(target);
842 return EPWMD_LOOP;
845 if (strv_printf(&elements->elements, "%s\t%s", elements->prefix, n->name) == FALSE) {
846 xmlFree(target);
847 return gpg_err_code_from_errno(ENOMEM);
850 tmp = g_strjoinv("\t", elements->elements);
852 if (!tmp) {
853 xmlFree(target);
854 return gpg_err_code_from_errno(ENOMEM);
857 if (update_element_list(elements) == FALSE) {
858 xmlFree(target);
859 return gpg_err_code_from_errno(ENOMEM);
862 elements->prefix = tmp;
863 elements->resolving = TRUE;
864 rc = create_path_list(doc, elements, (gchar *)target);
865 xmlFree(target);
866 elements->resolving = r;
867 elements->depth--;
868 g_free(tmp);
869 elements->prefix = save;
871 if (rc)
872 return rc;
875 children:
876 if (n->children) {
877 gchar *tmp = g_strdup_printf("%s\t!%s", elements->prefix, n->name);
878 gchar *save = elements->prefix;
880 if (!tmp)
881 return gpg_err_code_from_errno(ENOMEM);
883 elements->prefix = tmp;
884 rc = path_list_recurse(doc, n->children, elements);
885 g_free(elements->prefix);
886 elements->prefix = save;
888 if (rc)
889 return rc;
893 return rc;
897 * From the element path 'path', find sub-nodes and append them to the list.
899 gpg_error_t create_path_list(xmlDocPtr doc, struct element_list_s *elements,
900 gchar *path)
902 gpg_error_t rc;
903 gchar **req, **req_orig;
904 xmlNodePtr n;
905 gboolean a_target = FALSE;
907 req = split_input_line(path, "\t", 0);
909 if (!req) {
910 req = split_input_line(path, " ", 0);
912 if (!req)
913 return EPWMD_COMMAND_SYNTAX;
916 req_orig = g_strdupv(req);
918 if (!req_orig) {
919 rc = gpg_err_code_from_errno(ENOMEM);
920 goto fail;
923 n = find_account(doc, &req, &rc, &a_target, 0);
925 if (!n && rc == EPWMD_ELEMENT_NOT_FOUND && elements->resolving == TRUE) {
926 rc = 0;
927 goto fail;
929 else if (!n)
930 goto fail;
932 if (a_target == TRUE) {
933 g_free(*req);
934 *req = g_strdup(*req_orig);
937 if (*(req+1)) {
938 gboolean e_target = FALSE;
940 n = find_elements(doc, n->children, req+1, &rc, &e_target, NULL, NULL, TRUE, 0, NULL);
942 if (!n && rc == EPWMD_ELEMENT_NOT_FOUND && elements->resolving == TRUE) {
943 rc = 0;
944 goto fail;
946 else if (!n)
947 goto fail;
950 if (!elements->prefix) {
952 * FIXME
954 * If any req_orig element contains no target the element should be
955 * prefixed with the literal character. Not really crucial if the
956 * client isn't human because child elements are prefixed for the
957 * current path. But may be confusing if editing by hand.
959 elements->prefix = g_strjoinv("\t", req_orig);
961 if (!elements->prefix) {
962 rc = gpg_err_code_from_errno(ENOMEM);
963 goto fail;
966 if (strv_printf(&elements->elements, "%s", elements->prefix) == FALSE) {
967 rc = gpg_err_code_from_errno(ENOMEM);
968 goto fail;
971 if (update_element_list(elements) == FALSE) {
972 rc = gpg_err_code_from_errno(ENOMEM);
973 goto fail;
977 rc = path_list_recurse(doc, n->children, elements);
979 fail:
980 if (req_orig)
981 g_strfreev(req_orig);
983 g_strfreev(req);
984 return rc;
987 gpg_error_t recurse_xpath_nodeset(xmlDocPtr doc, xmlNodeSetPtr nodes,
988 xmlChar *value, xmlBufferPtr *result)
990 gint i = value ? nodes->nodeNr - 1 : 0;
991 xmlBufferPtr buf;
993 buf = xmlBufferCreate();
995 if (!buf)
996 return gpg_err_code_from_errno(ENOMEM);
998 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++) {
999 xmlNodePtr n = nodes->nodeTab[i];
1001 if (!n)
1002 continue;
1004 if (!value) {
1005 if (xmlNodeDump(buf, doc, n, 0, 0) == -1) {
1006 *result = buf;
1007 return EPWMD_LIBXML_ERROR;
1010 continue;
1013 xmlNodeSetContent(n, value);
1016 *result = buf;
1017 return 0;
1020 /* Updates the DTD and renames the root "accounts" and "account" elements. */
1021 gpg_error_t convert_xml(gchar **xml, goffset *len)
1023 gpg_error_t rc = EPWMD_LIBXML_ERROR;
1024 xmlDocPtr doc;
1025 xmlNodePtr n;
1027 doc = xmlReadMemory(*xml, *len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1029 if (!doc)
1030 return EPWMD_LIBXML_ERROR;
1032 doc = create_dtd(doc);
1034 if (!doc)
1035 goto fail;
1037 n = xmlDocGetRootElement(doc);
1038 xmlNodeSetName(n, (xmlChar *)"pwmd");
1040 for (n = n->children; n; n = n->next) {
1041 if (xmlStrcmp(n->name, (xmlChar *)"account") == 0)
1042 xmlNodeSetName(n, (xmlChar *)"root");
1045 gcry_free(*xml);
1046 xmlDocDumpMemory(doc, (xmlChar **)xml, (gint *)len);
1047 rc = 0;
1049 fail:
1050 xmlFreeDoc(doc);
1051 return rc;