aboutsummaryrefslogblamecommitdiffstats
path: root/filter/rule-context.c
blob: f24e9948be5d397317f524e62a9696e68196ff22 (plain) (tree)
1
2
  
                                  

















                                                                       



                    
                  



                                    


                         
            
 

                                                                       
 


                                                              














                                                
                           

                              
 




                                                 



                                                                   
                  

                                                                          
         
 



                    
                                                 

                                     


                                                             












                                                                         
                                  







                                                                    
                                      
 
                                             





















                                                           
 



                                      
 
                                                           











                                           

                                                                               


                 

                                                                                                                      












                                                                

                                                                                                                      



















                                                                
           
                                                    









                         
  



                                                               

                                                                        
 
                                                                 
 
                                                                                      

 

                                                           















                                                                                                 
                                                                                                                       



                                      
                                                  
                                     












                                                                                                     
 


                                                                                      
                                                                                     









                                                                                     








                                                                                   
                                                                                     

                                                                                                             
 


                                                                                                 
                                                                                             

                                                                                             
                                         
                                                          
                                 
                         
                                        
                 












                               

                                                    
 
                                                                              

 

                                       















                                                                  
                                                           










                                                                      

                                                         




                                                     

                                                           








                                               

                                                          



                                                     

                                                                              
 
                                                             

 

                                                                             
 
                                                             

 

                                                         



                                                 

                                                        



                                                
           
                                                                      
 
                   
                                                      
      
                          









                                                                                            
                           
                                                                          

                 
        
                           
                                                           



                                                                                       

                                                                                                  




                                            
                                                                                                             

                                                                  
                                                              

                                                                                                      
                 




                                                                                                              

 
    
                                                           
 
                                                  

 
    
                                                                   
 

                                                        

 
   
                                                                                 
 
                               
                  



                                           
                              
                                 

                                                                                     
                            

                                  
         

                  
 
/*
 *  Copyright (C) 2000 Ximian Inc.
 *
 *  Authors: Not Zed <notzed@lostzed.mmc.com.au>
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public License
 *  as published by the Free Software Foundation; either version 2 of
 *  the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <errno.h>
#include <string.h>
#include <gtk/gtksignal.h>
#include <libgnomeui/gnome-dialog.h>
#include <libgnomeui/gnome-stock.h>

#include "rule-context.h"

#define d(x)

static int load(RuleContext * f, const char *system, const char *user);
static int save(RuleContext * f, const char *user);

static void rule_context_class_init(RuleContextClass * class);
static void rule_context_init(RuleContext * gspaper);
static void rule_context_finalise(GtkObject * obj);

#define _PRIVATE(x) (((RuleContext *)(x))->priv)

struct _RuleContextPrivate {
};

static GtkObjectClass *parent_class;

enum {
    LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

guint
rule_context_get_type(void)
{
    static guint type = 0;

    if (!type) {
        GtkTypeInfo type_info = {
            "RuleContext",
            sizeof(RuleContext),
            sizeof(RuleContextClass),
            (GtkClassInitFunc) rule_context_class_init,
            (GtkObjectInitFunc) rule_context_init,
            (GtkArgSetFunc) NULL,
            (GtkArgGetFunc) NULL
        };

        type = gtk_type_unique(gtk_object_get_type(), &type_info);
    }

    return type;
}

static void
rule_context_class_init(RuleContextClass * class)
{
    GtkObjectClass *object_class;

    object_class = (GtkObjectClass *) class;
    parent_class = gtk_type_class(gtk_object_get_type());

    object_class->finalize = rule_context_finalise;

    /* override methods */
    class->load = load;
    class->save = save;

    /* signals */

    gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
}

static void
rule_context_init(RuleContext * o)
{
    o->priv = g_malloc0(sizeof(*o->priv));

    o->part_set_map = g_hash_table_new(g_str_hash, g_str_equal);
    o->rule_set_map = g_hash_table_new(g_str_hash, g_str_equal);
}

static void
rule_context_finalise(GtkObject * obj)
{
    RuleContext *o = (RuleContext *) obj;
    struct _part_set_map *psm;
    struct _rule_set_map *rsm;
    GList *next;

    g_free(o->priv);
    g_hash_table_destroy(o->part_set_map);
    g_hash_table_destroy(o->rule_set_map);

    for (; o->part_set_list; o->part_set_list = next) {
        psm = o->part_set_list->data;
        g_free (psm->name);
        g_free (psm);
        next = o->part_set_list->next;
        g_list_free_1 (o->part_set_list);
    }
    for (; o->rule_set_list; o->rule_set_list = next) {
        rsm = o->rule_set_list->data;
        g_free (rsm->name);
        g_free (rsm);
        next = o->rule_set_list->next;
        g_list_free_1 (o->rule_set_list);
    }

    if (o->system)
        xmlFreeDoc(o->system);
    if (o->user)
        xmlFreeDoc(o->user);

    ((GtkObjectClass *) (parent_class))->finalize(obj);
}

