2
* $Id: search_xml.c,v 1.23 2005/06/25 01:37:44 daichik Exp $
4
* Copyright (c) 2002-2003, Richard Eckart
6
*----------------------------------------------------------------------
7
* This file is part of gtk-gnutella.
9
* gtk-gnutella is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* gtk-gnutella is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with gtk-gnutella; if not, write to the Free Software
22
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
*----------------------------------------------------------------------
30
* Persistance for searches and filters in XML format.
32
* @author Richard Eckart
38
RCSID("$Id: search_xml.c,v 1.23 2005/06/25 01:37:44 daichik Exp $");
40
#include <libxml/tree.h>
41
#include <libxml/parser.h>
43
#include "filter_core.h"
44
#include "search_xml.h"
48
#include "if/gui_property_priv.h"
49
#include "if/gnet_property.h"
50
#include "if/bridge/ui2c.h"
52
#include "lib/glib-missing.h"
54
#include "lib/override.h" /* Must be the last header included */
59
#define TO_BOOL(v) ((v) != 0 ? TRUE : FALSE)
61
typedef struct node_parser {
63
void (*parser_func)(xmlNodePtr, gpointer);
68
* The rulesets are defined in filter.c, but I don't want
69
* them to be public. They are only needed here. As are
70
* global_ruleset_pre and global_ruleset_post.
72
extern void dump_ruleset(GList *ruleset);
73
extern void dump_filter(filter_t *filter);
75
extern GList *filters;
76
extern GList *filters_current;
79
* Private function prototypes
81
static void parse_xml(xmlNodePtr xmlnode, gpointer user_data);
82
static void builtin_to_xml(xmlNodePtr);
83
static void search_to_xml(xmlNodePtr, search_t *);
84
static void filter_to_xml(xmlNodePtr, filter_t *);
85
static void rule_to_xml(xmlNodePtr, rule_t *);
86
static void xml_to_builtin(xmlNodePtr, gpointer);
87
static void xml_to_search(xmlNodePtr, gpointer);
88
static void xml_to_filter(xmlNodePtr, gpointer);
89
static void xml_to_text_rule(xmlNodePtr, gpointer);
90
static void xml_to_ip_rule(xmlNodePtr, gpointer);
91
static void xml_to_size_rule(xmlNodePtr, gpointer);
92
static void xml_to_jump_rule(xmlNodePtr, gpointer);
93
static void xml_to_sha1_rule(xmlNodePtr, gpointer);
94
static void xml_to_flag_rule(xmlNodePtr, gpointer);
95
static void xml_to_state_rule(xmlNodePtr, gpointer);
96
static guint16 get_rule_flags_from_xml(xmlNodePtr);
97
static xmlAttrPtr xml_prop_printf(xmlNodePtr node, const gchar *name,
98
const char *fmt, ...) G_GNUC_PRINTF(3, 4);
103
static const gchar NODE_BUILTIN[] = "BuiltIn";
104
static const gchar NODE_SEARCH[] = "Search";
105
static const gchar NODE_FILTER[] = "Filter";
106
static const gchar NODE_RULE_TEXT[] = "TextRule";
107
static const gchar NODE_RULE_IP[] = "IpRule";
108
static const gchar NODE_RULE_SIZE[] = "SizeRule";
109
static const gchar NODE_RULE_JUMP[] = "JumpRule";
110
static const gchar NODE_RULE_SHA1[] = "SHA1Rule";
111
static const gchar NODE_RULE_FLAG[] = "FlagRule";
112
static const gchar NODE_RULE_STATE[] = "StateRule";
114
static const gchar TAG_BUILTIN_SHOW_UID[] = "ShowUID";
115
static const gchar TAG_BUILTIN_DROP_UID[] = "DropUID";
116
static const gchar TAG_BUILTIN_DOWNLOAD_UID[] = "DownloadUID";
117
static const gchar TAG_BUILTIN_NODOWNLOAD_UID[] = "NoDownloadUID";
118
static const gchar TAG_BUILTIN_RETURN_UID[] = "ReturnUID";
119
static const gchar TAG_FILTER_NAME[] = "Name";
120
static const gchar TAG_FILTER_GLOBAL[] = "Global";
121
static const gchar TAG_FILTER_UID[] = "UID";
122
static const gchar TAG_FILTER_ACTIVE[] = "Active";
123
static const gchar TAG_SEARCH_QUERY[] = "Query";
124
static const gchar TAG_SEARCH_ENABLED[] = "Enabled";
125
static const gchar TAG_SEARCH_SPEED[] = "Speed";
126
static const gchar TAG_SEARCH_PASSIVE[] = "Passive";
127
static const gchar TAG_SEARCH_REISSUE_TIMEOUT[] = "ReissueTimeout";
128
static const gchar TAG_SEARCH_SORT_COL[] = "SortCol";
129
static const gchar TAG_SEARCH_SORT_ORDER[] = "SortOrder";
130
static const gchar TAG_RULE_TEXT_CASE[] = "Case";
131
static const gchar TAG_RULE_TEXT_MATCH[] = "Match";
132
static const gchar TAG_RULE_TEXT_TYPE[] = "Type";
133
static const gchar TAG_RULE_IP_ADDR[] = "Address";
134
static const gchar TAG_RULE_IP_MASK[] = "Netmask";
135
static const gchar TAG_RULE_SIZE_LOWER[] = "Lower";
136
static const gchar TAG_RULE_SIZE_UPPER[] = "Upper";
137
static const gchar TAG_RULE_SHA1_HASH[] = "Hash";
138
static const gchar TAG_RULE_SHA1_FILENAME[] = "OriginalFilename";
139
static const gchar TAG_RULE_NEGATE[] = "Negate";
140
static const gchar TAG_RULE_ACTIVE[] = "Active";
141
static const gchar TAG_RULE_SOFT[] = "Soft";
142
static const gchar TAG_RULE_TARGET[] = "Target";
143
static const gchar TAG_RULE_FLAG_BUSY[] = "Busy";
144
static const gchar TAG_RULE_FLAG_PUSH[] = "Push";
145
static const gchar TAG_RULE_FLAG_STABLE[] = "Stable";
146
static const gchar TAG_RULE_STATE_DISPLAY[] = "Display";
147
static const gchar TAG_RULE_STATE_DOWNLOAD[] = "Download";
149
static const gchar search_file_xml[] = "searches.xml";
150
static const gchar search_file_xml_new[] = "searches.xml.new";
151
static const gchar search_file_xml_old[] = "searches.xml.orig";
153
static GHashTable *target_map = NULL;
154
static GHashTable *id_map = NULL;
156
static node_parser_t parser_map[] = {
157
{ NODE_BUILTIN, xml_to_builtin },
158
{ NODE_SEARCH, xml_to_search },
159
{ NODE_FILTER, xml_to_filter },
160
{ NODE_RULE_TEXT, xml_to_text_rule },
161
{ NODE_RULE_IP, xml_to_ip_rule },
162
{ NODE_RULE_SIZE, xml_to_size_rule },
163
{ NODE_RULE_JUMP, xml_to_jump_rule },
164
{ NODE_RULE_SHA1, xml_to_sha1_rule },
165
{ NODE_RULE_FLAG, xml_to_flag_rule },
166
{ NODE_RULE_STATE, xml_to_state_rule },
170
/** Get rid of the obnoxious (xmlChar *) */
171
static inline gchar *
172
xml_get_string(xmlNode *node, const gchar *id)
174
return (gchar *) xmlGetProp(node, (const xmlChar *) id);
177
static inline const xmlChar *
178
gchar_to_xmlChar(const gchar *p)
180
return (const xmlChar *) p;
183
static inline xmlNodePtr
184
xml_new_empty_child(xmlNodePtr parent, const gchar *name)
186
return xmlNewChild(parent, NULL, gchar_to_xmlChar(name), NULL);
191
* A wrapper around parse_uint64. It's a little stricter, so that trailing
192
* characters enforce an error. It accepts base 10 (decimal) only. On failure
193
* *error will be set to a non-zero "errno" value.
195
* @param buf the string to parse.
196
* @param error an int variable which will indicate success or failure.
197
* @return On success, the parsed value is returned.
200
parse_number(const gchar *buf, gint *error)
205
g_assert(buf != NULL);
206
g_assert(error != NULL);
208
ret = parse_uint64(buf, &endptr, 10, error);
209
if (0 == *error && *endptr != '\0') {
213
g_message("buf=\"%s\"", buf);
221
* A wrapper around parse_uint64. It's a little stricter, so that trailing
222
* characters enforce an error. It accepts base 16 (decimal) only. On failure
223
* *error will be set to a non-zero "errno" value. The value is casted to
226
* @param buf the string to parse.
227
* @param error an int variable which will indicate success or failure.
228
* @return On success, the parsed value is returned as a pointer.
231
parse_target(const gchar *buf, gint *error)
235
gulong target; /* Not guint32! for backwards compatibility. See below. */
237
g_assert(buf != NULL);
238
g_assert(error != NULL);
240
if ('0' == buf[0] && 'x' == buf[1]) {
242
* In previous versions, targets were printed using "%p". This format
243
* is implementation-specific and thus causes a non-portable
244
* configuration. We expect a hexadecimal value that is optionally
250
v = parse_uint64(buf, &endptr, 16, error);
251
if (0 == *error && *endptr != '\0') {
255
* For backwards compatibility we allow values above 2^32-1 if the
256
* machine doesn't use 32-bit wide pointers. Older versions used
257
* the pointer casted to an integer type as target ID.
259
if (0 == *error && 4 == sizeof(gpointer) && v > (~(guint32) 0)) {
263
g_message("buf=\"%s\"", buf);
269
/* Not using GUINT_TO_POINTER() is intentional to prevent truncation
270
* to 32-bit for backwards compability as explained above. */
271
return (gpointer) target;
275
* Returns the next available target ID.
277
* @param do_reset if TRUE, the ID counter is reset to an initial value.
278
* @return a 32-bit integer stuffed into a pointer
281
target_new_id(gboolean do_reset)
283
static guint32 id_counter;
286
/* If target_map is NULL, the counter is reset */
291
/* 4 billion filters/searches should be enough for everyone */
292
g_assert(0 != id_counter);
296
return GUINT_TO_POINTER(ret);
300
* Resets the target ID counter and frees target_map if it was created.
303
target_map_reset(void)
305
target_new_id(TRUE); /* Reset */
307
g_hash_table_destroy(target_map);
313
* Creates a string representation of a ``target''.
315
* @param target a filter target
316
* @return a static buffer holding the string representation
319
target_to_string(filter_t *target)
322
static gchar buf[128];
325
target_new_id(TRUE); /* Reset */
326
target_map = g_hash_table_new(NULL, NULL);
329
if (!g_hash_table_lookup_extended(target_map, target, NULL, &value)) {
330
value = target_new_id(FALSE);
331
g_hash_table_insert(target_map, target, value);
334
gm_snprintf(buf, sizeof buf, "0x%x", GPOINTER_TO_UINT(value));
340
* A wrapper around xmlSetProp() to get rid of (xmlChar *).
342
* @param node the node
343
* @param name the attribute name
344
* @param value an UTF-8 encoded string
345
* @return the result of xmlSetProp().
347
static inline xmlAttrPtr
348
xml_prop_set(xmlNodePtr node, const gchar *name, const char *value)
350
return xmlSetProp(node, gchar_to_xmlChar(name), gchar_to_xmlChar(value));
354
* A wrapper to set use xmlSetProp() through a printf-like interface. The
355
* length of the created string is limited to 4096 byte and truncation occurs
356
* if this limit is exceeded. For mere strings or longer values use
357
* xml_prop_set() instead.
359
* @param node the node
360
* @param name the attribute name
361
* @param fmt the format string
362
* @return the result of xmlSetProp().
365
xml_prop_printf(xmlNodePtr node, const gchar *name, const char *fmt, ...)
371
gm_vsnprintf(buf, sizeof buf, fmt, ap);
373
return xml_prop_set(node, name, buf);
377
* Store pending searches.
380
search_store_xml(void)
383
time_t now = time((time_t *) NULL);
389
/* Free target_map and reset the target ID counter */
393
* Create new xml document with version 1.0
395
doc = xmlNewDoc(gchar_to_xmlChar("1.0"));
398
* Create a new root node "gtkGnutella searches"
400
root = xmlNewDocNode(doc, NULL, gchar_to_xmlChar("Searches"), NULL);
401
xmlDocSetRootElement(doc, root);
402
/* Discard the newline of the ctime string */
403
xml_prop_printf(root, "Time", "%24.24s", ctime(&now));
404
xml_prop_printf(root, "Version", "%s", GTA_VERSION_NUMBER);
407
* Store UIDs for the builtin targets
409
builtin_to_xml(root);
412
* Iterate over the searches and add them to the tree
414
for (l = search_gui_get_searches(); l; l = g_list_next(l))
415
search_to_xml(root, (search_t *) l->data);
418
* Iterate over the rulesets and add them to the tree.
419
* Only those that are not bound to a search.
421
for (l = filters; l; l = g_list_next(l))
422
filter_to_xml(root, (filter_t *) l->data);
425
* Try to save the file
428
xmlKeepBlanksDefault(0);
429
filename_new = make_pathname(settings_gui_config_dir(),
430
search_file_xml_new);
433
NULL == filename_new ||
434
-1 == xmlSaveFormatFile(filename_new, doc, TRUE)
436
g_warning("Unable to create %s to persist search: %s",
437
filename_new, g_strerror(errno));
442
g_message("saved searches file: %s", filename_new);
444
filename = make_pathname(settings_gui_config_dir(), search_file_xml);
448
NULL == filename_new ||
449
-1 == rename(filename_new, filename)
451
g_warning("could not rename %s as %s: %s",
452
filename_new, filename, g_strerror(errno));
454
G_FREE_NULL(filename);
457
G_FREE_NULL(filename_new);
461
/* Free target_map and reset the target ID counter */
466
* Retrieve search list and restart searches.
467
* This is the new xml version. The searches are normally
468
* retrieved from ~/.gtk-gnutella/searches.xml.
471
search_retrieve_xml(void)
478
gchar *path_orig = NULL;
481
* We can't use routines from file.c here because libxml2 only defines
482
* interfaces for parsing a path or memory, but not for parsing a FILE
483
* stream! Unbelievable.
487
path = make_pathname(settings_gui_config_dir(), search_file_xml);
491
path_orig = make_pathname(settings_gui_config_dir(), search_file_xml_old);
492
if (NULL == path_orig)
496
* If the file doesn't exist, try retrieving from the .orig version.
499
if (file_exists(path)) {
500
if (-1 == rename(path, path_orig)) {
501
g_warning("could not rename \"%s\" as \"%s\": %s",
502
path, path_orig, g_strerror(errno));
503
G_FREE_NULL(path_orig);
510
g_warning("searches file does not exist: %s", path);
513
if (!file_exists(path_orig))
516
g_warning("retrieving searches from %s instead", path_orig);
520
* parse the file and put the result into newdoc
522
doc = xmlParseFile(path_orig);
523
root = xmlDocGetRootElement(doc);
526
* in case something went wrong
529
g_warning("error parsing searches file: %s", path_orig);
533
if (/* if there is no root element */
535
/* if it doesn't have a name */
536
(root->name == NULL) ||
537
/* if it isn't a Genealogy node */
538
g_ascii_strcasecmp((const gchar *) root->name, "Searches") != 0
540
g_warning("searches file has invalid format: %s", path);
544
G_FREE_NULL(path_orig);
546
id_map = g_hash_table_new(NULL, NULL);
549
* find nodes and add them to the list, this just
550
* loops through all the children of the root of the document
552
for (node = root->children; node != NULL; node = node->next)
553
parse_xml(node, NULL);
556
* We should have collected all ruleset UIDs now. So we can
557
* now resolve the UIDs to the actual pointers we use now.
558
* We need to commit before we do this, because we want to
559
* interate over the rulesets and don't want to cope with
564
g_message("resolving UIDs");
566
for (f = filters; f != NULL; f = f_next) {
567
gboolean damaged = FALSE;
568
filter_t *filter = (filter_t *) f->data;
572
f_next = g_list_next(f);
574
if (gui_debug >= 6) {
575
g_message("\n\nresolving on filter:");
579
if (!filter_is_builtin(filter)) {
581
for (r = filter->ruleset; r != NULL; r = g_list_next(r)) {
582
rule_t *rule = (rule_t *) r->data;
585
g_assert(rule->target != NULL);
586
new_target = g_hash_table_lookup(id_map, rule->target);
587
if (new_target == NULL) {
588
g_warning("Failed to resolve rule %d in \"%s\": "
591
cast_to_gconstpointer(filter_rule_to_gchar(rule)));
593
/* Remove the corrupted filter, we can't handle it */
597
rule->target = new_target;
598
set_flags(rule->flags, RULE_FLAG_VALID);
601
* We circumvent the shadows, so we must do refcounting
604
if (gui_debug >= 7) {
605
g_message("increasing refcount on \"%s\" to %d",
606
rule->target->name, rule->target->refcount + 1);
608
rule->target->refcount++;
613
if (gui_debug >= 6) {
614
g_message("resolved filter:");
619
g_warning("Removing damaged ruleset from filter (name=\"%s\")",
621
/* This causes a little memory leak but the priority is
623
filter->ruleset = NULL;
631
gboolean borked = FALSE;
635
g_message("verifying bindings...");
637
for (s = search_gui_get_searches(); s != NULL; s = g_list_next(s)) {
638
search_t *search = (search_t *) s->data;
640
if (search->filter->search == search) {
642
g_message("binding ok for: %s", search->query);
644
g_warning("binding broken for: %s", search->query);
652
g_list_free(filters_current);
653
filters_current = g_list_copy(filters);
655
g_hash_table_destroy(id_map);
664
G_FREE_NULL(path_orig);
670
builtin_to_xml(xmlNodePtr parent)
674
filter_t * (* target)(void);
676
{ TAG_BUILTIN_SHOW_UID, filter_get_show_target },
677
{ TAG_BUILTIN_DROP_UID, filter_get_drop_target },
678
{ TAG_BUILTIN_DOWNLOAD_UID, filter_get_download_target },
679
{ TAG_BUILTIN_NODOWNLOAD_UID, filter_get_nodownload_target },
680
{ TAG_BUILTIN_RETURN_UID, filter_get_return_target },
685
g_assert(parent != NULL);
687
newxml = xml_new_empty_child(parent, NODE_BUILTIN);
688
for (i = 0; i < G_N_ELEMENTS(builtins); i++) {
689
xml_prop_set(newxml, builtins[i].tag,
690
target_to_string(builtins[i].target()));
695
search_to_xml(xmlNodePtr parent, search_t *s)
702
g_assert(s->query != NULL);
703
g_assert(parent != NULL);
705
if (gui_debug >= 6) {
707
"saving search: %s (%p enabled=%d)\n"
708
" -- filter is bound to: %p\n"
709
" -- search is : %p",
710
s->query, cast_to_gconstpointer(s), s->enabled,
711
cast_to_gconstpointer(s->filter->search),
712
cast_to_gconstpointer(s));
715
if (NULL == (query = locale_to_utf8_full(s->query))) {
716
g_warning("search_to_xml: Cannot convert search string to UTF-8. "
717
"Search won't be saved. (query=\"%s\")", s->query);
721
newxml = xml_new_empty_child(parent, NODE_SEARCH);
722
xml_prop_set(newxml, TAG_SEARCH_QUERY, query);
723
if (query != s->query)
726
xml_prop_printf(newxml, TAG_SEARCH_ENABLED, "%u", s->enabled);
727
xml_prop_printf(newxml, TAG_SEARCH_PASSIVE, "%u", TO_BOOL(s->passive));
728
xml_prop_printf(newxml, TAG_SEARCH_REISSUE_TIMEOUT,
729
"%u", guc_search_get_reissue_timeout(s->search_handle));
730
xml_prop_printf(newxml, TAG_SEARCH_SORT_COL, "%i", s->sort_col);
731
xml_prop_printf(newxml, TAG_SEARCH_SORT_ORDER, "%i", s->sort_order);
733
for (l = s->filter->ruleset; l != NULL; l = g_list_next(l))
734
rule_to_xml(newxml, (rule_t *) l->data);
739
filter_to_xml(xmlNodePtr parent, filter_t *f)
746
g_assert(f->name != NULL);
747
g_assert(parent != NULL);
750
* Don't store the builtin targets or bound rulesets
752
if (filter_is_builtin(f) || filter_is_bound(f)) {
754
g_message("not saving bound/builtin: %s", f->name);
758
if (gui_debug >= 6) {
760
"saving filter: %s\n"
763
cast_to_gconstpointer(f->search));
766
if (NULL == (name = locale_to_utf8_full(f->name))) {
767
g_warning("filter_to_xml: Cannot convert search string to UTF-8. "
768
"Filter won't be saved. (name=\"%s\")", f->name);
772
newxml = xml_new_empty_child(parent, NODE_FILTER);
773
xml_prop_set(newxml, TAG_FILTER_NAME, name);
778
xml_prop_printf(newxml, TAG_FILTER_ACTIVE,
779
"%u", TO_BOOL(filter_is_active(f)));
782
* We take the pointer as a unique id which
783
* we use during read-in for setting the
784
* destination of JUMP actions.
786
xml_prop_set(newxml, TAG_FILTER_UID, target_to_string(f));
788
if (filter_get_global_pre() == f) {
789
xml_prop_printf(newxml, TAG_FILTER_GLOBAL, "%u", GLOBAL_PRE);
792
if (filter_get_global_post() == f) {
793
xml_prop_printf(newxml, TAG_FILTER_GLOBAL, "%u", GLOBAL_POST);
797
* Since free rulesets don't have bound searches,
798
* we need not save the ->search member.
799
* Visited is only used internally during filter
802
for (l = f->ruleset; l != NULL; l = g_list_next(l))
803
rule_to_xml(newxml, (rule_t *) l->data);
807
rule_to_xml(xmlNodePtr parent, rule_t *r)
809
xmlNodePtr newxml = NULL;
811
g_assert(parent != NULL);
814
* We create no node when there is no filter rule.
824
if (NULL == (match = locale_to_utf8_full(r->u.text.match))) {
825
g_warning("rule_to_xml: Cannot convert string to UTF-8. "
826
"Omitting rule (\"%s\")", r->u.text.match);
830
newxml = xml_new_empty_child(parent, NODE_RULE_TEXT);
831
xml_prop_set(newxml, TAG_RULE_TEXT_CASE,
832
r->u.text.case_sensitive ? "1" : "0");
833
xml_prop_set(newxml, TAG_RULE_TEXT_MATCH, match);
834
if (match != r->u.text.match)
837
xml_prop_printf(newxml, TAG_RULE_TEXT_TYPE, "%u", r->u.text.type);
841
newxml = xml_new_empty_child(parent, NODE_RULE_IP);
842
xml_prop_set(newxml, TAG_RULE_IP_ADDR, ip_to_gchar(r->u.ip.addr));
843
xml_prop_set(newxml, TAG_RULE_IP_MASK, ip_to_gchar(r->u.ip.mask));
849
newxml = xml_new_empty_child(parent, NODE_RULE_SIZE);
850
xml_prop_printf(newxml, TAG_RULE_SIZE_LOWER,
851
"%s", uint64_to_string_buf(buf, sizeof buf, r->u.size.lower));
852
xml_prop_printf(newxml, TAG_RULE_SIZE_UPPER,
853
"%s", uint64_to_string_buf(buf, sizeof buf, r->u.size.upper));
857
newxml = xml_new_empty_child(parent, NODE_RULE_JUMP);
860
* Only need target to this rule and that's done below.
867
newxml = xml_new_empty_child(parent, NODE_RULE_SHA1);
869
if (r->u.sha1.hash != NULL)
870
xml_prop_set(newxml, TAG_RULE_SHA1_HASH,
871
sha1_base32(r->u.sha1.hash));
873
if (NULL == (name = locale_to_utf8_full(r->u.sha1.filename))) {
874
g_warning("rule_to_xml: Cannot convert filename to UTF-8. "
875
"Omitting filename (\"%s\")", r->u.sha1.filename);
877
xml_prop_set(newxml, TAG_RULE_SHA1_FILENAME, name);
878
if (name != r->u.sha1.filename)
883
* r->u.sha1.hash is NULL, we just omit the hash.
887
newxml = xml_new_empty_child(parent, NODE_RULE_FLAG);
889
xml_prop_printf(newxml, TAG_RULE_FLAG_STABLE, "%u", r->u.flag.stable);
890
xml_prop_printf(newxml, TAG_RULE_FLAG_BUSY, "%u", r->u.flag.busy);
891
xml_prop_printf(newxml, TAG_RULE_FLAG_PUSH, "%u", r->u.flag.push);
894
newxml = xml_new_empty_child(parent, NODE_RULE_STATE);
895
xml_prop_printf(newxml, TAG_RULE_STATE_DISPLAY,
896
"%u", r->u.state.display);
897
xml_prop_printf(newxml, TAG_RULE_STATE_DOWNLOAD,
898
"%u", r->u.state.download);
901
g_error("Unknown rule type: 0x%x", r->type);
904
xml_prop_printf(newxml, TAG_RULE_NEGATE, "%u", TO_BOOL(RULE_IS_NEGATED(r)));
905
xml_prop_printf(newxml, TAG_RULE_ACTIVE, "%u", TO_BOOL(RULE_IS_ACTIVE(r)));
906
xml_prop_printf(newxml, TAG_RULE_SOFT, "%u", TO_BOOL(RULE_IS_SOFT(r)));
907
xml_prop_set(newxml, TAG_RULE_TARGET, target_to_string(r->target));
911
parse_xml(xmlNodePtr xmlnode, gpointer user_data)
915
g_assert(xmlnode != NULL);
917
if (xmlIsBlankNode(xmlnode))
920
if (!xmlnode->name) {
921
g_warning("Unnamed node: ignored");
925
for (n = 0; parser_map[n].name != NULL; n ++) {
927
0 == g_ascii_strcasecmp((const gchar *) xmlnode->name,
928
(const gchar *) parser_map[n].name)
930
parser_map[n].parser_func(xmlnode, user_data);
935
g_warning("Unknown node: \"%s\"", xmlnode->name);
939
xml_to_builtin(xmlNodePtr xmlnode, gpointer unused_udata)
946
g_assert(xmlnode != NULL);
947
g_assert(xmlnode->name != NULL);
948
g_assert(0 == g_ascii_strcasecmp((const gchar *) xmlnode->name,
950
g_assert(filter_get_show_target() != NULL);
951
g_assert(filter_get_drop_target() != NULL);
952
g_assert(filter_get_download_target() != NULL);
954
buf = STRTRACK(xml_get_string(xmlnode, TAG_BUILTIN_SHOW_UID));
955
g_assert(buf != NULL);
956
target = parse_target(buf, &error);
959
g_warning("xml_to_builtin: %s", g_strerror(error));
962
g_hash_table_insert(id_map, target, filter_get_show_target());
964
buf = STRTRACK(xml_get_string(xmlnode, TAG_BUILTIN_DROP_UID));
965
g_assert(buf != NULL);
966
target = parse_target(buf, &error);
968
g_warning("xml_to_builtin: %s", g_strerror(error));
971
g_hash_table_insert(id_map, target, filter_get_drop_target());
973
buf = STRTRACK(xml_get_string(xmlnode, TAG_BUILTIN_DOWNLOAD_UID));
975
target = parse_target(buf, &error);
978
g_warning("xml_to_builtin: %s", g_strerror(error));
981
g_hash_table_insert(id_map, target, filter_get_download_target());
983
g_warning("xml_to_builtin: no \"DOWNLOAD\" target");
986
buf = STRTRACK(xml_get_string(xmlnode, TAG_BUILTIN_NODOWNLOAD_UID));
988
target = parse_target(buf, &error);
991
g_warning("xml_to_builtin: %s", g_strerror(error));
994
g_hash_table_insert(id_map, target, filter_get_nodownload_target());
996
g_warning("xml_to_builtin: no \"DON'T DOWNLOAD\" target");
999
buf = STRTRACK(xml_get_string(xmlnode, TAG_BUILTIN_RETURN_UID));
1001
target = parse_target(buf, &error);
1004
g_warning("xml_to_builtin: %s", g_strerror(error));
1007
g_hash_table_insert(id_map, target, filter_get_return_target());
1009
g_warning("xml_to_builtin: no \"RETURN\" target");
1014
xml_to_search(xmlNodePtr xmlnode, gpointer unused_udata)
1018
gint sort_col = SORT_NO_COL, sort_order = SORT_NONE;
1019
guint32 reissue_timeout;
1025
(void) unused_udata;
1026
g_assert(xmlnode != NULL);
1027
g_assert(xmlnode->name != NULL);
1028
g_assert(0 == g_ascii_strcasecmp((const gchar *) xmlnode->name,
1031
gnet_prop_get_guint32_val(PROP_SEARCH_REISSUE_TIMEOUT, &reissue_timeout);
1032
gnet_prop_get_boolean_val(PROP_ALLOW_AUTO_REQUERIES, &override);
1034
buf = STRTRACK(xml_get_string(xmlnode, TAG_SEARCH_QUERY));
1036
g_warning("Ignored search without query");
1041
buf = STRTRACK(xml_get_string(xmlnode, TAG_SEARCH_ENABLED));
1043
if (atoi(buf) == 1) {
1044
flags |= SEARCH_ENABLED;
1048
flags |= SEARCH_ENABLED; /* Compatibility: searches always began */
1050
buf = STRTRACK(xml_get_string(xmlnode, TAG_SEARCH_SPEED));
1052
g_warning("xml_to_search: Found deprecated speed attribute.");
1056
buf = STRTRACK(xml_get_string(xmlnode, TAG_SEARCH_REISSUE_TIMEOUT));
1058
reissue_timeout = atol(buf);
1062
buf = STRTRACK(xml_get_string(xmlnode, TAG_SEARCH_PASSIVE));
1065
flags |= SEARCH_PASSIVE;
1069
buf = STRTRACK(xml_get_string(xmlnode, TAG_SEARCH_SORT_COL));
1071
sort_col = atol(buf);
1075
buf = STRTRACK(xml_get_string(xmlnode, TAG_SEARCH_SORT_ORDER));
1077
sort_order = atol(buf);
1082
* LimeWire considers *any* form of requerying unacceptable.
1083
* Deactivate it for now.
1084
* -- cbiere, 2005-03-22
1087
if (!(flags & SEARCH_PASSIVE) && !override)
1088
flags &= ~SEARCH_ENABLED;
1090
if (gui_debug >= 4) {
1091
g_message("adding new %s %s search: %s",
1092
(flags & SEARCH_ENABLED) ? "enabled" : "disabled",
1093
(flags & SEARCH_PASSIVE) ? "passive" : "active",
1097
search_gui_new_search_full(query, reissue_timeout,
1098
sort_col, sort_order, flags, &search);
1103
* Also parse all children.
1105
for (node = xmlnode->children; node != NULL; node = node->next)
1106
parse_xml(node, search->filter);
1110
xml_to_filter(xmlNodePtr xmlnode, gpointer unused_udata)
1117
gboolean active = TRUE;
1121
(void) unused_udata;
1122
g_assert(xmlnode != NULL);
1123
g_assert(xmlnode->name != NULL);
1124
g_assert(0 == g_ascii_strcasecmp((const gchar *) xmlnode->name,
1127
buf = STRTRACK(xml_get_string(xmlnode, TAG_FILTER_NAME));
1129
g_warning("Ignored unnamed filter");
1134
buf = STRTRACK(xml_get_string(xmlnode, TAG_FILTER_GLOBAL));
1136
v = parse_number(buf, &error);
1139
g_warning("xml_to_filter: %s", g_strerror(error));
1145
filter = filter_get_global_pre();
1148
filter = filter_get_global_post();
1152
g_warning("xml_to_filter: Invalid filter");
1157
g_message("adding new filter: %s", name);
1158
filter = filter_new(name);
1159
filters = g_list_append(filters, filter);
1162
buf = STRTRACK(xml_get_string(xmlnode, TAG_FILTER_ACTIVE));
1164
v = parse_number(buf, &error);
1166
if (error || v > 1) {
1167
g_warning("xml_to_filter: Invalid \"active\" tag");
1173
set_flags(filter->flags, FILTER_FLAG_ACTIVE);
1175
clear_flags(filter->flags, FILTER_FLAG_ACTIVE);
1177
buf = STRTRACK(xml_get_string(xmlnode, TAG_FILTER_UID));
1179
dest = parse_target(buf, &error);
1182
g_warning("xml_to_filter: %s", g_strerror(error));
1185
g_hash_table_insert(id_map, dest, filter);
1190
* Also parse all children.
1192
for (node = xmlnode->children; node != NULL; node = node->next)
1193
parse_xml(node, filter);
1197
xml_to_text_rule(xmlNodePtr xmlnode, gpointer data)
1200
enum rule_text_type type;
1201
gboolean case_sensitive;
1204
filter_t *target, *filter = data;
1209
g_assert(xmlnode != NULL);
1210
g_assert(xmlnode->name != NULL);
1211
g_assert(filter != NULL);
1212
g_assert(0 == g_ascii_strcasecmp((const gchar *) xmlnode->name,
1215
match = STRTRACK(xml_get_string(xmlnode, TAG_RULE_TEXT_MATCH));
1216
if (match == NULL) {
1217
g_warning("xml_to_text_rule: rule without match string");
1221
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_TEXT_CASE));
1222
v = parse_number(buf, &error);
1224
if (error || v > 1) {
1225
g_warning("xml_to_text_rule: invalid \"text case\" tag");
1229
case_sensitive = 0 != v;
1230
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_TEXT_TYPE));
1231
type = (enum rule_text_type) atol(buf);
1234
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_TARGET));
1235
target = parse_target(buf, &error);
1238
g_warning("xml_to_text_rule: %s", g_strerror(error));
1242
flags = get_rule_flags_from_xml(xmlnode);
1243
rule = filter_new_text_rule(match, type, case_sensitive, target, flags);
1244
clear_flags(rule->flags, RULE_FLAG_VALID);
1246
if (gui_debug >= 4) {
1247
g_message("added to filter \"%s\" rule with target %p",
1248
filter->name, cast_to_gconstpointer(rule->target));
1251
filter->ruleset = g_list_append(filter->ruleset, rule);
1257
xml_to_ip_rule(xmlNodePtr xmlnode, gpointer data)
1263
filter_t *target, *filter = data;
1267
g_assert(xmlnode != NULL);
1268
g_assert(xmlnode->name != NULL);
1269
g_assert(filter != NULL);
1270
g_assert(0 == g_ascii_strcasecmp((const gchar *) xmlnode->name,
1273
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_IP_ADDR));
1275
g_warning("xml_to_ip_rule: rule without ip address");
1278
addr = gchar_to_ip(buf); /* XXX: Needs validity check! */
1281
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_IP_MASK));
1283
g_warning("xml_to_ip_rule: rule without netmask");
1286
mask = gchar_to_ip(buf); /* XXX: Needs validity check! */
1289
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_TARGET));
1290
target = parse_target(buf, &error);
1292
g_warning( "xml_to_ip_rule: %s", g_strerror(error));
1297
flags = get_rule_flags_from_xml(xmlnode);
1298
rule = filter_new_ip_rule(addr, mask, target, flags);
1299
clear_flags(rule->flags, RULE_FLAG_VALID);
1301
if (gui_debug >= 4) {
1302
g_message("added to filter \"%s\" rule with target %p",
1303
filter->name, cast_to_gconstpointer(rule->target));
1306
filter->ruleset = g_list_append(filter->ruleset, rule);
1310
xml_to_size_rule(xmlNodePtr xmlnode, gpointer data)
1312
filter_t *target = NULL, *filter = data;
1313
filesize_t lower, upper;
1319
g_assert(xmlnode != NULL);
1320
g_assert(xmlnode->name != NULL);
1321
g_assert(filter != NULL);
1322
g_assert(0 == g_ascii_strcasecmp((const gchar *) xmlnode->name,
1325
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_SIZE_LOWER));
1327
g_warning("xml_to_size_rule: rule without lower bound");
1330
lower = parse_number(buf, &error);
1332
g_warning("xml_to_size_rule: invalid lower bound");
1337
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_SIZE_UPPER));
1339
g_warning("xml_to_size_rule: rule without upper bound");
1342
upper = parse_number(buf, &error);
1344
g_warning("xml_to_size_rule: invalid upper bound");
1349
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_TARGET));
1350
target = parse_target(buf, &error);
1352
g_warning("xml_to_size_rule: %s (%p)",
1353
g_strerror(error), cast_to_gconstpointer(target));
1358
flags = get_rule_flags_from_xml(xmlnode);
1359
rule = filter_new_size_rule(lower, upper, target, flags);
1360
clear_flags(rule->flags, RULE_FLAG_VALID);
1362
if (gui_debug >= 4) {
1363
g_message("added to filter \"%s\" rule with target %p",
1364
filter->name, cast_to_gconstpointer(rule->target));
1367
filter->ruleset = g_list_append(filter->ruleset, rule);
1371
xml_to_jump_rule(xmlNodePtr xmlnode, gpointer data)
1375
filter_t *target, *filter = data;
1379
g_assert(xmlnode != NULL);
1380
g_assert(xmlnode->name != NULL);
1381
g_assert(filter != NULL);
1382
g_assert(0 == g_ascii_strcasecmp((const gchar *) xmlnode->name,
1385
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_TARGET));
1386
g_assert(buf != NULL);
1387
target = parse_target(buf, &error);
1390
g_warning( "xml_to_jump_rule: %s", g_strerror(error));
1394
flags = get_rule_flags_from_xml(xmlnode);
1395
rule = filter_new_jump_rule(target,flags);
1396
clear_flags(rule->flags, RULE_FLAG_VALID);
1398
if (gui_debug >= 4) {
1399
g_message("added to filter \"%s\" rule with target %p",
1400
filter->name, cast_to_gconstpointer(rule->target));
1403
filter->ruleset = g_list_append(filter->ruleset, rule);
1407
xml_to_sha1_rule(xmlNodePtr xmlnode, gpointer data)
1409
const gchar *hash = NULL;
1410
gchar *filename = NULL;
1413
filter_t *target, *filter = data;
1417
g_assert(xmlnode != NULL);
1418
g_assert(xmlnode->name != NULL);
1419
g_assert(filter != NULL);
1420
g_assert(0 == g_ascii_strcasecmp((const gchar *) xmlnode->name,
1423
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_SHA1_FILENAME));
1424
filename = buf != NULL ? buf : g_strdup("[Unknown]");
1426
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_SHA1_HASH));
1428
hash = strlen(buf) == SHA1_BASE32_SIZE ? base32_sha1(buf) : NULL;
1431
g_warning("xml_to_sha1_rule: Invalidly encoded SHA1");
1438
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_TARGET));
1439
g_assert(buf != NULL);
1440
target = parse_target(buf, &error);
1443
g_warning("xml_to_sha1_rule: %s", g_strerror(error));
1447
flags = get_rule_flags_from_xml(xmlnode);
1448
rule = filter_new_sha1_rule(hash, filename, target, flags);
1449
clear_flags(rule->flags, RULE_FLAG_VALID);
1451
G_FREE_NULL(filename);
1453
if (gui_debug >= 4) {
1454
g_message("added to filter \"%s\" rule with target %p",
1455
filter->name, cast_to_gconstpointer(rule->target));
1458
filter->ruleset = g_list_append(filter->ruleset, rule);
1462
xml_to_flag_rule(xmlNodePtr xmlnode, gpointer data)
1464
enum rule_flag_action stable = RULE_FLAG_IGNORE;
1465
enum rule_flag_action busy = RULE_FLAG_IGNORE;
1466
enum rule_flag_action push = RULE_FLAG_IGNORE;
1469
filter_t *target, *filter = data;
1474
g_assert(xmlnode != NULL);
1475
g_assert(xmlnode->name != NULL);
1476
g_assert(filter != NULL);
1477
g_assert(0 == g_ascii_strcasecmp((const gchar *) xmlnode->name,
1480
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_FLAG_STABLE));
1482
v = parse_number(buf, &error);
1485
g_warning("xml_to_flag_rule: %s", g_strerror(error));
1486
} else if (v == RULE_FLAG_SET || v == RULE_FLAG_UNSET) {
1491
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_FLAG_BUSY));
1493
v = parse_number(buf, &error);
1496
g_warning("xml_to_flag_rule: %s", g_strerror(error));
1497
} else if (v == RULE_FLAG_SET || v == RULE_FLAG_UNSET) {
1502
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_FLAG_PUSH));
1504
v = parse_number(buf, &error);
1507
g_warning("xml_to_flag_rule: %s", g_strerror(error));
1508
} else if (v == RULE_FLAG_SET || v == RULE_FLAG_UNSET) {
1513
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_TARGET));
1514
g_assert(buf != NULL);
1515
target = parse_target(buf, &error);
1518
g_warning( "xml_to_flag_rule: %s", g_strerror(error));
1522
flags = get_rule_flags_from_xml(xmlnode);
1523
rule = filter_new_flag_rule(stable, busy, push, target, flags);
1524
clear_flags(rule->flags, RULE_FLAG_VALID);
1526
if (gui_debug >= 4) {
1527
g_message("added to filter \"%s\" rule with target %p",
1528
filter->name, cast_to_gconstpointer(rule->target));
1531
filter->ruleset = g_list_append(filter->ruleset, rule);
1535
xml_to_state_rule(xmlNodePtr xmlnode, gpointer data)
1537
enum filter_prop_state display = FILTER_PROP_STATE_UNKNOWN;
1538
enum filter_prop_state download = FILTER_PROP_STATE_UNKNOWN;
1541
filter_t *target, *filter = data;
1546
g_assert(xmlnode != NULL);
1547
g_assert(xmlnode->name != NULL);
1548
g_assert(filter != NULL);
1549
g_assert(0 == g_ascii_strcasecmp((const gchar *) xmlnode->name,
1552
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_STATE_DISPLAY));
1554
v = parse_number(buf, &error);
1557
g_warning( "xml_to_state_rule: %s", g_strerror(error));
1559
if (v <= MAX_FILTER_PROP_STATE || v == FILTER_PROP_STATE_IGNORE) {
1564
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_STATE_DOWNLOAD));
1566
v = parse_number(buf, &error);
1569
g_warning( "xml_to_state_rule: %s", g_strerror(error));
1572
if (v <= MAX_FILTER_PROP_STATE || v == FILTER_PROP_STATE_IGNORE) {
1577
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_TARGET));
1578
g_assert(buf != NULL);
1579
target = parse_target(buf, &error);
1582
g_warning( "xml_to_state_rule: %s", g_strerror(error));
1586
flags = get_rule_flags_from_xml(xmlnode);
1587
rule = filter_new_state_rule(display, download, target, flags);
1588
clear_flags(rule->flags, RULE_FLAG_VALID);
1590
if (gui_debug >= 4) {
1591
g_message("added to filter \"%s\" rule with target %p",
1592
filter->name, cast_to_gconstpointer(rule->target));
1595
filter->ruleset = g_list_append(filter->ruleset, rule);
1599
get_rule_flags_from_xml(xmlNodePtr xmlnode)
1601
gboolean negate = FALSE;
1602
gboolean active = TRUE;
1603
gboolean soft = FALSE;
1609
g_assert(xmlnode != NULL);
1610
g_assert(xmlnode->name != NULL);
1612
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_NEGATE));
1614
v = parse_number(buf, &error);
1616
if (error || v > 1) {
1617
g_warning("get_rule_flags_from_xml: Invalid \"negate\" tag");
1623
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_ACTIVE));
1625
v = parse_number(buf, &error);
1627
if (error || v > 1) {
1628
g_warning("get_rule_flags_from_xml: Invalid \"active\" tag");
1634
buf = STRTRACK(xml_get_string(xmlnode, TAG_RULE_SOFT));
1636
v = parse_number(buf, &error);
1638
if (error || v > 1) {
1639
g_warning("get_rule_flags_from_xml: Invalid \"soft\" tag");
1646
(negate ? RULE_FLAG_NEGATE : 0) |
1647
(active ? RULE_FLAG_ACTIVE : 0) |
1648
(soft ? RULE_FLAG_SOFT : 0);
1653
/* vi: set ts=4 sw=4 cindent: */