aboutsummaryrefslogblamecommitdiffstats
path: root/e-util/e-filter-part.c
blob: 75988339e4b6c27a0a68f08a5cd68010650edfa3 (plain) (tree)




































                                                                             



                      













                                                                      
                                                                       


           
                                                  


                                   



                                                      

                                      
 
















                                                       
                                       








                                                                              
                                                                
























































                                                                  
                                                             





                                    

                                                                           







                                                                                             

                                                                   
                                           
                                                                      



                                                             
                                                                 
                                          
                                                                      





















                                                                                 
                                                                     











































































                                                                                 
                                               






















































                                                                              
                                                           












































                                                                              
         






















                                                                    
         
















                                                                    
                                                      







                                    
         






































                                                                        
                                    








                                                         
                                                        






                                                  
                                                 



                                                                  
                                                                                              


                                                                               
                                                                                      
                                                            

                        
                                                                                             





                                     
/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) version 3.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with the program; if not, see <http://www.gnu.org/licenses/>
 *
 *
 * Authors:
 *      Not Zed <notzed@lostzed.mmc.com.au>
 *      Jepartrey Stedfast <fejj@ximian.com>
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 *
 */

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

#include <stdlib.h>
#include <string.h>

#include <gtk/gtk.h>
#include <glib/gi18n.h>

#include "e-filter-file.h"
#include "e-filter-part.h"
#include "e-rule-context.h"

G_DEFINE_TYPE (
    EFilterPart,
    e_filter_part,
    G_TYPE_OBJECT)

static void
filter_part_finalize (GObject *object)
{
    EFilterPart *part = E_FILTER_PART (object);

    g_list_foreach (part->elements, (GFunc) g_object_unref, NULL);
    g_list_free (part->elements);

    g_free (part->name);
    g_free (part->title);
    g_free (part->code);

    /* Chain up to parent's finalize() method. */
    G_OBJECT_CLASS (e_filter_part_parent_class)->finalize (object);
}

static void
e_filter_part_class_init (EFilterPartClass *class)
{
    GObjectClass *object_class;

    object_class = G_OBJECT_CLASS (class);
    object_class->finalize = filter_part_finalize;
}

static void
e_filter_part_init (EFilterPart *part)
{
}

/**
 * e_filter_part_new:
 *
 * Create a new EFilterPart object.
 *
 * Return value: A new #EFilterPart object.
 **/
EFilterPart *
e_filter_part_new (void)
{
    return g_object_new (E_TYPE_FILTER_PART, NULL);
}

gboolean
e_filter_part_validate (EFilterPart *part,
                        EAlert **alert)
{
    GList *link;

    g_return_val_if_fail (E_IS_FILTER_PART (part), FALSE);

    /* The part is valid if all of its elements are valid. */
    for (link = part->elements; link != NULL; link = g_list_next (link)) {
        EFilterElement *element = link->data;

        if (!e_filter_element_validate (element, alert))
            return FALSE;
    }

    return TRUE;
}

gint
e_filter_part_eq (EFilterPart *part_a,
                  EFilterPart *part_b)
{
    GList *link_a, *link_b;

    g_return_val_if_fail (E_IS_FILTER_PART (part_a), FALSE);
    g_return_val_if_fail (E_IS_FILTER_PART (part_b), FALSE);

    if (g_strcmp0 (part_a->name, part_b->name) != 0)
        return FALSE;

    if (g_strcmp0 (part_a->title, part_b->title) != 0)
        return FALSE;

    if (g_strcmp0 (part_a->code, part_b->code) != 0)
        return FALSE;

    link_a = part_a->elements;
    link_b = part_b->elements;

    while (link_a != NULL && link_b != NULL) {
        EFilterElement *element_a = link_a->data;
        EFilterElement *element_b = link_b->data;

        if (!e_filter_element_eq (element_a, element_b))
            return FALSE;

        link_a = g_list_next (link_a);
        link_b = g_list_next (link_b);
    }

    if (link_a != NULL || link_b != NULL)
        return FALSE;

    return TRUE;
}