/**
 * rule_context_new:
 *
 * Create a new RuleContext object.
 * 
 * Return value: A new #RuleContext object.
 **/
RuleContext *
rule_context_new(void)
{
    RuleContext *o = (RuleContext *) gtk_type_new(rule_context_get_type());

    return o;
}

void
rule_context_add_part_set(RuleContext * f, const char *setname, int part_type, RCPartFunc append, RCNextPartFunc next)
{
    struct _part_set_map *map;

    map = g_malloc0(sizeof(*map));
    map->type = part_type;
    map->append = append;
    map->next = next;
    map->name = g_strdup(setname);
    g_hash_table_insert(f->part_set_map, map->name, map);
    f->part_set_list = g_list_append(f->part_set_list, map);
    d(printf("adding part set '%s'\n", setname));
}

void
rule_context_add_rule_set(RuleContext * f, const char *setname, int rule_type, RCRuleFunc append, RCNextRuleFunc next)
{
    struct _rule_set_map *map;

    map = g_malloc0(sizeof(*map));
    map->type = rule_type;
    map->append = append;
    map->next = next;
    map->name = g_strdup(setname);
    g_hash_table_insert(f->rule_set_map, map->name, map);
    f->rule_set_list = g_list_append(f->rule_set_list, map);
    d(printf("adding rule set '%s'\n", setname));
}

/**
 * rule_context_set_error:
 * @f: 
 * @error: 
 * 
 * Set the text error for the context, or NULL to clear it.
 **/
static void
rule_context_set_error(RuleContext * f, char *error)
{
    g_free(f->error);
    f->error = error;
}

/**
 * rule_context_load:
 * @f: 
 * @system: 
 * @user: 
 *
 * Load a rule context from a system and user description file.
 * 
 * Return value: 
 **/
int
rule_context_load(RuleContext * f, const char *system, const char *user)
{
    d(printf("rule_context: loading %s %s\n", system, user));

    return ((RuleContextClass *) ((GtkObject *) f)->klass)->load(f, system, user);
}

static int
load(RuleContext * f, const char *system, const char *user)
{
    xmlNodePtr set, rule;
    struct _part_set_map *part_map;
    struct _rule_set_map *rule_map;

    rule_context_set_error(f, NULL);

    d(printf("loading rules %s %s\n", system, user));

    f->system = xmlParseFile(system);
    if (f->system == NULL) {
        rule_context_set_error(f, g_strdup_printf("Unable to load system rules '%s': %s",
                              system, strerror(errno)));
        return -1;
    }
    if (strcmp(f->system->root->name, "filterdescription")) {
        rule_context_set_error(f, g_strdup_printf("Unable to load system rules '%s': Invalid format", system));
        xmlFreeDoc(f->system);
        f->system = NULL;
        return -1;
    }
    /* doesn't matter if this doens't exist */
    f->user = xmlParseFile(user);

    /* now parse structure */
    /* get rule parts */
    set = f->system->root->childs;
    while (set) {
        d(printf("set name = %s\n", set->name));
        part_map = g_hash_table_lookup(f->part_set_map, set->name);
        if (part_map) {
            d(printf("loading parts ...\n"));
            rule = set->childs;
            while (rule) {
                if (!strcmp(rule->name, "part")) {
                    FilterPart *part = FILTER_PART(gtk_type_new(part_map->type));

                    if (filter_part_xml_create(part, rule) == 0) {
                        part_map->append(f, part);
                    } else {
                        gtk_object_unref((GtkObject *) part);
                        g_warning("Cannot load filter part");
                    }
                }
                rule = rule->next;
            }
        }
        set = set->next;
    }

    /* now load actual rules */
    if (f->user) {
        set = f->user->root->childs;
        while (set) {
            d(printf("set name = %s\n", set->name));
            rule_map = g_hash_table_lookup(f->rule_set_map, set->name);
            if (rule_map) {
                d(printf("loading rules ...\n"));
                rule = set->childs;
                while (rule) {
                    d(printf("checking node: %s\n", rule->name));
                    if (!strcmp(rule->name, "rule")) {
                        FilterRule *part = FILTER_RULE(gtk_type_new(rule_map->type));

                        if (filter_rule_xml_decode(part, rule, f) == 0) {
                            rule_map->append(f, part);
                        } else {
                            gtk_object_unref((GtkObject *) part);
                            g_warning("Cannot load filter part");
                        }
                    }
                    rule = rule->next;
                }
            }
            set = set->next;
        }
    }
    return 0;
}

/**
 * rule_context_save:
 * @f: 
 * @user: 
 * 
 * Save a rule context to disk.
 * 
 * Return value: 
 **/
int
rule_context_save(RuleContext * f, const char *user)
{
    return ((RuleContextClass *) ((GtkObject *) f)->klass)->save(f, user);
}

