1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of pwmd.
8 Pwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Pwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
34 #include <libxml/xmlwriter.h>
36 #include "pwmd-error.h"
42 extern void log_write(const gchar
*fmt
, ...);
45 * 'element' must be allocated.
47 gboolean
is_literal_element(gchar
**element
)
51 if (!element
|| !*element
)
54 if (*(*element
) == '!') {
57 for (p
= *element
, c
= p
+1; *c
; c
++)
67 gboolean
valid_xml_element(xmlChar
*element
)
69 gchar
*p
= (gchar
*)element
;
71 if (!element
|| !*element
|| *element
== '!')
75 if (g_ascii_isspace(*p
))
82 gboolean
valid_element_path(gchar
**path
, gboolean with_content
)
84 gchar
**dup
= NULL
, **p
;
90 /* Save some memory by not duplicating the element content. */
92 t
= g_strv_length(path
);
93 for (i
= 0; i
< t
-1; i
++) {
94 gchar
**tmp
= g_realloc(dup
, (i
+2)*sizeof(gchar
*));
102 dup
[i
] = g_strdup(path
[i
]);
107 dup
= g_strdupv(path
);
112 for (p
= dup
; *p
&& *(*p
); p
++) {
113 is_literal_element(&(*p
));
114 if (!valid_xml_element((xmlChar
*)*p
)) {
124 gpg_error_t
attr_ctime(xmlNodePtr n
)
126 gchar
*buf
= g_strdup_printf("%li", time(NULL
));
130 return GPG_ERR_ENOMEM
;
132 rc
= add_attribute(n
, "_ctime", buf
);
137 static gpg_error_t
create_new_element(xmlNodePtr parent
, const gchar
*name
,
140 xmlNodePtr n
= xmlNewNode(NULL
, (xmlChar
*)"element");
144 return GPG_ERR_ENOMEM
;
146 rc
= add_attribute(n
, "_name", name
);
152 *result
= xmlAddChild(parent
, n
);
154 (void)xmlAddChild(parent
, n
);
162 gpg_error_t
new_root_element(xmlDocPtr doc
, gchar
*name
)
164 xmlNodePtr root
= xmlDocGetRootElement(doc
);
168 return GPG_ERR_BAD_DATA
;
173 if (!valid_xml_element((xmlChar
*)p
))
174 return GPG_ERR_INV_VALUE
;
176 return create_new_element(root
, p
, NULL
);
179 static xmlDocPtr
create_dtd()
182 xmlTextWriterPtr wr
= xmlNewTextWriterDoc(&doc
, 0);
187 if (xmlTextWriterStartDocument(wr
, NULL
, NULL
, NULL
))
190 if (xmlTextWriterStartDTD(wr
, (xmlChar
*)"pwmd", NULL
, NULL
) == -1)
193 if (xmlTextWriterWriteDTDElement(wr
, (xmlChar
*)"pwmd",
194 (xmlChar
*)"(element)") == -1)
197 xmlTextWriterEndDTDElement(wr
);
199 if (xmlTextWriterWriteDTDAttlist(wr
, (xmlChar
*)"element",
200 (xmlChar
*)"_name CDATA #REQUIRED") == -1)
203 xmlTextWriterEndDTDAttlist(wr
);
204 xmlTextWriterEndDTD(wr
);
206 if (xmlTextWriterStartElement(wr
, (xmlChar
*)"pwmd"))
209 xmlTextWriterEndElement(wr
);
210 xmlTextWriterEndDocument(wr
);
211 xmlFreeTextWriter(wr
);
215 xmlTextWriterEndDocument(wr
);
216 xmlFreeTextWriter(wr
);
221 xmlDocPtr
new_document()
226 xmlNodePtr
find_element_node(xmlNodePtr node
)
230 if (n
&& n
->type
== XML_ELEMENT_NODE
)
233 for (n
= node
; n
; n
= n
->next
) {
234 if (n
->type
== XML_ELEMENT_NODE
)
242 * Lists root element names; the value of the attribute "_name" of an element
243 * "element". If there's a target attribute both literal and non-literal
244 * element names will be added. This is the primary reason why XML entities
245 * cannot be used. There wouldn't be a way to get the literal an non-literal
248 gpg_error_t
list_root_elements(xmlDocPtr doc
, GString
**result
,
257 n
= xmlDocGetRootElement(doc
);
259 if (!n
|| !n
->children
)
260 return GPG_ERR_NO_DATA
;
262 for (n
= n
->children
; n
; n
= n
->next
) {
264 xmlChar
*val
, *target
;
268 if (n
->type
!= XML_ELEMENT_NODE
)
271 a
= xmlHasProp(n
, (xmlChar
*)"_name");
273 if (!a
|| !a
->children
->content
)
276 val
= xmlNodeGetContent(a
->children
);
283 tmp
= g_strdup_printf("!%s%s", (gchar
*)val
, verbose
? find_element_node(n
->children
) ? " 1" : " 0" : "");
291 tlist
= g_slist_append(list
, tmp
);
300 target
= node_has_attribute(n
, (xmlChar
*)"target");
306 gchar
**req
= split_input_line((gchar
*)target
, "\t", 0);
307 xmlNodePtr tnode
= find_root_element(doc
, &req
, &rc
, NULL
, 0, FALSE
);
309 if (tnode
&& req
[1]) {
310 tnode
= find_elements(doc
, tnode
->children
, req
+1, &rc
,
311 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
315 t
= g_strdup_printf("%s%s", (gchar
*)val
,
316 tnode
&& find_element_node(tnode
->children
) ? " 1" : " 0");
319 t
= g_strdup((gchar
*)val
);
328 tlist
= g_slist_append(list
, t
);
344 total
= g_slist_length(list
);
347 return GPG_ERR_NO_DATA
;
349 string
= g_string_new(NULL
);
356 for (i
= 0; i
< total
; i
++) {
357 gchar
*val
= g_slist_nth_data(list
, i
);
359 g_string_append_printf(string
, "%s\n", val
);
362 string
= g_string_truncate(string
, string
->len
- 1);
366 total
= g_slist_length(list
);
368 for (i
= 0; i
< total
; i
++)
369 g_free(g_slist_nth_data(list
, i
));
376 * Prevents a sibling element past the current element path with the same
379 static xmlNodePtr
find_stop_node(xmlNodePtr node
)
383 for (n
= node
->parent
->children
; n
; n
= n
->next
) {
391 xmlNodePtr
create_target_elements_cb(xmlNodePtr node
, gchar
**path
,
392 gpg_error_t
*rc
, void *data
)
396 xmlNodePtr parent
= data
;
398 for (i
= 0; req
[i
] && *req
[i
]; i
++) {
401 if (parent
&& node
== parent
) {
402 *rc
= GPG_ERR_CONFLICT
;
406 is_literal_element(&req
[i
]);
408 if ((n
= find_element(node
, req
[i
], find_stop_node(node
))) == NULL
||
409 (n
&& n
->parent
== node
->parent
)) {
411 *rc
= create_new_element(node
, req
[i
], &node
);
422 xmlNodePtr
find_text_node(xmlNodePtr node
)
426 if (n
&& n
->type
== XML_TEXT_NODE
)
429 for (n
= node
; n
; n
= n
->next
) {
430 if (n
->type
== XML_TEXT_NODE
)
437 xmlNodePtr
create_elements_cb(xmlNodePtr node
, gchar
**elements
,
438 gpg_error_t
*rc
, void *data
)
441 gchar
**req
= elements
;
443 if (node
->type
== XML_TEXT_NODE
)
446 for (i
= 0; req
[i
] && *req
[i
]; i
++) {
450 * Strip the first '!' if needed. If there's another, it's an
451 * rc. The syntax has already been checked before calling this
454 is_literal_element(&req
[i
]);
455 n
= find_element(node
, req
[i
], find_stop_node(node
));
458 * If the found element has the same parent as the current element,
459 * they are siblings and the new element needs to be created as a
460 * child of the current element (node).
462 if (n
&& n
->parent
== node
->parent
)
466 *rc
= create_new_element(node
, req
[i
], &node
);
477 /* The root element is really req[0]. It is need as a pointer in case there is
478 * a target attribute so it can be updated. */
479 xmlNodePtr
find_root_element(xmlDocPtr doc
, gchar
***req
, gpg_error_t
*rc
,
480 gboolean
*target
, gint recursion_depth
, gboolean stop
)
482 xmlNodePtr n
= xmlDocGetRootElement(doc
);
484 gchar
*root
= g_strdup(*req
[0]);
485 gboolean literal
= is_literal_element(&root
);
488 *rc
= GPG_ERR_ENOMEM
;
495 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
) {
496 xmlChar
*t
= xmlGetNodePath(n
);
498 log_write("%s: %s", pwmd_strerror(GPG_ERR_ELOOP
), t
);
506 if (n
->type
== XML_ELEMENT_NODE
) {
507 if (depth
== 0 && xmlStrEqual(n
->name
, (xmlChar
*)"pwmd")) {
513 if (depth
== 1 && xmlStrEqual(n
->name
, (xmlChar
*)"element")) {
514 xmlChar
*content
= node_has_attribute(n
, (xmlChar
*)"_name");
519 if (xmlStrEqual(content
, (xmlChar
*)root
)) {
520 gchar
**nreq
, **tmp
= NULL
;
522 if (literal
== TRUE
) {
529 content
= node_has_attribute(n
, (xmlChar
*)"target");
534 if (!content
|| stop
) {
542 if (strchr((gchar
*)content
, '\t')) {
543 nreq
= split_input_line((gchar
*)content
, "\t", 0);
551 *rc
= GPG_ERR_ENOMEM
;
557 tmp
= strvcatv(nreq
, tmp
+1);
562 *rc
= GPG_ERR_ENOMEM
;
570 if (strv_printf(&tmp
, "%s", content
) == FALSE
) {
573 *rc
= GPG_ERR_ENOMEM
;
579 nreq
= strvcatv(tmp
, nreq
+1);
583 *rc
= GPG_ERR_ENOMEM
;
593 n
= find_root_element(doc
, req
, rc
, target
, recursion_depth
, FALSE
);
605 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
609 xmlNodePtr
find_element(xmlNodePtr node
, gchar
*element
, xmlNodePtr stop
)
613 if (!node
|| !element
)
616 for (n
= node
; n
; n
= n
->next
) {
617 if (n
->type
!= XML_ELEMENT_NODE
)
623 xmlChar
*a
= node_has_attribute(n
, (xmlChar
*)"_name");
625 if (a
&& xmlStrEqual(a
, (xmlChar
*)element
)) {
636 xmlChar
*node_has_attribute(xmlNodePtr n
, xmlChar
*attr
)
638 xmlAttrPtr a
= xmlHasProp(n
, attr
);
643 if (!a
->children
|| !a
->children
->content
)
646 return xmlGetProp(n
, attr
);
649 static gboolean
element_to_literal(gchar
**element
)
651 gchar
*p
= g_strdup_printf("!%s", *element
);
661 /* Resolves elements in 'req' one at a time. It's recursive in case of
662 * "target" attributes. */
663 xmlNodePtr
find_elements(xmlDocPtr doc
, xmlNodePtr node
,
664 gchar
**req
, gpg_error_t
*rc
, gboolean
*target
,
665 xmlNodePtr (*found_fn
)(xmlNodePtr
, gchar
**, gpg_error_t
*, gchar
**, void *),
666 xmlNodePtr (*not_found_fn
)(xmlNodePtr
, gchar
**, gpg_error_t
*, void *),
667 gboolean is_list_command
, gint recursion_depth
, void *data
, gboolean stop
)
669 xmlNodePtr n
, last
, last_node
;
676 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
) {
677 xmlChar
*t
= xmlGetNodePath(node
);
679 log_write("%s: %s", pwmd_strerror(GPG_ERR_ELOOP
), t
);
686 for (last_node
= last
= n
= node
, p
= req
; *p
&& *(*p
); p
++) {
688 gchar
*t
= g_strdup(*p
);
692 *rc
= GPG_ERR_ENOMEM
;
696 literal
= is_literal_element(&t
);
697 n
= find_element(last
, t
, NULL
);
702 return not_found_fn(found
? last_node
: last_node
->parent
, p
, rc
, data
);
704 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
712 if (literal
== FALSE
) {
713 xmlChar
*content
= node_has_attribute(n
, (xmlChar
*)"target");
714 gchar
**nreq
= NULL
, **nnreq
;
717 if (is_list_command
== TRUE
) {
718 if (element_to_literal(&(*p
)) == FALSE
) {
719 *rc
= GPG_ERR_ENOMEM
;
730 if (!*(p
+1) && stop
) {
735 if (strchr((gchar
*)content
, '\t') != NULL
) {
736 if ((nreq
= split_input_line((gchar
*)content
, "\t", 0)) == NULL
) {
738 *rc
= GPG_ERR_INV_VALUE
;
743 if ((nreq
= split_input_line((gchar
*)content
, " ", 0)) == NULL
) {
745 *rc
= GPG_ERR_INV_VALUE
;
751 tmp
= find_root_element(doc
, &nreq
, rc
, target
, 0, FALSE
);
759 found_fn(tmp
, nreq
, rc
, p
+1, data
);
767 nnreq
= strvcatv(nreq
+1, p
+1);
771 if (!nnreq
|| !*nnreq
) {
779 n
= find_elements(doc
, tmp
->children
, nnreq
, rc
, NULL
, found_fn
,
780 not_found_fn
, is_list_command
, recursion_depth
, data
, stop
);
785 return not_found_fn(tmp
, p
+1, rc
, data
);
787 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
792 gchar
**zz
= p
+1, **qq
= nnreq
;
794 if (g_strv_length(nnreq
) > g_strv_length(p
+1))
797 for (; *qq
&& *zz
; zz
++) {
799 *zz
= g_strdup(*qq
++);
802 *rc
= GPG_ERR_ENOMEM
;
817 static gboolean
update_element_list(struct element_list_s
*elements
)
822 if (!elements
|| !elements
->elements
)
825 line
= g_strjoinv("\t", elements
->elements
);
830 g_strfreev(elements
->elements
);
831 elements
->elements
= NULL
;
832 l
= g_slist_append(elements
->list
, line
);
841 static gpg_error_t
path_list_recurse(xmlDocPtr doc
, xmlNodePtr node
,
842 struct element_list_s
*elements
)
847 for (n
= node
; n
; n
= n
->next
) {
848 xmlChar
*target
= NULL
;
849 xmlChar
*a
= node_has_attribute(n
, (xmlChar
*)"_name");
854 if (n
->type
!= XML_ELEMENT_NODE
)
857 if (elements
->verbose
) {
858 if (strv_printf(&elements
->elements
, "%s\t!%s%s", elements
->prefix
, a
, find_element_node(n
->children
) ? " 1" : " 0") == FALSE
) {
860 return GPG_ERR_ENOMEM
;
863 else if (strv_printf(&elements
->elements
, "%s\t!%s", elements
->prefix
, a
) == FALSE
) {
865 return GPG_ERR_ENOMEM
;
868 if (update_element_list(elements
) == FALSE
) {
870 return GPG_ERR_ENOMEM
;
873 target
= node_has_attribute(n
, (xmlChar
*)"target");
877 gchar
*save
= elements
->prefix
;
878 gboolean r
= elements
->resolving
;
882 if (max_recursion_depth
>= 1 && elements
->depth
> max_recursion_depth
) {
883 xmlChar
*t
= xmlGetNodePath(n
);
885 log_write("%s: %s", pwmd_strerror(GPG_ERR_ELOOP
), t
);
889 return GPG_ERR_ELOOP
;
892 if (elements
->verbose
) {
893 gchar
**req
= split_input_line((gchar
*)target
, "\t", 0);
894 xmlNodePtr tnode
= find_root_element(doc
, &req
, &rc
, NULL
, 0, FALSE
);
903 tnode
= find_elements(doc
, tnode
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
912 if (strv_printf(&elements
->elements
, "%s\t%s%s", elements
->prefix
, a
, find_element_node(tnode
->children
) ? " 1" : " 0") == FALSE
) {
915 return GPG_ERR_ENOMEM
;
918 else if (strv_printf(&elements
->elements
, "%s\t%s", elements
->prefix
, a
) == FALSE
) {
921 return GPG_ERR_ENOMEM
;
924 tmp
= g_strjoinv("\t", elements
->elements
);
929 return GPG_ERR_ENOMEM
;
932 if (update_element_list(elements
) == FALSE
) {
936 return GPG_ERR_ENOMEM
;
939 if (elements
->recurse
) {
940 if (elements
->verbose
)
941 tmp
[strlen(tmp
)-2] = 0;
943 elements
->prefix
= tmp
;
944 elements
->resolving
= TRUE
;
945 rc
= create_path_list(doc
, elements
, (gchar
*)target
);
947 elements
->resolving
= r
;
950 elements
->prefix
= save
;
960 if (n
->children
&& elements
->recurse
) {
961 gchar
*tmp
= g_strdup_printf("%s\t!%s", elements
->prefix
, a
);
962 gchar
*save
= elements
->prefix
;
966 return GPG_ERR_ENOMEM
;
969 elements
->prefix
= tmp
;
970 rc
= path_list_recurse(doc
, n
->children
, elements
);
971 g_free(elements
->prefix
);
972 elements
->prefix
= save
;
986 gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
992 if (name
&& !xmlSetProp(node
, (xmlChar
*)name
, (xmlChar
*)value
))
993 return GPG_ERR_BAD_DATA
;
995 if (name
&& xmlStrEqual((xmlChar
*)name
, (xmlChar
*)"_mtime"))
998 buf
= g_strdup_printf("%li", time(NULL
));
999 rc
= add_attribute(node
, "_mtime", buf
);
1005 * From the element path 'path', find sub-nodes and append them to the list.
1007 gpg_error_t
create_path_list(xmlDocPtr doc
, struct element_list_s
*elements
,
1011 gchar
**req
, **req_orig
;
1013 gboolean a_target
= FALSE
;
1015 req
= split_input_line(path
, "\t", 0);
1017 req
= split_input_line(path
, " ", 0);
1019 return GPG_ERR_SYNTAX
;
1022 req_orig
= g_strdupv(req
);
1024 rc
= GPG_ERR_ENOMEM
;
1028 n
= find_root_element(doc
, &req
, &rc
, &a_target
, 0, FALSE
);
1030 if (!n
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== TRUE
) {
1037 if (a_target
== TRUE
) {
1039 *req
= g_strdup(*req_orig
);
1043 gboolean e_target
= FALSE
;
1045 n
= find_elements(doc
, n
->children
, req
+1, &rc
, &e_target
, NULL
, NULL
, TRUE
, 0, NULL
, FALSE
);
1047 if (!n
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== TRUE
) {
1055 if (!elements
->prefix
) {
1059 * If any req_orig element contains no target the element should be
1060 * prefixed with the literal character. Not really crucial if the
1061 * client isn't human because child elements are prefixed for the
1062 * current path. But may be confusing if editing by hand.
1064 elements
->prefix
= g_strjoinv("\t", req_orig
);
1066 if (!elements
->prefix
) {
1067 rc
= GPG_ERR_ENOMEM
;
1071 if (elements
->verbose
) {
1072 if (strv_printf(&elements
->elements
, "%s%s", elements
->prefix
, find_element_node(n
->children
) ? " 1" : " 0") == FALSE
) {
1073 rc
= GPG_ERR_ENOMEM
;
1077 else if (strv_printf(&elements
->elements
, "%s", elements
->prefix
) == FALSE
) {
1078 rc
= GPG_ERR_ENOMEM
;
1082 if (update_element_list(elements
) == FALSE
) {
1083 rc
= GPG_ERR_ENOMEM
;
1088 rc
= path_list_recurse(doc
, n
->children
, elements
);
1092 g_strfreev(req_orig
);
1098 gpg_error_t
recurse_xpath_nodeset(xmlDocPtr doc
, xmlNodeSetPtr nodes
,
1099 xmlChar
*value
, xmlBufferPtr
*result
, gboolean cmd
, const xmlChar
*attr
)
1101 gint i
= value
? nodes
->nodeNr
- 1 : 0;
1104 buf
= xmlBufferCreate();
1107 return GPG_ERR_ENOMEM
;
1109 for (; value
? i
>= 0 : i
< nodes
->nodeNr
; value
? i
-- : i
++) {
1110 xmlNodePtr n
= nodes
->nodeTab
[i
];
1116 if (!value
&& !attr
) {
1117 if (xmlNodeDump(buf
, doc
, n
, 0, 0) == -1) {
1119 return GPG_ERR_BAD_DATA
;
1126 xmlNodeSetContent(n
, value
);
1127 rc
= update_element_mtime(n
);
1134 rc
= add_attribute(n
, (gchar
*)attr
, (gchar
*)value
);
1136 rc
= delete_attribute(n
, attr
);
1147 static gpg_error_t
convert_root_element(xmlNodePtr n
)
1149 xmlChar
*a
= xmlGetProp(n
, (xmlChar
*)"_name");
1154 xmlChar
*t
= xmlGetNodePath(n
);
1156 log_write(_("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"), t
);
1158 return GPG_ERR_AMBIGUOUS_NAME
;
1161 a
= xmlGetProp(n
, (xmlChar
*)"name");
1164 rc
= add_attribute(n
, "_name", (gchar
*)a
);
1170 rc
= delete_attribute(n
, (xmlChar
*)"name");
1175 xmlNodeSetName(n
, (xmlChar
*)"element");
1181 gpg_error_t
delete_attribute(xmlNodePtr n
, const xmlChar
*name
)
1185 if ((a
= xmlHasProp(n
, name
)) == NULL
)
1186 return GPG_ERR_NOT_FOUND
;
1188 if (xmlRemoveProp(a
) == -1)
1189 return GPG_ERR_BAD_DATA
;
1191 return update_element_mtime(n
);
1194 static gpg_error_t
convert_elements_recurse(xmlDocPtr doc
, xmlNodePtr n
,
1201 for (n
= n
->children
; n
; n
= n
->next
) {
1202 if (n
->type
== XML_ELEMENT_NODE
) {
1206 if (xmlStrEqual(n
->name
, (xmlChar
*)"element")) {
1207 xmlChar
*t
= xmlGetNodePath(n
);
1209 log_write(_("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"), t
);
1211 return GPG_ERR_AMBIGUOUS_NAME
;
1214 a
= xmlGetProp(n
, (xmlChar
*)"_name");
1218 xmlChar
*t
= xmlGetNodePath(n
);
1220 log_write(_("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"), t
);
1222 return GPG_ERR_AMBIGUOUS_NAME
;
1225 xmlChar
*tmp
= xmlStrdup(n
->name
);
1228 return GPG_ERR_ENOMEM
;
1230 xmlNodeSetName(n
, (xmlChar
*)"element");
1231 rc
= add_attribute(n
, "_name", (gchar
*)tmp
);
1238 rc
= convert_root_element(n
);
1246 rc
= convert_elements_recurse(doc
, n
, depth
);
1256 /* Renames ALL elements to the new "element" name. Existing element names are
1257 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1258 * elements can contain common characters that the XML parser barfs on (an
1259 * email address for example. */
1260 gpg_error_t
convert_pre_212_elements(xmlDocPtr doc
)
1262 xmlNodePtr n
= xmlDocGetRootElement(doc
);
1264 log_write(_("Converting pre 2.12 data file..."));
1265 return convert_elements_recurse(doc
, n
, 0);
1268 gpg_error_t
validate_import(xmlNodePtr node
)
1275 for (xmlNodePtr n
= node
; n
; n
= n
->next
) {
1276 if (n
->type
== XML_ELEMENT_NODE
) {
1277 if (xmlStrEqual(n
->name
, (xmlChar
*)"element")) {
1278 xmlChar
*a
= xmlGetProp(n
, (xmlChar
*)"_name");
1281 xmlChar
*t
= xmlGetNodePath(n
);
1283 log_write(_("Missing attribute '_name' at %s."), t
);
1285 return GPG_ERR_INV_VALUE
;
1288 if (!valid_xml_element(a
)) {
1289 xmlChar
*t
= xmlGetNodePath(n
);
1291 log_write(_("'%s' is not a valid element name at %s."), a
, t
);
1294 return GPG_ERR_INV_VALUE
;
1298 a
= xmlGetProp(n
, (xmlChar
*)"_ctime");
1303 a
= xmlGetProp(n
, (xmlChar
*)"_mtime");
1305 update_element_mtime(n
);
1309 xmlChar
*t
= xmlGetNodePath(n
);
1311 log_write(_("Warning: unknown element '%s' at %s. Ignoring."), n
->name
, t
);
1318 rc
= validate_import(n
->children
);
1328 gpg_error_t
update_element_mtime(xmlNodePtr n
)
1330 return add_attribute(n
, NULL
, NULL
);
1333 gpg_error_t
unlink_node(xmlNodePtr n
)
1341 rc
= update_element_mtime(n
->parent
);
1347 xmlDocPtr
parse_doc(const gchar
*xml
, gsize len
)
1349 return xmlReadMemory(xml
, len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);