source: trunk/third/evolution/mail/mail-vfolder.c @ 17188

Revision 17188, 25.5 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17187, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2  Copyright 2000, 2001 Ximian Inc.
3
4  Author: Michael Zucchi <notzed@ximian.com>
5
6  code for managing vfolders
7
8  NOTE: dont run this through fucking indent.
9*/
10
11#ifdef HAVE_CONFIG_H
12#include <config.h>
13#endif
14
15#include <glib.h>
16#include <libgnome/gnome-defs.h>
17#include <libgnome/gnome-i18n.h>
18#include <libgnomeui/gnome-dialog.h>
19#include <libgnomeui/gnome-dialog-util.h>
20#include <libgnomeui/gnome-stock.h>
21
22#include "Evolution.h"
23#include "evolution-storage.h"
24
25#include "evolution-shell-component.h"
26#include "folder-browser.h"
27#include "mail-vfolder.h"
28#include "mail-tools.h"
29#include "mail-autofilter.h"
30#include "mail-folder-cache.h"
31#include "mail.h"
32#include "mail-ops.h"
33#include "mail-mt.h"
34
35#include "gal/widgets/e-gui-utils.h"
36#include "gal/util/e-unicode-i18n.h"
37
38#include "camel/camel.h"
39#include "camel/camel-remote-store.h"
40#include "camel/camel-vee-folder.h"
41#include "camel/camel-vee-store.h"
42
43#include "filter/vfolder-context.h"
44#include "filter/vfolder-editor.h"
45
46#define d(x)
47
48static VfolderContext *context; /* context remains open all time */
49static CamelStore *vfolder_store; /* the 1 static vfolder store */
50
51/* lock for accessing shared resources (below) */
52static pthread_mutex_t vfolder_lock = PTHREAD_MUTEX_INITIALIZER;
53
54static GList *source_folders_remote;    /* list of source folder uri's - remote ones */
55static GList *source_folders_local;     /* list of source folder uri's - local ones */
56static GHashTable *vfolder_hash;
57
58extern EvolutionShellClient *global_shell_client;
59
60/* more globals ... */
61extern char *evolution_dir;
62extern CamelSession *session;
63
64static void rule_changed(FilterRule *rule, CamelFolder *folder);
65
66#define LOCK() pthread_mutex_lock(&vfolder_lock);
67#define UNLOCK() pthread_mutex_unlock(&vfolder_lock);
68
69/* ********************************************************************** */
70
71struct _setup_msg {
72        struct _mail_msg msg;
73
74        CamelFolder *folder;
75        char *query;
76        GList *sources_uri;
77        GList *sources_folder;
78};
79
80static char *
81vfolder_setup_desc(struct _mail_msg *mm, int done)
82{
83        struct _setup_msg *m = (struct _setup_msg *)mm;
84
85        return g_strdup_printf(_("Setting up vfolder: %s"), m->folder->full_name);
86}
87
88static void
89vfolder_setup_do(struct _mail_msg *mm)
90{
91        struct _setup_msg *m = (struct _setup_msg *)mm;
92        GList *l, *list = NULL;
93        CamelFolder *folder;
94
95        d(printf("Setting up vfolder: %s\n", m->folder->full_name));
96
97        camel_vee_folder_set_expression((CamelVeeFolder *)m->folder, m->query);
98
99        l = m->sources_uri;
100        while (l) {
101                d(printf(" Adding uri: %s\n", (char *)l->data));
102                folder = mail_tool_uri_to_folder (l->data, 0, &mm->ex);
103                if (folder) {
104                        list = g_list_append(list, folder);
105                } else {
106                        g_warning("Could not open vfolder source: %s", (char *)l->data);
107                        camel_exception_clear(&mm->ex);
108                }
109                l = l->next;
110        }
111
112        l = m->sources_folder;
113        while (l) {
114                d(printf(" Adding folder: %s\n", ((CamelFolder *)l->data)->full_name));
115                camel_object_ref((CamelObject *)l->data);
116                list = g_list_append(list, l->data);
117                l = l->next;
118        }
119
120        camel_vee_folder_set_folders((CamelVeeFolder *)m->folder, list);
121
122        l = list;
123        while (l) {
124                camel_object_unref((CamelObject *)l->data);
125                l = l->next;
126        }
127        g_list_free(list);
128}
129
130static void
131vfolder_setup_done(struct _mail_msg *mm)
132{
133        struct _setup_msg *m = (struct _setup_msg *)mm;
134
135        m = m;
136}
137
138static void
139vfolder_setup_free (struct _mail_msg *mm)
140{
141        struct _setup_msg *m = (struct _setup_msg *)mm;
142        GList *l;
143
144        camel_object_unref((CamelObject *)m->folder);
145        g_free(m->query);
146
147        l = m->sources_uri;
148        while (l) {
149                g_free(l->data);
150                l = l->next;
151        }
152        g_list_free(m->sources_uri);
153
154        l = m->sources_folder;
155        while (l) {
156                camel_object_unref(l->data);
157                l = l->next;
158        }
159        g_list_free(m->sources_folder);
160}
161
162static struct _mail_msg_op vfolder_setup_op = {
163        vfolder_setup_desc,
164        vfolder_setup_do,
165        vfolder_setup_done,
166        vfolder_setup_free,
167};
168
169static int
170vfolder_setup(CamelFolder *folder, const char *query, GList *sources_uri, GList *sources_folder)
171{
172        struct _setup_msg *m;
173        int id;
174       
175        m = mail_msg_new(&vfolder_setup_op, NULL, sizeof (*m));
176        m->folder = folder;
177        camel_object_ref((CamelObject *)folder);
178        m->query = g_strdup(query);
179        m->sources_uri = sources_uri;
180        m->sources_folder = sources_folder;
181       
182        id = m->msg.seq;
183        e_thread_put(mail_thread_queued_slow, (EMsg *)m);
184
185        return id;
186}
187
188/* ********************************************************************** */
189
190struct _adduri_msg {
191        struct _mail_msg msg;
192
193        char *uri;
194        GList *folders;
195        int remove;
196};
197
198static char *
199vfolder_adduri_desc(struct _mail_msg *mm, int done)
200{
201        struct _adduri_msg *m = (struct _adduri_msg *)mm;
202
203        return g_strdup_printf(_("Updating vfolders for uri: %s"), m->uri);
204}
205
206static void
207vfolder_adduri_do(struct _mail_msg *mm)
208{
209        struct _adduri_msg *m = (struct _adduri_msg *)mm;
210        GList *l;
211        CamelFolder *folder = NULL;
212        extern CamelFolder *drafts_folder, *outbox_folder, *sent_folder;
213
214        d(printf("%s uri to vfolder: %s\n", m->remove?"Removing":"Adding", m->uri));
215
216        /* we dont try lookup the cache if we are removing it, its no longer there */
217        if (!m->remove && !mail_note_get_folder_from_uri(m->uri, &folder)) {
218                g_warning("Folder '%s' disappeared while I was adding/remove it to/from my vfolder", m->uri);
219                return;
220        }
221
222        if (folder == NULL)
223                folder = mail_tool_uri_to_folder (m->uri, 0, &mm->ex);
224
225        if (folder != NULL) {
226                if (folder != drafts_folder && folder != outbox_folder && folder != sent_folder) {
227                        l = m->folders;
228                        while (l) {
229                                if (m->remove)
230                                        camel_vee_folder_remove_folder((CamelVeeFolder *)l->data, folder);
231                                else
232                                        camel_vee_folder_add_folder((CamelVeeFolder *)l->data, folder);
233                                l = l->next;
234                        }
235                }
236                camel_object_unref((CamelObject *)folder);
237        }
238}
239
240static void
241vfolder_adduri_done(struct _mail_msg *mm)
242{
243        struct _adduri_msg *m = (struct _adduri_msg *)mm;
244
245        m = m;
246}
247
248static void
249vfolder_adduri_free (struct _mail_msg *mm)
250{
251        struct _adduri_msg *m = (struct _adduri_msg *)mm;
252
253        g_list_foreach(m->folders, (GFunc)camel_object_unref, NULL);
254        g_list_free(m->folders);
255        g_free(m->uri);
256}
257
258static struct _mail_msg_op vfolder_adduri_op = {
259        vfolder_adduri_desc,
260        vfolder_adduri_do,
261        vfolder_adduri_done,
262        vfolder_adduri_free,
263};
264
265static int
266vfolder_adduri(const char *uri, GList *folders, int remove)
267{
268        struct _adduri_msg *m;
269        int id;
270       
271        m = mail_msg_new(&vfolder_adduri_op, NULL, sizeof (*m));
272        m->folders = folders;
273        m->uri = g_strdup(uri);
274        m->remove = remove;
275       
276        id = m->msg.seq;
277        e_thread_put(mail_thread_queued_slow, (EMsg *)m);
278
279        return id;
280}
281
282/* ********************************************************************** */
283
284/* So, uh, apparently g_list_find_custom expect the compare func to return 0 to mean true? */
285static GList *
286my_list_find(GList *l, const char *uri, GCompareFunc cmp)
287{
288        while (l) {
289                if (cmp(l->data, uri))
290                        break;
291                l = l->next;
292        }
293        return l;
294}
295
296/* called when a new uri becomes (un)available */
297void
298mail_vfolder_add_uri(CamelStore *store, const char *uri, int remove)
299{
300        FilterRule *rule;
301        const char *source;
302        CamelVeeFolder *vf;
303        GList *folders = NULL, *link;
304        int remote = (((CamelService *)store)->provider->flags & CAMEL_PROVIDER_IS_REMOTE) != 0;
305        GCompareFunc uri_cmp = CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->compare_folder_name;
306
307        if (CAMEL_IS_VEE_STORE(store) || !strncmp(uri, "vtrash:", 7) || context == NULL)
308                return;
309
310        g_assert(pthread_self() == mail_gui_thread);
311
312        LOCK();
313
314        d(printf("%s uri to check: %s\n", remove?"Removing":"Adding", uri));
315
316        /* maintain the source folders lists for changed rules later on */
317        if (remove) {
318                if (remote) {
319                        if ((link = my_list_find(source_folders_remote, (void *)uri, uri_cmp)) != NULL) {
320                                g_free(link->data);
321                                source_folders_remote = g_list_remove_link(source_folders_remote, link);
322                        }
323                } else {
324                        if ((link = my_list_find(source_folders_local, (void *)uri, uri_cmp)) != NULL) {
325                                g_free(link->data);
326                                source_folders_local = g_list_remove_link(source_folders_local, link);
327                        }
328                }
329        } else {
330                if (remote) {
331                        if (my_list_find(source_folders_remote, (void *)uri, uri_cmp) == NULL)
332                                source_folders_remote = g_list_prepend(source_folders_remote, g_strdup(uri));
333                } else {
334                        if (my_list_find(source_folders_local, (void *)uri, uri_cmp) == NULL)
335                                source_folders_local = g_list_prepend(source_folders_local, g_strdup(uri));
336                }
337        }
338
339        rule = NULL;
340        while ((rule = rule_context_next_rule((RuleContext *)context, rule, NULL))) {
341                int found = FALSE;
342               
343                if (!rule->name) {
344                        d(printf ("invalid rule (%p): rule->name is set to NULL\n"));
345                        continue;
346                }
347               
348                if (rule->source
349                    && ((!strcmp(rule->source, "local") && !remote)
350                        || (!strcmp(rule->source, "remote_active") && remote)
351                        || (!strcmp(rule->source, "local_remote_active"))))
352                        found = TRUE;
353               
354                /* we check using the store uri_cmp since its more accurate */
355                source = NULL;
356                while (!found && (source = vfolder_rule_next_source((VfolderRule *)rule, source)))
357                        found = uri_cmp(uri, source);
358               
359                if (found) {
360                        vf = g_hash_table_lookup(vfolder_hash, rule->name);
361                        g_assert(vf);
362                        camel_object_ref((CamelObject *)vf);
363                        folders = g_list_prepend(folders, vf);
364                }
365        }
366       
367        UNLOCK();
368       
369        if (folders != NULL)
370                vfolder_adduri(uri, folders, remove);
371}
372
373/* called when a uri is deleted from a store */
374void
375mail_vfolder_delete_uri(CamelStore *store, const char *uri)
376{
377        GCompareFunc uri_cmp = CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->compare_folder_name;
378        FilterRule *rule;
379        const char *source;
380        CamelVeeFolder *vf;
381        GString *changed;
382
383        if (context == NULL || !strncmp(uri, "vtrash:", 7))
384                return;
385
386        d(printf("Deleting uri to check: %s\n", uri));
387
388        g_assert(pthread_self() == mail_gui_thread);
389
390        changed = g_string_new("");
391
392        LOCK();
393
394        /* see if any rules directly reference this removed uri */
395        rule = NULL;
396        while ( (rule = rule_context_next_rule((RuleContext *)context, rule, NULL)) ) {
397                source = NULL;
398                while ( (source = vfolder_rule_next_source((VfolderRule *)rule, source)) ) {
399                        /* Remove all sources that match, ignore changed events though
400                           because the adduri call above does the work async */
401                        if (uri_cmp(uri, source)) {
402                                vf = g_hash_table_lookup(vfolder_hash, rule->name);
403                                g_assert(vf);
404                                gtk_signal_disconnect_by_func((GtkObject *)rule, rule_changed, vf);
405                                vfolder_rule_remove_source((VfolderRule *)rule, source);
406                                gtk_signal_connect((GtkObject *)rule, "changed", rule_changed, vf);
407                                g_string_sprintfa(changed, "    %s\n", rule->name);
408                                source = NULL;
409                        }
410                }
411        }
412
413        UNLOCK();
414
415        if (changed->str[0]) {
416                GnomeDialog *gd;
417                char *text, *user;
418
419                text = g_strdup_printf(_("The following vFolder(s):\n%s"
420                                         "Used the removed folder:\n    '%s'\n"
421                                         "And have been updated."),
422                                       changed->str, uri);
423
424                gd = (GnomeDialog *)gnome_warning_dialog(text);
425                g_free(text);
426                gnome_dialog_set_close(gd, TRUE);
427                gtk_widget_show((GtkWidget *)gd);
428
429                user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
430                rule_context_save((RuleContext *)context, user);
431                g_free(user);
432        }
433
434        g_string_free(changed, TRUE);
435}
436
437/* called when a uri is renamed in a store */
438void
439mail_vfolder_rename_uri(CamelStore *store, const char *from, const char *to)
440{
441        GCompareFunc uri_cmp = CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->compare_folder_name;
442        FilterRule *rule;
443        const char *source;
444        CamelVeeFolder *vf;
445        int changed = 0;
446
447        d(printf("vfolder rename uri: %s to %s\n", from, to));
448
449        if (context == NULL || !strncmp(from, "vtrash:", 7) || !strncmp(to, "vtrash:", 7))
450                return;
451
452        g_assert(pthread_self() == mail_gui_thread);
453
454        LOCK();
455
456        /* see if any rules directly reference this removed uri */
457        rule = NULL;
458        while ( (rule = rule_context_next_rule((RuleContext *)context, rule, NULL)) ) {
459                source = NULL;
460                while ( (source = vfolder_rule_next_source((VfolderRule *)rule, source)) ) {
461                        /* Remove all sources that match, ignore changed events though
462                           because the adduri call above does the work async */
463                        if (uri_cmp(from, source)) {
464                                d(printf("Vfolder '%s' used '%s' ('%s') now uses '%s'\n", rule->name, source, from, to));
465                                vf = g_hash_table_lookup(vfolder_hash, rule->name);
466                                g_assert(vf);
467                                gtk_signal_disconnect_by_func((GtkObject *)rule, rule_changed, vf);
468                                vfolder_rule_remove_source((VfolderRule *)rule, source);
469                                vfolder_rule_add_source((VfolderRule *)rule, to);
470                                gtk_signal_connect((GtkObject *)rule, "changed", rule_changed, vf);
471                                changed++;
472                                source = NULL;
473                        }
474                }
475        }
476
477        UNLOCK();
478
479        if (changed) {
480                char *user;
481
482                d(printf("Vfolders updated from renamed folder\n"));
483                user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
484                rule_context_save((RuleContext *)context, user);
485                g_free(user);
486        }
487}
488
489/* ********************************************************************** */
490
491static void context_rule_added(RuleContext *ctx, FilterRule *rule);
492
493static void
494rule_changed(FilterRule *rule, CamelFolder *folder)
495{
496        const char *sourceuri;
497        GList *l;
498        GList *sources_uri = NULL, *sources_folder = NULL;
499        GString *query;
500        int i;
501        CamelFolder *newfolder;
502
503        /* if the folder has changed name, then add it, then remove the old manually */
504        if (strcmp(folder->full_name, rule->name) != 0) {
505                char *key, *oldname;
506                CamelFolder *old;
507
508                LOCK();
509                d(printf("Changing folder name in hash table to '%s'\n", rule->name));
510                if (g_hash_table_lookup_extended(vfolder_hash, folder->full_name, (void **)&key, (void **)&old)) {
511                        g_hash_table_remove(vfolder_hash, key);
512                        g_free(key);
513                        g_hash_table_insert(vfolder_hash, g_strdup(rule->name), folder);
514                        UNLOCK();
515                } else {
516                        UNLOCK();
517                        g_warning("couldn't find a vfolder rule in our table? %s", folder->full_name);
518                }
519
520                /* TODO: make the folder->full_name var thread accessible */
521                oldname = g_strdup(folder->full_name);
522                camel_store_rename_folder(vfolder_store, oldname, rule->name, NULL);
523                g_free(oldname);
524        }
525
526        d(printf("Filter rule changed? for folder '%s'!!\n", folder->name));
527
528        /* find any (currently available) folders, and add them to the ones to open */
529        sourceuri = NULL;
530        while ( (sourceuri = vfolder_rule_next_source((VfolderRule *)rule, sourceuri)) ) {
531                if (mail_note_get_folder_from_uri(sourceuri, &newfolder)) {
532                        if (newfolder)
533                                sources_folder = g_list_append(sources_folder, newfolder);
534                        else
535                                sources_uri = g_list_append(sources_uri, g_strdup(sourceuri));
536                }
537        }
538
539        /* check the remote/local uri lists for any other uri's that should be looked at */
540        if (rule->source) {
541                LOCK();
542                for (i=0;i<2;i++) {
543                        if (i==0 && (!strcmp(rule->source, "local") || !strcmp(rule->source, "local_remote_active")))
544                                l = source_folders_local;
545                        else if (i==1 && (!strcmp(rule->source, "remote_active") || !strcmp(rule->source, "local_remote_active")))
546                                l = source_folders_remote;
547                        else
548                                l = NULL;
549
550                        while (l) {
551                                if (mail_note_get_folder_from_uri(l->data, &newfolder)) {
552                                        if (newfolder)
553                                                sources_folder = g_list_append(sources_folder, newfolder);
554                                        else
555                                                sources_uri = g_list_append(sources_uri, g_strdup(l->data));
556                                } else {
557                                        d(printf("  -> No such folder?\n"));
558                                }
559                                l = l->next;
560                        }
561                }
562                UNLOCK();
563        }
564
565        query = g_string_new("");
566        filter_rule_build_code(rule, query);
567
568        vfolder_setup(folder, query->str, sources_uri, sources_folder);
569
570        g_string_free(query, TRUE);
571}
572
573static void context_rule_added(RuleContext *ctx, FilterRule *rule)
574{
575        CamelFolder *folder;
576
577        d(printf("rule added: %s\n", rule->name));
578
579        /* this always runs quickly */
580        folder = camel_store_get_folder(vfolder_store, rule->name, 0, NULL);
581        if (folder) {
582                gtk_signal_connect((GtkObject *)rule, "changed", rule_changed, folder);
583
584                LOCK();
585                g_hash_table_insert(vfolder_hash, g_strdup(rule->name), folder);
586                UNLOCK();
587
588                mail_note_folder(folder);
589                rule_changed(rule, folder);
590        }
591}
592
593static void context_rule_removed(RuleContext *ctx, FilterRule *rule)
594{
595        char *key, *path;
596        CamelFolder *folder;
597
598        d(printf("rule removed; %s\n", rule->name));
599
600        /* TODO: remove from folder info cache? */
601
602        path = g_strdup_printf("/%s", rule->name);
603        evolution_storage_removed_folder(mail_lookup_storage(vfolder_store), path);
604        g_free(path);
605
606        LOCK();
607        if (g_hash_table_lookup_extended(vfolder_hash, rule->name, (void **)&key, (void **)&folder)) {
608                g_hash_table_remove(vfolder_hash, key);
609                g_free(key);
610                UNLOCK();
611                camel_object_unref((CamelObject *)folder);
612        } else
613                UNLOCK();
614
615        camel_store_delete_folder(vfolder_store, rule->name, NULL);
616}
617
618static void
619store_folder_created(CamelObject *o, void *event_data, void *data)
620{
621        CamelStore *store = (CamelStore *)o;
622        CamelFolderInfo *info = event_data;
623
624        store = store;
625        info = info;
626}
627
628static void
629store_folder_deleted(CamelObject *o, void *event_data, void *data)
630{
631        CamelStore *store = (CamelStore *)o;
632        CamelFolderInfo *info = event_data;
633        FilterRule *rule;
634        char *user;
635
636        d(printf("Folder deleted: %s\n", info->name));
637        store = store;
638
639        /* Warning not thread safe, but might be enough */
640
641        LOCK();
642
643        /* delete it from our list */
644        rule = rule_context_find_rule((RuleContext *)context, info->full_name, NULL);
645        if (rule) {
646                /* We need to stop listening to removed events, otherwise we'll try and remove it again */
647                gtk_signal_disconnect_by_func((GtkObject *)context, context_rule_removed, context);
648                rule_context_remove_rule((RuleContext *)context, rule);
649                gtk_object_unref((GtkObject *)rule);
650                gtk_signal_connect((GtkObject *)context, "rule_removed", context_rule_removed, context);
651
652                user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
653                rule_context_save((RuleContext *)context, user);
654                g_free(user);
655        } else {
656                g_warning("Cannot find rule for deleted vfolder '%s'", info->name);
657        }
658
659        UNLOCK();
660}
661
662static void
663store_folder_renamed(CamelObject *o, void *event_data, void *data)
664{
665        CamelStore *store = (CamelStore *)o;
666        CamelRenameInfo *info = event_data;
667        FilterRule *rule;
668        char *user;
669        char *key;
670        CamelFolder *folder;
671
672        store = store;
673
674        /* This should be more-or-less thread-safe */
675
676        d(printf("Folder renamed to '%s' from '%s'\n", info->new->full_name, info->old_base));
677
678        /* Folder is already renamed? */
679        LOCK();
680        d(printf("Changing folder name in hash table to '%s'\n", info->new->full_name));
681        if (g_hash_table_lookup_extended(vfolder_hash, info->old_base, (void **)&key, (void **)&folder)) {
682                g_hash_table_remove(vfolder_hash, key);
683                g_free(key);
684                g_hash_table_insert(vfolder_hash, g_strdup(info->new->full_name), folder);
685
686                rule = rule_context_find_rule((RuleContext *)context, info->old_base, NULL);
687                g_assert(rule);
688
689                gtk_signal_disconnect_by_func((GtkObject *)rule, rule_changed, folder);
690                filter_rule_set_name(rule, info->new->name);           
691                gtk_signal_connect((GtkObject *)rule, "changed", rule_changed, folder);
692
693                user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
694                rule_context_save((RuleContext *)context, user);
695                g_free(user);
696
697                UNLOCK();
698        } else {
699                UNLOCK();
700                g_warning("couldn't find a vfolder rule in our table? %s", info->new->full_name);
701        }
702}
703
704void
705vfolder_load_storage(GNOME_Evolution_Shell shell)
706{
707        char *user, *storeuri;
708        FilterRule *rule;
709
710        vfolder_hash = g_hash_table_new(g_str_hash, g_str_equal);
711
712        /* first, create the vfolder store, and set it up */
713        storeuri = g_strdup_printf("vfolder:%s/vfolder", evolution_dir);
714        vfolder_store = camel_session_get_store(session, storeuri, NULL);
715        if (vfolder_store == NULL) {
716                g_warning("Cannot open vfolder store - no vfolders available");
717                return;
718        }
719
720        camel_object_hook_event((CamelObject *)vfolder_store, "folder_created",
721                                (CamelObjectEventHookFunc)store_folder_created, NULL);
722        camel_object_hook_event((CamelObject *)vfolder_store, "folder_deleted",
723                                (CamelObjectEventHookFunc)store_folder_deleted, NULL);
724        camel_object_hook_event((CamelObject *)vfolder_store, "folder_renamed",
725                                (CamelObjectEventHookFunc)store_folder_renamed, NULL);
726
727        d(printf("got store '%s' = %p\n", storeuri, vfolder_store));
728        mail_load_storage_by_uri(shell, storeuri, U_("VFolders"));
729
730        /* load our rules */
731        user = g_strdup_printf ("%s/vfolders.xml", evolution_dir);
732        context = vfolder_context_new ();
733        if (rule_context_load ((RuleContext *)context, EVOLUTION_DATADIR "/evolution/vfoldertypes.xml", user) != 0) {
734                g_warning("cannot load vfolders: %s\n", ((RuleContext *)context)->error);
735        }
736        g_free (user);
737       
738        gtk_signal_connect((GtkObject *)context, "rule_added", context_rule_added, context);
739        gtk_signal_connect((GtkObject *)context, "rule_removed", context_rule_removed, context);
740
741        /* and setup the rules we have */
742        rule = NULL;
743        while ( (rule = rule_context_next_rule((RuleContext *)context, rule, NULL)) ) {
744                if (rule->name)
745                        context_rule_added((RuleContext *)context, rule);
746                else
747                        d(printf ("invalid rule (%p) encountered: rule->name is NULL\n"));
748        }
749
750        g_free(storeuri);
751}
752
753static GtkWidget *vfolder_editor = NULL;
754
755static void
756vfolder_editor_destroy (GtkWidget *widget, gpointer user_data)
757{
758        vfolder_editor = NULL;
759}
760
761static void
762vfolder_editor_clicked (GtkWidget *dialog, int button, void *data)
763{
764        if (button == 0) {
765                char *user;
766
767                user = g_strdup_printf ("%s/vfolders.xml", evolution_dir);
768                rule_context_save ((RuleContext *)context, user);
769                g_free (user);
770        }
771        if (button != -1) {
772                gnome_dialog_close (GNOME_DIALOG (dialog));
773        }
774}
775
776void
777vfolder_edit (void)
778{
779        if (vfolder_editor) {
780                gdk_window_raise (GTK_WIDGET (vfolder_editor)->window);
781                return;
782        }
783       
784        vfolder_editor = GTK_WIDGET (vfolder_editor_new (context));
785        gtk_window_set_title (GTK_WINDOW (vfolder_editor), _("vFolders"));
786        gtk_signal_connect (GTK_OBJECT (vfolder_editor), "clicked", vfolder_editor_clicked, NULL);
787        gtk_signal_connect (GTK_OBJECT (vfolder_editor), "destroy", vfolder_editor_destroy, NULL);
788        gtk_widget_show (vfolder_editor);
789}
790
791static void
792edit_rule_clicked(GtkWidget *w, int button, void *data)
793{
794        if (button == 0) {
795                char *user;
796                FilterRule *rule = gtk_object_get_data((GtkObject *)w, "rule");
797                FilterRule *orig = gtk_object_get_data((GtkObject *)w, "orig");
798
799                filter_rule_copy(orig, rule);
800                user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
801                rule_context_save((RuleContext *)context, user);
802                g_free(user);
803        }
804        if (button != -1) {
805                gnome_dialog_close((GnomeDialog *)w);
806        }
807}
808
809void
810vfolder_edit_rule(const char *uri)
811{
812        GtkWidget *w;
813        GnomeDialog *gd;
814        FilterRule *rule, *newrule;
815        CamelURL *url;
816
817        url = camel_url_new(uri, NULL);
818        if (url && url->fragment
819            && (rule = rule_context_find_rule((RuleContext *)context, url->fragment, NULL))) {
820                gtk_object_ref((GtkObject *)rule);
821                newrule = filter_rule_clone(rule);
822
823                w = filter_rule_get_widget((FilterRule *)newrule, (RuleContext *)context);
824
825                gd = (GnomeDialog *)gnome_dialog_new(_("Edit VFolder"),
826                                                     GNOME_STOCK_BUTTON_OK,
827                                                     GNOME_STOCK_BUTTON_CANCEL,
828                                                     NULL);
829                gnome_dialog_set_default (gd, 0);
830
831                gtk_window_set_policy(GTK_WINDOW(gd), FALSE, TRUE, FALSE);
832                gtk_window_set_default_size (GTK_WINDOW (gd), 500, 500);
833                gtk_box_pack_start((GtkBox *)gd->vbox, w, TRUE, TRUE, 0);
834                gtk_widget_show((GtkWidget *)gd);
835                gtk_object_set_data_full((GtkObject *)gd, "rule", newrule, (GtkDestroyNotify)gtk_object_unref);
836                gtk_object_set_data_full((GtkObject *)gd, "orig", rule, (GtkDestroyNotify)gtk_object_unref);
837                gtk_signal_connect((GtkObject *)gd, "clicked", edit_rule_clicked, NULL);
838                gtk_widget_show((GtkWidget *)gd);
839        } else {
840                e_notice (NULL, GNOME_MESSAGE_BOX_WARNING,
841                          _("Trying to edit a vfolder '%s' which doesn't exist."), uri);
842        }
843
844        if (url)
845                camel_url_free(url);
846}
847
848static void
849new_rule_clicked(GtkWidget *w, int button, void *data)
850{
851        if (button == 0) {
852                char *user;
853                FilterRule *rule = gtk_object_get_data((GtkObject *)w, "rule");
854
855                gtk_object_ref((GtkObject *)rule);
856                rule_context_add_rule((RuleContext *)context, rule);
857                user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
858                rule_context_save((RuleContext *)context, user);
859                g_free(user);
860        }
861        if (button != -1) {
862                gnome_dialog_close((GnomeDialog *)w);
863        }
864}
865
866FilterPart *
867vfolder_create_part(const char *name)
868{
869        return rule_context_create_part((RuleContext *)context, name);
870}
871
872/* clones a filter/search rule into a matching vfolder rule (assuming the same system definitions) */
873FilterRule *
874vfolder_clone_rule(FilterRule *in)
875{
876        FilterRule *rule = (FilterRule *)vfolder_rule_new();
877        xmlNodePtr xml;
878
879        xml = filter_rule_xml_encode(in);
880        filter_rule_xml_decode(rule, xml, (RuleContext *)context);
881        xmlFreeNodeList(xml);
882
883        return rule;
884}
885
886/* adds a rule with a gui */
887void
888vfolder_gui_add_rule(VfolderRule *rule)
889{
890        GtkWidget *w;
891        GnomeDialog *gd;
892
893        w = filter_rule_get_widget((FilterRule *)rule, (RuleContext *)context);
894
895        gd = (GnomeDialog *)gnome_dialog_new(_("New VFolder"),
896                                             GNOME_STOCK_BUTTON_OK,
897                                             GNOME_STOCK_BUTTON_CANCEL,
898                                             NULL);
899        gnome_dialog_set_default (gd, 0);
900
901        gtk_window_set_policy(GTK_WINDOW(gd), FALSE, TRUE, FALSE);
902        gtk_window_set_default_size (GTK_WINDOW (gd), 500, 500);
903        gtk_box_pack_start((GtkBox *)gd->vbox, w, TRUE, TRUE, 0);
904        gtk_widget_show((GtkWidget *)gd);
905        gtk_object_set_data_full((GtkObject *)gd, "rule", rule, (GtkDestroyNotify)gtk_object_unref);
906        gtk_signal_connect((GtkObject *)gd, "clicked", new_rule_clicked, NULL);
907        gtk_widget_show((GtkWidget *)gd);
908}
909
910void
911vfolder_gui_add_from_message(CamelMimeMessage *msg, int flags, const char *source)
912{
913        VfolderRule *rule;
914
915        g_return_if_fail (msg != NULL);
916
917        rule = (VfolderRule*)vfolder_rule_from_message(context, msg, flags, source);
918        vfolder_gui_add_rule(rule);
919}
920
921void
922vfolder_gui_add_from_mlist(CamelMimeMessage *msg, const char *mlist, const char *source)
923{
924        VfolderRule *rule;
925
926        g_return_if_fail (msg != NULL);
927
928        rule = (VfolderRule*)vfolder_rule_from_mlist(context, mlist, source);
929        vfolder_gui_add_rule(rule);
930}
931
932static void
933vfolder_foreach_cb (gpointer key, gpointer data, gpointer user_data)
934{
935        CamelFolder *folder = CAMEL_FOLDER (data);
936       
937        if (folder)
938                camel_object_unref (CAMEL_OBJECT (folder));
939       
940        g_free (key);
941}
942
943void
944mail_vfolder_shutdown (void)
945{
946        g_hash_table_foreach (vfolder_hash, vfolder_foreach_cb, NULL);
947        g_hash_table_destroy (vfolder_hash);
948        vfolder_hash = NULL;
949
950        if (vfolder_store) {
951                camel_object_unref (CAMEL_OBJECT (vfolder_store));
952                vfolder_store = NULL;
953        }
954       
955        if (context) {
956                gtk_object_unref (GTK_OBJECT (context));
957                context = NULL;
958        }
959}
Note: See TracBrowser for help on using the repository browser.