/*
* 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
*
*
* Authors:
* Not Zed
* Jepartrey Stedfast
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#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:
* @l:
* @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:
* @l:
* @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:
* @l:
* @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);
}