aboutsummaryrefslogblamecommitdiffstats
path: root/filter/filter-xml.c
blob: e59ad5199a8dfce806524511fc78587c42072e58 (plain) (tree)
1
2
3
4

                                                                                     

                                                            










                             

            









































                                                                   








                                      















                                                             

                                       
 
                                                      

                                                  
                                        


                     

                                                                             



                        
                                                                                                 


                                                             
                                                                       

                                                 
                              

                        




                                    
















                                                                    
                                                                                                                                   
                                                         
                                                                     




                                                       
                                                                                    



                                                              
                                                                  


                                                                                                  

                                         





                                  
                                  














                                                          
                                                                             
 
                                                                 







                                                           
                                                                 


                                                         


                                                                           
                                                
                                                                                                





                                                                       
                                                                               
                                                                                              
                                                                                    


















                                                                                       
                                                           





                                         
                                                           









                                                           
 
                                                                  


                                
                                                            

                               
                                                           

                      
                                                   





































                                                                                        
                                                  















                                                              
                            




                                                        

                                                                           
                                                                            
                           

                                      


                                                   

                                                                                                            

                                                         
                                                                                 












                                                                                                                             
                                                                  
                                                                                                                        

                                                                                                        



                                                                           
                                                            
                                                                                  
                                 
                                              

                                             
                                                                           










                                                                                            

                                                     












































                                                                                   











                                                     


                                                                         










                                                          
                                            
 








































                                                                            



































































                                                                        
 














                                                     











                                                                        
/* -*- Mode: C; c-file-style: "linux"; indent-tabs-mode: t; c-basic-offset: 8; -*- */

/* Load save filter descriptions/options from an xml file */

#include <glib.h>
#include <gtk/gtk.h>
#include <gnome.h>
#include <gtkhtml/gtkhtml.h>

#include <gnome-xml/tree.h>
#include <gnome-xml/parser.h>

#include "filter-arg-types.h"
#include "filter-xml.h"

#define d(x)

struct token_tab {
    char *name;
    enum filter_xml_token token;
};

struct token_tab token_table[] = {
    { "action", FILTER_XML_ACTION },
    { "address", FILTER_XML_ADDRESS },
    { "code", FILTER_XML_CODE },
    { "description", FILTER_XML_DESC },
    { "except", FILTER_XML_EXCEPT },
    { "folder", FILTER_XML_FOLDER },
    { "match", FILTER_XML_MATCH },
    { "name", FILTER_XML_NAME },
    { "option", FILTER_XML_OPTION },
    { "optionrule", FILTER_XML_OPTIONRULE },
    { "optionset", FILTER_XML_OPTIONSET },
    { "optionvalue", FILTER_XML_OPTIONVALUE },
    { "receive", FILTER_XML_RECEIVE },
    { "rule", FILTER_XML_RULE },
    { "ruleset", FILTER_XML_RULESET },
    { "send", FILTER_XML_SEND },
    { "source", FILTER_XML_SOURCE },
    { "text", FILTER_XML_TEXT },
};

/* convert a name to a token value */
static int
tokenise(const char *name)
{
    int i;
    int len = sizeof(token_table)/sizeof(token_table[0]);

    if (name) {
        for (i=0;i<len;i++) {
            if (strcmp(name, token_table[i].name) == 0)
                return token_table[i].token;
        }
    }
    return -1;
}

static int
tokenise_xmlfreeprop(const char *name)
{
    int ret = -1;
    ret = tokenise(name);
    free(name);
    return ret;
}

static char *
detokenise(int token)
{
    int i;
    int len = sizeof(token_table)/sizeof(token_table[0]);

    if (token>=0) {
        for (i=0;i<len;i++) {
            if (token_table[i].token == token)
                return token_table[i].name;
        }
    }
    return "<unknown>";
}


static xmlNodePtr
find_node(xmlNodePtr start, char *name)
{
    d(printf("trying to find node '%s'\n", name));
    while (start && strcmp(start->name, name))
        start = start->next;
    d(printf("node = %p\n", start));
    return start;
}