static int
save(RuleContext * f, const char *user)
{
    xmlDocPtr doc;
    xmlNodePtr root, rules, work;
    GList *l;
    FilterRule *rule;
    struct _rule_set_map *map;

    doc = xmlNewDoc("1.0");
    root = xmlNewDocNode(doc, NULL, "filteroptions", NULL);
    xmlDocSetRootElement(doc, root);
    l = f->rule_set_list;
    while (l) {
        map = l->data;
        rules = xmlNewDocNode(doc, NULL, map->name, NULL);
        xmlAddChild(root, rules);
        rule = NULL;
        while ((rule = map->next(f, rule, NULL))) {
            d(printf("processing rule %s\n", rule->name));
            work = filter_rule_xml_encode(rule);
            xmlAddChild(rules, work);
        }
        l = g_list_next(l);
    }
    xmlSaveFile(user, doc);
    xmlFreeDoc(doc);
    return 0;
}

FilterPart *
rule_context_find_part(RuleContext * f, const char *name)
{
    d(printf("find part : "));
    return filter_part_find_list(f->parts, name);
}

FilterPart *
rule_context_create_part(RuleContext * f, const char *name)
{
    FilterPart *part;

    part = rule_context_find_part(f, name);
    if (part)
        part = filter_part_clone(part);
    return part;
}

FilterPart *
rule_context_next_part(RuleContext * f, FilterPart * last)
{
    return filter_part_next_list(f->parts, last);
}

FilterRule *
rule_context_next_rule(RuleContext * f, FilterRule * last, const char *source)
{
    return filter_rule_next_list(f->rules, last, source);
}

FilterRule *
rule_context_find_rule(RuleContext * f, const char *name, const char *source)
{
    return filter_rule_find_list(f->rules, name, source);
}

void
rule_context_add_part(RuleContext * f, FilterPart * part)
{
    f->parts = g_list_append(f->parts, part);
}

void
rule_context_add_rule(RuleContext * f, FilterRule * new)
{
    f->rules = g_list_append(f->rules, new);
}

static void
new_rule_clicked (GtkWidget *dialog, int button, RuleContext *context)
{
#ifndef NO_WARNINGS
#warning "Need a changed signal for this to work best"
#endif
    if (button == 0) {
        FilterRule *rule = gtk_object_get_data (GTK_OBJECT (dialog), "rule");
        char *user = gtk_object_get_data (GTK_OBJECT (dialog), "path");
        
        if (!filter_rule_validate (rule)) {
            /* no need to popup a dialog because the validate code does that. */
            return;
        }
        
        gtk_object_ref (GTK_OBJECT (rule));
        rule_context_add_rule (context, rule);
        if (user) {
            rule_context_save ((RuleContext *) context, user);
        }
    }
    
    if (button != -1) {
        gnome_dialog_close (GNOME_DIALOG (dialog));
    }
}

/* add a rule, with a gui, asking for confirmation first ... optionally save to path */
void
rule_context_add_rule_gui(RuleContext * f, FilterRule * rule, const char *title, const char *path)
{
    GtkWidget *w;
    GnomeDialog *gd;

    w = filter_rule_get_widget(rule, f);
    gd = (GnomeDialog *) gnome_dialog_new(title, GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL);
    gtk_window_set_policy(GTK_WINDOW(gd), FALSE, TRUE, FALSE);
    gtk_box_pack_start((GtkBox *) gd->vbox, w, TRUE, TRUE, 0);
    gtk_window_set_default_size(GTK_WINDOW(gd), 600, 400);
    gtk_widget_show((GtkWidget *) gd);
    gtk_object_set_data_full((GtkObject *) gd, "rule", rule, (GtkDestroyNotify) gtk_object_unref);
    if (path)
        gtk_object_set_data_full((GtkObject *) gd, "path", g_strdup(path), (GtkDestroyNotify) g_free);
    gtk_signal_connect((GtkObject *) gd, "clicked", new_rule_clicked, f);
    gtk_object_ref((GtkObject *) f);
    gtk_object_set_data_full((GtkObject *) gd, "context", f, (GtkDestroyNotify) gtk_object_unref);
    gtk_widget_show((GtkWidget *) gd);
}

void
rule_context_remove_rule (RuleContext *f, FilterRule *rule)
{
    f->rules = g_list_remove (f->rules, rule);
}

void
rule_context_rank_rule (RuleContext *f, FilterRule *rule, int rank)
{
    f->rules = g_list_remove (f->rules, rule);
    f->rules = g_list_insert (f->rules, rule, rank);
}

int
rule_context_get_rank_rule (RuleContext *f, FilterRule *rule, const char *source)
{
    GList *node = f->rules;
    int i = 0;
    
    while (node) {
        FilterRule *r = node->data;
        
        if (r == rule)
            return i;
        
        if (source == NULL || (r->source && strcmp (r->source, source) == 0))
            i++;
        
        node = node->next;
    }
    
    return -1;
}