1 /*
2  * This program is free software; you can redistribute it and/or modify it
3  * under the terms of the GNU Lesser General Public License as published by
4  * the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful, but
7  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
9  * for more details.
10  *
11  * You should have received a copy of the GNU Lesser General Public License
12  * along with this program; if not, see <http://www.gnu.org/licenses/>.
13  *
14  *
15  * Authors:
16  *		Jeffrey Stedfast <fejj@ximian.com>
17  *
18  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19  *
20  */
21 
22 #include "evolution-config.h"
23 
24 #include <string.h>
25 #include <sys/types.h>
26 
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 #include <glib/gstdio.h>
30 
31 #include "e-alert.h"
32 #include "e-filter-file.h"
33 #include "e-filter-part.h"
34 
G_DEFINE_TYPE(EFilterFile,e_filter_file,E_TYPE_FILTER_ELEMENT)35 G_DEFINE_TYPE (
36 	EFilterFile,
37 	e_filter_file,
38 	E_TYPE_FILTER_ELEMENT)
39 
40 static void
41 filter_file_filename_changed (GtkFileChooser *file_chooser,
42                               EFilterElement *element)
43 {
44 	EFilterFile *file = E_FILTER_FILE (element);
45 	const gchar *path;
46 
47 	path = gtk_file_chooser_get_filename (file_chooser);
48 
49 	g_free (file->path);
50 	file->path = g_strdup (path);
51 }
52 
53 static void
filter_file_finalize(GObject * object)54 filter_file_finalize (GObject *object)
55 {
56 	EFilterFile *file = E_FILTER_FILE (object);
57 
58 	xmlFree (file->type);
59 	g_free (file->path);
60 
61 	/* Chain up to parent's finalize() method. */
62 	G_OBJECT_CLASS (e_filter_file_parent_class)->finalize (object);
63 }
64 
65 static gboolean
filter_file_validate(EFilterElement * element,EAlert ** alert)66 filter_file_validate (EFilterElement *element,
67                       EAlert **alert)
68 {
69 	EFilterFile *file = E_FILTER_FILE (element);
70 
71 	g_warn_if_fail (alert == NULL || *alert == NULL);
72 
73 	if (!file->path) {
74 		if (alert)
75 			*alert = e_alert_new ("filter:no-file", NULL);
76 		return FALSE;
77 	}
78 
79 	/* FIXME: do more to validate command-lines? */
80 
81 	if (g_strcmp0 (file->type, "file") == 0) {
82 		if (!g_file_test (file->path, G_FILE_TEST_IS_REGULAR)) {
83 			if (alert)
84 				*alert = e_alert_new ("filter:bad-file",
85 						       file->path, NULL);
86 			return FALSE;
87 		}
88 	} else if (g_strcmp0 (file->type, "command") == 0) {
89 		/* Only requirements so far is that the
90 		 * command can't be an empty string. */
91 		return (file->path[0] != '\0');
92 	}
93 
94 	return TRUE;
95 }
96 
97 static gint
filter_file_eq(EFilterElement * element_a,EFilterElement * element_b)98 filter_file_eq (EFilterElement *element_a,
99                 EFilterElement *element_b)
100 {
101 	EFilterFile *file_a = E_FILTER_FILE (element_a);
102 	EFilterFile *file_b = E_FILTER_FILE (element_b);
103 
104 	/* Chain up to parent's eq() method. */
105 	if (!E_FILTER_ELEMENT_CLASS (e_filter_file_parent_class)->
106 		eq (element_a, element_b))
107 		return FALSE;
108 
109 	if (g_strcmp0 (file_a->path, file_b->path) != 0)
110 		return FALSE;
111 
112 	if (g_strcmp0 (file_a->type, file_b->type) != 0)
113 		return FALSE;
114 
115 	return TRUE;
116 }
117 
118 static xmlNodePtr
filter_file_xml_encode(EFilterElement * element)119 filter_file_xml_encode (EFilterElement *element)
120 {
121 	EFilterFile *file = E_FILTER_FILE (element);
122 	xmlNodePtr cur, value;
123 	const gchar *type;
124 
125 	type = file->type ? file->type : "file";
126 
127 	value = xmlNewNode (NULL, (xmlChar *)"value");
128 	xmlSetProp (value, (xmlChar *) "name", (xmlChar *) element->name);
129 	xmlSetProp (value, (xmlChar *) "type", (xmlChar *) type);
130 
131 	cur = xmlNewChild (value, NULL, (xmlChar *) type, NULL);
132 	xmlNodeSetContent (cur, (xmlChar *) file->path);
133 
134 	return value;
135 }
136 
137 static gint
filter_file_xml_decode(EFilterElement * element,xmlNodePtr node)138 filter_file_xml_decode (EFilterElement *element,
139                         xmlNodePtr node)
140 {
141 	EFilterFile *file = E_FILTER_FILE (element);
142 	gchar *name, *str, *type;
143 	xmlNodePtr child;
144 
145 	name = (gchar *) xmlGetProp (node, (xmlChar *) "name");
146 	type = (gchar *) xmlGetProp (node, (xmlChar *) "type");
147 
148 	xmlFree (element->name);
149 	element->name = name;
150 
151 	xmlFree (file->type);
152 	file->type = type;
153 
154 	g_free (file->path);
155 	file->path = NULL;
156 
157 	child = node->children;
158 	while (child != NULL) {
159 		if (!strcmp ((gchar *) child->name, type)) {
160 			str = (gchar *) xmlNodeGetContent (child);
161 			file->path = g_strdup (str ? str : "");
162 			xmlFree (str);
163 
164 			break;
165 		} else if (child->type == XML_ELEMENT_NODE) {
166 			g_warning (
167 				"Unknown node type '%s' encountered "
168 				"decoding a %s\n", child->name, type);
169 		}
170 
171 		child = child->next;
172 	}
173 
174 	return 0;
175 }
176 
177 static GtkWidget *
filter_file_get_widget(EFilterElement * element)178 filter_file_get_widget (EFilterElement *element)
179 {
180 	EFilterFile *file = E_FILTER_FILE (element);
181 	GtkWidget *widget;
182 
183 	widget = gtk_file_chooser_button_new (
184 		_("Choose a File"), GTK_FILE_CHOOSER_ACTION_OPEN);
185 	gtk_file_chooser_set_filename (
186 		GTK_FILE_CHOOSER (widget), file->path);
187 	g_signal_connect (
188 		widget, "selection-changed",
189 		G_CALLBACK (filter_file_filename_changed), element);
190 
191 	return widget;
192 }
193 
194 static void
filter_file_format_sexp(EFilterElement * element,GString * out)195 filter_file_format_sexp (EFilterElement *element,
196                          GString *out)
197 {
198 	EFilterFile *file = E_FILTER_FILE (element);
199 
200 	camel_sexp_encode_string (out, file->path);
201 }
202 
203 static void
filter_file_describe(EFilterElement * element,GString * out)204 filter_file_describe (EFilterElement *element,
205 		      GString *out)
206 {
207 	EFilterFile *file = E_FILTER_FILE (element);
208 
209 	g_string_append_c (out, E_FILTER_ELEMENT_DESCRIPTION_VALUE_START);
210 	g_string_append (out, file->path);
211 	g_string_append_c (out, E_FILTER_ELEMENT_DESCRIPTION_VALUE_END);
212 }
213 
214 static void
e_filter_file_class_init(EFilterFileClass * class)215 e_filter_file_class_init (EFilterFileClass *class)
216 {
217 	GObjectClass *object_class;
218 	EFilterElementClass *filter_element_class;
219 
220 	object_class = G_OBJECT_CLASS (class);
221 	object_class->finalize = filter_file_finalize;
222 
223 	filter_element_class = E_FILTER_ELEMENT_CLASS (class);
224 	filter_element_class->validate = filter_file_validate;
225 	filter_element_class->eq = filter_file_eq;
226 	filter_element_class->xml_encode = filter_file_xml_encode;
227 	filter_element_class->xml_decode = filter_file_xml_decode;
228 	filter_element_class->get_widget = filter_file_get_widget;
229 	filter_element_class->format_sexp = filter_file_format_sexp;
230 	filter_element_class->describe = filter_file_describe;
231 }
232 
233 static void
e_filter_file_init(EFilterFile * filter)234 e_filter_file_init (EFilterFile *filter)
235 {
236 }
237 
238 /**
239  * filter_file_new:
240  *
241  * Create a new EFilterFile object.
242  *
243  * Return value: A new #EFilterFile object.
244  **/
245 EFilterFile *
e_filter_file_new(void)246 e_filter_file_new (void)
247 {
248 	return g_object_new (E_TYPE_FILTER_FILE, NULL);
249 }
250 
251 EFilterFile *
e_filter_file_new_type_name(const gchar * type)252 e_filter_file_new_type_name (const gchar *type)
253 {
254 	EFilterFile *file;
255 
256 	file = e_filter_file_new ();
257 	file->type = (gchar *) xmlStrdup ((xmlChar *) type);
258 
259 	return file;
260 }
261 
262 void
e_filter_file_set_path(EFilterFile * file,const gchar * path)263 e_filter_file_set_path (EFilterFile *file,
264                         const gchar *path)
265 {
266 	g_return_if_fail (E_IS_FILTER_FILE (file));
267 
268 	g_free (file->path);
269 	file->path = g_strdup (path);
270 }
271