static xmlNodePtr
find_node_attr(xmlNodePtr start, char *name, char *attrname, char *attrvalue)
{
    xmlNodePtr node;
    char *s;

    d(printf("looking for node named %s with attribute %s=%s\n", name, attrname, attrvalue));

    while ( start && (start = find_node(start, name)) ) {
        s = xmlGetProp(start, attrname);
        d(printf("   comparing '%s' to '%s'\n", s, attrvalue));
        if (s && !strcmp(s, attrvalue)) {
            free(s);
            break;
        }
        free(s);
        start = start->next;
    }
    return start;
}

static GList *
load_desc(xmlNodePtr node, int type, int vartype, char *varname)
{
    struct filter_desc *desc;
    xmlNodePtr n;
    int newtype;
    int newvartype;
    char *newvarname;
    GList *list = NULL;

    while (node) {
        if (node->content) {
            desc = g_malloc0(sizeof(*desc));
            desc->data = node->content;
            desc->type = type;
            desc->vartype = vartype;
            desc->varname = varname?g_strdup(varname):0;
            d(printf(" **** node name = %s var name = %s  var type = %s\n", node->name, varname, detokenise(vartype)));
            list = g_list_append(list, desc);
            d(printf("appending '%s'\n", node->content));
            newtype = type;
            newvartype = -1;
            newvarname = NULL;
        } else {
            newtype = tokenise(node->name);
            newvartype = tokenise_xmlfreeprop(xmlGetProp(node, "type"));
            newvarname = xmlGetProp(node, "name");
        }
        n = node->childs;
        while (n) {
            d(printf("adding child '%s'\n", n->name));
            list = g_list_concat(list, load_desc(n, newtype, newvartype, newvarname));
            n = n->next;
        }
        if (newvarname)
            free(newvarname);
        node = node->next;
    }
    return list;
}

GList *
filter_load_ruleset(xmlDocPtr doc)
{
    xmlNodePtr ruleset, rule, n;
    struct filter_rule *r;
    int type;
    int ruletype;
    GList *rules = NULL;

    g_return_val_if_fail(doc!=NULL, NULL);

    ruleset = find_node(doc->root->childs, "ruleset");

    while (ruleset) {

        rule = ruleset->childs;
        
        ruletype = tokenise_xmlfreeprop(xmlGetProp(ruleset, "type"));

        d(printf("ruleset, name = %s\n", ruleset->name));

        while (rule) {

            n = rule->childs;
            r = g_malloc0(sizeof(*r));
            r->type = ruletype;
            r->name = xmlGetProp(rule, "name");

            d(printf(" rule, name = %s\n", r->name));

            while (n) {
                type = tokenise(n->name);
                d(printf("  n, name = %s\n", n->name));
                d(printf("  ncontent = %s\n", n->content));
                d(printf("  childs = %p\n", n->childs));
                if (n->childs) {
                    d(printf(" childs content = %s\n", n->childs->content));
                }
                switch(type) {
                case FILTER_XML_CODE:
                    r->code = xmlNodeGetContent(n);
                    break;
                case FILTER_XML_DESC:
                    d(printf(" ** loading description\n"));
                    r->description = load_desc(n->childs, type, -1, NULL);
                    d(printf(" ** done loading description\n"));
                    break;
                default:
                    printf("warning, unknown token encountered\n");
                    break;
                }
                n = n->next;
            }
            if (r)
                rules = g_list_append(rules, r);
            rule = rule->next;
        }
        ruleset = find_node(ruleset->next, "ruleset");
    }
    return rules;
}

int
filter_find_rule(struct filter_rule *a, char *name)
{
    d(printf("finding, is %s = %s?\n", a->name, name));
    return strcmp(a->name, name);
}

int
filter_find_arg(FilterArg *a, char *name)
{
    d(printf("finding, is %s = %s?\n", a->name, name));
    return strcmp(a->name, name);
}

static FilterArg *
load_optionvalue(struct filter_desc *desc, xmlNodePtr node)
{
    xmlNodePtr n;
    int token;
    int lasttoken = -2;
    FilterArg *arg = NULL;

    d(printf("creating arg entry for '%s'\n", desc->varname));

    switch(desc->vartype) {
    case FILTER_XML_ADDRESS:
        arg = filter_arg_address_new(desc->varname);
        break;
    case FILTER_XML_FOLDER:
        arg = filter_arg_folder_new(desc->varname);
        break;
    default:
        d(printf("ok, maybe we're not\n"));
        /* unknown arg type, drop it */
        return NULL;
    }

    if (node == NULL)
        return arg;

    filter_arg_values_add_xml(arg, node);

    return arg;
}

