evolution-3.6.4/filter/e-filter-part.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Not Zed <notzed@lostzed.mmc.com.au>
 18  *      Jepartrey Stedfast <fejj@ximian.com>
 19  *
 20  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 21  *
 22  */
 23 
 24 #ifdef HAVE_CONFIG_H
 25 #include <config.h>
 26 #endif
 27 
 28 #include <stdlib.h>
 29 #include <string.h>
 30 
 31 #include <gtk/gtk.h>
 32 #include <glib/gi18n.h>
 33 
 34 #include "e-filter-file.h"
 35 #include "e-filter-part.h"
 36 #include "e-rule-context.h"
 37 
 38 G_DEFINE_TYPE (
 39 	EFilterPart,
 40 	e_filter_part,
 41 	G_TYPE_OBJECT)
 42 
 43 static void
 44 filter_part_finalize (GObject *object)
 45 {
 46 	EFilterPart *part = E_FILTER_PART (object);
 47 
 48 	g_list_foreach (part->elements, (GFunc) g_object_unref, NULL);
 49 	g_list_free (part->elements);
 50 
 51 	g_free (part->name);
 52 	g_free (part->title);
 53 	g_free (part->code);
 54 
 55 	/* Chain up to parent's finalize() method. */
 56 	G_OBJECT_CLASS (e_filter_part_parent_class)->finalize (object);
 57 }
 58 
 59 static void
 60 e_filter_part_class_init (EFilterPartClass *class)
 61 {
 62 	GObjectClass *object_class;
 63 
 64 	object_class = G_OBJECT_CLASS (class);
 65 	object_class->finalize = filter_part_finalize;
 66 }
 67 
 68 static void
 69 e_filter_part_init (EFilterPart *part)
 70 {
 71 }
 72 
 73 /**
 74  * e_filter_part_new:
 75  *
 76  * Create a new EFilterPart object.
 77  *
 78  * Return value: A new #EFilterPart object.
 79  **/
 80 EFilterPart *
 81 e_filter_part_new (void)
 82 {
 83 	return g_object_new (E_TYPE_FILTER_PART, NULL);
 84 }
 85 
 86 gboolean
 87 e_filter_part_validate (EFilterPart *part,
 88                         EAlert **alert)
 89 {
 90 	GList *link;
 91 
 92 	g_return_val_if_fail (E_IS_FILTER_PART (part), FALSE);
 93 
 94 	/* The part is valid if all of its elements are valid. */
 95 	for (link = part->elements; link != NULL; link = g_list_next (link)) {
 96 		EFilterElement *element = link->data;
 97 
 98 		if (!e_filter_element_validate (element, alert))
 99 			return FALSE;
100 	}
101 
102 	return TRUE;
103 }
104 
105 gint
106 e_filter_part_eq (EFilterPart *part_a,
107                   EFilterPart *part_b)
108 {
109 	GList *link_a, *link_b;
110 
111 	g_return_val_if_fail (E_IS_FILTER_PART (part_a), FALSE);
112 	g_return_val_if_fail (E_IS_FILTER_PART (part_b), FALSE);
113 
114 	if (g_strcmp0 (part_a->name, part_b->name) != 0)
115 		return FALSE;
116 
117 	if (g_strcmp0 (part_a->title, part_b->title) != 0)
118 		return FALSE;
119 
120 	if (g_strcmp0 (part_a->code, part_b->code) != 0)
121 		return FALSE;
122 
123 	link_a = part_a->elements;
124 	link_b = part_b->elements;
125 
126 	while (link_a != NULL && link_b != NULL) {
127 		EFilterElement *element_a = link_a->data;
128 		EFilterElement *element_b = link_b->data;
129 
130 		if (!e_filter_element_eq (element_a, element_b))
131 			return FALSE;
132 
133 		link_a = g_list_next (link_a);
134 		link_b = g_list_next (link_b);
135 	}
136 
137 	if (link_a != NULL || link_b != NULL)
138 		return FALSE;
139 
140 	return TRUE;
141 }
142 
143 gint
144 e_filter_part_xml_create (EFilterPart *part,
145                           xmlNodePtr node,
146                           ERuleContext *context)
147 {
148 	xmlNodePtr n;
149 	gchar *type, *str;
150 	EFilterElement *el;
151 
152 	g_return_val_if_fail (E_IS_FILTER_PART (part), FALSE);
153 	g_return_val_if_fail (node != NULL, FALSE);
154 	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), FALSE);
155 
156 	str = (gchar *) xmlGetProp (node, (xmlChar *)"name");
157 	part->name = g_strdup (str);
158 	if (str)
159 		xmlFree (str);
160 
161 	n = node->children;
162 	while (n) {
163 		if (!strcmp ((gchar *) n->name, "input")) {
164 			type = (gchar *) xmlGetProp (n, (xmlChar *)"type");
165 			if (type != NULL
166 			    && (el = e_rule_context_new_element (context, type)) != NULL) {
167 				e_filter_element_xml_create (el, n);
168 				xmlFree (type);
169 				part->elements = g_list_append (part->elements, el);
170 			} else {
171 				g_warning ("Invalid xml format, missing/unknown input type");
172 			}
173 		} else if (!strcmp ((gchar *) n->name, "title") ||
174 			   !strcmp ((gchar *) n->name, "_title")) {
175 			if (!part->title) {
176 				str = (gchar *) xmlNodeGetContent (n);
177 				part->title = g_strdup (str);
178 				if (str)
179 					xmlFree (str);
180 			}
181 		} else if (!strcmp ((gchar *) n->name, "code")) {
182 			if (!part->code) {
183 				str = (gchar *) xmlNodeGetContent (n);
184 				part->code = g_strdup (str);
185 				if (str)
186 					xmlFree (str);
187 			}
188 		} else if (n->type == XML_ELEMENT_NODE) {
189 			g_warning ("Unknown part element in xml: %s\n", n->name);
190 		}
191 		n = n->next;
192 	}
193 
194 	return 0;
195 }
196 
197 xmlNodePtr
198 e_filter_part_xml_encode (EFilterPart *part)
199 {
200 	xmlNodePtr node;
201 	GList *link;
202 
203 	g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
204 
205 	node = xmlNewNode (NULL, (xmlChar *)"part");
206 	xmlSetProp (node, (xmlChar *)"name", (xmlChar *) part->name);
207 
208 	for (link = part->elements; link != NULL; link = g_list_next (link)) {
209 		EFilterElement *element = link->data;
210 		xmlNodePtr value;
211 
212 		value = e_filter_element_xml_encode (element);
213 		xmlAddChild (node, value);
214 	}
215 
216 	return node;
217 }
218 
219 gint
220 e_filter_part_xml_decode (EFilterPart *part,
221                           xmlNodePtr node)
222 {
223 	xmlNodePtr child;
224 
225 	g_return_val_if_fail (E_IS_FILTER_PART (part), -1);
226 	g_return_val_if_fail (node != NULL, -1);
227 
228 	for (child = node->children; child != NULL; child = child->next) {
229 		EFilterElement *element;
230 		xmlChar *name;
231 
232 		if (strcmp ((gchar *) child->name, "value") != 0)
233 			continue;
234 
235 		name = xmlGetProp (child, (xmlChar *) "name");
236 		element = e_filter_part_find_element (part, (gchar *) name);
237 		xmlFree (name);
238 
239 		if (element != NULL)
240 			e_filter_element_xml_decode (element, child);
241 	}
242 
243 	return 0;
244 }
245 
246 EFilterPart *
247 e_filter_part_clone (EFilterPart *part)
248 {
249 	EFilterPart *clone;
250 	GList *link;
251 
252 	g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
253 
254 	clone = g_object_new (G_OBJECT_TYPE (part), NULL, NULL);
255 	clone->name = g_strdup (part->name);
256 	clone->title = g_strdup (part->title);
257 	clone->code = g_strdup (part->code);
258 
259 	for (link = part->elements; link != NULL; link = g_list_next (link)) {
260 		EFilterElement *element = link->data;
261 		EFilterElement *clone_element;
262 
263 		clone_element = e_filter_element_clone (element);
264 		clone->elements = g_list_append (clone->elements, clone_element);
265 	}
266 
267 	return clone;
268 }
269 
270 /* only copies values of matching parts in the right order */
271 void
272 e_filter_part_copy_values (EFilterPart *dst_part,
273                            EFilterPart *src_part)
274 {
275 	GList *dst_link, *src_link;
276 
277 	g_return_if_fail (E_IS_FILTER_PART (dst_part));
278 	g_return_if_fail (E_IS_FILTER_PART (src_part));
279 
280 	/* NOTE: we go backwards, it just works better that way */
281 
282 	/* for each source type, search the dest type for
283 	 * a matching type in the same order */
284 	src_link = g_list_last (src_part->elements);
285 	dst_link = g_list_last (dst_part->elements);
286 
287 	while (src_link != NULL && dst_link != NULL) {
288 		EFilterElement *src_element = src_link->data;
289 		GList *link = dst_link;
290 
291 		while (link != NULL) {
292 			EFilterElement *dst_element = link->data;
293 			GType dst_type = G_OBJECT_TYPE (dst_element);
294 			GType src_type = G_OBJECT_TYPE (src_element);
295 
296 			if (dst_type == src_type) {
297 				e_filter_element_copy_value (
298 					dst_element, src_element);
299 				dst_link = g_list_previous (link);
300 				break;
301 			}
302 
303 			link = g_list_previous (link);
304 		}
305 
306 		src_link = g_list_previous (src_link);
307 	}
308 }
309 
310 EFilterElement *
311 e_filter_part_find_element (EFilterPart *part,
312                             const gchar *name)
313 {
314 	GList *link;
315 
316 	g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
317 
318 	if (name == NULL)
319 		return NULL;
320 
321 	for (link = part->elements; link != NULL; link = g_list_next (link)) {
322 		EFilterElement *element = link->data;
323 
324 		if (g_strcmp0 (element->name, name) == 0)
325 			return element;
326 	}
327 
328 	return NULL;
329 }
330 
331 GtkWidget *
332 e_filter_part_get_widget (EFilterPart *part)
333 {
334 	GtkWidget *hbox;
335 	GList *link;
336 
337 	g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
338 
339 	hbox = gtk_hbox_new (FALSE, 3);
340 
341 	for (link = part->elements; link != NULL; link = g_list_next (link)) {
342 		EFilterElement *element = link->data;
343 		GtkWidget *widget;
344 
345 		widget = e_filter_element_get_widget (element);
346 		if (widget != NULL)
347 			gtk_box_pack_start (
348 				GTK_BOX (hbox), widget,
349 				E_IS_FILTER_FILE (element),
350 				E_IS_FILTER_FILE (element), 3);
351 	}
352 
353 	gtk_widget_show_all (hbox);
354 
355 	return hbox;
356 }
357 
358 /**
359  * e_filter_part_build_code:
360  * @part:
361  * @out:
362  *
363  * Outputs the code of a part.
364  **/
365 void
366 e_filter_part_build_code (EFilterPart *part,
367                           GString *out)
368 {
369 	GList *link;
370 
371 	g_return_if_fail (E_IS_FILTER_PART (part));
372 	g_return_if_fail (out != NULL);
373 
374 	if (part->code != NULL)
375 		e_filter_part_expand_code (part, part->code, out);
376 
377 	for (link = part->elements; link != NULL; link = g_list_next (link)) {
378 		EFilterElement *element = link->data;
379 		e_filter_element_build_code (element, out, part);
380 	}
381 }
382 
383 /**
384  * e_filter_part_build_code_list:
385  * @l:
386  * @out:
387  *
388  * Construct a list of the filter parts code into
389  * a single string.
390  **/
391 void
392 e_filter_part_build_code_list (GList *list,
393                                GString *out)
394 {
395 	GList *link;
396 
397 	g_return_if_fail (out != NULL);
398 
399 	for (link = list; link != NULL; link = g_list_next (link)) {
400 		EFilterPart *part = link->data;
401 
402 		e_filter_part_build_code (part, out);
403 		g_string_append (out, "\n  ");
404 	}
405 }
406 
407 /**
408  * e_filter_part_find_list:
409  * @l:
410  * @name:
411  *
412  * Find a filter part stored in a list.
413  *
414  * Return value:
415  **/
416 EFilterPart *
417 e_filter_part_find_list (GList *list,
418                          const gchar *name)
419 {
420 	GList *link;
421 
422 	g_return_val_if_fail (name != NULL, NULL);
423 
424 	for (link = list; link != NULL; link = g_list_next (link)) {
425 		EFilterPart *part = link->data;
426 
427 		if (g_strcmp0 (part->name, name) == 0)
428 			return part;
429 	}
430 
431 	return NULL;
432 }
433 
434 /**
435  * e_filter_part_next_list:
436  * @l:
437  * @last: The last item retrieved, or NULL to start
438  * from the beginning of the list.
439  *
440  * Iterate through a filter part list.
441  *
442  * Return value: The next value in the list, or NULL if the
443  * list is expired.
444  **/
445 EFilterPart *
446 e_filter_part_next_list (GList *list,
447                          EFilterPart *last)
448 {
449 	GList *link = list;
450 
451 	if (last != NULL) {
452 		link = g_list_find (list, last);
453 		if (link == NULL)
454 			link = list;
455 		else
456 			link = link->next;
457 	}
458 
459 	return (link != NULL) ? link->data : NULL;
460 }
461 
462 /**
463  * e_filter_part_expand_code:
464  * @part:
465  * @str:
466  * @out:
467  *
468  * Expands the variables in string @str based on the values of the part.
469  **/
470 void
471 e_filter_part_expand_code (EFilterPart *part,
472                            const gchar *source,
473                            GString *out)
474 {
475 	const gchar *newstart, *start, *end;
476 	gchar *name = g_alloca (32);
477 	gint len, namelen = 32;
478 
479 	g_return_if_fail (E_IS_FILTER_PART (part));
480 	g_return_if_fail (source != NULL);
481 	g_return_if_fail (out != NULL);
482 
483 	start = source;
484 
485 	while (start && (newstart = strstr (start, "${"))
486 		&& (end = strstr (newstart + 2, "}"))) {
487 		EFilterElement *element;
488 
489 		len = end - newstart - 2;
490 		if (len + 1 > namelen) {
491 			namelen = (len + 1) * 2;
492 			name = g_alloca (namelen);
493 		}
494 		memcpy (name, newstart + 2, len);
495 		name[len] = 0;
496 
497 		element = e_filter_part_find_element (part, name);
498 		if (element != NULL) {
499 			g_string_append_printf (out, "%.*s", (gint)(newstart - start), start);
500 			e_filter_element_format_sexp (element, out);
501 #if 0
502 		} else if ((val = g_hash_table_lookup (part->globals, name))) {
503 			g_string_append_printf (out, "%.*s", newstart - start, start);
504 			camel_sexp_encode_string (out, val);
505 #endif
506 		} else {
507 			g_string_append_printf (out, "%.*s", (gint)(end - start + 1), start);
508 		}
509 		start = end + 1;
510 	}
511 
512 	g_string_append (out, start);
513 }