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 }