/* loads a blank (empty args) optionrule from a rule */
static struct filter_optionrule *
optionrule_new(struct filter_rule *rule)
{
    GList *ldesc;
    struct filter_desc *desc;
    struct filter_optionrule *optionrule;

    optionrule = g_malloc0(sizeof(*optionrule));
    optionrule->rule = rule;

    ldesc = rule->description;
    while (ldesc) {
        desc = ldesc->data;
        if (desc->varname && desc->vartype!=-1) {
            FilterArg *arg;
            arg = load_optionvalue(desc, NULL);
            if (arg)
                optionrule->args = g_list_append(optionrule->args, arg);
        }
        ldesc = g_list_next(ldesc);
    }
    return optionrule;
}

GList *
filter_load_optionset(xmlDocPtr doc, GList *rules)
{
    xmlNodePtr optionset, option, o, or;
    struct filter_option *op;
    struct filter_optionrule *optionrule;
    struct filter_rule *fr;
    struct filter_desc *desc;
    int type, token;
    GList *l = NULL;
    GList *lrule;
    GList *ldesc;

    g_return_val_if_fail(doc!=NULL, NULL);

    optionset = find_node(doc->root->childs, "optionset");
    if (optionset == NULL) {
        printf("optionset not found\n");
        return NULL;
    }
    option = find_node(optionset->childs, "option");
    while (option) {
        o = option->childs;
        op = g_malloc0(sizeof(*op));
        d(printf("option = %s\n", o->name));
        d(printf("option, type=%s\n", xmlGetProp(option, "type")));
        op->type = tokenise_xmlfreeprop(xmlGetProp(option, "type"));
        while (o) {
            char *rulestr;

            type = tokenise(o->name);
            switch (type) {
            case FILTER_XML_OPTIONRULE:
                rulestr = xmlGetProp(o, "rule");
                lrule = g_list_find_custom(rules, rulestr, (GCompareFunc) filter_find_rule);
                if (lrule) {
                    fr = lrule->data;
                    d(printf("found rule : %s\n", fr->name));
                    optionrule = g_malloc0(sizeof(*optionrule));
                    optionrule->rule = fr;
                    op->options = g_list_append(op->options, optionrule);

                    /* scan through all variables required, setup blank variables if they do not exist */
                    ldesc = fr->description;
                    while (ldesc) {
                        desc = ldesc->data;
                        if (desc->varname && desc->vartype!=-1) {
                            FilterArg *arg;
                            /* try and see if there is a setting for this value */
                            or = find_node_attr(o->childs, "optionvalue", "name", desc->varname);
                            arg = load_optionvalue(desc, or);
                            if (arg) {
                                optionrule->args = g_list_append(optionrule->args, arg);
                                d(printf("Adding arg %s\n", arg->name));
                            }
                        }
                        ldesc = g_list_next(ldesc);
                    }
                } else {
                    /* FIXME: memleak */
                    printf("Cannot find rule: %s\n", rulestr);
                }
                free(rulestr);
                break;
            case FILTER_XML_DESC:
                d(printf("loading option descriptiong\n"));
                op->description = load_desc(option->childs, type, -1, NULL);
                break;
            }
            o = o->next;
        }
        l = g_list_append(l, op);
        option = find_node(option->next, "option");
    }
    return l;
}

xmlNodePtr
filter_write_optionset(xmlDocPtr doc, GList *optionl)
{
    xmlNodePtr root, cur, option, optionrule, optionvalue;
    GList *optionrulel, *argl;
    struct filter_optionrule *or;

    root = xmlNewDocNode(doc, NULL, "optionset", NULL);

    /* for all options */
    while (optionl) {
        struct filter_option *op = optionl->data;

        option = xmlNewDocNode(doc, NULL, "option", NULL);
        xmlSetProp(option, "type", detokenise(op->type));

        optionrulel = op->options;
        while (optionrulel) {
            or = optionrulel->data;

            optionrule = xmlNewDocNode(doc, NULL, "optionrule", NULL);
            xmlSetProp(optionrule, "type", detokenise(or->rule->type));
            xmlSetProp(optionrule, "rule", or->rule->name);

            argl = or->args;
            while (argl) {
                FilterArg *arg = argl->data;

                optionvalue = filter_arg_values_get_xml(arg);
                if (optionvalue)
                    xmlAddChild(optionrule, optionvalue);

                argl = g_list_next(argl);
            }

            xmlAddChild(option, optionrule);

            optionrulel = g_list_next(optionrulel);
        }

        xmlAddChild(root, option);
        optionl = g_list_next(optionl);
    }

    return root;
}

