From e9d465dc00673029069fee10393e03ba024959a5 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Thu, 4 Jan 2007 20:48:06 -0500 Subject: [PATCH] Added the TARGET attribute (was going to be VALUE, but TARGET makes more sense). Read PROTOCOL for more information. --- PROTOCOL | 8 +- TODO | 35 ++-- src/commands.c | 498 ++++++++++++++++++++++++++++++++++++++++++++++----------- src/commands.h | 2 +- src/pwmd.c | 27 +--- src/xml.c | 10 +- 6 files changed, 441 insertions(+), 139 deletions(-) rewrite TODO (64%) diff --git a/PROTOCOL b/PROTOCOL index 97bad8cb..1228d08e 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -79,14 +79,14 @@ ATTR SET | DELETE | LIST [] [arg2] account name. Although it can be SET to change the account name. It also won't be shown with the LIST command. - There is one other special attribute which is VALUE. This is like a + There is one other special attribute which is TARGET. This is like a "pointer" that points to another element in the document: - ATTR SET VALUE account[element[...]] account[element[...]] + ATTR SET TARGET account[element[...]] account[element[...]] Then the GET and LIST commands for would show the value of . - Note that if has both a VALUE attribute and an element value, then - only the VALUE attribute will be used in other commands. + Note that if has both a TARGET attribute and an element value, then + only the TARGET attribute will be used in other commands. HELP [] diff --git a/TODO b/TODO dissimilarity index 64% index 5970e6f4..0f83975b 100644 --- a/TODO +++ b/TODO @@ -1,17 +1,18 @@ -More secure memory allocation in libxml, libgcrypt and everywhere else. Both -of these API's have the ability to specify custom memory allocators. - -Change SETATTR's second argument to support an element path and not just an -account name. Also add attribute DEST to have the specified element path -"point" to another element path in the document: - - list account - BEGIN ... - account isp username value1 - OK - setattr account2 isp2 username DEST account isp username - OK - list account2 - BEGIN ... - account2 isp2 username value1 - OK +More secure memory allocation in libxml, libgcrypt and everywhere else. Both +of these API's have the ability to specify custom memory allocators. + +Let the LIST command take an element path as an argument. + +If an element has a TARGET attribute, should following elements be inherited +from the target?: + + list orig + BEGIN ... + orig element1 element2 value + OK + attr set target new orig + OK + get new element1 + BEGIN ... + new element2 value + OK diff --git a/src/commands.c b/src/commands.c index a9e5f15e..fc5de48a 100644 --- a/src/commands.c +++ b/src/commands.c @@ -380,27 +380,23 @@ again: * client->reader should be at the position in the document where the element * search should start. It won't search past the closing account element. */ -static gboolean get_elements(struct client_s *client, gchar **req) +static gboolean get_elements(struct client_s *client, xmlTextReaderPtr reader, + gchar **req, gint quiet) { gint i; if (!req || !req[0]) { - send_error(client, EPWMD_COMMAND_SYNTAX); + if (!quiet) + send_error(client, EPWMD_COMMAND_SYNTAX); return FALSE; } for (i = 0; req[i]; i++) { - switch (find_element(client->reader, req[i], req[i+1] != NULL)) { - case 0: - break; - case 1: + if (find_element(reader, req[i], req[i+1] != NULL) == FALSE) { + if (!quiet) send_error(client, EPWMD_ELEMENT_NOT_FOUND); - return FALSE; - case 2: - send_error(client, EPWMD_TRAILING_ELEMENT); - return FALSE; - default: - break; + + return FALSE; } } @@ -507,20 +503,22 @@ static gboolean contains_whitespace(const gchar *str) } /* - * Create a new or modify an existing element. + * the 'reader' should be at the element of the document where the elements + * 'req' are to be created. */ -static gboolean create_elements(struct client_s *client, gchar **req) +static gboolean create_elements(struct client_s *client, xmlTextReaderPtr reader, + gchar **req, gint novalue) { gint i; gboolean ret = TRUE; xmlNodePtr r; - r = xmlTextReaderCurrentNode(client->reader); + r = xmlTextReaderCurrentNode(reader); - if (xmlTextReaderDepth(client->reader) > 1) + if (xmlTextReaderDepth(reader) > 1) r = r->parent; - for (i = 1; req[i]; i++) { + for (i = 0; req[i]; i++) { xmlNodePtr n; gchar *b64 = NULL; @@ -536,11 +534,11 @@ static gboolean create_elements(struct client_s *client, gchar **req) /* * The value of the element tree. */ - if (!req[i+1]) { + if (!req[i+1] && !novalue) { /* * Prevent creating 'text' elements in the root of the account. */ - if (i < 2) { + if (i < 1) { send_error(client, EPWMD_ROOT_TEXT_ELEMENT); return FALSE; } @@ -568,10 +566,14 @@ static gboolean create_elements(struct client_s *client, gchar **req) } else r = n; + + if (!req[i+1] && novalue) + return TRUE; } return ret; } + /* * FIXME reuse reader handle */ @@ -665,58 +667,134 @@ again: } xmlTextReaderNext(client->reader); - return create_elements(client, req); + return create_elements(client, client->reader, req+1, 0); } -gboolean get_command(struct client_s *client, gchar **req) +static gboolean do_get_command(struct client_s *client, xmlTextReaderPtr reader, + gchar **req, xmlChar **content, gint quiet, gint list) { xmlNodePtr n; - xmlChar *content; - gint type; + xmlAttrPtr a; + gchar **nreq; + gboolean ret; + xmlChar *p; - if (reset_reader(client->doc, &client->reader) == FALSE) { - send_error(client, EPWMD_LIBXML_ERROR); + if (reset_reader(client->doc, &reader) == FALSE) { + if (!quiet) + send_error(client, EPWMD_LIBXML_ERROR); return FALSE; } - if (find_account(client->reader, req[0]) == FALSE) { - send_error(client, EPWMD_ELEMENT_NOT_FOUND); + if (find_account(reader, req[0]) == FALSE) { + if (!quiet) + send_error(client, EPWMD_ELEMENT_NOT_FOUND); return FALSE; } - if (get_elements(client, req + 1) == FALSE) - return FALSE; + /* + * May be an account with only a TARGET attribute. + */ + if (req[1]) { + if (get_elements(client, reader, req + 1, 0) == FALSE) + return FALSE; + } - if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) { - send_error(client, EPWMD_LIBXML_ERROR); + if ((n = xmlTextReaderCurrentNode(reader)) == NULL) { + if (!quiet) + send_error(client, EPWMD_LIBXML_ERROR); return FALSE; } - switch (xmlTextReaderNext(client->reader)) { + /* + * If the current element has a TARGET attribute, the value of the + * attribute is an element path somewhere else in the document. Use this + * value and not any TEXT element value. The value may be another element + * with a TARGET attribute and this function will recurse until a non-TARGET + * attribute in the element is found. + */ + if ((a = xmlHasProp(n, (xmlChar *)"target")) != NULL) { + if ((p = xmlNodeGetContent(a->children)) != NULL) { + if (strchr((gchar *)p, '\t') != NULL) { + if ((nreq = split_input_line((gchar *)p, "\t", 0)) == NULL) { + xmlFree(p); + + if (!quiet) + send_error(client, EPWMD_INVALID_ELEMENT); + return FALSE; + } + } + else { + if ((nreq = split_input_line((gchar *)p, " ", 0)) == NULL) { + xmlFree(p); + + if (!quiet) + send_error(client, EPWMD_INVALID_ELEMENT); + return FALSE; + } + } + + xmlFree(p); + ret = do_get_command(client, reader, nreq, content, quiet, list); + g_strfreev(nreq); + return ret; + } + } + + switch (xmlTextReaderNext(reader)) { case -1: - send_error(client, EPWMD_LIBXML_ERROR); + if (!quiet) + send_error(client, EPWMD_LIBXML_ERROR); return FALSE; case 0: - send_error(client, EPWMD_EMPTY_ELEMENT); + if (!quiet) + send_error(client, EPWMD_EMPTY_ELEMENT); return FALSE; default: break; } - if ((type = xmlTextReaderNodeType(client->reader)) == -1) { - send_error(client, EPWMD_LIBXML_ERROR); - return FALSE; + switch (xmlTextReaderNodeType(reader)) { + case XML_READER_TYPE_END_ELEMENT: + /* + * May be an empty element after an ATTR DELETE TARGET command. + */ + return TRUE; + case XML_READER_TYPE_TEXT: + break; + case -1: + if (!quiet) + send_error(client, EPWMD_LIBXML_ERROR); + + return FALSE; + default: + if (!quiet) { + if (n->children && !list) + send_error(client, EPWMD_TRAILING_ELEMENT); + else if (!n->children && !list) + send_error(client, EPWMD_INVALID_ELEMENT); + } + return FALSE; } - if (type != XML_READER_TYPE_TEXT) { - send_error(client, EPWMD_INVALID_ELEMENT); + if ((*content = xmlNodeGetContent(n)) == NULL) { + if (!quiet) + send_error(client, EPWMD_EMPTY_ELEMENT); return FALSE; } - if ((content = xmlNodeGetContent(n)) == NULL) { - send_error(client, EPWMD_EMPTY_ELEMENT); + return TRUE; +} + +/* + * Retrieves the value associated with the element tree 'req'. + */ +gboolean get_command(struct client_s *client, xmlTextReaderPtr reader, + gchar **req, gint quiet) +{ + xmlChar *content = NULL; + + if (do_get_command(client, reader, req, &content, quiet, 0) == FALSE) return FALSE; - } send_to_client(client, "BEGIN %li\n%s\nOK \n", xmlStrlen(content), content); memset(content, 0, xmlStrlen(content)); @@ -724,16 +802,65 @@ gboolean get_command(struct client_s *client, gchar **req) return TRUE; } +static gchar *element_path_to_req(const gchar *account, xmlChar *path, + const xmlChar *content) +{ + xmlChar *p = path; + gint n; + gchar *buf; + + if (!p) + return NULL; + + for (n = 0; *p && n < 3; p++) { + if (*p == '/') + n++; + } + + if (strstr((gchar *)p, "text()") != NULL) + p[xmlStrlen(p) - 7] = 0; + + for (n = 0; p[n]; n++) { + if (p[n] == '/') + p[n] = '\t'; + } + + buf = g_strdup_printf("%s\t%s\t%s", account, p, content); + return buf; +} + +static gboolean append_to_array(gchar ***array, gint *total, const gchar *str) +{ + gchar **a; + gint t = *total; + + if ((a = g_realloc(*array, (t + 2) * sizeof(gchar *))) == NULL) + return FALSE; + + a[t++] = g_strdup(str); + a[t] = NULL; + *total = t; + *array = a; + return TRUE; +} + gboolean list_command(struct client_s *client, gchar *str) { gchar *dst = NULL; gchar *p = str; - xmlNodePtr n; - gint depth = 0; gchar **elements = NULL; - gint i = 0; + gint pwmd_errno = -1; + gchar *account; + gint total = 0; + xmlChar *path = NULL; + xmlAttrPtr a; + xmlNodePtr n; + xmlChar *content; + xmlTextReaderPtr r = NULL; + gchar **nreq; + gboolean ret; + gint type; gchar *line; - int pwmd_errno = -1; if (reset_reader(client->doc, &client->reader) == FALSE) { send_error(client, EPWMD_LIBXML_ERROR); @@ -752,73 +879,135 @@ list_only: memset(dst, 0, strlen(dst)); g_free(dst); } + + return TRUE; } - else { - p = str + 5; - while (*p && isspace(*p)) - p++; + p = str + 5; - if (!*p) - goto list_only; + while (*p && isspace(*p)) + p++; - if (find_account(client->reader, p) == FALSE) { - send_error(client, EPWMD_ELEMENT_NOT_FOUND); + if (!*p) + goto list_only; + + if (find_account(client->reader, p) == FALSE) { + send_error(client, EPWMD_ELEMENT_NOT_FOUND); + return FALSE; + } + + if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) { + send_error(client, EPWMD_LIBXML_ERROR); + return FALSE; + } + + if ((a = xmlHasProp(n, (xmlChar *)"target")) != NULL) { + if (reset_reader(client->doc, &client->reader) == FALSE) { + send_error(client, EPWMD_LIBXML_ERROR); return FALSE; } - depth = xmlTextReaderDepth(client->reader); + if ((content = xmlNodeGetContent(a->children)) != NULL) { + if (find_account(client->reader, (gchar *)content) == FALSE) { + xmlFree(content); + send_error(client, EPWMD_ELEMENT_NOT_FOUND); + return FALSE; + } - while (xmlTextReaderNext(client->reader) == 1) { - gchar *buf; - gint x = 0; + xmlFree(content); + } + } - if (xmlTextReaderDepth(client->reader) == depth) - break; + account = g_strdup(p); - n = xmlTextReaderCurrentNode(client->reader); - - if (xmlTextReaderNodeType(client->reader) == XML_READER_TYPE_TEXT) { - xmlChar *np = xmlGetNodePath(n), *t = np; + while (xmlTextReaderNext(client->reader) == 1) { + if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) { + send_error(client, EPWMD_LIBXML_ERROR); + return FALSE; + } + + /* + * If the current element has a TARGET attribute, the value of the + * attribute is an element path somewhere else in the document. Use this + * value and not any TEXT element value. + */ + type = xmlTextReaderNodeType(client->reader); + a = xmlHasProp(n, (xmlChar *)"target"); + + if (type == XML_READER_TYPE_ELEMENT && a) { + if ((content = xmlNodeGetContent(a->children)) != NULL) { + path = xmlStrdup(xmlGetNodePath(n)); + + if ((nreq = split_input_line((gchar *)content, "\t", 0)) == NULL) { + if (elements) + g_strfreev(elements); - for (x = 0; *t && x < 3; t++) { - if (*t == '/') - x++; + xmlFree(path); + xmlFree(content); + send_error(client, EPWMD_INVALID_ELEMENT); + return FALSE; } - t[xmlStrlen(t) - 7] = 0; + xmlFree(content); + r = NULL; + + if ((ret = do_get_command(client, r, nreq, &content, 0, 1)) == TRUE) { + if (content && *content) { + line = element_path_to_req(account, path, content); + + if (append_to_array(&elements, &total, line) == FALSE) { + if (elements) + g_strfreev(elements); + + xmlFree(path); + g_free(line); + g_strfreev(nreq); + xmlFreeTextReader(r); + send_error(client, EPWMD_ERROR); + return FALSE; + } - for (x = 0; t[x]; x++) { - if (t[x] == '/') - t[x] = '\t'; + memset(line, 0, g_utf8_strlen(line, -1)); + g_free(line); + } } - buf = g_malloc(xmlStrlen(t)+xmlStrlen(n->content)+strlen(p)+3); - g_sprintf(buf, "%s\t%s\t%s", p, t, n->content); - elements = g_realloc(elements, (i + 2) * sizeof(gchar *)); - elements[i++] = buf; - elements[i] = NULL; - xmlFree(np); + g_strfreev(nreq); + xmlFreeTextReader(r); + xmlFree(path); + continue; } } - if (!elements) { - send_error(client, EPWMD_EMPTY_ELEMENT); - return FALSE; + if (type == XML_READER_TYPE_TEXT) { + xmlChar *np = xmlStrdup(xmlGetNodePath(n)); + + content = xmlNodeGetContent(n); + line = element_path_to_req(account, np, content); + xmlFree(np); + append_to_array(&elements, &total, line); + memset(line, 0, g_utf8_strlen(line, -1)); + g_free(line); } + } - line = g_strjoinv("\n", elements); - send_to_client(client, "BEGIN %li\n%s\nOK \n", - g_utf8_strlen(line, -1), line); - g_strfreev(elements); - g_free(line); + if (!elements) { + send_error(client, EPWMD_EMPTY_ELEMENT); + g_free(account); + return FALSE; } + g_free(account); + line = g_strjoinv("\n", elements); + send_to_client(client, "BEGIN %li\n%s\nOK \n", + g_utf8_strlen(line, -1), line); + g_strfreev(elements); + g_free(line); return TRUE; } /* - * The client->reader handle should be at the position in the document where + * The client->reader handle should be at the element in the document where * the attribute will be created or modified. */ static gboolean add_attribute(struct client_s *client, const gchar *name, const gchar *value) @@ -877,7 +1066,7 @@ static gboolean attribute_list(struct client_s *client, gchar **req) } if (epath[1]) { - if ((get_elements(client, epath+1)) == FALSE) + if ((get_elements(client, client->reader, epath+1, 0)) == FALSE) goto blah; } @@ -960,7 +1149,7 @@ static gboolean attribute_delete(struct client_s *client, gchar **req) } if (epath[1]) { - if ((get_elements(client, epath+1)) == FALSE) + if ((get_elements(client, client->reader, epath+1, 0)) == FALSE) goto blah; } @@ -986,8 +1175,131 @@ blah: return FALSE; } -static gboolean value_attribute(struct client_s *client, gchar **req) +/* + * req[0] - source element path + * req[1] - destination element path + */ +static gboolean target_attribute(struct client_s *client, gchar **req) { + gchar **src, **dst, *line; + + if (!req || !req[0] || !req[1]) { + send_error(client, EPWMD_COMMAND_SYNTAX); + return FALSE; + } + + if ((src = split_input_line(req[0], "\t", 0)) == NULL) { + /* + * The first argument may be only an account. + */ + if ((src = split_input_line(req[0], " ", 0)) == NULL) { + send_error(client, EPWMD_COMMAND_SYNTAX); + return FALSE; + } + } + + if ((dst = split_input_line(req[1], "\t", 0)) == NULL) { + /* + * The first argument may be only an account. + */ + if ((dst = split_input_line(req[1], " ", 0)) == NULL) { + send_error(client, EPWMD_COMMAND_SYNTAX); + return FALSE; + } + } + + /* + * Prevent an element tree pointing to only and account. Accounts require + * at least one element. Accounts pointing to accounts are allowed. + */ + if ((!src[1] && dst[1]) || (!dst[1] && src[1])) { + send_error(client, EPWMD_ATTR_SYNTAX); + return FALSE; + } + + if (reset_reader(client->doc, &client->reader) == FALSE) { + send_error(client, EPWMD_LIBXML_ERROR); + return FALSE; + } + + /* + * Make sure the destination element path exists. + */ + if (find_account(client->reader, dst[0]) == FALSE) { + send_error(client, EPWMD_ELEMENT_NOT_FOUND); + return FALSE; + } + + if (dst[1]) { + if (get_elements(client, client->reader, dst+1, 0) == FALSE) + return FALSE; + } + + if (reset_reader(client->doc, &client->reader) == FALSE) { + send_error(client, EPWMD_LIBXML_ERROR); + return FALSE; + } + + /* + * If the source element tree doesn't exist, create it. + */ + if (find_account(client->reader, src[0]) == FALSE) { + if (new_account(client->doc, src[0]) == FALSE) { + send_error(client, EPWMD_LIBXML_ERROR); + return FALSE; + } + + if (reset_reader(client->doc, &client->reader) == FALSE) { + send_error(client, EPWMD_LIBXML_ERROR); + return FALSE; + } + + if (find_account(client->reader, src[0]) == FALSE) { + send_error(client, EPWMD_ELEMENT_NOT_FOUND); + return FALSE; + } + } + + if (src[1]) { + if (get_elements(client, client->reader, src+1, 1) == FALSE) { + if (reset_reader(client->doc, &client->reader) == FALSE) { + send_error(client, EPWMD_LIBXML_ERROR); + return FALSE; + } + + if (find_account(client->reader, src[0]) == FALSE) { + send_error(client, EPWMD_ELEMENT_NOT_FOUND); + return FALSE; + } + + xmlTextReaderNext(client->reader); + + if (create_elements(client, client->reader, src+1, 1) == FALSE) + return FALSE; + + if (reset_reader(client->doc, &client->reader) == FALSE) { + send_error(client, EPWMD_LIBXML_ERROR); + return FALSE; + } + + if (find_account(client->reader, src[0]) == FALSE) { + send_error(client, EPWMD_ELEMENT_NOT_FOUND); + return FALSE; + } + + if (get_elements(client, client->reader, src+1, 0) == FALSE) + return FALSE; + } + } + + line = g_strjoinv("\t", dst); + + if (add_attribute(client, "target", line) == FALSE) { + g_free(line); + return FALSE; + } + + g_free(line); return TRUE; } @@ -1069,8 +1381,8 @@ static gboolean attribute_set(struct client_s *client, gchar **req) if (strchr(req[1], '\t') == NULL) return name_attribute(client, req + 1); } - else if (g_ascii_strcasecmp(req[0], "VALUE") == 0) - return value_attribute(client, req + 1); + else if (g_ascii_strcasecmp(req[0], "TARGET") == 0) + return target_attribute(client, req + 1); if ((epath = split_input_line(req[1], "\t", 0)) == NULL) { /* @@ -1093,7 +1405,7 @@ static gboolean attribute_set(struct client_s *client, gchar **req) } if (epath[1]) { - if ((get_elements(client, epath+1)) == FALSE) + if ((get_elements(client, client->reader, epath+1, 0)) == FALSE) goto blah; } @@ -1270,7 +1582,7 @@ gboolean help_command(struct client_s *client, const gchar *what) line = "NFO syntax: ATTR SET|DELETE|LIST [ATTRIBUTE] arg1 [arg2]\n" "NFO ATTR SET NAME account value\n" - "NFO ATTR SET VALUE account[element[...]] account[element[...]\n" + "NFO ATTR SET TARGET account[element[...]] account[element[...]\n" "NFO ATTR SET attribute account[element[...]] attribute_value\n" "NFO ATTR DELETE attribute account[element[...]]\n" "NFO ATTR LIST account[element[...]]\n"; diff --git a/src/commands.h b/src/commands.h index 6db760c1..4858fd0a 100644 --- a/src/commands.h +++ b/src/commands.h @@ -23,7 +23,7 @@ gboolean open_command(struct client_s *client, gchar **req); gboolean save_command(struct client_s *client, const gchar *filename, gchar *b64key); gboolean delete_command(struct client_s *client, gchar **req); gboolean store_command(struct client_s *client, gchar **req); -gboolean get_command(struct client_s *client, gchar **req); +gboolean get_command(struct client_s *client, xmlTextReaderPtr r, gchar **req, gint quiet); gboolean list_command(struct client_s *client, gchar *str); gboolean attr_command(struct client_s *client, gchar **req); gboolean cache_command(struct client_s *client, gchar **req); diff --git a/src/pwmd.c b/src/pwmd.c index 6b708562..51b96109 100644 --- a/src/pwmd.c +++ b/src/pwmd.c @@ -54,32 +54,21 @@ void send_to_client(struct client_s *client, const gchar *fmt, ...) { va_list ap; - gint n; + gint n = 0; gchar **p; va_start(ap, fmt); - if (client->outbuf) { + if (client->outbuf) for (p = client->outbuf, n = 0; *p; p++, n++); - if ((client->outbuf = g_realloc(client->outbuf, (n + 2) * sizeof(gchar *))) == NULL) { - warn("g_realloc()"); - return; - } - - client->outbuf[n++] = g_strdup_vprintf(fmt, ap); - client->outbuf[n] = NULL; - } - else { - if ((client->outbuf = g_realloc(client->outbuf, 2 * sizeof(gchar *))) == NULL) { - warn("g_realloc()"); - return; - } - - client->outbuf[0] = g_strdup_vprintf(fmt, ap); - client->outbuf[1] = NULL; + if ((client->outbuf = g_realloc(client->outbuf, (n + 2) * sizeof(gchar *))) == NULL) { + warn("g_realloc()"); + return; } + client->outbuf[n++] = g_strdup_vprintf(fmt, ap); + client->outbuf[n] = NULL; va_end(ap); } @@ -247,7 +236,7 @@ static gint input_parser(gchar *str) send_error(cl, EPWMD_NO_FILE); else { if ((req = split_input_line(t, "\t", 0)) != NULL) - get_command(cl, req); + get_command(cl, cl->reader, req, 0); else send_error(cl, EPWMD_COMMAND_SYNTAX); } diff --git a/src/xml.c b/src/xml.c index a184e7c7..414e3b03 100644 --- a/src/xml.c +++ b/src/xml.c @@ -160,13 +160,13 @@ gboolean find_account(xmlTextReaderPtr reader, gchar *name) return FALSE; } -gint find_element(xmlTextReaderPtr reader, gchar *e, gint more) +gboolean find_element(xmlTextReaderPtr reader, gchar *e, gint more) { xmlNodePtr n; while (xmlTextReaderRead(reader) == 1) { if ((n = xmlTextReaderCurrentNode(reader)) == NULL) - return 1; + return FALSE; /* * Stop processing after the closing account element to prevent @@ -175,14 +175,14 @@ gint find_element(xmlTextReaderPtr reader, gchar *e, gint more) if (xmlTextReaderDepth(reader) == 1 && xmlStrcmp(n->name, (xmlChar *)"account") == 0 && xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) - return 1; + return FALSE; if (xmlStrcmp(n->name, (xmlChar *)e) == 0 && xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) - return 0; + return TRUE; } - return 1; + return FALSE; } xmlNodePtr find_node(xmlNodePtr root, xmlChar *name) -- 2.11.4.GIT