gint
e_filter_part_xml_create (EFilterPart *part,
                          xmlNodePtr node,
                          ERuleContext *context)
{
    xmlNodePtr n;
    gchar *type, *str;
    EFilterElement *el;

    g_return_val_if_fail (E_IS_FILTER_PART (part), FALSE);
    g_return_val_if_fail (node != NULL, FALSE);
    g_return_val_if_fail (E_IS_RULE_CONTEXT (context), FALSE);

    str = (gchar *) xmlGetProp (node, (xmlChar *)"name");
    part->name = g_strdup (str);
    if (str)
        xmlFree (str);

    n = node->children;
    while (n) {
        if (!strcmp ((gchar *) n->name, "input")) {
            type = (gchar *) xmlGetProp (n, (xmlChar *)"type");
            if (type != NULL
                && (el = e_rule_context_new_element (context, type)) != NULL) {
                e_filter_element_xml_create (el, n);
                xmlFree (type);
                part->elements = g_list_append (part->elements, el);
            } else {
                g_warning ("Invalid xml format, missing/unknown input type");
            }
        } else if (!strcmp ((gchar *) n->name, "title") ||
               !strcmp ((gchar *) n->name, "_title")) {
            if (!part->title) {
                str = (gchar *) xmlNodeGetContent (n);
                part->title = g_strdup (str);
                if (str)
                    xmlFree (str);
            }
        } else if (!strcmp ((gchar *) n->name, "code")) {
            if (!part->code) {
                str = (gchar *) xmlNodeGetContent (n);
                part->code = g_strdup (str);
                if (str)
                    xmlFree (str);
            }
        } else if (n->type == XML_ELEMENT_NODE) {
            g_warning ("Unknown part element in xml: %s\n", n->name);
        }
        n = n->next;
    }

    return 0;
}

xmlNodePtr
e_filter_part_xml_encode (EFilterPart *part)
{
    xmlNodePtr node;
    GList *link;

    g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);

    node = xmlNewNode (NULL, (xmlChar *)"part");
    xmlSetProp (node, (xmlChar *)"name", (xmlChar *) part->name);

    for (link = part->elements; link != NULL; link = g_list_next (link)) {
        EFilterElement *element = link->data;
        xmlNodePtr value;

        value = e_filter_element_xml_encode (element);
        xmlAddChild (node, value);
    }

    return node;
}

gint
e_filter_part_xml_decode (EFilterPart *part,
                          xmlNodePtr node)
{
    xmlNodePtr child;

    g_return_val_if_fail (E_IS_FILTER_PART (part), -1);
    g_return_val_if_fail (node != NULL, -1);

    for (child = node->children; child != NULL; child = child->next) {
        EFilterElement *element;
        xmlChar *name;

        if (strcmp ((gchar *) child->name, "value") != 0)
            continue;

        name = xmlGetProp (child, (xmlChar *) "name");
        element = e_filter_part_find_element (part, (gchar *) name);
        xmlFree (name);

        if (element != NULL)
            e_filter_element_xml_decode (element, child);
    }

    return 0;
}

EFilterPart *
e_filter_part_clone (EFilterPart *part)
{
    EFilterPart *clone;
    GList *link;

    g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);

    clone = g_object_new (G_OBJECT_TYPE (part), NULL, NULL);
    clone->name = g_strdup (part->name);
    clone->title = g_strdup (part->title);
    clone->code = g_strdup (part->code);

    for (link = part->elements; link != NULL; link = g_list_next (link)) {
        EFilterElement *element = link->data;
        EFilterElement *clone_element;

        clone_element = e_filter_element_clone (element);
        clone->elements = g_list_append (clone->elements, clone_element);
    }

    return clone;
}

/* only copies values of matching parts in the right order */
void
e_filter_part_copy_values (EFilterPart *dst_part,
                           EFilterPart *src_part)
{
    GList *dst_link, *src_link;

    g_return_if_fail (E_IS_FILTER_PART (dst_part));
    g_return_if_fail (E_IS_FILTER_PART (src_part));

    /* NOTE: we go backwards, it just works better that way */

    /* for each source type, search the dest type for
     * a matching type in the same order */
    src_link = g_list_last (src_part->elements);
    dst_link = g_list_last (dst_part->elements);

    while (src_link != NULL && dst_link != NULL) {
        EFilterElement *src_element = src_link->data;
        GList *link = dst_link;

        while (link != NULL) {
            EFilterElement *dst_element = link->data;
            GType dst_type = G_OBJECT_TYPE (dst_element);
            GType src_type = G_OBJECT_TYPE (src_element);

            if (dst_type == src_type) {
                e_filter_element_copy_value (
                    dst_element, src_element);
                dst_link = g_list_previous (link);
                break;
            }

            link = g_list_previous (link);
        }

        src_link = g_list_previous (src_link);
    }
}

