1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006-2011 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
33 #include <libxml/xmlwriter.h>
34 #include "pwmd_error.h"
38 extern void log_write(const gchar
*fmt
, ...);
41 * 'element' must be allocated.
43 gboolean
is_literal_element(gchar
**element
)
47 if (!element
|| !*element
)
50 if (*(*element
) == '!') {
53 for (p
= *element
, c
= p
+1; *c
; c
++)
63 gboolean
valid_xml_element(xmlChar
*element
)
65 gchar
*p
= (gchar
*)element
;
67 if (!element
|| *element
== '!')
71 if (g_ascii_isspace(*p
))
78 gpg_error_t
new_root_element(xmlDocPtr doc
, gchar
*name
)
80 xmlNodePtr root
= xmlDocGetRootElement(doc
);
85 return EPWMD_LIBXML_ERROR
;
90 if (!valid_xml_element((xmlChar
*)p
))
91 return GPG_ERR_INV_VALUE
;
93 n
= xmlNewNode(NULL
, (xmlChar
*)"element");
94 n
= xmlAddChild(root
, n
);
95 return add_attribute(n
, "_name", p
);
98 xmlDocPtr
create_dtd()
101 xmlTextWriterPtr wr
= xmlNewTextWriterDoc(&doc
, 0);
106 if (xmlTextWriterStartDocument(wr
, NULL
, NULL
, NULL
))
109 if (xmlTextWriterStartDTD(wr
, (xmlChar
*)"pwmd", NULL
, NULL
) == -1)
112 if (xmlTextWriterWriteDTDElement(wr
, (xmlChar
*)"pwmd",
113 (xmlChar
*)"(element)") == -1)
116 xmlTextWriterEndDTDElement(wr
);
118 if (xmlTextWriterWriteDTDAttlist(wr
, (xmlChar
*)"element",
119 (xmlChar
*)"_name CDATA #REQUIRED") == -1)
122 xmlTextWriterEndDTDAttlist(wr
);
123 xmlTextWriterEndDTD(wr
);
125 if (xmlTextWriterStartElement(wr
, (xmlChar
*)"pwmd"))
128 xmlTextWriterEndElement(wr
);
129 xmlTextWriterEndDocument(wr
);
130 xmlFreeTextWriter(wr
);
134 xmlTextWriterEndDocument(wr
);
135 xmlFreeTextWriter(wr
);
140 xmlChar
*new_document()
144 xmlDocPtr doc
= create_dtd();
149 xmlDocDumpMemory(doc
, &xml
, &len
);
154 xmlNodePtr
find_element_node(xmlNodePtr node
)
158 if (n
&& n
->type
== XML_ELEMENT_NODE
)
161 for (n
= node
; n
; n
= n
->next
) {
162 if (n
->type
== XML_ELEMENT_NODE
)
170 * Lists root element names; the value of the attribute "_name" of an element
171 * "element". If there's a target attribute both literal and non-literal
172 * element names will be added. This is the primary reason why XML entities
173 * cannot be used. There wouldn't be a way to get the literal an non-literal
176 gpg_error_t
list_root_elements(xmlDocPtr doc
, GString
**result
,
185 n
= xmlDocGetRootElement(doc
);
187 if (!n
|| !n
->children
)
188 return GPG_ERR_NO_VALUE
;
190 for (n
= n
->children
; n
; n
= n
->next
) {
192 xmlChar
*val
, *target
;
196 if (n
->type
!= XML_ELEMENT_NODE
)
199 a
= xmlHasProp(n
, (xmlChar
*)"_name");
201 if (!a
|| !a
->children
->content
)
204 val
= xmlNodeGetContent(a
->children
);
211 tmp
= g_strdup_printf("!%s%s", (gchar
*)val
, verbose
? find_element_node(n
->children
) ? " 1" : " 0" : "");
219 tlist
= g_slist_append(list
, tmp
);
228 target
= node_has_attribute(n
, (xmlChar
*)"target");
234 gchar
**req
= split_input_line((gchar
*)target
, "\t", 0);
235 xmlNodePtr tnode
= find_root_element(doc
, &req
, &rc
, NULL
, 0, FALSE
);
237 if (tnode
&& req
[1]) {
238 tnode
= find_elements(doc
, tnode
->children
, req
+1, &rc
,
239 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
243 t
= g_strdup_printf("%s%s", (gchar
*)val
,
244 tnode
&& find_element_node(tnode
->children
) ? " 1" : " 0");
247 t
= g_strdup((gchar
*)val
);
256 tlist
= g_slist_append(list
, t
);
272 total
= g_slist_length(list
);
275 return GPG_ERR_NO_VALUE
;
277 string
= g_string_new(NULL
);
284 for (i
= 0; i
< total
; i
++) {
285 gchar
*val
= g_slist_nth_data(list
, i
);
287 g_string_append_printf(string
, "%s\n", val
);
290 string
= g_string_truncate(string
, string
->len
- 1);
294 total
= g_slist_length(list
);
296 for (i
= 0; i
< total
; i
++)
297 g_free(g_slist_nth_data(list
, i
));
304 * Prevents a sibling element past the current element path with the same
307 static xmlNodePtr
find_stop_node(xmlNodePtr node
)
311 for (n
= node
->parent
->children
; n
; n
= n
->next
) {
320 * Alot like create_elements_cb() but doesn't use the last element of 'req' as
321 * content but as an element.
323 xmlNodePtr
create_target_elements_cb(xmlNodePtr node
, gchar
**path
,
324 gpg_error_t
*rc
, void *data
)
329 for (i
= 0; req
[i
]; i
++) {
332 if ((n
= find_element(node
, req
[i
], find_stop_node(node
))) == NULL
||
333 (n
&& n
->parent
== node
->parent
)) {
334 is_literal_element(&req
[i
]);
336 if (!valid_xml_element((xmlChar
*)req
[i
])) {
337 *rc
= GPG_ERR_INV_VALUE
;
341 //n = xmlNewNode(NULL, (xmlChar *)req[i]);
342 n
= xmlNewNode(NULL
, (xmlChar
*)"element");
345 *rc
= GPG_ERR_ENOMEM
;
349 add_attribute(n
, "_name", req
[i
]);
350 node
= xmlAddChild(node
, n
);
353 *rc
= GPG_ERR_ENOMEM
;
364 xmlNodePtr
find_text_node(xmlNodePtr node
)
368 if (n
&& n
->type
== XML_TEXT_NODE
)
371 for (n
= node
; n
; n
= n
->next
) {
372 if (n
->type
== XML_TEXT_NODE
)
379 xmlNodePtr
create_elements_cb(xmlNodePtr node
, gchar
**elements
,
380 gpg_error_t
*rc
, void *data
)
383 gchar
**req
= elements
;
385 if (node
->type
== XML_TEXT_NODE
)
388 xmlChar
*a
= node_has_attribute(node
, (xmlChar
*)"_name");
393 for (i
= 0; req
[i
]; i
++) {
398 * Strip the first '!' if needed. If there's another, it's an
399 * rc. The syntax has already been checked before calling this
402 is_literal_element(&req
[i
]);
406 * The value of the element tree.
409 n
= find_text_node(node
->children
);
412 /* Use AddContent here to prevent overwriting any children. */
413 xmlNodeAddContent(node
, (xmlChar
*)req
[i
]);
414 else if (n
&& !*req
[i
])
415 xmlNodeSetContent(n
, NULL
);
417 xmlNodeSetContent(n
, (xmlChar
*)req
[i
]);
422 n
= find_element(node
, req
[i
], find_stop_node(node
));
425 * If the found element has the same parent as the current element,
426 * they are siblings and the new element needs to be created as a
427 * child of the current element (node).
429 if (n
&& n
->parent
== node
->parent
)
433 if (!valid_xml_element((xmlChar
*)req
[i
])) {
434 *rc
= GPG_ERR_INV_VALUE
;
438 //n = xmlNewNode(NULL, (xmlChar *)req[i]);
439 n
= xmlNewNode(NULL
, (xmlChar
*)"element");
442 *rc
= GPG_ERR_ENOMEM
;
446 *rc
= add_attribute(n
, "_name", req
[i
]);
451 node
= xmlAddChild(node
, n
);
454 *rc
= GPG_ERR_ENOMEM
;
465 /* The root element is really req[0]. It is need as a pointer in case there is
466 * a target attribute so it can be updated. */
467 xmlNodePtr
find_root_element(xmlDocPtr doc
, gchar
***req
, gpg_error_t
*rc
,
468 gboolean
*target
, gint recursion_depth
, gboolean stop
)
470 xmlNodePtr n
= xmlDocGetRootElement(doc
);
472 gchar
*root
= g_strdup(*req
[0]);
473 gboolean literal
= is_literal_element(&root
);
476 *rc
= GPG_ERR_ENOMEM
;
483 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
) {
484 xmlChar
*t
= xmlGetNodePath(n
);
486 log_write("%s: %s", pwmd_strerror(GPG_ERR_ELOOP
), t
);
494 if (n
->type
== XML_ELEMENT_NODE
) {
495 if (depth
== 0 && xmlStrEqual(n
->name
, (xmlChar
*)"pwmd")) {
501 if (depth
== 1 && xmlStrEqual(n
->name
, (xmlChar
*)"element")) {
502 xmlChar
*content
= node_has_attribute(n
, (xmlChar
*)"_name");
507 if (xmlStrEqual(content
, (xmlChar
*)root
)) {
508 gchar
**nreq
, **tmp
= NULL
;
510 if (literal
== TRUE
) {
517 content
= node_has_attribute(n
, (xmlChar
*)"target");
522 if (!content
|| stop
) {
530 if (strchr((gchar
*)content
, '\t')) {
531 nreq
= split_input_line((gchar
*)content
, "\t", 0);
539 *rc
= GPG_ERR_ENOMEM
;
545 tmp
= strvcatv(nreq
, tmp
+1);
550 *rc
= GPG_ERR_ENOMEM
;
558 if (strv_printf(&tmp
, "%s", content
) == FALSE
) {
561 *rc
= GPG_ERR_ENOMEM
;
567 nreq
= strvcatv(tmp
, nreq
+1);
571 *rc
= GPG_ERR_ENOMEM
;
581 n
= find_root_element(doc
, req
, rc
, target
, recursion_depth
, FALSE
);
593 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
597 xmlNodePtr
find_element(xmlNodePtr node
, gchar
*element
, xmlNodePtr stop
)
601 if (!node
|| !element
)
604 for (n
= node
; n
; n
= n
->next
) {
605 if (n
->type
!= XML_ELEMENT_NODE
)
611 xmlChar
*a
= node_has_attribute(n
, (xmlChar
*)"_name");
613 if (a
&& xmlStrEqual(a
, (xmlChar
*)element
)) {
624 xmlChar
*node_has_attribute(xmlNodePtr n
, xmlChar
*attr
)
626 xmlAttrPtr a
= xmlHasProp(n
, attr
);
631 if (!a
->children
|| !a
->children
->content
)
634 return xmlGetProp(n
, attr
);
637 static gboolean
element_to_literal(gchar
**element
)
639 gchar
*p
= g_strdup_printf("!%s", *element
);
649 /* Resolves elements in 'req' one at a time. It's recursive in case of
650 * "target" attributes. */
651 xmlNodePtr
find_elements(xmlDocPtr doc
, xmlNodePtr node
,
652 gchar
**req
, gpg_error_t
*rc
, gboolean
*target
,
653 xmlNodePtr (*found_fn
)(xmlNodePtr
, gchar
**, gpg_error_t
*, gchar
**, void *),
654 xmlNodePtr (*not_found_fn
)(xmlNodePtr
, gchar
**, gpg_error_t
*, void *),
655 gboolean is_list_command
, gint recursion_depth
, void *data
, gboolean stop
)
657 xmlNodePtr n
, last
, last_node
;
664 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
) {
665 xmlChar
*t
= xmlGetNodePath(node
);
667 log_write("%s: %s", pwmd_strerror(GPG_ERR_ELOOP
), t
);
674 for (last_node
= last
= n
= node
, p
= req
; *p
; p
++) {
676 gchar
*t
= g_strdup(*p
);
680 *rc
= GPG_ERR_ENOMEM
;
684 literal
= is_literal_element(&t
);
685 n
= find_element(last
, t
, NULL
);
690 return not_found_fn(found
? last_node
: last_node
->parent
, p
, rc
, data
);
692 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
700 if (literal
== FALSE
) {
701 xmlChar
*content
= node_has_attribute(n
, (xmlChar
*)"target");
702 gchar
**nreq
= NULL
, **nnreq
;
705 if (is_list_command
== TRUE
) {
706 if (element_to_literal(&(*p
)) == FALSE
) {
707 *rc
= GPG_ERR_ENOMEM
;
718 if (!*(p
+1) && stop
) {
723 if (strchr((gchar
*)content
, '\t') != NULL
) {
724 if ((nreq
= split_input_line((gchar
*)content
, "\t", 0)) == NULL
) {
726 *rc
= GPG_ERR_INV_VALUE
;
731 if ((nreq
= split_input_line((gchar
*)content
, " ", 0)) == NULL
) {
733 *rc
= GPG_ERR_INV_VALUE
;
739 tmp
= find_root_element(doc
, &nreq
, rc
, target
, 0, FALSE
);
747 found_fn(tmp
, nreq
, rc
, p
+1, data
);
755 nnreq
= strvcatv(nreq
+1, p
+1);
759 if (!nnreq
|| !*nnreq
) {
766 n
= find_elements(doc
, tmp
->children
, nnreq
, rc
, NULL
, found_fn
,
767 not_found_fn
, is_list_command
, recursion_depth
, data
, stop
);
770 gchar
**zz
= p
+1, **qq
= nnreq
;
772 if (g_strv_length(nnreq
) > g_strv_length(p
+1))
775 for (; *qq
&& *zz
; zz
++) {
777 *zz
= g_strdup(*qq
++);
780 *rc
= GPG_ERR_ENOMEM
;
795 static gboolean
update_element_list(struct element_list_s
*elements
)
800 if (!elements
|| !elements
->elements
)
803 line
= g_strjoinv("\t", elements
->elements
);
808 g_strfreev(elements
->elements
);
809 elements
->elements
= NULL
;
810 l
= g_slist_append(elements
->list
, line
);
819 static gpg_error_t
path_list_recurse(xmlDocPtr doc
, xmlNodePtr node
,
820 struct element_list_s
*elements
)
825 for (n
= node
; n
; n
= n
->next
) {
826 xmlChar
*target
= NULL
;
827 xmlChar
*a
= node_has_attribute(n
, (xmlChar
*)"_name");
832 if (n
->type
!= XML_ELEMENT_NODE
)
835 if (elements
->verbose
) {
836 if (strv_printf(&elements
->elements
, "%s\t!%s%s", elements
->prefix
, a
, find_element_node(n
->children
) ? " 1" : " 0") == FALSE
) {
838 return GPG_ERR_ENOMEM
;
841 else if (strv_printf(&elements
->elements
, "%s\t!%s", elements
->prefix
, a
) == FALSE
) {
843 return GPG_ERR_ENOMEM
;
846 if (update_element_list(elements
) == FALSE
) {
848 return GPG_ERR_ENOMEM
;
851 target
= node_has_attribute(n
, (xmlChar
*)"target");
855 gchar
*save
= elements
->prefix
;
856 gboolean r
= elements
->resolving
;
860 if (max_recursion_depth
>= 1 && elements
->depth
> max_recursion_depth
) {
861 xmlChar
*t
= xmlGetNodePath(n
);
863 log_write("%s: %s", pwmd_strerror(GPG_ERR_ELOOP
), t
);
867 return GPG_ERR_ELOOP
;
870 if (elements
->verbose
) {
871 gchar
**req
= split_input_line((gchar
*)target
, "\t", 0);
872 xmlNodePtr tnode
= find_root_element(doc
, &req
, &rc
, NULL
, 0, FALSE
);
881 tnode
= find_elements(doc
, tnode
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
890 if (strv_printf(&elements
->elements
, "%s\t%s%s", elements
->prefix
, a
, find_element_node(tnode
->children
) ? " 1" : " 0") == FALSE
) {
893 return GPG_ERR_ENOMEM
;
896 else if (strv_printf(&elements
->elements
, "%s\t%s", elements
->prefix
, a
) == FALSE
) {
899 return GPG_ERR_ENOMEM
;
902 tmp
= g_strjoinv("\t", elements
->elements
);
907 return GPG_ERR_ENOMEM
;
910 if (update_element_list(elements
) == FALSE
) {
914 return GPG_ERR_ENOMEM
;
917 if (elements
->recurse
) {
918 if (elements
->verbose
)
919 tmp
[strlen(tmp
)-2] = 0;
921 elements
->prefix
= tmp
;
922 elements
->resolving
= TRUE
;
923 rc
= create_path_list(doc
, elements
, (gchar
*)target
);
925 elements
->resolving
= r
;
928 elements
->prefix
= save
;
938 if (n
->children
&& elements
->recurse
) {
939 gchar
*tmp
= g_strdup_printf("%s\t!%s", elements
->prefix
, a
);
940 gchar
*save
= elements
->prefix
;
944 return GPG_ERR_ENOMEM
;
947 elements
->prefix
= tmp
;
948 rc
= path_list_recurse(doc
, n
->children
, elements
);
949 g_free(elements
->prefix
);
950 elements
->prefix
= save
;
964 gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
970 if (name
&& !xmlSetProp(node
, (xmlChar
*)name
, (xmlChar
*)value
))
971 return EPWMD_LIBXML_ERROR
;
973 if (name
&& xmlStrEqual((xmlChar
*)name
, (xmlChar
*)"_mtime"))
976 buf
= g_strdup_printf("%li", time(NULL
));
977 rc
= add_attribute(node
, "_mtime", buf
);
983 * From the element path 'path', find sub-nodes and append them to the list.
985 gpg_error_t
create_path_list(xmlDocPtr doc
, struct element_list_s
*elements
,
989 gchar
**req
, **req_orig
;
991 gboolean a_target
= FALSE
;
993 req
= split_input_line(path
, "\t", 0);
996 req
= split_input_line(path
, " ", 0);
999 return GPG_ERR_SYNTAX
;
1002 req_orig
= g_strdupv(req
);
1005 rc
= GPG_ERR_ENOMEM
;
1009 n
= find_root_element(doc
, &req
, &rc
, &a_target
, 0, FALSE
);
1011 if (!n
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== TRUE
) {
1018 if (a_target
== TRUE
) {
1020 *req
= g_strdup(*req_orig
);
1024 gboolean e_target
= FALSE
;
1026 n
= find_elements(doc
, n
->children
, req
+1, &rc
, &e_target
, NULL
, NULL
, TRUE
, 0, NULL
, FALSE
);
1028 if (!n
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== TRUE
) {
1036 if (!elements
->prefix
) {
1040 * If any req_orig element contains no target the element should be
1041 * prefixed with the literal character. Not really crucial if the
1042 * client isn't human because child elements are prefixed for the
1043 * current path. But may be confusing if editing by hand.
1045 elements
->prefix
= g_strjoinv("\t", req_orig
);
1047 if (!elements
->prefix
) {
1048 rc
= GPG_ERR_ENOMEM
;
1052 if (elements
->verbose
) {
1053 if (strv_printf(&elements
->elements
, "%s%s", elements
->prefix
, find_element_node(n
->children
) ? " 1" : " 0") == FALSE
) {
1054 rc
= GPG_ERR_ENOMEM
;
1058 else if (strv_printf(&elements
->elements
, "%s", elements
->prefix
) == FALSE
) {
1059 rc
= GPG_ERR_ENOMEM
;
1063 if (update_element_list(elements
) == FALSE
) {
1064 rc
= GPG_ERR_ENOMEM
;
1069 rc
= path_list_recurse(doc
, n
->children
, elements
);
1073 g_strfreev(req_orig
);
1079 gpg_error_t
recurse_xpath_nodeset(xmlDocPtr doc
, xmlNodeSetPtr nodes
,
1080 xmlChar
*value
, xmlBufferPtr
*result
, gboolean cmd
, const xmlChar
*attr
)
1082 gint i
= value
? nodes
->nodeNr
- 1 : 0;
1085 buf
= xmlBufferCreate();
1088 return GPG_ERR_ENOMEM
;
1090 for (; value
? i
>= 0 : i
< nodes
->nodeNr
; value
? i
-- : i
++) {
1091 xmlNodePtr n
= nodes
->nodeTab
[i
];
1097 if (!value
&& !attr
) {
1098 if (xmlNodeDump(buf
, doc
, n
, 0, 0) == -1) {
1100 return EPWMD_LIBXML_ERROR
;
1107 xmlNodeSetContent(n
, value
);
1108 rc
= update_element_mtime(n
);
1115 rc
= add_attribute(n
, (gchar
*)attr
, (gchar
*)value
);
1117 rc
= delete_attribute(n
, attr
);
1128 /* Common between a version 1 data file and version < 2.12. */
1129 static gpg_error_t
convert_root_element(xmlNodePtr n
)
1131 xmlChar
*a
= xmlGetProp(n
, (xmlChar
*)"_name");
1136 xmlChar
*t
= xmlGetNodePath(n
);
1138 log_write(N_("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"), t
);
1140 return GPG_ERR_AMBIGUOUS_NAME
;
1143 a
= xmlGetProp(n
, (xmlChar
*)"name");
1146 rc
= add_attribute(n
, "_name", (gchar
*)a
);
1152 rc
= delete_attribute(n
, (xmlChar
*)"name");
1157 xmlNodeSetName(n
, (xmlChar
*)"element");
1163 /* For a version 1 data file. */
1164 static gpg_error_t
convert_elements_recurse_v1(xmlNodePtr n
)
1166 for (; n
; n
= n
->next
) {
1169 if (n
->type
== XML_ELEMENT_NODE
&&
1170 !xmlStrEqual(n
->name
, (xmlChar
*)"_element")) {
1171 xmlChar
*a
= xmlGetProp(n
, (xmlChar
*)"_name");
1175 xmlChar
*t
= xmlGetNodePath(n
);
1177 log_write(N_("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"), t
);
1179 return GPG_ERR_AMBIGUOUS_NAME
;
1182 rc
= add_attribute(n
, "_name", (gchar
*)n
->name
);
1187 xmlNodeSetName(n
, (xmlChar
*)"element");
1190 rc
= convert_elements_recurse_v1(n
->children
);
1199 /* Updates the DTD and renames the root "accounts" and "account" elements from
1200 * a version 1 data file. */
1201 gpg_error_t
convert_xml(gchar
**xml
, goffset
*len
)
1203 gpg_error_t rc
= EPWMD_LIBXML_ERROR
;
1204 xmlDocPtr doc
, new = NULL
;
1207 doc
= xmlReadMemory(*xml
, *len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
1210 return EPWMD_LIBXML_ERROR
;
1214 n
= xmlDocGetRootElement(doc
);
1215 xmlNodeSetName(n
, (xmlChar
*)"pwmd");
1217 for (n
= n
->children
; n
; n
= n
->next
) {
1218 if (xmlStrEqual(n
->name
, (xmlChar
*)"account")) {
1219 rc
= convert_root_element(n
);
1226 rc
= convert_elements_recurse_v1(n
->children
);
1240 n
= xmlDocGetRootElement(doc
);
1241 xmlDocSetRootElement(new, n
);
1242 xmlDocDumpMemory(new, (xmlChar
**)xml
, (gint
*)len
);
1243 xmlDocSetRootElement(new, xmlCopyNode(n
, 0));
1254 gpg_error_t
delete_attribute(xmlNodePtr n
, const xmlChar
*name
)
1258 if ((a
= xmlHasProp(n
, name
)) == NULL
)
1259 return GPG_ERR_NOT_FOUND
;
1261 if (xmlRemoveProp(a
) == -1)
1262 return EPWMD_LIBXML_ERROR
;
1264 return update_element_mtime(n
);
1267 static gpg_error_t
convert_elements_recurse(xmlDocPtr doc
, xmlNodePtr n
,
1274 for (n
= n
->children
; n
; n
= n
->next
) {
1275 if (n
->type
== XML_ELEMENT_NODE
) {
1279 if (xmlStrEqual(n
->name
, (xmlChar
*)"element")) {
1280 xmlChar
*t
= xmlGetNodePath(n
);
1282 log_write(N_("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"), t
);
1284 return GPG_ERR_AMBIGUOUS_NAME
;
1287 a
= xmlGetProp(n
, (xmlChar
*)"_name");
1291 xmlChar
*t
= xmlGetNodePath(n
);
1293 log_write(N_("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"), t
);
1295 return GPG_ERR_AMBIGUOUS_NAME
;
1298 xmlChar
*tmp
= xmlStrdup(n
->name
);
1301 return GPG_ERR_ENOMEM
;
1303 xmlNodeSetName(n
, (xmlChar
*)"element");
1304 rc
= add_attribute(n
, "_name", (gchar
*)tmp
);
1311 rc
= convert_root_element(n
);
1319 rc
= convert_elements_recurse(doc
, n
, depth
);
1329 /* Renames ALL elements to the new "element" name. Existing element names are
1330 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1331 * elements can contain common characters that the XML parser barfs on (an
1332 * email address for example. */
1333 gpg_error_t
convert_elements(xmlDocPtr doc
)
1335 xmlNodePtr n
= xmlDocGetRootElement(doc
);
1338 log_write(N_("Converting pre 2.12 data file..."));
1339 rc
= convert_elements_recurse(doc
, n
, 0);
1342 log_write(N_("Finished converting. Please SAVE to update."));
1347 gpg_error_t
validate_import(xmlNodePtr node
)
1354 for (xmlNodePtr n
= node
; n
; n
= n
->next
) {
1355 if (n
->type
== XML_ELEMENT_NODE
) {
1356 if (xmlStrEqual(n
->name
, (xmlChar
*)"element")) {
1357 xmlChar
*a
= xmlGetProp(n
, (xmlChar
*)"_name");
1360 xmlChar
*t
= xmlGetNodePath(n
);
1362 log_write(N_("Missing attribute '_name' at %s."), t
);
1364 return GPG_ERR_INV_VALUE
;
1367 if (!valid_xml_element(a
)) {
1368 xmlChar
*t
= xmlGetNodePath(n
);
1370 log_write(N_("'%s' is not a valid element name at %s."), a
, t
);
1373 return GPG_ERR_INV_VALUE
;
1379 xmlChar
*t
= xmlGetNodePath(n
);
1381 log_write(N_("Warning: unknown element '%s' at %s. Ignoring."), n
->name
, t
);
1388 rc
= validate_import(n
->children
);
1398 gpg_error_t
update_element_mtime(xmlNodePtr n
)
1400 return add_attribute(n
, NULL
, NULL
);
1403 gpg_error_t
unlink_node(xmlNodePtr n
)
1411 rc
= update_element_mtime(n
->parent
);