2.25.91
[evolution.git] / filter / rule-context.c
blobcc8151378489e06ba5fee5f0feb37ae7cb01ce4b
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 * Authors:
17 * Not Zed <notzed@lostzed.mmc.com.au>
18 * Jeffrey Stedfast <fejj@ximian.com>
20 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
24 #include <config.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
33 #include <glib.h>
34 #include <glib/gstdio.h>
36 #include <gtk/gtk.h>
38 #include <glib/gi18n.h>
40 #include <libedataserver/e-xml-utils.h>
42 #include "e-util/e-error.h"
43 #include "e-util/e-xml-utils.h"
45 #include "filter-code.h"
46 #include "filter-colour.h"
47 #include "filter-datespec.h"
48 #include "filter-file.h"
49 #include "filter-input.h"
50 #include "filter-int.h"
51 #include "filter-marshal.h"
52 #include "filter-option.h"
53 #include "filter-rule.h"
54 #include "rule-context.h"
56 #define d(x)
58 static int load(RuleContext *rc, const char *system, const char *user);
59 static int save(RuleContext *rc, const char *user);
60 static int revert(RuleContext *rc, const char *user);
61 static GList *rename_uri(RuleContext *rc, const char *olduri, const char *newuri, GCompareFunc cmp);
62 static GList *delete_uri(RuleContext *rc, const char *uri, GCompareFunc cmp);
63 static FilterElement *new_element(RuleContext *rc, const char *name);
65 static void rule_context_class_init(RuleContextClass *klass);
66 static void rule_context_init(RuleContext *rc);
67 static void rule_context_finalise(GObject *obj);
69 #define _PRIVATE(x)(((RuleContext *)(x))->priv)
71 struct _RuleContextPrivate {
72 int frozen;
75 static GObjectClass *parent_class = NULL;
77 enum {
78 RULE_ADDED,
79 RULE_REMOVED,
80 CHANGED,
81 LAST_SIGNAL
84 static guint signals[LAST_SIGNAL] = { 0 };
87 GType
88 rule_context_get_type(void)
90 static GType type = 0;
92 if (!type) {
93 static const GTypeInfo info = {
94 sizeof(RuleContextClass),
95 NULL, /* base_class_init */
96 NULL, /* base_class_finalize */
97 (GClassInitFunc) rule_context_class_init,
98 NULL, /* class_finalize */
99 NULL, /* class_data */
100 sizeof(RuleContext),
101 0, /* n_preallocs */
102 (GInstanceInitFunc) rule_context_init,
105 type = g_type_register_static(G_TYPE_OBJECT, "RuleContext", &info, 0);
108 return type;
111 static void
112 rule_context_class_init(RuleContextClass *klass)
114 GObjectClass *object_class = G_OBJECT_CLASS(klass);
116 parent_class = g_type_class_ref(G_TYPE_OBJECT);
118 object_class->finalize = rule_context_finalise;
120 /* override methods */
121 klass->load = load;
122 klass->save = save;
123 klass->revert = revert;
124 klass->rename_uri = rename_uri;
125 klass->delete_uri = delete_uri;
126 klass->new_element = new_element;
128 /* signals */
129 signals[RULE_ADDED] =
130 g_signal_new("rule_added",
131 RULE_TYPE_CONTEXT,
132 G_SIGNAL_RUN_LAST,
133 G_STRUCT_OFFSET(RuleContextClass, rule_added),
134 NULL,
135 NULL,
136 g_cclosure_marshal_VOID__POINTER,
137 G_TYPE_NONE, 1, G_TYPE_POINTER);
139 signals[RULE_REMOVED] =
140 g_signal_new("rule_removed",
141 RULE_TYPE_CONTEXT,
142 G_SIGNAL_RUN_LAST,
143 G_STRUCT_OFFSET(RuleContextClass, rule_removed),
144 NULL,
145 NULL,
146 g_cclosure_marshal_VOID__POINTER,
147 G_TYPE_NONE, 1, G_TYPE_POINTER);
149 signals[CHANGED] =
150 g_signal_new("changed",
151 RULE_TYPE_CONTEXT,
152 G_SIGNAL_RUN_LAST,
153 G_STRUCT_OFFSET(RuleContextClass, changed),
154 NULL,
155 NULL,
156 g_cclosure_marshal_VOID__VOID,
157 G_TYPE_NONE, 0);
160 static void
161 rule_context_init(RuleContext *rc)
163 rc->priv = g_malloc0(sizeof(*rc->priv));
165 rc->part_set_map = g_hash_table_new(g_str_hash, g_str_equal);
166 rc->rule_set_map = g_hash_table_new(g_str_hash, g_str_equal);
168 rc->flags = RULE_CONTEXT_GROUPING;
171 static void
172 free_part_set(struct _part_set_map *map, void *data)
174 g_free(map->name);
175 g_free(map);
178 static void
179 free_rule_set(struct _rule_set_map *map, void *data)
181 g_free(map->name);
182 g_free(map);
185 static void
186 rule_context_finalise(GObject *obj)
188 RuleContext *rc =(RuleContext *) obj;
190 g_list_foreach(rc->rule_set_list, (GFunc)free_rule_set, NULL);
191 g_list_free(rc->rule_set_list);
192 g_hash_table_destroy(rc->rule_set_map);
194 g_list_foreach(rc->part_set_list, (GFunc)free_part_set, NULL);
195 g_list_free(rc->part_set_list);
196 g_hash_table_destroy(rc->part_set_map);
198 g_free(rc->error);
200 g_list_foreach(rc->parts, (GFunc)g_object_unref, NULL);
201 g_list_free(rc->parts);
202 g_list_foreach(rc->rules, (GFunc)g_object_unref, NULL);
203 g_list_free(rc->rules);
205 g_free(rc->priv);
207 G_OBJECT_CLASS(parent_class)->finalize(obj);
211 * rule_context_new:
213 * Create a new RuleContext object.
215 * Return value: A new #RuleContext object.
217 RuleContext *
218 rule_context_new(void)
220 return(RuleContext *) g_object_new(RULE_TYPE_CONTEXT, NULL, NULL);
223 void
224 rule_context_add_part_set(RuleContext *rc, const char *setname, GType part_type, RCPartFunc append, RCNextPartFunc next)
226 struct _part_set_map *map;
228 g_return_if_fail (g_hash_table_lookup(rc->part_set_map, setname) == NULL);
230 map = g_malloc0(sizeof(*map));
231 map->type = part_type;
232 map->append = append;
233 map->next = next;
234 map->name = g_strdup(setname);
235 g_hash_table_insert(rc->part_set_map, map->name, map);
236 rc->part_set_list = g_list_append(rc->part_set_list, map);
237 d(printf("adding part set '%s'\n", setname));
240 void
241 rule_context_add_rule_set(RuleContext *rc, const char *setname, GType rule_type, RCRuleFunc append, RCNextRuleFunc next)
243 struct _rule_set_map *map;
245 g_return_if_fail (g_hash_table_lookup(rc->rule_set_map, setname) == NULL);
247 map = g_malloc0(sizeof(*map));
248 map->type = rule_type;
249 map->append = append;
250 map->next = next;
251 map->name = g_strdup(setname);
252 g_hash_table_insert(rc->rule_set_map, map->name, map);
253 rc->rule_set_list = g_list_append(rc->rule_set_list, map);
254 d(printf("adding rule set '%s'\n", setname));
258 * rule_context_set_error:
259 * @f:
260 * @error:
262 * Set the text error for the context, or NULL to clear it.
264 static void
265 rule_context_set_error(RuleContext *rc, char *error)
267 g_return_if_fail (rc);
269 g_free(rc->error);
270 rc->error = error;
274 * rule_context_load:
275 * @f:
276 * @system:
277 * @user:
279 * Load a rule context from a system and user description file.
281 * Return value:
284 rule_context_load(RuleContext *rc, const char *system, const char *user)
286 int res;
288 g_return_val_if_fail (rc, -1);
290 d(printf("rule_context: loading %s %s\n", system, user));
292 rc->priv->frozen++;
293 res = RULE_CONTEXT_GET_CLASS(rc)->load(rc, system, user);
294 rc->priv->frozen--;
296 return res;
299 static int
300 load(RuleContext *rc, const char *system, const char *user)
302 xmlNodePtr set, rule, root;
303 xmlDocPtr systemdoc, userdoc;
304 struct _part_set_map *part_map;
305 struct _rule_set_map *rule_map;
307 rule_context_set_error(rc, NULL);
309 d(printf("loading rules %s %s\n", system, user));
311 systemdoc = e_xml_parse_file (system);
312 if (systemdoc == NULL) {
313 rule_context_set_error(rc, g_strdup_printf("Unable to load system rules '%s': %s",
314 system, g_strerror(errno)));
315 return -1;
318 root = xmlDocGetRootElement(systemdoc);
319 if (root == NULL || strcmp((char *)root->name, "filterdescription")) {
320 rule_context_set_error(rc, g_strdup_printf("Unable to load system rules '%s': Invalid format", system));
321 xmlFreeDoc(systemdoc);
322 return -1;
324 /* doesn't matter if this doens't exist */
325 userdoc = NULL;
326 if (g_file_test(user, G_FILE_TEST_IS_REGULAR))
327 userdoc = e_xml_parse_file (user);
329 /* now parse structure */
330 /* get rule parts */
331 set = root->children;
332 while (set) {
333 d(printf("set name = %s\n", set->name));
334 part_map = g_hash_table_lookup(rc->part_set_map, set->name);
335 if (part_map) {
336 d(printf("loading parts ...\n"));
337 rule = set->children;
338 while (rule) {
339 if (!strcmp((char *)rule->name, "part")) {
340 FilterPart *part = FILTER_PART(g_object_new(part_map->type, NULL, NULL));
342 if (filter_part_xml_create(part, rule, rc) == 0) {
343 part_map->append(rc, part);
344 } else {
345 g_object_unref(part);
346 g_warning("Cannot load filter part");
349 rule = rule->next;
351 } else if ((rule_map = g_hash_table_lookup(rc->rule_set_map, set->name))) {
352 d(printf("loading system rules ...\n"));
353 rule = set->children;
354 while (rule) {
355 d(printf("checking node: %s\n", rule->name));
356 if (!strcmp((char *)rule->name, "rule")) {
357 FilterRule *part = FILTER_RULE(g_object_new(rule_map->type, NULL, NULL));
359 if (filter_rule_xml_decode(part, rule, rc) == 0) {
360 part->system = TRUE;
361 rule_map->append(rc, part);
362 } else {
363 g_object_unref(part);
364 g_warning("Cannot load filter part");
367 rule = rule->next;
370 set = set->next;
373 /* now load actual rules */
374 if (userdoc) {
375 root = xmlDocGetRootElement(userdoc);
376 set = root?root->children:NULL;
377 while (set) {
378 d(printf("set name = %s\n", set->name));
379 rule_map = g_hash_table_lookup(rc->rule_set_map, set->name);
380 if (rule_map) {
381 d(printf("loading rules ...\n"));
382 rule = set->children;
383 while (rule) {
384 d(printf("checking node: %s\n", rule->name));
385 if (!strcmp((char *)rule->name, "rule")) {
386 FilterRule *part = FILTER_RULE(g_object_new(rule_map->type, NULL, NULL));
388 if (filter_rule_xml_decode(part, rule, rc) == 0) {
389 rule_map->append(rc, part);
390 } else {
391 g_object_unref(part);
392 g_warning("Cannot load filter part");
395 rule = rule->next;
398 set = set->next;
402 xmlFreeDoc(userdoc);
403 xmlFreeDoc(systemdoc);
405 return 0;
409 * rule_context_save:
410 * @f:
411 * @user:
413 * Save a rule context to disk.
415 * Return value:
418 rule_context_save(RuleContext *rc, const char *user)
420 g_return_val_if_fail (rc, -1);
421 g_return_val_if_fail (user, -1);
423 return RULE_CONTEXT_GET_CLASS(rc)->save(rc, user);
426 static int
427 save(RuleContext *rc, const char *user)
429 xmlDocPtr doc;
430 xmlNodePtr root, rules, work;
431 GList *l;
432 FilterRule *rule;
433 struct _rule_set_map *map;
434 int ret;
436 doc = xmlNewDoc((const unsigned char *)"1.0");
437 /* FIXME: set character encoding to UTF-8? */
438 root = xmlNewDocNode(doc, NULL, (const unsigned char *)"filteroptions", NULL);
439 xmlDocSetRootElement(doc, root);
440 l = rc->rule_set_list;
441 while (l) {
442 map = l->data;
443 rules = xmlNewDocNode(doc, NULL, (unsigned char *)map->name, NULL);
444 xmlAddChild(root, rules);
445 rule = NULL;
446 while ((rule = map->next(rc, rule, NULL))) {
447 if (!rule->system) {
448 d(printf("processing rule %s\n", rule->name));
449 work = filter_rule_xml_encode(rule);
450 xmlAddChild(rules, work);
453 l = g_list_next(l);
456 ret = e_xml_save_file(user, doc);
458 xmlFreeDoc(doc);
460 return ret;
464 * rule_context_revert:
465 * @f:
466 * @user:
468 * Reverts a rule context from a user description file. Assumes the
469 * system description file is unchanged from when it was loaded.
471 * Return value:
474 rule_context_revert(RuleContext *rc, const char *user)
476 g_return_val_if_fail (rc, 0);
478 d(printf("rule_context: restoring %s\n", user));
480 return RULE_CONTEXT_GET_CLASS(rc)->revert(rc, user);
483 struct _revert_data {
484 GHashTable *rules;
485 int rank;
488 static void
489 revert_rule_remove(void *key, FilterRule *frule, RuleContext *rc)
491 rule_context_remove_rule(rc, frule);
492 g_object_unref(frule);
495 static void
496 revert_source_remove(void *key, struct _revert_data *rest_data, RuleContext *rc)
498 g_hash_table_foreach(rest_data->rules, (GHFunc)revert_rule_remove, rc);
499 g_hash_table_destroy(rest_data->rules);
500 g_free(rest_data);
503 static guint
504 source_hashf(const char *a)
506 if (a)
507 return g_str_hash(a);
508 return 0;
511 static int
512 source_eqf(const char *a, const char *b)
514 return((a && b && strcmp(a, b) == 0))
515 || (a == NULL && b == NULL);
518 static int
519 revert(RuleContext *rc, const char *user)
521 xmlNodePtr set, rule;
522 /*struct _part_set_map *part_map;*/
523 struct _rule_set_map *rule_map;
524 struct _revert_data *rest_data;
525 GHashTable *source_hash;
526 xmlDocPtr userdoc;
527 FilterRule *frule;
529 rule_context_set_error(rc, NULL);
531 d(printf("restoring rules %s\n", user));
533 userdoc = e_xml_parse_file (user);
534 if (userdoc == NULL)
535 /* clear out anythign we have? */
536 return 0;
538 source_hash = g_hash_table_new((GHashFunc)source_hashf, (GCompareFunc)source_eqf);
540 /* setup stuff we have now */
541 /* Note that we assume there is only 1 set of rules in a given rule context,
542 although other parts of the code dont assume this */
543 frule = NULL;
544 while ((frule = rule_context_next_rule(rc, frule, NULL))) {
545 rest_data = g_hash_table_lookup(source_hash, frule->source);
546 if (rest_data == NULL) {
547 rest_data = g_malloc0(sizeof(*rest_data));
548 rest_data->rules = g_hash_table_new(g_str_hash, g_str_equal);
549 g_hash_table_insert(source_hash, frule->source, rest_data);
551 g_hash_table_insert(rest_data->rules, frule->name, frule);
554 /* make what we have, match what we load */
555 set = xmlDocGetRootElement(userdoc);
556 set = set?set->children:NULL;
557 while (set) {
558 d(printf("set name = %s\n", set->name));
559 rule_map = g_hash_table_lookup(rc->rule_set_map, set->name);
560 if (rule_map) {
561 d(printf("loading rules ...\n"));
562 rule = set->children;
563 while (rule) {
564 d(printf("checking node: %s\n", rule->name));
565 if (!strcmp((char *)rule->name, "rule")) {
566 FilterRule *part = FILTER_RULE(g_object_new(rule_map->type, NULL, NULL));
568 if (filter_rule_xml_decode(part, rule, rc) == 0) {
569 /* use the revert data to keep track of the right rank of this rule part */
570 rest_data = g_hash_table_lookup(source_hash, part->source);
571 if (rest_data == NULL) {
572 rest_data = g_malloc0(sizeof(*rest_data));
573 rest_data->rules = g_hash_table_new(g_str_hash, g_str_equal);
574 g_hash_table_insert(source_hash, part->source, rest_data);
576 frule = g_hash_table_lookup(rest_data->rules, part->name);
577 if (frule) {
578 if (rc->priv->frozen == 0 && !filter_rule_eq(frule, part))
579 filter_rule_copy(frule, part);
581 g_object_unref(part);
582 rule_context_rank_rule(rc, frule, frule->source, rest_data->rank);
583 g_hash_table_remove(rest_data->rules, frule->name);
584 } else {
585 rule_context_add_rule(rc, part);
586 rule_context_rank_rule(rc, part, part->source, rest_data->rank);
588 rest_data->rank++;
589 } else {
590 g_object_unref(part);
591 g_warning("Cannot load filter part");
594 rule = rule->next;
597 set = set->next;
600 xmlFreeDoc(userdoc);
602 /* remove any we still have that weren't in the file */
603 g_hash_table_foreach(source_hash, (GHFunc)revert_source_remove, rc);
604 g_hash_table_destroy(source_hash);
606 return 0;
609 FilterPart *
610 rule_context_find_part(RuleContext *rc, const char *name)
612 g_return_val_if_fail (rc, NULL);
613 g_return_val_if_fail (name, NULL);
615 d(printf("find part : "));
616 return filter_part_find_list(rc->parts, name);
619 FilterPart *
620 rule_context_create_part(RuleContext *rc, const char *name)
622 FilterPart *part;
624 g_return_val_if_fail (rc, NULL);
625 g_return_val_if_fail (name, NULL);
627 if ((part = rule_context_find_part(rc, name)))
628 return filter_part_clone(part);
630 return NULL;
633 FilterPart *
634 rule_context_next_part(RuleContext *rc, FilterPart *last)
636 g_return_val_if_fail (rc, NULL);
638 return filter_part_next_list(rc->parts, last);
641 FilterRule *
642 rule_context_next_rule(RuleContext *rc, FilterRule *last, const char *source)
644 g_return_val_if_fail (rc, NULL);
646 return filter_rule_next_list(rc->rules, last, source);
649 FilterRule *
650 rule_context_find_rule(RuleContext *rc, const char *name, const char *source)
652 g_return_val_if_fail (name, NULL);
653 g_return_val_if_fail (rc, NULL);
655 return filter_rule_find_list(rc->rules, name, source);
658 void
659 rule_context_add_part(RuleContext *rc, FilterPart *part)
661 g_return_if_fail (rc);
662 g_return_if_fail (part);
664 rc->parts = g_list_append(rc->parts, part);
667 void
668 rule_context_add_rule(RuleContext *rc, FilterRule *new)
670 g_return_if_fail (rc);
671 g_return_if_fail (new);
673 d(printf("add rule '%s'\n", new->name));
675 rc->rules = g_list_append(rc->rules, new);
677 if (rc->priv->frozen == 0) {
678 g_signal_emit(rc, signals[RULE_ADDED], 0, new);
679 g_signal_emit(rc, signals[CHANGED], 0);
683 static void
684 new_rule_response(GtkWidget *dialog, int button, RuleContext *context)
686 if (button == GTK_RESPONSE_OK) {
687 FilterRule *rule = g_object_get_data((GObject *) dialog, "rule");
688 char *user = g_object_get_data((GObject *) dialog, "path");
690 if (!filter_rule_validate(rule)) {
691 /* no need to popup a dialog because the validate code does that. */
692 return;
695 if (rule_context_find_rule (context, rule->name, rule->source)) {
696 e_error_run((GtkWindow *)dialog, "filter:bad-name-notunique", rule->name, NULL);
698 return;
701 g_object_ref(rule);
702 rule_context_add_rule(context, rule);
703 if (user)
704 rule_context_save(context, user);
707 gtk_widget_destroy(dialog);
710 /* add a rule, with a gui, asking for confirmation first ... optionally save to path */
711 void
712 rule_context_add_rule_gui(RuleContext *rc, FilterRule *rule, const char *title, const char *path)
714 GtkDialog *dialog;
715 GtkWidget *widget;
717 d(printf("add rule gui '%s'\n", rule->name));
719 g_return_if_fail (rc);
720 g_return_if_fail (rule);
722 widget = filter_rule_get_widget(rule, rc);
723 gtk_widget_show(widget);
725 dialog =(GtkDialog *) gtk_dialog_new();
726 gtk_dialog_add_buttons(dialog,
727 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
728 GTK_STOCK_OK, GTK_RESPONSE_OK,
729 NULL);
730 gtk_dialog_set_has_separator (dialog, FALSE);
732 gtk_window_set_title((GtkWindow *) dialog, title);
733 gtk_window_set_default_size((GtkWindow *) dialog, 600, 400);
734 gtk_window_set_resizable((GtkWindow *) dialog, TRUE);
736 gtk_box_pack_start((GtkBox *) dialog->vbox, widget, TRUE, TRUE, 0);
738 g_object_set_data_full((GObject *) dialog, "rule", rule, g_object_unref);
739 if (path)
740 g_object_set_data_full((GObject *) dialog, "path", g_strdup(path), g_free);
742 g_signal_connect(dialog, "response", G_CALLBACK(new_rule_response), rc);
744 g_object_ref(rc);
746 g_object_set_data_full((GObject *) dialog, "context", rc, g_object_unref);
748 gtk_widget_show((GtkWidget *) dialog);
751 void
752 rule_context_remove_rule(RuleContext *rc, FilterRule *rule)
754 g_return_if_fail (rc);
755 g_return_if_fail (rule);
757 d(printf("remove rule '%s'\n", rule->name));
759 rc->rules = g_list_remove(rc->rules, rule);
761 if (rc->priv->frozen == 0) {
762 g_signal_emit(rc, signals[RULE_REMOVED], 0, rule);
763 g_signal_emit(rc, signals[CHANGED], 0);
767 void
768 rule_context_rank_rule(RuleContext *rc, FilterRule *rule, const char *source, int rank)
770 GList *node;
771 int i = 0, index = 0;
773 g_return_if_fail (rc);
774 g_return_if_fail (rule);
776 if (rule_context_get_rank_rule (rc, rule, source) == rank)
777 return;
779 rc->rules = g_list_remove(rc->rules, rule);
780 node = rc->rules;
781 while (node) {
782 FilterRule *r = node->data;
784 if (i == rank) {
785 rc->rules = g_list_insert(rc->rules, rule, index);
786 if (rc->priv->frozen == 0)
787 g_signal_emit(rc, signals[CHANGED], 0);
789 return;
792 index++;
793 if (source == NULL || (r->source && strcmp(r->source, source) == 0))
794 i++;
796 node = node->next;
799 rc->rules = g_list_append(rc->rules, rule);
800 if (rc->priv->frozen == 0)
801 g_signal_emit(rc, signals[CHANGED], 0);
805 rule_context_get_rank_rule(RuleContext *rc, FilterRule *rule, const char *source)
807 GList *node;
808 int i = 0;
810 g_return_val_if_fail (rc, -1);
811 g_return_val_if_fail (rule, -1);
813 d(printf("getting rank of rule '%s'\n", rule->name));
815 node = rc->rules;
816 while (node) {
817 FilterRule *r = node->data;
819 d(printf(" checking against rule '%s' rank '%d'\n", r->name, i));
821 if (r == rule)
822 return i;
824 if (source == NULL || (r->source && strcmp(r->source, source) == 0))
825 i++;
827 node = node->next;
830 return -1;
833 FilterRule *
834 rule_context_find_rank_rule(RuleContext *rc, int rank, const char *source)
836 GList *node;
837 int i = 0;
839 g_return_val_if_fail (rc, NULL);
841 d(printf("getting rule at rank %d source '%s'\n", rank, source?source:"<any>"));
843 node = rc->rules;
844 while (node) {
845 FilterRule *r = node->data;
847 d(printf(" checking against rule '%s' rank '%d'\n", r->name, i));
849 if (source == NULL || (r->source && strcmp(r->source, source) == 0)) {
850 if (rank == i)
851 return r;
852 i++;
855 node = node->next;
858 return NULL;
861 static GList *
862 delete_uri(RuleContext *rc, const char *uri, GCompareFunc cmp)
864 return NULL;
867 GList *
868 rule_context_delete_uri(RuleContext *rc, const char *uri, GCompareFunc cmp)
870 return RULE_CONTEXT_GET_CLASS(rc)->delete_uri(rc, uri, cmp);
873 static GList *
874 rename_uri(RuleContext *rc, const char *olduri, const char *newuri, GCompareFunc cmp)
876 return NULL;
879 GList *
880 rule_context_rename_uri(RuleContext *rc, const char *olduri, const char *newuri, GCompareFunc cmp)
882 return RULE_CONTEXT_GET_CLASS(rc)->rename_uri(rc, olduri, newuri, cmp);
885 void
886 rule_context_free_uri_list(RuleContext *rc, GList *uris)
888 GList *l = uris, *n;
890 /* TODO: should be virtual */
892 while (l) {
893 n = l->next;
894 g_free(l->data);
895 g_list_free_1(l);
896 l = n;
900 static FilterElement *
901 new_element(RuleContext *rc, const char *type)
903 if (!strcmp (type, "string")) {
904 return (FilterElement *) filter_input_new ();
905 } else if (!strcmp (type, "address")) {
906 /* FIXME: temporary ... need real address type */
907 return (FilterElement *) filter_input_new_type_name (type);
908 } else if (!strcmp (type, "code")) {
909 return (FilterElement *) filter_code_new (FALSE);
910 } else if (!strcmp (type, "rawcode")) {
911 return (FilterElement *) filter_code_new (TRUE);
912 } else if (!strcmp (type, "colour")) {
913 return (FilterElement *) filter_colour_new ();
914 } else if (!strcmp (type, "optionlist")) {
915 return (FilterElement *) filter_option_new ();
916 } else if (!strcmp (type, "datespec")) {
917 return (FilterElement *) filter_datespec_new ();
918 } else if (!strcmp (type, "command")) {
919 return (FilterElement *) filter_file_new_type_name (type);
920 } else if (!strcmp (type, "file")) {
921 return (FilterElement *) filter_file_new_type_name (type);
922 } else if (!strcmp (type, "integer")) {
923 return (FilterElement *) filter_int_new ();
924 } else if (!strcmp (type, "regex")) {
925 return (FilterElement *) filter_input_new_type_name (type);
926 }else if (!strcmp(type, "completedpercent")) {
927 return (FilterElement *) filter_int_new_type("completedpercent", 0,100);
929 } else {
930 g_warning("Unknown filter type '%s'", type);
931 return NULL;
936 * rule_context_new_element:
937 * @rc:
938 * @name:
940 * create a new filter element based on name.
942 * Return value:
944 FilterElement *
945 rule_context_new_element(RuleContext *rc, const char *name)
947 if (name == NULL)
948 return NULL;
950 return RULE_CONTEXT_GET_CLASS(rc)->new_element(rc, name);