evolution-3.6.4/libemail-utils/em-vfolder-rule.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  *      Jeffrey 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 <string.h>
 29 
 30 #include <gtk/gtk.h>
 31 #include <glib/gi18n.h>
 32 
 33 #include <libevolution-utils/e-alert.h>
 34 
 35 #include <libemail-engine/e-mail-folder-utils.h>
 36 
 37 #include "em-vfolder-context.h"
 38 #include "em-vfolder-rule.h"
 39 
 40 #define EM_VFOLDER_RULE_GET_PRIVATE(obj) \
 41 	(G_TYPE_INSTANCE_GET_PRIVATE \
 42 	((obj), EM_TYPE_VFOLDER_RULE, EMVFolderRulePrivate))
 43 
 44 #define EM_VFOLDER_RULE_GET_PRIVATE(obj) \
 45 	(G_TYPE_INSTANCE_GET_PRIVATE \
 46 	((obj), EM_TYPE_VFOLDER_RULE, EMVFolderRulePrivate))
 47 
 48 struct _EMVFolderRulePrivate {
 49 	em_vfolder_rule_with_t with;
 50 	GQueue sources;		/* uri's of the source folders */
 51 	gboolean autoupdate;
 52 	GHashTable *include_subfolders;
 53 };
 54 
 55 static gint validate (EFilterRule *, EAlert **alert);
 56 static gint vfolder_eq (EFilterRule *fr, EFilterRule *cm);
 57 static xmlNodePtr xml_encode (EFilterRule *);
 58 static gint xml_decode (EFilterRule *, xmlNodePtr, ERuleContext *f);
 59 static void rule_copy (EFilterRule *dest, EFilterRule *src);
 60 static GtkWidget *get_widget (EFilterRule *fr, ERuleContext *f);
 61 
 62 /* DO NOT internationalise these strings */
 63 static const gchar *with_names[] = {
 64 	"specific",
 65 	"local_remote_active",
 66 	"remote_active",
 67 	"local"
 68 };
 69 
 70 G_DEFINE_TYPE (
 71 	EMVFolderRule,
 72 	em_vfolder_rule,
 73 	E_TYPE_FILTER_RULE)
 74 
 75 static void
 76 vfolder_rule_finalize (GObject *object)
 77 {
 78 	EMVFolderRule *rule = EM_VFOLDER_RULE (object);
 79 	gchar *uri;
 80 
 81 	while ((uri = g_queue_pop_head (&rule->priv->sources)) != NULL)
 82 		g_free (uri);
 83 
 84 	g_hash_table_destroy (rule->priv->include_subfolders);
 85 
 86 	/* Chain up to parent's finalize() method. */
 87 	G_OBJECT_CLASS (em_vfolder_rule_parent_class)->finalize (object);
 88 }
 89 
 90 static void
 91 em_vfolder_rule_class_init (EMVFolderRuleClass *class)
 92 {
 93 	GObjectClass *object_class;
 94 	EFilterRuleClass *filter_rule_class;
 95 
 96 	g_type_class_add_private (class, sizeof (EMVFolderRulePrivate));
 97 
 98 	object_class = G_OBJECT_CLASS (class);
 99 	object_class->finalize = vfolder_rule_finalize;
100 
101 	filter_rule_class = E_FILTER_RULE_CLASS (class);
102 	filter_rule_class->validate = validate;
103 	filter_rule_class->eq = vfolder_eq;
104 	filter_rule_class->xml_encode = xml_encode;
105 	filter_rule_class->xml_decode = xml_decode;
106 	filter_rule_class->copy = rule_copy;
107 	filter_rule_class->get_widget = get_widget;
108 }
109 
110 static void
111 em_vfolder_rule_init (EMVFolderRule *rule)
112 {
113 	rule->priv = EM_VFOLDER_RULE_GET_PRIVATE (rule);
114 	rule->priv->with = EM_VFOLDER_RULE_WITH_SPECIFIC;
115 	rule->priv->autoupdate = TRUE;
116 	/* it's using pointers from priv::sources, and those
117 	 * included has include_subfolders set to true */
118 	rule->priv->include_subfolders = g_hash_table_new (g_direct_hash, g_direct_equal);
119 
120 	rule->rule.source = g_strdup ("incoming");
121 }
122 
123 EFilterRule *
124 em_vfolder_rule_new (void)
125 {
126 	return g_object_new (
127 		EM_TYPE_VFOLDER_RULE, NULL);
128 }
129 
130 void
131 em_vfolder_rule_add_source (EMVFolderRule *rule,
132                             const gchar *uri)
133 {
134 	g_return_if_fail (EM_IS_VFOLDER_RULE (rule));
135 	g_return_if_fail (uri);
136 
137 	g_queue_push_tail (&rule->priv->sources, g_strdup (uri));
138 
139 	e_filter_rule_emit_changed (E_FILTER_RULE (rule));
140 }
141 
142 const gchar *
143 em_vfolder_rule_find_source (EMVFolderRule *rule,
144                              const gchar *uri)
145 {
146 	GList *link;
147 
148 	g_return_val_if_fail (EM_IS_VFOLDER_RULE (rule), NULL);
149 
150 	/* only does a simple string or address comparison, should
151 	 * probably do a decoded url comparison */
152 	link = g_queue_find_custom (
153 		&rule->priv->sources, uri, (GCompareFunc) strcmp);
154 
155 	return (link != NULL) ? link->data : NULL;
156 }
157 
158 void
159 em_vfolder_rule_remove_source (EMVFolderRule *rule,
160                                const gchar *uri)
161 {
162 	gchar *found;
163 
164 	g_return_if_fail (EM_IS_VFOLDER_RULE (rule));
165 
166 	found =(gchar *) em_vfolder_rule_find_source (rule, uri);
167 	if (found != NULL) {
168 		g_queue_remove (&rule->priv->sources, found);
169 		g_hash_table_remove (rule->priv->include_subfolders, found);
170 		g_free (found);
171 		e_filter_rule_emit_changed (E_FILTER_RULE (rule));
172 	}
173 }
174 
175 const gchar *
176 em_vfolder_rule_next_source (EMVFolderRule *rule,
177                              const gchar *last)
178 {
179 	GList *link;
180 
181 	if (last == NULL) {
182 		link = g_queue_peek_head_link (&rule->priv->sources);
183 	} else {
184 		link = g_queue_find (&rule->priv->sources, last);
185 		if (link == NULL)
186 			link = g_queue_peek_head_link (&rule->priv->sources);
187 		else
188 			link = g_list_next (link);
189 	}
190 
191 	return (link != NULL) ? link->data : NULL;
192 }
193 
194 GQueue *
195 em_vfolder_rule_get_sources (EMVFolderRule *rule)
196 {
197 	g_return_val_if_fail (rule != NULL, NULL);
198 
199 	return &rule->priv->sources;
200 }
201 
202 static gboolean
203 check_queue_has_key (gpointer key,
204                      gpointer value,
205                      gpointer user_data)
206 {
207 	EMVFolderRule *rule = user_data;
208 
209 	g_return_val_if_fail (rule != NULL, FALSE);
210 
211 	return g_queue_find (&rule->priv->sources, key) == NULL;
212 }
213 
214 void
215 em_vfolder_rule_sources_changed (EMVFolderRule *rule)
216 {
217 	g_return_if_fail (rule != NULL);
218 
219 	g_hash_table_foreach_remove (rule->priv->include_subfolders,
220 		check_queue_has_key, rule);
221 }
222 
223 gboolean
224 em_vfolder_rule_source_get_include_subfolders (EMVFolderRule *rule,
225                                                const gchar *source)
226 {
227 	g_return_val_if_fail (rule != NULL, FALSE);
228 	g_return_val_if_fail (source != NULL, FALSE);
229 
230 	source = em_vfolder_rule_find_source (rule, source);
231 
232 	return source && g_hash_table_lookup (rule->priv->include_subfolders, source);
233 }
234 
235 void
236 em_vfolder_rule_source_set_include_subfolders (EMVFolderRule *rule,
237                                                const gchar *source,
238                                                gboolean include_subfolders)
239 {
240 	g_return_if_fail (rule != NULL);
241 	g_return_if_fail (source != NULL);
242 
243 	source = em_vfolder_rule_find_source (rule, source);
244 	g_return_if_fail (source != NULL);
245 
246 	if (include_subfolders)
247 		g_hash_table_insert (rule->priv->include_subfolders, (gpointer) source, GINT_TO_POINTER (1));
248 	else
249 		g_hash_table_remove (rule->priv->include_subfolders, (gpointer) source);
250 }
251 
252 void
253 em_vfolder_rule_set_with (EMVFolderRule *rule,
254                           em_vfolder_rule_with_t with)
255 {
256 	g_return_if_fail (rule != NULL);
257 
258 	rule->priv->with = with;
259 }
260 
261 em_vfolder_rule_with_t
262 em_vfolder_rule_get_with (EMVFolderRule *rule)
263 {
264 	g_return_val_if_fail (rule != NULL, FALSE);
265 
266 	return rule->priv->with;
267 }
268 
269 void
270 em_vfolder_rule_set_autoupdate (EMVFolderRule *rule,
271                                 gboolean autoupdate)
272 {
273 	g_return_if_fail (rule != NULL);
274 
275 	rule->priv->autoupdate = autoupdate;
276 }
277 
278 gboolean
279 em_vfolder_rule_get_autoupdate (EMVFolderRule *rule)
280 {
281 	g_return_val_if_fail (rule != NULL, EM_VFOLDER_RULE_WITH_SPECIFIC);
282 
283 	return rule->priv->autoupdate;
284 }
285 
286 static gint
287 validate (EFilterRule *fr,
288           EAlert **alert)
289 {
290 	g_return_val_if_fail (fr != NULL, 0);
291 	g_warn_if_fail (alert == NULL || *alert == NULL);
292 
293 	if (!fr->name || !*fr->name) {
294 		if (alert)
295 			*alert = e_alert_new ("mail:no-name-vfolder", NULL);
296 		return 0;
297 	}
298 
299 	/* We have to have at least one source set in the "specific" case.
300 	 * Do not translate this string! */
301 	if (((EMVFolderRule *) fr)->priv->with == EM_VFOLDER_RULE_WITH_SPECIFIC &&
302 		g_queue_is_empty (&((EMVFolderRule *) fr)->priv->sources)) {
303 		if (alert)
304 			*alert = e_alert_new ("mail:vfolder-no-source", NULL);
305 		return 0;
306 	}
307 
308 	return E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)->validate (fr, alert);
309 }
310 
311 static gint
312 queue_eq (GQueue *queue_a,
313           GQueue *queue_b)
314 {
315 	GList *link_a;
316 	GList *link_b;
317 	gint truth = TRUE;
318 
319 	link_a = g_queue_peek_head_link (queue_a);
320 	link_b = g_queue_peek_head_link (queue_b);
321 
322 	while (truth && link_a != NULL && link_b != NULL) {
323 		gchar *uri_a = link_a->data;
324 		gchar *uri_b = link_b->data;
325 
326 		truth = (strcmp (uri_a, uri_b)== 0);
327 
328 		link_a = g_list_next (link_a);
329 		link_b = g_list_next (link_b);
330 	}
331 
332 	return truth && link_a == NULL && link_b == NULL;
333 }
334 
335 static gint
336 vfolder_eq (EFilterRule *fr,
337             EFilterRule *cm)
338 {
339 	return E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)->eq (fr, cm)
340 		&& queue_eq (
341 			&((EMVFolderRule *) fr)->priv->sources,
342 			&((EMVFolderRule *) cm)->priv->sources);
343 }
344 
345 static xmlNodePtr
346 xml_encode (EFilterRule *fr)
347 {
348 	EMVFolderRule *vr =(EMVFolderRule *) fr;
349 	xmlNodePtr node, set, work;
350 	GList *head, *link;
351 
352 	node = E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)->xml_encode (fr);
353 	g_return_val_if_fail (node != NULL, NULL);
354 	g_return_val_if_fail (vr->priv->with < G_N_ELEMENTS (with_names), NULL);
355 
356 	set = xmlNewNode (NULL, (const guchar *)"sources");
357 	xmlAddChild (node, set);
358 	xmlSetProp (set, (const guchar *)"with", (guchar *) with_names[vr->priv->with]);
359 	xmlSetProp (set, (const guchar *)"autoupdate", (guchar *) (vr->priv->autoupdate ? "true" : "false"));
360 
361 	head = g_queue_peek_head_link (&vr->priv->sources);
362 	for (link = head; link != NULL; link = g_list_next (link)) {
363 		const gchar *uri = link->data;
364 
365 		work = xmlNewNode (NULL, (const guchar *) "folder");
366 		xmlSetProp (work, (const guchar *) "uri", (guchar *) uri);
367 		xmlSetProp (work, (const guchar *) "include-subfolders", (guchar *)
368 			(em_vfolder_rule_source_get_include_subfolders (vr, uri) ? "true" : "false"));
369 		xmlAddChild (set, work);
370 	}
371 
372 	return node;
373 }
374 
375 static void
376 set_with (EMVFolderRule *vr,
377           const gchar *name)
378 {
379 	gint i;
380 
381 	for (i = 0; i < G_N_ELEMENTS (with_names); i++) {
382 		if (!strcmp (name, with_names[i])) {
383 			vr->priv->with = i;
384 			return;
385 		}
386 	}
387 
388 	vr->priv->with = 0;
389 }
390 
391 static gint
392 xml_decode (EFilterRule *fr,
393             xmlNodePtr node,
394             ERuleContext *f)
395 {
396 	xmlNodePtr set, work;
397 	gint result;
398 	EMVFolderRule *vr =(EMVFolderRule *) fr;
399 	gchar *tmp;
400 
401 	result = E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)->
402 		xml_decode (fr, node, f);
403 	if (result != 0)
404 		return result;
405 
406 	/* handle old format file, vfolder source is in filterrule */
407 	if (strcmp (fr->source, "incoming")!= 0) {
408 		set_with (vr, fr->source);
409 		g_free (fr->source);
410 		fr->source = g_strdup ("incoming");
411 	}
412 
413 	set = node->children;
414 	while (set) {
415 		if (!strcmp ((gchar *) set->name, "sources")) {
416 			tmp = (gchar *) xmlGetProp (set, (const guchar *)"with");
417 			if (tmp) {
418 				set_with (vr, tmp);
419 				xmlFree (tmp);
420 			}
421 			tmp = (gchar *) xmlGetProp (set, (const guchar *) "autoupdate");
422 			if (tmp) {
423 				vr->priv->autoupdate = g_str_equal (tmp, "true");
424 				xmlFree (tmp);
425 			}
426 			work = set->children;
427 			while (work) {
428 				if (!strcmp ((gchar *) work->name, "folder")) {
429 					tmp = (gchar *) xmlGetProp (work, (const guchar *)"uri");
430 					if (tmp) {
431 						gchar *include_subfolders;
432 
433 						g_queue_push_tail (&vr->priv->sources, g_strdup (tmp));
434 
435 						include_subfolders = (gchar *) xmlGetProp (work, (const guchar *) "include-subfolders");
436 						if (include_subfolders) {
437 							em_vfolder_rule_source_set_include_subfolders (
438 								vr,
439 								tmp, g_str_equal (include_subfolders, "true"));
440 							xmlFree (include_subfolders);
441 						}
442 
443 						xmlFree (tmp);
444 					}
445 				}
446 				work = work->next;
447 			}
448 		}
449 		set = set->next;
450 	}
451 	return 0;
452 }
453 
454 static void
455 rule_copy (EFilterRule *dest,
456            EFilterRule *src)
457 {
458 	EMVFolderRule *vdest, *vsrc;
459 	GList *head, *link;
460 	gchar *uri;
461 
462 	vdest =(EMVFolderRule *) dest;
463 	vsrc =(EMVFolderRule *) src;
464 
465 	while ((uri = g_queue_pop_head (&vdest->priv->sources)) != NULL)
466 		g_free (uri);
467 
468 	em_vfolder_rule_sources_changed (vdest);
469 
470 	head = g_queue_peek_head_link (&vsrc->priv->sources);
471 	for (link = head; link != NULL; link = g_list_next (link)) {
472 		const gchar *uri = link->data;
473 		g_queue_push_tail (&vdest->priv->sources, g_strdup (uri));
474 
475 		em_vfolder_rule_source_set_include_subfolders (
476 			vdest, uri,
477 			em_vfolder_rule_source_get_include_subfolders (vsrc, uri));
478 	}
479 
480 	vdest->priv->with = vsrc->priv->with;
481 	vdest->priv->autoupdate = vsrc->priv->autoupdate;
482 
483 	E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)->copy (dest, src);
484 }
485 
486 static GtkWidget *
487 get_widget (EFilterRule *fr,
488             ERuleContext *rc)
489 {
490 	GtkWidget *widget;
491 
492 	widget = E_FILTER_RULE_CLASS (em_vfolder_rule_parent_class)->
493 		get_widget (fr, rc);
494 
495 	return widget;
496 }