Files
evolution/mail/mail-vfolder.c
9 3e6cd9a7e5 Free folders_uri. (real_folder_deleted): If folder is deleted, remove it
2001-10-19    <NotZed@Ximian.com>

	* mail-folder-cache.c (store_finalised): Free folders_uri.
	(real_folder_deleted): If folder is deleted, remove it from the
	hashtables.

	* subscribe-dialog.c (get_short_folderinfo_get): Remove the
	register/unregister, they're already done above us.

	* mail-vfolder.c
	(mail_vfolder_delete_uri): Dont do any work to remove the actual
	folder from the vfolder (we'd have to look it up first), let the
	vfolder remove it itself.  Just update the rules.

svn path=/trunk/; revision=13787
2001-10-19 05:40:42 +00:00

864 lines
22 KiB
C

/*
Copyright 2000, 2001 Ximian Inc.
Author: Michael Zucchi <notzed@ximian.com>
code for managing vfolders
NOTE: dont run this through fucking indent.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <glib.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-i18n.h>
#include <libgnomeui/gnome-dialog.h>
#include <libgnomeui/gnome-dialog-util.h>
#include <libgnomeui/gnome-stock.h>
#include "Evolution.h"
#include "evolution-storage.h"
#include "evolution-shell-component.h"
#include "folder-browser.h"
#include "mail-vfolder.h"
#include "mail-tools.h"
#include "mail-autofilter.h"
#include "mail-folder-cache.h"
#include "mail.h"
#include "mail-ops.h"
#include "mail-mt.h"
#include "gal/widgets/e-gui-utils.h"
#include "camel/camel.h"
#include "camel/camel-remote-store.h"
#include "camel/camel-vee-folder.h"
#include "camel/camel-vee-store.h"
#include "filter/vfolder-context.h"
#include "filter/vfolder-editor.h"
#include "e-util/e-unicode-i18n.h"
#define d(x)
static VfolderContext *context; /* context remains open all time */
static CamelStore *vfolder_store; /* the 1 static vfolder store */
/* lock for accessing shared resources (below) */
static pthread_mutex_t vfolder_lock = PTHREAD_MUTEX_INITIALIZER;
static GList *source_folders_remote; /* list of source folder uri's - remote ones */
static GList *source_folders_local; /* list of source folder uri's - local ones */
static GHashTable *vfolder_hash;
extern EvolutionShellClient *global_shell_client;
/* more globals ... */
extern char *evolution_dir;
extern CamelSession *session;
static void rule_changed(FilterRule *rule, CamelFolder *folder);
#define LOCK() pthread_mutex_lock(&vfolder_lock);
#define UNLOCK() pthread_mutex_unlock(&vfolder_lock);
/* ********************************************************************** */
struct _setup_msg {
struct _mail_msg msg;
CamelFolder *folder;
char *query;
GList *sources_uri;
GList *sources_folder;
};
static char *
vfolder_setup_desc(struct _mail_msg *mm, int done)
{
struct _setup_msg *m = (struct _setup_msg *)mm;
return g_strdup_printf(_("Setting up vfolder: %s"), m->folder->full_name);
}
static void
vfolder_setup_do(struct _mail_msg *mm)
{
struct _setup_msg *m = (struct _setup_msg *)mm;
GList *l, *list = NULL;
CamelFolder *folder;
d(printf("Setting up vfolder: %s\n", m->folder->full_name));
camel_vee_folder_set_expression((CamelVeeFolder *)m->folder, m->query);
l = m->sources_uri;
while (l) {
d(printf(" Adding uri: %s\n", (char *)l->data));
folder = mail_tool_uri_to_folder (l->data, 0, &mm->ex);
if (folder) {
list = g_list_append(list, folder);
} else {
g_warning("Could not open vfolder source: %s", (char *)l->data);
camel_exception_clear(&mm->ex);
}
l = l->next;
}
l = m->sources_folder;
while (l) {
d(printf(" Adding folder: %s\n", ((CamelFolder *)l->data)->full_name));
camel_object_ref((CamelObject *)l->data);
list = g_list_append(list, l->data);
l = l->next;
}
camel_vee_folder_set_folders((CamelVeeFolder *)m->folder, list);
l = list;
while (l) {
camel_object_unref((CamelObject *)l->data);
l = l->next;
}
g_list_free(list);
}
static void
vfolder_setup_done(struct _mail_msg *mm)
{
struct _setup_msg *m = (struct _setup_msg *)mm;
m = m;
}
static void
vfolder_setup_free (struct _mail_msg *mm)
{
struct _setup_msg *m = (struct _setup_msg *)mm;
GList *l;
camel_object_unref((CamelObject *)m->folder);
g_free(m->query);
l = m->sources_uri;
while (l) {
g_free(l->data);
l = l->next;
}
g_list_free(m->sources_uri);
l = m->sources_folder;
while (l) {
camel_object_unref(l->data);
l = l->next;
}
g_list_free(m->sources_folder);
}
static struct _mail_msg_op vfolder_setup_op = {
vfolder_setup_desc,
vfolder_setup_do,
vfolder_setup_done,
vfolder_setup_free,
};
static int
vfolder_setup(CamelFolder *folder, const char *query, GList *sources_uri, GList *sources_folder)
{
struct _setup_msg *m;
int id;
m = mail_msg_new(&vfolder_setup_op, NULL, sizeof (*m));
m->folder = folder;
camel_object_ref((CamelObject *)folder);
m->query = g_strdup(query);
m->sources_uri = sources_uri;
m->sources_folder = sources_folder;
id = m->msg.seq;
e_thread_put(mail_thread_queued_slow, (EMsg *)m);
return id;
}
/* ********************************************************************** */
struct _adduri_msg {
struct _mail_msg msg;
char *uri;
GList *folders;
int remove;
};
static char *
vfolder_adduri_desc(struct _mail_msg *mm, int done)
{
struct _adduri_msg *m = (struct _adduri_msg *)mm;
return g_strdup_printf(_("Updating vfolders for uri: %s"), m->uri);
}
static void
vfolder_adduri_do(struct _mail_msg *mm)
{
struct _adduri_msg *m = (struct _adduri_msg *)mm;
GList *l;
CamelFolder *folder = NULL;
extern CamelFolder *drafts_folder, *outbox_folder, *sent_folder;
d(printf("%s uri to vfolder: %s\n", m->remove?"Removing":"Adding", m->uri));
/* we dont try lookup the cache if we are removing it, its no longer there */
if (!m->remove && !mail_note_get_folder_from_uri(m->uri, &folder)) {
g_warning("Folder '%s' disappeared while I was adding/remove it to/from my vfolder", m->uri);
return;
}
if (folder == NULL)
folder = mail_tool_uri_to_folder (m->uri, 0, &mm->ex);
if (folder != NULL) {
if (folder != drafts_folder && folder != outbox_folder && folder != sent_folder) {
l = m->folders;
while (l) {
if (m->remove)
camel_vee_folder_remove_folder((CamelVeeFolder *)l->data, folder);
else
camel_vee_folder_add_folder((CamelVeeFolder *)l->data, folder);
l = l->next;
}
}
camel_object_unref((CamelObject *)folder);
}
}
static void
vfolder_adduri_done(struct _mail_msg *mm)
{
struct _adduri_msg *m = (struct _adduri_msg *)mm;
m = m;
}
static void
vfolder_adduri_free (struct _mail_msg *mm)
{
struct _adduri_msg *m = (struct _adduri_msg *)mm;
g_list_foreach(m->folders, (GFunc)camel_object_unref, NULL);
g_list_free(m->folders);
g_free(m->uri);
}
static struct _mail_msg_op vfolder_adduri_op = {
vfolder_adduri_desc,
vfolder_adduri_do,
vfolder_adduri_done,
vfolder_adduri_free,
};
static int
vfolder_adduri(const char *uri, GList *folders, int remove)
{
struct _adduri_msg *m;
int id;
m = mail_msg_new(&vfolder_adduri_op, NULL, sizeof (*m));
m->folders = folders;
m->uri = g_strdup(uri);
m->remove = remove;
id = m->msg.seq;
e_thread_put(mail_thread_queued_slow, (EMsg *)m);
return id;
}
/* ********************************************************************** */
/* So, uh, apparently g_list_find_custom expect the compare func to return 0 to mean true? */
static GList *
my_list_find(GList *l, const char *uri, GCompareFunc cmp)
{
while (l) {
if (cmp(l->data, uri))
break;
l = l->next;
}
return l;
}
/* called when a new uri becomes (un)available */
void
mail_vfolder_add_uri(CamelStore *store, const char *uri, int remove)
{
FilterRule *rule;
const char *source;
CamelVeeFolder *vf;
GList *folders = NULL, *link;
int remote = (((CamelService *)store)->provider->flags & CAMEL_PROVIDER_IS_REMOTE) != 0;
GCompareFunc uri_cmp = CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->compare_folder_name;
if (CAMEL_IS_VEE_STORE(store) || !strncmp(uri, "vtrash:", 7))
return;
g_assert(pthread_self() == mail_gui_thread);
LOCK();
d(printf("%s uri to check: %s\n", remove?"Removing":"Adding", uri));
/* maintain the source folders lists for changed rules later on */
if (remove) {
if (remote) {
if ((link = my_list_find(source_folders_remote, (void *)uri, uri_cmp)) != NULL) {
g_free(link->data);
source_folders_remote = g_list_remove_link(source_folders_remote, link);
}
} else {
if ((link = my_list_find(source_folders_local, (void *)uri, uri_cmp)) != NULL) {
g_free(link->data);
source_folders_local = g_list_remove_link(source_folders_local, link);
}
}
} else {
if (remote) {
if (my_list_find(source_folders_remote, (void *)uri, uri_cmp) == NULL)
source_folders_remote = g_list_prepend(source_folders_remote, g_strdup(uri));
} else {
if (my_list_find(source_folders_local, (void *)uri, uri_cmp) == NULL)
source_folders_local = g_list_prepend(source_folders_local, g_strdup(uri));
}
}
rule = NULL;
while ( (rule = rule_context_next_rule((RuleContext *)context, rule, NULL)) ) {
int found = FALSE;
if (rule->source
&& ((!strcmp(rule->source, "local") && !remote)
|| (!strcmp(rule->source, "remote_active") && remote)
|| (!strcmp(rule->source, "local_remote_active"))))
found = TRUE;
/* we check using the store uri_cmp since its more accurate */
source = NULL;
while ( !found && (source = vfolder_rule_next_source((VfolderRule *)rule, source)) )
found = uri_cmp(uri, source);
if (found) {
vf = g_hash_table_lookup(vfolder_hash, rule->name);
g_assert(vf);
camel_object_ref((CamelObject *)vf);
folders = g_list_prepend(folders, vf);
}
}
UNLOCK();
if (folders != NULL)
vfolder_adduri(uri, folders, remove);
}
/* called when a uri is deleted from a store */
void
mail_vfolder_delete_uri(CamelStore *store, const char *uri)
{
GCompareFunc uri_cmp = CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->compare_folder_name;
FilterRule *rule;
const char *source;
CamelVeeFolder *vf;
GString *changed;
if (CAMEL_IS_VEE_STORE(store) || !strncmp(uri, "vtrash:", 7))
return;
d(printf("Deleting uri to check: %s\n", uri));
g_assert(pthread_self() == mail_gui_thread);
changed = g_string_new("");
LOCK();
/* see if any rules directly reference this removed uri */
rule = NULL;
while ( (rule = rule_context_next_rule((RuleContext *)context, rule, NULL)) ) {
source = NULL;
while ( (source = vfolder_rule_next_source((VfolderRule *)rule, source)) ) {
/* Remove all sources that match, ignore changed events though
because the adduri call above does the work async */
if (uri_cmp(uri, source)) {
vf = g_hash_table_lookup(vfolder_hash, rule->name);
g_assert(vf);
gtk_signal_disconnect_by_func((GtkObject *)rule, rule_changed, vf);
vfolder_rule_remove_source((VfolderRule *)rule, source);
gtk_signal_connect((GtkObject *)rule, "changed", rule_changed, vf);
g_string_sprintfa(changed, " %s\n", rule->name);
source = NULL;
}
}
}
UNLOCK();
if (changed->str[0]) {
GnomeDialog *gd;
char *text, *user;
text = g_strdup_printf(_("The following vFolder(s):\n%s"
"Used the removed folder:\n '%s'\n"
"And have been updated."),
changed->str, uri);
gd = (GnomeDialog *)gnome_warning_dialog(text);
g_free(text);
gnome_dialog_set_close(gd, TRUE);
gtk_widget_show((GtkWidget *)gd);
user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
rule_context_save((RuleContext *)context, user);
g_free(user);
}
g_string_free(changed, TRUE);
}
/* called when a uri is renamed in a store */
#if 0
void
mail_vfolder_rename_uri(CamelStore *store, const char *from, const char *to)
{
printf("vfolder rename uri: %s to %s\n", from, to);
}
#endif
/* ********************************************************************** */
static void context_rule_added(RuleContext *ctx, FilterRule *rule);
static void
rule_changed(FilterRule *rule, CamelFolder *folder)
{
const char *sourceuri;
GList *l;
GList *sources_uri = NULL, *sources_folder = NULL;
GString *query;
int i;
CamelFolder *newfolder;
/* if the folder has changed name, then add it, then remove the old manually */
if (strcmp(folder->full_name, rule->name) != 0) {
char *path, *key;
CamelFolder *old;
gtk_signal_disconnect_by_func((GtkObject *)rule, rule_changed, folder);
context_rule_added((RuleContext *)context, rule);
/* TODO: remove folder from folder info cache? */
path = g_strdup_printf("/%s", folder->full_name);
evolution_storage_removed_folder(mail_lookup_storage(vfolder_store), path);
g_free(path);
LOCK();
if (g_hash_table_lookup_extended(vfolder_hash, folder->full_name, (void **)&key, (void **)&old)) {
g_hash_table_remove(vfolder_hash, key);
g_free(key);
UNLOCK();
camel_object_unref((CamelObject *)folder);
} else {
UNLOCK();
g_warning("couldn't find a vfolder rule in our table? %s", folder->full_name);
}
return;
}
d(printf("Filter rule changed? for folder '%s'!!\n", folder->name));
/* find any (currently available) folders, and add them to the ones to open */
sourceuri = NULL;
while ( (sourceuri = vfolder_rule_next_source((VfolderRule *)rule, sourceuri)) ) {
if (mail_note_get_folder_from_uri(sourceuri, &newfolder)) {
if (newfolder)
sources_folder = g_list_append(sources_folder, newfolder);
else
sources_uri = g_list_append(sources_uri, g_strdup(sourceuri));
}
}
/* check the remote/local uri lists for any other uri's that should be looked at */
if (rule->source) {
LOCK();
for (i=0;i<2;i++) {
if (i==0 && (!strcmp(rule->source, "local") || !strcmp(rule->source, "local_remote_active")))
l = source_folders_local;
else if (i==1 && (!strcmp(rule->source, "remote_active") || !strcmp(rule->source, "local_remote_active")))
l = source_folders_remote;
else
l = NULL;
while (l) {
if (mail_note_get_folder_from_uri(l->data, &newfolder)) {
if (newfolder)
sources_folder = g_list_append(sources_folder, newfolder);
else
sources_uri = g_list_append(sources_uri, g_strdup(l->data));
} else {
printf(" -> No such folder?\n");
}
l = l->next;
}
}
UNLOCK();
}
query = g_string_new("");
filter_rule_build_code(rule, query);
vfolder_setup(folder, query->str, sources_uri, sources_folder);
g_string_free(query, TRUE);
}
static void context_rule_added(RuleContext *ctx, FilterRule *rule)
{
CamelFolder *folder;
d(printf("rule added: %s\n", rule->name));
/* this always runs quickly */
folder = camel_store_get_folder(vfolder_store, rule->name, 0, NULL);
if (folder) {
gtk_signal_connect((GtkObject *)rule, "changed", rule_changed, folder);
LOCK();
g_hash_table_insert(vfolder_hash, g_strdup(rule->name), folder);
UNLOCK();
mail_note_folder(folder);
rule_changed(rule, folder);
}
}
static void context_rule_removed(RuleContext *ctx, FilterRule *rule)
{
char *key, *path;
CamelFolder *folder;
d(printf("rule removed; %s\n", rule->name));
/* TODO: remove from folder info cache? */
path = g_strdup_printf("/%s", rule->name);
evolution_storage_removed_folder(mail_lookup_storage(vfolder_store), path);
g_free(path);
LOCK();
if (g_hash_table_lookup_extended(vfolder_hash, rule->name, (void **)&key, (void **)&folder)) {
g_hash_table_remove(vfolder_hash, key);
g_free(key);
UNLOCK();
camel_object_unref((CamelObject *)folder);
} else
UNLOCK();
camel_store_delete_folder(vfolder_store, rule->name, NULL);
}
static void
store_folder_created(CamelObject *o, void *event_data, void *data)
{
CamelStore *store = (CamelStore *)o;
CamelFolderInfo *info = event_data;
store = store;
info = info;
}
static void
store_folder_deleted(CamelObject *o, void *event_data, void *data)
{
CamelStore *store = (CamelStore *)o;
CamelFolderInfo *info = event_data;
FilterRule *rule;
char *user;
d(printf("Folder deleted: %s\n", info->name));
store = store;
/* delete it from our list */
rule = rule_context_find_rule((RuleContext *)context, info->name, NULL);
if (rule) {
/* We need to stop listening to removed events, otherwise we'll try and remove it again */
gtk_signal_disconnect_by_func((GtkObject *)context, context_rule_removed, context);
rule_context_remove_rule((RuleContext *)context, rule);
gtk_object_unref((GtkObject *)rule);
gtk_signal_connect((GtkObject *)context, "rule_removed", context_rule_removed, context);
user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
rule_context_save((RuleContext *)context, user);
g_free(user);
} else {
g_warning("Cannot find rule for deleted vfolder '%s'", info->name);
}
}
void
vfolder_load_storage(GNOME_Evolution_Shell shell)
{
char *user, *storeuri;
FilterRule *rule;
vfolder_hash = g_hash_table_new(g_str_hash, g_str_equal);
/* first, create the vfolder store, and set it up */
storeuri = g_strdup_printf("vfolder:%s/vfolder", evolution_dir);
vfolder_store = camel_session_get_store(session, storeuri, NULL);
if (vfolder_store == NULL) {
g_warning("Cannot open vfolder store - no vfolders available");
return;
}
camel_object_hook_event((CamelObject *)vfolder_store, "folder_created",
(CamelObjectEventHookFunc)store_folder_created, NULL);
camel_object_hook_event((CamelObject *)vfolder_store, "folder_deleted",
(CamelObjectEventHookFunc)store_folder_deleted, NULL);
d(printf("got store '%s' = %p\n", storeuri, vfolder_store));
mail_load_storage_by_uri(shell, storeuri, U_("VFolders"));
/* load our rules */
user = g_strdup_printf ("%s/vfolders.xml", evolution_dir);
context = vfolder_context_new ();
if (rule_context_load ((RuleContext *)context, EVOLUTION_DATADIR "/evolution/vfoldertypes.xml", user) != 0) {
g_warning("cannot load vfolders: %s\n", ((RuleContext *)context)->error);
}
g_free (user);
gtk_signal_connect((GtkObject *)context, "rule_added", context_rule_added, context);
gtk_signal_connect((GtkObject *)context, "rule_removed", context_rule_removed, context);
/* and setup the rules we have */
rule = NULL;
while ( (rule = rule_context_next_rule((RuleContext *)context, rule, NULL)) ) {
context_rule_added((RuleContext *)context, rule);
}
g_free(storeuri);
}
static GtkWidget *vfolder_editor = NULL;
static void
vfolder_editor_destroy (GtkWidget *widget, gpointer user_data)
{
vfolder_editor = NULL;
}
static void
vfolder_editor_clicked (GtkWidget *dialog, int button, void *data)
{
if (button == 0) {
char *user;
user = g_strdup_printf ("%s/vfolders.xml", evolution_dir);
rule_context_save ((RuleContext *)context, user);
g_free (user);
}
if (button != -1) {
gnome_dialog_close (GNOME_DIALOG (dialog));
}
}
void
vfolder_edit (void)
{
if (vfolder_editor) {
gdk_window_raise (GTK_WIDGET (vfolder_editor)->window);
return;
}
vfolder_editor = GTK_WIDGET (vfolder_editor_new (context));
gtk_signal_connect (GTK_OBJECT (vfolder_editor), "clicked", vfolder_editor_clicked, NULL);
gtk_signal_connect (GTK_OBJECT (vfolder_editor), "destroy", vfolder_editor_destroy, NULL);
gtk_widget_show (vfolder_editor);
}
static void
edit_rule_clicked(GtkWidget *w, int button, void *data)
{
if (button == 0) {
char *user;
FilterRule *rule = gtk_object_get_data((GtkObject *)w, "rule");
FilterRule *orig;
orig = rule_context_find_rule((RuleContext *)context, rule->name, NULL);
if (orig) {
filter_rule_copy(orig, rule);
} else {
gtk_object_ref((GtkObject *)rule);
rule_context_add_rule((RuleContext *)context, rule);
}
user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
rule_context_save((RuleContext *)context, user);
g_free(user);
}
if (button != -1) {
gnome_dialog_close((GnomeDialog *)w);
}
}
void
vfolder_edit_rule(const char *uri)
{
GtkWidget *w;
GnomeDialog *gd;
FilterRule *rule;
CamelURL *url;
url = camel_url_new(uri, NULL);
if (url && url->fragment
&& (rule = rule_context_find_rule((RuleContext *)context, url->fragment, NULL))) {
rule = filter_rule_clone(rule);
w = filter_rule_get_widget((FilterRule *)rule, (RuleContext *)context);
gd = (GnomeDialog *)gnome_dialog_new(_("Edit VFolder"),
GNOME_STOCK_BUTTON_OK,
GNOME_STOCK_BUTTON_CANCEL,
NULL);
gnome_dialog_set_default (gd, 0);
gtk_window_set_policy(GTK_WINDOW(gd), FALSE, TRUE, FALSE);
gtk_window_set_default_size (GTK_WINDOW (gd), 500, 500);
gtk_box_pack_start((GtkBox *)gd->vbox, w, TRUE, TRUE, 0);
gtk_widget_show((GtkWidget *)gd);
gtk_object_set_data_full((GtkObject *)gd, "rule", rule, (GtkDestroyNotify)gtk_object_unref);
gtk_signal_connect((GtkObject *)gd, "clicked", edit_rule_clicked, NULL);
gtk_widget_show((GtkWidget *)gd);
} else {
e_notice (NULL, GNOME_MESSAGE_BOX_WARNING,
_("Trying to edit a vfolder '%s' which doesn't exist."), uri);
}
if (url)
camel_url_free(url);
}
static void
new_rule_clicked(GtkWidget *w, int button, void *data)
{
if (button == 0) {
char *user;
FilterRule *rule = gtk_object_get_data((GtkObject *)w, "rule");
gtk_object_ref((GtkObject *)rule);
rule_context_add_rule((RuleContext *)context, rule);
user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
rule_context_save((RuleContext *)context, user);
g_free(user);
}
if (button != -1) {
gnome_dialog_close((GnomeDialog *)w);
}
}
FilterPart *
vfolder_create_part(const char *name)
{
return rule_context_create_part((RuleContext *)context, name);
}
/* clones a filter/search rule into a matching vfolder rule (assuming the same system definitions) */
FilterRule *
vfolder_clone_rule(FilterRule *in)
{
FilterRule *rule = (FilterRule *)vfolder_rule_new();
xmlNodePtr xml;
xml = filter_rule_xml_encode(in);
filter_rule_xml_decode(rule, xml, (RuleContext *)context);
xmlFreeNodeList(xml);
return rule;
}
/* adds a rule with a gui */
void
vfolder_gui_add_rule(VfolderRule *rule)
{
GtkWidget *w;
GnomeDialog *gd;
w = filter_rule_get_widget((FilterRule *)rule, (RuleContext *)context);
gd = (GnomeDialog *)gnome_dialog_new(_("New VFolder"),
GNOME_STOCK_BUTTON_OK,
GNOME_STOCK_BUTTON_CANCEL,
NULL);
gnome_dialog_set_default (gd, 0);
gtk_window_set_policy(GTK_WINDOW(gd), FALSE, TRUE, FALSE);
gtk_window_set_default_size (GTK_WINDOW (gd), 500, 500);
gtk_box_pack_start((GtkBox *)gd->vbox, w, TRUE, TRUE, 0);
gtk_widget_show((GtkWidget *)gd);
gtk_object_set_data_full((GtkObject *)gd, "rule", rule, (GtkDestroyNotify)gtk_object_unref);
gtk_signal_connect((GtkObject *)gd, "clicked", new_rule_clicked, NULL);
gtk_widget_show((GtkWidget *)gd);
}
void
vfolder_gui_add_from_message(CamelMimeMessage *msg, int flags, const char *source)
{
VfolderRule *rule;
g_return_if_fail (msg != NULL);
rule = (VfolderRule*)vfolder_rule_from_message(context, msg, flags, source);
vfolder_gui_add_rule(rule);
}
void
vfolder_gui_add_from_mlist(CamelMimeMessage *msg, const char *mlist, const char *source)
{
VfolderRule *rule;
g_return_if_fail (msg != NULL);
rule = (VfolderRule*)vfolder_rule_from_mlist(context, mlist, source);
vfolder_gui_add_rule(rule);
}
static void
vfolder_foreach_cb (gpointer key, gpointer data, gpointer user_data)
{
CamelFolder *folder = CAMEL_FOLDER (data);
if (folder)
camel_object_unref (CAMEL_OBJECT (folder));
g_free (key);
}
void
mail_vfolder_shutdown (void)
{
g_hash_table_foreach (vfolder_hash, vfolder_foreach_cb, NULL);
g_hash_table_destroy (vfolder_hash);
if (vfolder_store)
camel_object_unref (CAMEL_OBJECT (vfolder_store));
if (context)
gtk_object_unref (GTK_OBJECT (context));
}