2005-09-15 09:58:31 -04:00
|
|
|
/* Internal bookmarks XBEL bookmarks basic support */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: Decent XML output.
|
|
|
|
* TODO: Validation of the document (with librxp?). An invalid document can
|
|
|
|
* crash elinks.
|
|
|
|
* TODO: Support all the XBEL elements. */
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif /* HAVE_CONFIG_H */
|
|
|
|
|
|
|
|
#include <ctype.h>
|
2009-01-04 06:59:04 -05:00
|
|
|
#include <errno.h>
|
2005-09-15 09:58:31 -04:00
|
|
|
#include <expat.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "elinks.h"
|
|
|
|
|
|
|
|
#include "bfu/dialog.h"
|
|
|
|
#include "bookmarks/bookmarks.h"
|
|
|
|
#include "bookmarks/backend/common.h"
|
|
|
|
#include "bookmarks/backend/xbel.h"
|
|
|
|
#include "intl/charsets.h"
|
2021-08-08 15:25:08 -04:00
|
|
|
#include "intl/libintl.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "util/conv.h"
|
|
|
|
#include "util/lists.h"
|
|
|
|
#include "util/string.h"
|
|
|
|
|
|
|
|
#define BOOKMARKS_XBEL_FILENAME "bookmarks.xbel"
|
|
|
|
|
|
|
|
|
|
|
|
/* Elements' attributes */
|
|
|
|
struct attributes {
|
|
|
|
LIST_HEAD(struct attributes);
|
|
|
|
|
2021-01-02 10:20:27 -05:00
|
|
|
char *name;
|
|
|
|
char *value;
|
2005-09-15 09:58:31 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Prototypes */
|
|
|
|
static void on_element_open(void *data, const char *name, const char **attr);
|
|
|
|
static void on_element_close(void *data, const char *name);
|
|
|
|
static void on_text(void *data, const XML_Char *text, int len);
|
|
|
|
|
|
|
|
static struct tree_node *new_node(struct tree_node *parent);
|
|
|
|
static void free_node(struct tree_node *node);
|
|
|
|
static void free_xbeltree(struct tree_node *node);
|
2022-01-30 04:44:29 -05:00
|
|
|
static struct tree_node *get_child(struct tree_node *node, const char *name);
|
2021-01-02 10:20:27 -05:00
|
|
|
static char *get_attribute_value(struct tree_node *node,
|
2022-01-30 04:44:29 -05:00
|
|
|
const char *name);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
|
2009-01-04 06:59:04 -05:00
|
|
|
struct read_bookmarks_xbel {
|
|
|
|
int utf8_cp;
|
|
|
|
};
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
static void read_bookmarks_xbel(FILE *f);
|
2022-01-31 09:32:24 -05:00
|
|
|
static const char * filename_bookmarks_xbel(int writing);
|
2009-01-04 06:59:04 -05:00
|
|
|
static int xbeltree_to_bookmarks_list(const struct read_bookmarks_xbel *preload,
|
|
|
|
struct tree_node *root,
|
2005-09-15 09:58:31 -04:00
|
|
|
struct bookmark *current_parent);
|
|
|
|
static void write_bookmarks_list(struct secure_save_info *ssi,
|
2007-07-26 15:39:08 -04:00
|
|
|
LIST_OF(struct bookmark) *bookmarks_list,
|
2005-09-15 09:58:31 -04:00
|
|
|
int n, int folder_state);
|
|
|
|
static void write_bookmarks_xbel(struct secure_save_info *ssi,
|
2007-07-26 15:39:08 -04:00
|
|
|
LIST_OF(struct bookmark) *bookmarks_list);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
/* Element */
|
|
|
|
struct tree_node {
|
2021-01-02 10:20:27 -05:00
|
|
|
char *name; /* Name of the element */
|
|
|
|
char *text; /* Text inside the element */
|
2007-07-26 12:04:35 -04:00
|
|
|
LIST_OF(struct attributes) attrs;
|
2005-09-15 09:58:31 -04:00
|
|
|
struct tree_node *parent;
|
|
|
|
struct tree_node *children;
|
|
|
|
|
|
|
|
struct tree_node *prev;
|
|
|
|
struct tree_node *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct tree_node *root_node = NULL;
|
|
|
|
static struct tree_node *current_node = NULL;
|
|
|
|
|
|
|
|
/* This is 1 so that we won't fail miserably if we read bookmarks in a
|
|
|
|
* different format. */
|
|
|
|
static int readok = 1;
|
|
|
|
|
|
|
|
static void
|
|
|
|
read_bookmarks_xbel(FILE *f)
|
|
|
|
{
|
2021-01-02 10:20:27 -05:00
|
|
|
char in_buffer[BUFSIZ];
|
2005-09-15 09:58:31 -04:00
|
|
|
XML_Parser p;
|
|
|
|
int done = 0;
|
|
|
|
int err = 0;
|
2009-01-04 06:59:04 -05:00
|
|
|
struct read_bookmarks_xbel preload;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
readok = 0;
|
|
|
|
|
|
|
|
p = XML_ParserCreate(NULL);
|
|
|
|
if (!p) {
|
|
|
|
ERROR(gettext("read_bookmarks_xbel(): Error in XML_ParserCreate()"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
XML_SetElementHandler(p, on_element_open, on_element_close);
|
|
|
|
XML_SetCharacterDataHandler(p, on_text);
|
|
|
|
|
|
|
|
while (!done && !err) {
|
|
|
|
size_t len = fread(in_buffer, 1, BUFSIZ, f);
|
|
|
|
|
|
|
|
if (ferror(f)) {
|
|
|
|
ERROR(gettext("read_bookmarks_xbel(): Error reading %s"),
|
|
|
|
filename_bookmarks_xbel(0));
|
|
|
|
err = 1;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
done = feof(f);
|
|
|
|
|
|
|
|
if (!err && !XML_Parse(p, in_buffer, len, done)) {
|
|
|
|
usrerror(gettext("Parse error while processing "
|
|
|
|
"XBEL bookmarks in %s at line %d "
|
|
|
|
"column %d:\n%s"),
|
|
|
|
filename_bookmarks_xbel(0),
|
|
|
|
XML_GetCurrentLineNumber(p),
|
|
|
|
XML_GetCurrentColumnNumber(p),
|
|
|
|
XML_ErrorString(XML_GetErrorCode(p)));
|
|
|
|
err = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-04 06:59:04 -05:00
|
|
|
if (!err) {
|
|
|
|
preload.utf8_cp = get_cp_index("UTF-8");
|
|
|
|
readok = xbeltree_to_bookmarks_list(&preload,
|
|
|
|
root_node->children, /* Top node is xbel */
|
|
|
|
NULL);
|
|
|
|
}
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
XML_ParserFree(p);
|
|
|
|
free_xbeltree(root_node);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
write_bookmarks_xbel(struct secure_save_info *ssi,
|
2007-07-26 15:39:08 -04:00
|
|
|
LIST_OF(struct bookmarks) *bookmarks_list)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2007-08-28 12:41:18 -04:00
|
|
|
int folder_state = get_opt_bool("bookmarks.folder_state", NULL);
|
2005-09-15 09:58:31 -04:00
|
|
|
/* We check for readok in filename_bookmarks_xbel(). */
|
|
|
|
|
|
|
|
secure_fputs(ssi,
|
2009-01-04 06:59:04 -05:00
|
|
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
2005-09-15 09:58:31 -04:00
|
|
|
"<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD XML "
|
|
|
|
"Bookmark Exchange Language 1.0//EN//XML\"\n"
|
|
|
|
" "
|
|
|
|
"\"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">\n\n"
|
|
|
|
"<xbel>\n\n\n");
|
|
|
|
|
|
|
|
|
|
|
|
write_bookmarks_list(ssi, bookmarks_list, 0, folder_state);
|
|
|
|
secure_fputs(ssi, "\n</xbel>\n");
|
|
|
|
}
|
|
|
|
|
2022-01-31 09:32:24 -05:00
|
|
|
static const char *
|
2005-09-15 09:58:31 -04:00
|
|
|
filename_bookmarks_xbel(int writing)
|
|
|
|
{
|
|
|
|
if (writing && !readok) return NULL;
|
|
|
|
return BOOKMARKS_XBEL_FILENAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
indentation(struct secure_save_info *ssi, int num)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < num; i++)
|
|
|
|
secure_fputs(ssi, " ");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-01-02 10:20:27 -05:00
|
|
|
print_xml_entities(struct secure_save_info *ssi, const char *str)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2019-04-21 06:27:40 -04:00
|
|
|
struct string entitized = NULL_STRING;
|
2009-01-04 06:59:04 -05:00
|
|
|
|
|
|
|
if (init_string(&entitized)
|
|
|
|
&& add_html_to_string(&entitized, str, strlen(str))) {
|
|
|
|
secure_fputs(ssi, entitized.source);
|
|
|
|
} else {
|
|
|
|
secsave_errno = SS_ERR_OUT_OF_MEM;
|
|
|
|
ssi->err = ENOMEM;
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
2009-01-04 06:59:04 -05:00
|
|
|
done_string(&entitized);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
write_bookmarks_list(struct secure_save_info *ssi,
|
2007-07-26 15:39:08 -04:00
|
|
|
LIST_OF(struct bookmark) *bookmarks_list,
|
2005-09-15 09:58:31 -04:00
|
|
|
int n, int folder_state)
|
|
|
|
{
|
|
|
|
struct bookmark *bm;
|
|
|
|
|
|
|
|
foreach (bm, *bookmarks_list) {
|
|
|
|
indentation(ssi, n + 1);
|
|
|
|
|
|
|
|
if (bm->box_item->type == BI_FOLDER) {
|
|
|
|
int expanded = folder_state && bm->box_item->expanded;
|
|
|
|
|
|
|
|
secure_fputs(ssi, "<folder folded=\"");
|
|
|
|
secure_fputs(ssi, expanded ? "no" : "yes");
|
|
|
|
secure_fputs(ssi, "\">\n");
|
|
|
|
|
|
|
|
indentation(ssi, n + 2);
|
|
|
|
secure_fputs(ssi, "<title>");
|
|
|
|
print_xml_entities(ssi, bm->title);
|
|
|
|
secure_fputs(ssi, "</title>\n");
|
|
|
|
|
|
|
|
if (!list_empty(bm->child))
|
|
|
|
write_bookmarks_list(ssi, &bm->child, n + 2, folder_state);
|
|
|
|
|
|
|
|
indentation(ssi, n + 1);
|
|
|
|
secure_fputs(ssi, "</folder>\n\n");
|
|
|
|
|
|
|
|
} else if (bm->box_item->type == BI_LEAF) {
|
|
|
|
|
|
|
|
secure_fputs(ssi, "<bookmark href=\"");
|
|
|
|
print_xml_entities(ssi, bm->url);
|
|
|
|
secure_fputs(ssi, "\">\n");
|
|
|
|
|
|
|
|
indentation(ssi, n + 2);
|
|
|
|
secure_fputs(ssi, "<title>");
|
|
|
|
print_xml_entities(ssi, bm->title);
|
|
|
|
secure_fputs(ssi, "</title>\n");
|
|
|
|
|
|
|
|
indentation(ssi, n + 1);
|
|
|
|
secure_fputs(ssi, "</bookmark>\n\n");
|
|
|
|
|
|
|
|
} else if (bm->box_item->type == BI_SEPARATOR) {
|
|
|
|
secure_fputs(ssi, "<separator/>\n\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_element_open(void *data, const char *name, const char **attr)
|
|
|
|
{
|
|
|
|
struct tree_node *node;
|
|
|
|
|
|
|
|
node = new_node(current_node);
|
|
|
|
if (!node) return;
|
|
|
|
|
|
|
|
if (root_node) {
|
|
|
|
if (current_node->children) {
|
|
|
|
struct tree_node *tmp;
|
|
|
|
|
|
|
|
tmp = current_node->children;
|
|
|
|
current_node->children = node;
|
|
|
|
current_node->children->next = tmp;
|
|
|
|
current_node->children->prev = NULL;
|
|
|
|
}
|
|
|
|
else current_node->children = node;
|
|
|
|
}
|
|
|
|
else root_node = node;
|
|
|
|
|
|
|
|
current_node = node;
|
|
|
|
|
2021-01-02 10:20:27 -05:00
|
|
|
current_node->name = stracpy((char *) name);
|
2005-09-15 09:58:31 -04:00
|
|
|
if (!current_node->name) {
|
|
|
|
mem_free(current_node);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
XBEL bug 761: Distinguish between names and values of attributes.
When ELinks is parsing an XML element in from an XBEL bookmark file,
it collects the attributes of the element to the current_node->attrs
list. Previously, struct attributes had room for one string only:
the last element of current_node->attrs was the name of the first
attribute, and it was preceded by the value of the first attribute,
the name of the second attribute, the value of the second attribute,
and so on. However, when get_attribute_value() was looking for a
given name, it compared the values as well. So, if you had for
example <bookmark id="href" href="http://elinks.cz/">, then
get_attribute_value("href") would incorrectly return "href".
To fix this confusion, store values in the new member
attributes.value, rather than in attributes.name.
2006-06-11 08:08:00 -04:00
|
|
|
for (; *attr; attr += 2) {
|
2022-01-16 15:08:50 -05:00
|
|
|
struct attributes *attribute = (struct attributes *)mem_calloc(1, sizeof(*attribute));
|
2021-01-02 10:20:27 -05:00
|
|
|
char *name = stracpy((char *) attr[0]);
|
|
|
|
char *value = stracpy((char *) attr[1]);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
XBEL bug 761: Distinguish between names and values of attributes.
When ELinks is parsing an XML element in from an XBEL bookmark file,
it collects the attributes of the element to the current_node->attrs
list. Previously, struct attributes had room for one string only:
the last element of current_node->attrs was the name of the first
attribute, and it was preceded by the value of the first attribute,
the name of the second attribute, the value of the second attribute,
and so on. However, when get_attribute_value() was looking for a
given name, it compared the values as well. So, if you had for
example <bookmark id="href" href="http://elinks.cz/">, then
get_attribute_value("href") would incorrectly return "href".
To fix this confusion, store values in the new member
attributes.value, rather than in attributes.name.
2006-06-11 08:08:00 -04:00
|
|
|
if (!attribute || !name || !value) {
|
|
|
|
mem_free_if(attribute);
|
|
|
|
mem_free_if(name);
|
|
|
|
mem_free_if(value);
|
2005-09-15 09:58:31 -04:00
|
|
|
free_node(current_node);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
XBEL bug 761: Distinguish between names and values of attributes.
When ELinks is parsing an XML element in from an XBEL bookmark file,
it collects the attributes of the element to the current_node->attrs
list. Previously, struct attributes had room for one string only:
the last element of current_node->attrs was the name of the first
attribute, and it was preceded by the value of the first attribute,
the name of the second attribute, the value of the second attribute,
and so on. However, when get_attribute_value() was looking for a
given name, it compared the values as well. So, if you had for
example <bookmark id="href" href="http://elinks.cz/">, then
get_attribute_value("href") would incorrectly return "href".
To fix this confusion, store values in the new member
attributes.value, rather than in attributes.name.
2006-06-11 08:08:00 -04:00
|
|
|
attribute->name = name;
|
|
|
|
attribute->value = value;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
XBEL bug 761: Distinguish between names and values of attributes.
When ELinks is parsing an XML element in from an XBEL bookmark file,
it collects the attributes of the element to the current_node->attrs
list. Previously, struct attributes had room for one string only:
the last element of current_node->attrs was the name of the first
attribute, and it was preceded by the value of the first attribute,
the name of the second attribute, the value of the second attribute,
and so on. However, when get_attribute_value() was looking for a
given name, it compared the values as well. So, if you had for
example <bookmark id="href" href="http://elinks.cz/">, then
get_attribute_value("href") would incorrectly return "href".
To fix this confusion, store values in the new member
attributes.value, rather than in attributes.name.
2006-06-11 08:08:00 -04:00
|
|
|
add_to_list_end(current_node->attrs, attribute);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_element_close(void *data, const char *name)
|
|
|
|
{
|
|
|
|
current_node = current_node->parent;
|
|
|
|
}
|
|
|
|
|
2021-01-02 10:20:27 -05:00
|
|
|
static char *
|
|
|
|
delete_whites(const char *s)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2021-01-02 10:20:27 -05:00
|
|
|
char *r;
|
2009-01-04 06:59:04 -05:00
|
|
|
int last_was_space = 0, c = 0, i;
|
2005-09-15 09:58:31 -04:00
|
|
|
int len = strlen(s);
|
|
|
|
|
2022-01-16 13:09:27 -05:00
|
|
|
r = (char *)mem_alloc(len + 1);
|
2005-09-15 09:58:31 -04:00
|
|
|
if (!r) return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
2009-01-04 06:59:04 -05:00
|
|
|
/* Recognize only the whitespace characters listed
|
|
|
|
* in section 2.3 of XML 1.1. U+0085 and U+2028 need
|
|
|
|
* not be recognized here because section 2.11 says
|
|
|
|
* the XML processor must translate them to U+000A.
|
2022-06-28 14:25:06 -04:00
|
|
|
* Do not use isspace((unsigned char)) because the string is in UTF-8
|
2009-01-04 06:59:04 -05:00
|
|
|
* and individual bytes might not be characters at
|
|
|
|
* all. */
|
|
|
|
switch (s[i]) {
|
|
|
|
case '\x20': case '\x09': case '\x0D': case '\x0A':
|
|
|
|
if (last_was_space) continue;
|
|
|
|
last_was_space = 1;
|
2005-09-15 09:58:31 -04:00
|
|
|
r[c++] = ' ';
|
2009-01-04 06:59:04 -05:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
last_was_space = 0;
|
|
|
|
r[c++] = s[i];
|
|
|
|
break;
|
|
|
|
}
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
r[c] = '\0';
|
|
|
|
|
|
|
|
/* XXX This should never return NULL, right? wrong! --fabio */
|
|
|
|
/* r = mem_realloc(r, strlen(r + 1)); */
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_text(void *data, const XML_Char *text, int len)
|
|
|
|
{
|
|
|
|
char *tmp;
|
|
|
|
int len2 = 0;
|
|
|
|
|
|
|
|
if (len) {
|
|
|
|
len2 = current_node->text ? strlen(current_node->text) : 0;
|
|
|
|
|
2022-01-16 13:09:27 -05:00
|
|
|
tmp = (char *)mem_realloc(current_node->text, (size_t) (len + 1 + len2));
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
/* Out of memory */
|
|
|
|
if (!tmp) return;
|
|
|
|
|
|
|
|
strncpy(tmp + len2, text, len);
|
|
|
|
tmp[len + len2] = '\0';
|
|
|
|
current_node->text = delete_whites(tmp);
|
|
|
|
|
|
|
|
mem_free(tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* xbel_tree_to_bookmarks_list: returns 0 on fail,
|
|
|
|
* 1 on success */
|
|
|
|
static int
|
2009-01-04 06:59:04 -05:00
|
|
|
xbeltree_to_bookmarks_list(const struct read_bookmarks_xbel *preload,
|
|
|
|
struct tree_node *node,
|
2005-09-15 09:58:31 -04:00
|
|
|
struct bookmark *current_parent)
|
|
|
|
{
|
|
|
|
struct bookmark *tmp;
|
|
|
|
struct tree_node *title;
|
|
|
|
static struct bookmark *lastbm;
|
|
|
|
|
|
|
|
while (node) {
|
|
|
|
if (!strcmp(node->name, "bookmark")) {
|
2021-01-02 10:20:27 -05:00
|
|
|
char *href;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
title = get_child(node, "title");
|
2006-05-28 11:58:02 -04:00
|
|
|
href = get_attribute_value(node, "href");
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2009-01-04 06:59:04 -05:00
|
|
|
intl_set_charset_by_index(preload->utf8_cp);
|
2005-09-15 09:58:31 -04:00
|
|
|
tmp = add_bookmark(current_parent, 0,
|
|
|
|
/* The <title> element is optional */
|
2006-01-30 21:52:48 -05:00
|
|
|
title && title->text ? title->text
|
2021-01-02 10:20:27 -05:00
|
|
|
: (char *) gettext("No title"),
|
2005-09-15 09:58:31 -04:00
|
|
|
/* XXX: The href attribute isn't optional but
|
|
|
|
* we don't validate the source XML yet, so
|
|
|
|
* we can't always assume a non NULL value for
|
|
|
|
* get_attribute_value() */
|
|
|
|
href ? href
|
2021-01-02 10:20:27 -05:00
|
|
|
: (char *) gettext("No URL"));
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
/* Out of memory */
|
|
|
|
if (!tmp) return 0;
|
|
|
|
|
|
|
|
tmp->root = current_parent;
|
|
|
|
lastbm = tmp;
|
|
|
|
|
|
|
|
} else if (!strcmp(node->name, "folder")) {
|
2021-01-02 10:20:27 -05:00
|
|
|
char *folded;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
title = get_child(node, "title");
|
|
|
|
|
2009-01-04 06:59:04 -05:00
|
|
|
intl_set_charset_by_index(preload->utf8_cp);
|
2005-09-15 09:58:31 -04:00
|
|
|
tmp = add_bookmark(current_parent, 0,
|
2006-01-30 21:52:48 -05:00
|
|
|
title && title->text ? title->text
|
2021-01-02 10:20:27 -05:00
|
|
|
: (char *) gettext("No title"),
|
2005-09-15 09:58:31 -04:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* Out of memory */
|
|
|
|
if (!tmp) return 0;
|
|
|
|
|
2006-05-28 11:58:02 -04:00
|
|
|
folded = get_attribute_value(node, "folded");
|
2005-09-15 09:58:31 -04:00
|
|
|
if (folded && !strcmp(folded, "no"))
|
|
|
|
tmp->box_item->expanded = 1;
|
|
|
|
|
|
|
|
lastbm = tmp;
|
|
|
|
|
|
|
|
} else if (!strcmp(node->name, "separator")) {
|
|
|
|
tmp = add_bookmark(current_parent, 0, "-", "");
|
|
|
|
|
|
|
|
/* Out of memory */
|
|
|
|
if (!tmp) return 0;
|
|
|
|
tmp->root = current_parent;
|
|
|
|
lastbm = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->children) {
|
|
|
|
int ret;
|
2009-01-04 06:59:04 -05:00
|
|
|
struct bookmark *parent_for_nested;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
/* If this node is a <folder> element, current parent
|
|
|
|
* changes */
|
2009-01-04 06:59:04 -05:00
|
|
|
if (!strcmp(node->name, "folder"))
|
|
|
|
parent_for_nested = lastbm;
|
|
|
|
else
|
|
|
|
parent_for_nested = current_parent;
|
|
|
|
|
|
|
|
ret = xbeltree_to_bookmarks_list(preload,
|
|
|
|
node->children,
|
|
|
|
parent_for_nested);
|
2005-09-15 09:58:31 -04:00
|
|
|
/* Out of memory */
|
|
|
|
if (!ret) return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
node = node->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Success */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_xbeltree(struct tree_node *node)
|
|
|
|
{
|
|
|
|
struct tree_node *next_node;
|
|
|
|
|
|
|
|
while (node) {
|
|
|
|
|
|
|
|
if (node->children)
|
|
|
|
free_xbeltree(node->children);
|
|
|
|
|
|
|
|
next_node = node->next;
|
|
|
|
free_node(node);
|
|
|
|
|
|
|
|
node = next_node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct tree_node *
|
2022-01-30 04:44:29 -05:00
|
|
|
get_child(struct tree_node *node, const char *name)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
struct tree_node *ret;
|
|
|
|
|
|
|
|
if (!node) return NULL;
|
|
|
|
|
|
|
|
ret = node->children;
|
|
|
|
|
|
|
|
while (ret) {
|
|
|
|
if (!strcmp(name, ret->name)) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = ret->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-01-02 10:20:27 -05:00
|
|
|
static char *
|
2022-01-30 04:44:29 -05:00
|
|
|
get_attribute_value(struct tree_node *node, const char *name)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
struct attributes *attribute;
|
|
|
|
|
XBEL bug 761: Distinguish between names and values of attributes.
When ELinks is parsing an XML element in from an XBEL bookmark file,
it collects the attributes of the element to the current_node->attrs
list. Previously, struct attributes had room for one string only:
the last element of current_node->attrs was the name of the first
attribute, and it was preceded by the value of the first attribute,
the name of the second attribute, the value of the second attribute,
and so on. However, when get_attribute_value() was looking for a
given name, it compared the values as well. So, if you had for
example <bookmark id="href" href="http://elinks.cz/">, then
get_attribute_value("href") would incorrectly return "href".
To fix this confusion, store values in the new member
attributes.value, rather than in attributes.name.
2006-06-11 08:08:00 -04:00
|
|
|
foreach (attribute, node->attrs) {
|
2005-09-15 09:58:31 -04:00
|
|
|
if (!strcmp(attribute->name, name)) {
|
XBEL bug 761: Distinguish between names and values of attributes.
When ELinks is parsing an XML element in from an XBEL bookmark file,
it collects the attributes of the element to the current_node->attrs
list. Previously, struct attributes had room for one string only:
the last element of current_node->attrs was the name of the first
attribute, and it was preceded by the value of the first attribute,
the name of the second attribute, the value of the second attribute,
and so on. However, when get_attribute_value() was looking for a
given name, it compared the values as well. So, if you had for
example <bookmark id="href" href="http://elinks.cz/">, then
get_attribute_value("href") would incorrectly return "href".
To fix this confusion, store values in the new member
attributes.value, rather than in attributes.name.
2006-06-11 08:08:00 -04:00
|
|
|
return attribute->value;
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct tree_node *
|
|
|
|
new_node(struct tree_node *parent)
|
|
|
|
{
|
|
|
|
struct tree_node *node;
|
|
|
|
|
2022-01-16 15:08:50 -05:00
|
|
|
node = (struct tree_node *)mem_calloc(1, sizeof(*node));
|
2005-09-15 09:58:31 -04:00
|
|
|
if (!node) return NULL;
|
|
|
|
|
|
|
|
node->parent = parent ? parent : node;
|
2006-05-28 11:58:02 -04:00
|
|
|
init_list(node->attrs);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_node(struct tree_node *node)
|
|
|
|
{
|
|
|
|
struct attributes *attribute;
|
|
|
|
|
XBEL bug 761: Distinguish between names and values of attributes.
When ELinks is parsing an XML element in from an XBEL bookmark file,
it collects the attributes of the element to the current_node->attrs
list. Previously, struct attributes had room for one string only:
the last element of current_node->attrs was the name of the first
attribute, and it was preceded by the value of the first attribute,
the name of the second attribute, the value of the second attribute,
and so on. However, when get_attribute_value() was looking for a
given name, it compared the values as well. So, if you had for
example <bookmark id="href" href="http://elinks.cz/">, then
get_attribute_value("href") would incorrectly return "href".
To fix this confusion, store values in the new member
attributes.value, rather than in attributes.name.
2006-06-11 08:08:00 -04:00
|
|
|
foreach (attribute, node->attrs) {
|
|
|
|
/* on_element_open() ensures ->name and ->value aren't NULL. */
|
|
|
|
mem_free(attribute->name);
|
|
|
|
mem_free(attribute->value);
|
|
|
|
}
|
2006-05-28 11:58:02 -04:00
|
|
|
free_list(node->attrs); /* Don't free list during traversal */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
mem_free_if(node->name);
|
|
|
|
mem_free_if(node->text);
|
|
|
|
|
|
|
|
mem_free(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read and write functions for the XBEL backend */
|
|
|
|
struct bookmarks_backend xbel_bookmarks_backend = {
|
|
|
|
filename_bookmarks_xbel,
|
|
|
|
read_bookmarks_xbel,
|
|
|
|
write_bookmarks_xbel,
|
|
|
|
};
|