EFilterElement *
e_filter_part_find_element (EFilterPart *part,
                            const gchar *name)
{
    GList *link;

    g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);

    if (name == NULL)
        return NULL;

    for (link = part->elements; link != NULL; link = g_list_next (link)) {
        EFilterElement *element = link->data;

        if (g_strcmp0 (element->name, name) == 0)
            return element;
    }

    return NULL;
}

GtkWidget *
e_filter_part_get_widget (EFilterPart *part)
{
    GtkWidget *hbox;
    GList *link;

    g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);

    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);

    for (link = part->elements; link != NULL; link = g_list_next (link)) {
        EFilterElement *element = link->data;
        GtkWidget *widget;

        widget = e_filter_element_get_widget (element);
        if (widget != NULL)
            gtk_box_pack_start (
                GTK_BOX (hbox), widget,
                E_IS_FILTER_FILE (element),
                E_IS_FILTER_FILE (element), 3);
    }

    gtk_widget_show_all (hbox);

    return hbox;
}

/**
 * e_filter_part_build_code:
 * @part:
 * @out:
 *
 * Outputs the code of a part.
 **/
void
e_filter_part_build_code (EFilterPart *part,
                          GString *out)
{
    GList *link;

    g_return_if_fail (E_IS_FILTER_PART (part));
    g_return_if_fail (out != NULL);

    if (part->code != NULL)
        e_filter_part_expand_code (part, part->code, out);

    for (link = part->elements; link != NULL; link = g_list_next (link)) {
        EFilterElement *element = link->data;
        e_filter_element_build_code (element, out, part);
    }
}

/**
 * e_filter_part_build_code_list:
 * @list:
 * @out:
 *
 * Construct a list of the filter parts code into
 * a single string.
 **/
void
e_filter_part_build_code_list (GList *list,
                               GString *out)
{
    GList *link;

    g_return_if_fail (out != NULL);

    for (link = list; link != NULL; link = g_list_next (link)) {
        EFilterPart *part = link->data;

        e_filter_part_build_code (part, out);
        g_string_append (out, "\n  ");
    }
}

/**
 * e_filter_part_find_list:
 * @list:
 * @name:
 *
 * Find a filter part stored in a list.
 *
 * Return value:
 **/
EFilterPart *
e_filter_part_find_list (GList *list,
                         const gchar *name)
{
    GList *link;

    g_return_val_if_fail (name != NULL, NULL);

    for (link = list; link != NULL; link = g_list_next (link)) {
        EFilterPart *part = link->data;

        if (g_strcmp0 (part->name, name) == 0)
            return part;
    }

    return NULL;
}

/**
 * e_filter_part_next_list:
 * @list:
 * @last: The last item retrieved, or NULL to start
 * from the beginning of the list.
 *
 * Iterate through a filter part list.
 *
 * Return value: The next value in the list, or NULL if the
 * list is expired.
 **/
EFilterPart *
e_filter_part_next_list (GList *list,
                         EFilterPart *last)
{
    GList *link = list;

    if (last != NULL) {
        link = g_list_find (list, last);
        if (link == NULL)
            link = list;
        else
            link = link->next;
    }

    return (link != NULL) ? link->data : NULL;
}

/**
 * e_filter_part_expand_code:
 * @part:
 * @str:
 * @out:
 *
 * Expands the variables in string @str based on the values of the part.
 **/
void
e_filter_part_expand_code (EFilterPart *part,
                           const gchar *source,
                           GString *out)
{
    const gchar *newstart, *start, *end;
    gchar *name = g_alloca (32);
    gint len, namelen = 32;

    g_return_if_fail (E_IS_FILTER_PART (part));
    g_return_if_fail (source != NULL);
    g_return_if_fail (out != NULL);

    start = source;

    while (start && (newstart = strstr (start, "${"))
        && (end = strstr (newstart + 2, "}"))) {
        EFilterElement *element;

        len = end - newstart - 2;
        if (len + 1 > namelen) {
            namelen = (len + 1) * 2;
            name = g_alloca (namelen);
        }
        memcpy (name, newstart + 2, len);
        name[len] = 0;

        element = e_filter_part_find_element (part, name);
        if (element != NULL) {
            g_string_append_printf (out, "%.*s", (gint)(newstart - start), start);
            e_filter_element_format_sexp (element, out);
#if 0
        } else if ((val = g_hash_table_lookup (part->globals, name))) {
            g_string_append_printf (out, "%.*s", newstart - start, start);
            camel_sexp_encode_string (out, val);
#endif
        } else {
            g_string_append_printf (out, "%.*s", (gint)(end - start + 1), start);
        }
        start = end + 1;
    }

    g_string_append (out, start);
}