/* utility functions */
struct filter_optionrule *
filter_clone_optionrule(struct filter_optionrule *or)
{
    GList *arg;
    struct filter_optionrule *rule;

    rule = g_malloc0(sizeof(*rule));

    rule->rule = or->rule;
    arg = or->args;
    while (arg) {
        FilterArg *new = filter_arg_clone(FILTER_ARG(arg->data));
        gtk_object_set_data(new, "origin", arg->data);
        rule->args = g_list_append(rule->args, new);
        arg = g_list_next(arg);
    }
    return rule;
}

void
filter_clone_optionrule_free(struct filter_optionrule *or)
{
    GList *argl;
    struct filter_optionrule *rule;

    d(printf("---- free optionrule\n"));

    argl = or->args;
    while (argl) {
        gtk_object_unref(GTK_OBJECT(argl->data));
        argl = g_list_next(argl);
    }
    g_list_free(or->args);
    g_free(or);
}

struct filter_optionrule *
filter_optionrule_new_from_rule(struct filter_rule *rule)
{
    struct filter_optionrule *or;
    GList *descl;

    or = g_malloc0(sizeof(*or));

    or->rule = rule;

    descl = rule->description;
    while (descl) {
        struct filter_desc *desc = descl->data;
        if (desc->varname && desc->vartype != -1) {
            FilterArg *arg = NULL;
            switch (desc->vartype) {
            case FILTER_XML_ADDRESS:
                arg = filter_arg_address_new(desc->varname);
                break;
            case FILTER_XML_FOLDER:
                arg = filter_arg_folder_new(desc->varname);
                break;
            }
            if (arg) {
                or->args = g_list_append(or->args, arg);
            }
        }
        descl = g_list_next(descl);
    }
    return or;
}

void
filter_description_free(GList *descl)
{
    GList *node;

    node = descl;
    while (node) {
        GList *next = g_list_next(node);
        struct filter_desc *d = node->data;

        g_free(d->data);
        g_free(d->varname);
        g_free(d);

        node = next;
    }
    g_list_free(descl);
}

void
filter_load_ruleset_free(GList *nodel)
{
    GList *node = nodel;

    while (node) {
        GList *next = g_list_next(node);
        struct filter_rule *r = node->data;

        filter_description_free(r->description);

        /* g_free(r->name); */
        /* g_free(r->code); */

        g_free(r);
        node = next;
    }
    g_list_free(nodel);
}

void
filter_load_optionset_free(GList *optionl)
{
    GList *option = optionl;
    while (option) {
        GList *next = g_list_next(option);
        struct filter_option *fo = option->data;
        GList *optionrule = fo->options;

        while (optionrule) {
            GList *next = g_list_next(optionrule);
            struct filter_optionrule *or = optionrule->data;
            GList *arg = or->args;

            while (arg) {
                gtk_object_unref(arg->data);
                arg = g_list_next(arg);
            }

            g_list_free(or->args);
            g_free(or);
            optionrule = next;
        }
        filter_description_free(fo->description);
        g_list_free(fo->options);
        g_free(fo);
        option = next;
    }
}

#ifdef TESTER
int main(int argc, char **argv)
{
    GList *rules, *options;
    xmlDocPtr doc, out, optionset, filteroptions;

    gnome_init("Test", "0.0", argc, argv);

    doc = xmlParseFile("filterdescription.xml");

    rules = load_ruleset(doc);
    options = load_optionset(doc, rules);

    out = xmlParseFile("saveoptions.xml");
    options = load_optionset(doc, rules);
#if 0
    out = xmlNewDoc("1.0");
    optionset = save_optionset(out, options);
    filteroptions = xmlNewDocNode(out, NULL, "filteroptions", NULL);
    xmlAddChild(filteroptions, optionset);
    xmlDocSetRootElement(out, filteroptions);
    xmlSaveFile("saveoptions.xml", out);
#endif
    return 0;
}
#endif