diff options
Diffstat (limited to 'mail/mail-ops.c')
-rw-r--r-- | mail/mail-ops.c | 1032 |
1 files changed, 472 insertions, 560 deletions
diff --git a/mail/mail-ops.c b/mail/mail-ops.c index 3391001fae..363c9a282a 100644 --- a/mail/mail-ops.c +++ b/mail/mail-ops.c @@ -38,6 +38,8 @@ #include "folder-browser.h" #include "e-util/e-html-utils.h" +#include "filter/filter-filter.h" + #include "mail-mt.h" #define d(x) x @@ -47,506 +49,448 @@ int mail_operation_run(const mail_operation_spec *op, void *in, int free); #define mail_tool_camel_lock_down() #define mail_tool_camel_lock_up() - -/* Utility functions. */ +FilterContext * +mail_load_filter_context(void) +{ + char *userrules; + char *systemrules; + FilterContext *fc; + + userrules = g_strdup_printf ("%s/filters.xml", evolution_dir); + systemrules = g_strdup_printf ("%s/evolution/filtertypes.xml", EVOLUTION_DATADIR); + fc = filter_context_new (); + rule_context_load ((RuleContext *)fc, systemrules, userrules); + g_free (userrules); + g_free (systemrules); + + return fc; +} static void -set_x_mailer (CamelMimeMessage *message) +setup_filter_driver(CamelFilterDriver *driver, FilterContext *fc, const char *source) { - const char *xmailer_version; + GString *fsearch, *faction; + FilterFilter *rule = NULL; - if (SUB_VERSION[0] == '\0') - xmailer_version = "Evolution (" VERSION " - Preview Release)"; - else - xmailer_version = "Evolution (" VERSION "/" SUB_VERSION " - Preview Release)"; + if (TRUE /* perform_logging */) { + char *filename = g_strdup_printf("%s/evolution-filter-log", evolution_dir); + /* FIXME: This is a nasty little thing to stop leaking file handles. + Needs to be setup elsewhere. */ + static FILE *logfile = NULL; + + if (logfile == NULL) + logfile = fopen(filename, "a+"); + g_free(filename); + if (logfile) + camel_filter_driver_set_logfile(driver, logfile); + } - camel_medium_add_header(CAMEL_MEDIUM (message), "X-Mailer", xmailer_version); + fsearch = g_string_new (""); + faction = g_string_new (""); + + while ((rule = (FilterFilter *)rule_context_next_rule((RuleContext *)fc, (FilterRule *)rule, source))) { + g_string_truncate (fsearch, 0); + g_string_truncate (faction, 0); + + filter_rule_build_code ((FilterRule *)rule, fsearch); + filter_filter_build_action (rule, faction); + + camel_filter_driver_add_rule(driver, ((FilterRule *)rule)->name, fsearch->str, faction->str); + } + + g_string_free (fsearch, TRUE); + g_string_free (faction, TRUE); } +static CamelFolder * +filter_get_folder(CamelFilterDriver *d, const char *uri, void *data, CamelException *ex) +{ + CamelFolder *folder; -/* ** FETCH MAIL ********************************************************** */ + folder = mail_tool_uri_to_folder(uri, ex); -typedef struct fetch_mail_input_s -{ - gchar *source_url; - gboolean keep_on_server; - CamelFolder *destination; - gpointer hook_func; - gpointer hook_data; - CamelCancel *cancel; + return folder; } -fetch_mail_input_t; -typedef struct fetch_mail_update_info_s { - gchar *name; - gchar *display; - gboolean new_messages; -} fetch_mail_update_info_t; +/* used for both just filtering a folder + uid's, and for filtering a whole folder */ +/* used both for fetching mail, and for filtering mail */ +struct _filter_mail_msg { + struct _mail_msg msg; -typedef struct fetch_mail_data_s { - gboolean empty; - EvolutionStorage *storage; - GPtrArray *update_infos; -} fetch_mail_data_t; + CamelFolder *source_folder; /* where they come from */ + GPtrArray *source_uids; /* uids to copy, or NULL == copy all */ + CamelCancel *cancel; + CamelFilterDriver *driver; + int delete; /* delete messages after filtering them? */ + CamelFolder *destination; /* default destination for any messages, NULL for none */ +}; -static gchar * -describe_fetch_mail (gpointer in_data, gboolean gerund) -{ - fetch_mail_input_t *input = (fetch_mail_input_t *) in_data; - char *name; - - /*source = camel_session_get_store (session, input->source_url, NULL); - *if (source) { - * name = camel_service_get_name (CAMEL_SERVICE (source), FALSE); - * camel_object_unref (CAMEL_OBJECT (source)); - *} else - */ - name = input->source_url; - - if (gerund) - return g_strdup_printf (_("Fetching email from %s"), name); - else - return g_strdup_printf (_("Fetch email from %s"), name); -} +/* since fetching also filters, we subclass the data here */ +struct _fetch_mail_msg { + struct _filter_mail_msg fmsg; + + CamelCancel *cancel; /* we have our own cancellation struct, the other should be empty */ + int keep; /* keep on server? */ + + char *source_uri; + + void (*done)(char *source, void *data); + void *data; +}; +/* filter a folder, or a subset thereof, uses source_folder/source_uids */ +/* this is shared with fetch_mail */ static void -setup_fetch_mail (gpointer in_data, gpointer op_data, CamelException *ex) +filter_folder_filter(struct _mail_msg *mm) { - fetch_mail_input_t *input = (fetch_mail_input_t *) in_data; - fetch_mail_data_t *data = (fetch_mail_data_t *) op_data; - - data->empty = FALSE; - data->storage = NULL; - data->update_infos = NULL; + struct _filter_mail_msg *m = (struct _filter_mail_msg *)mm; + CamelFolder *folder; + GPtrArray *uids, *folder_uids = NULL; - if (input->destination) - camel_object_ref (CAMEL_OBJECT (input->destination)); -} + if (m->cancel) + camel_cancel_register(m->cancel); -static FilterContext * -mail_load_evolution_rule_context () -{ - gchar *userrules; - gchar *systemrules; - FilterContext *fc; - - userrules = g_strdup_printf ("%s/filters.xml", evolution_dir); - systemrules = g_strdup_printf ("%s/evolution/filtertypes.xml", EVOLUTION_DATADIR); - fc = filter_context_new (); - rule_context_load ((RuleContext *)fc, systemrules, userrules); - g_free (userrules); - g_free (systemrules); - - return fc; -} + folder = m->source_folder; -static void -mail_op_report_status (FilterDriver *driver, enum filter_status_t status, const char *desc, void *data) -{ - /* FIXME: make it work */ - switch (status) { - case FILTER_STATUS_START: - mail_status(desc); - break; - case FILTER_STATUS_END: - break; - case FILTER_STATUS_ACTION: - break; - default: - break; + if (folder == NULL || camel_folder_get_message_count (folder) == 0) { + if (m->cancel) + camel_cancel_unregister(m->cancel); + return; } -} -static void -update_changed_folders (CamelStore *store, CamelFolderInfo *info, - EvolutionStorage *storage, const char *path, - GPtrArray *update_infos, CamelException *ex) -{ - char *name; + if (m->destination) { + camel_folder_freeze(m->destination); + camel_filter_driver_set_default_folder(m->driver, m->destination); + } - name = g_strdup_printf ("%s/%s", path, info->name); + camel_folder_freeze(folder); - if (info->url) { - CamelFolder *folder; - fetch_mail_update_info_t *update_info; + if (m->source_uids) + uids = m->source_uids; + else + folder_uids = uids = camel_folder_get_uids (folder); - update_info = g_new (fetch_mail_update_info_t, 1); - update_info->name = g_strdup (name); + camel_filter_driver_filter_folder(m->driver, folder, uids, m->delete, &mm->ex); - if (info->unread_message_count > 0) { - update_info->new_messages = TRUE; - update_info->display = g_strdup_printf ("%s (%d)", info->name, - info->unread_message_count); - } else { - update_info->new_messages = FALSE; - update_info->display = g_strdup (info->name); - } + if (folder_uids) + camel_folder_free_uids(folder, folder_uids); - /* This is a bit of a hack... if the store is already - * caching the folder, then we update it. Otherwise - * we don't. - */ - folder = CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS (store))-> - lookup_folder (store, info->full_name); - if (folder) { - camel_folder_sync (folder, FALSE, ex); - if (!camel_exception_is_set (ex)) - camel_folder_refresh_info (folder, ex); - camel_object_unref (CAMEL_OBJECT (folder)); - } + /* sync and expunge */ + camel_folder_sync (folder, TRUE, &mm->ex); + camel_folder_thaw(folder); - /* Save our info to update */ - g_ptr_array_add (update_infos, update_info); - } - if (!camel_exception_is_set (ex) && info->sibling) { - update_changed_folders (store, info->sibling, storage, - path, update_infos, ex); + if (m->destination) + camel_folder_thaw(m->destination); + + if (m->cancel) + camel_cancel_unregister(m->cancel); +} + +static void +filter_folder_filtered(struct _mail_msg *mm) +{ +} + +static void +filter_folder_free(struct _mail_msg *mm) +{ + struct _filter_mail_msg *m = (struct _filter_mail_msg *)mm; + int i; + + if (m->source_folder) + camel_object_unref((CamelObject *)m->source_folder); + if (m->source_uids) { + for (i=0;i<m->source_uids->len;i++) + g_free(m->source_uids->pdata[i]); + g_ptr_array_free(m->source_uids, TRUE); } - if (!camel_exception_is_set (ex) && info->child) { - update_changed_folders (store, info->child, storage, - name, update_infos, ex); + if (m->cancel) + camel_cancel_unref(m->cancel); + if (m->destination) + camel_object_unref((CamelObject *)m->destination); + camel_object_unref((CamelObject *)m->driver); +} + +static struct _mail_msg_op filter_folder_op = { + NULL, /* we do our own progress reporting? */ + filter_folder_filter, + filter_folder_filtered, + filter_folder_free, +}; + +void +mail_filter_folder(CamelFolder *source_folder, GPtrArray *uids, + FilterContext *fc, const char *type, + CamelCancel *cancel) +{ + struct _filter_mail_msg *m; + + m = mail_msg_new(&filter_folder_op, NULL, sizeof(*m)); + m->source_folder = source_folder; + camel_object_ref((CamelObject *)source_folder); + m->source_uids = uids; + m->delete = FALSE; + if (cancel) { + m->cancel = cancel; + camel_cancel_ref(cancel); } - g_free (name); + + m->driver = camel_filter_driver_new(filter_get_folder, NULL); + setup_filter_driver(m->driver, fc, type); + + e_thread_put(mail_thread_new, (EMsg *)m); } -static void -do_fetch_mail (gpointer in_data, gpointer op_data, CamelException *ex) +/* convenience function for it */ +void mail_filter_on_demand(CamelFolder *folder, GPtrArray *uids) { - fetch_mail_input_t *input = (fetch_mail_input_t *) in_data; - fetch_mail_data_t *data = (fetch_mail_data_t *) op_data; FilterContext *fc; - FilterDriver *filter; - FILE *logfile = NULL; - CamelFolder *folder; - - camel_cancel_register(input->cancel); - /* FIXME: This shouldn't be checking for "imap" specifically. */ - if (!strncmp (input->source_url, "imap:", 5)) { - CamelStore *store; - CamelFolderInfo *info; - EvolutionStorage *storage; + fc = mail_load_filter_context(); + mail_filter_folder(folder, uids, fc, FILTER_SOURCE_INCOMING, NULL); + gtk_object_unref((GtkObject *)fc); +} - store = camel_session_get_store (session, input->source_url, ex); - if (!store) - return; - storage = mail_lookup_storage (store); - g_return_if_fail (storage != NULL); - - info = camel_store_get_folder_info (store, NULL, FALSE, - TRUE, TRUE, ex); - if (!info) { - camel_object_unref (CAMEL_OBJECT (store)); - gtk_object_unref (GTK_OBJECT (storage)); - return; - } +/* ********************************************************************** */ - data->storage = storage; - data->update_infos = g_ptr_array_new (); - update_changed_folders (store, info, storage, "", data->update_infos, ex); +static void +fetch_mail_fetch(struct _mail_msg *mm) +{ + struct _fetch_mail_msg *m = (struct _fetch_mail_msg *)mm; + struct _filter_mail_msg *fm = (struct _filter_mail_msg *)mm; + int i; - camel_store_free_folder_info (store, info); - camel_object_unref (CAMEL_OBJECT (store)); - gtk_object_unref (GTK_OBJECT (storage)); + if (m->cancel) + camel_cancel_register(m->cancel); - data->empty = FALSE; + if ( (fm->destination = mail_tool_get_local_inbox(&mm->ex)) == NULL) { + if (m->cancel) + camel_cancel_unregister(m->cancel); return; } - - if (input->destination == NULL) { - input->destination = mail_tool_get_local_inbox (ex); - - if (input->destination == NULL) - return; - } - - /* setup filter driver */ - fc = mail_load_evolution_rule_context (); - filter = filter_driver_new (fc, mail_tool_filter_get_folder_func, 0); - filter_driver_set_default_folder (filter, input->destination); - - if (TRUE /* perform_logging */) { - char *filename = g_strdup_printf ("%s/evolution-filter-log", evolution_dir); - logfile = fopen (filename, "a+"); - g_free (filename); - } - - filter_driver_set_logfile (filter, logfile); - filter_driver_set_status_func (filter, mail_op_report_status, NULL); - - camel_folder_freeze (input->destination); - - if (!strncmp (input->source_url, "mbox:", 5)) { - char *path = mail_tool_do_movemail (input->source_url, ex); + + /* FIXME: this should support keep_on_server too, which would then perform a spool + access thingy, right? problem is matching raw messages to uid's etc. */ + if (!strncmp (m->source_uri, "mbox:", 5)) { + char *path = mail_tool_do_movemail (m->source_uri, &mm->ex); - if (path && !camel_exception_is_set (ex)) { - filter_driver_filter_mbox (filter, path, FILTER_SOURCE_INCOMING, ex); + if (path && !camel_exception_is_set (&mm->ex)) { + camel_filter_driver_filter_mbox(fm->driver, path, &mm->ex); - /* ok? zap the output file */ - if (!camel_exception_is_set (ex)) { + if (!camel_exception_is_set (&mm->ex)) unlink (path); - } } g_free (path); } else { - folder = mail_tool_get_inbox (input->source_url, ex); + CamelFolder *folder = fm->source_folder = mail_tool_get_inbox(m->source_uri, &mm->ex); + CamelUIDCache *cache = NULL; if (folder) { - if (camel_folder_get_message_count (folder) > 0) { - CamelUIDCache *cache = NULL; - GPtrArray *uids; - - uids = camel_folder_get_uids (folder); - if (input->keep_on_server) { - char *cachename = mail_config_folder_to_cachename (folder, "cache-"); - - cache = camel_uid_cache_new (cachename); - if (cache) { - GPtrArray *new_uids; - - new_uids = camel_uid_cache_get_new_uids (cache, uids); - camel_folder_free_uids (folder, uids); - uids = new_uids; - } - - g_free (cachename); - } - - filter_driver_filter_folder (filter, folder, FILTER_SOURCE_INCOMING, - uids, !input->keep_on_server, ex); - + /* this handles 'keep on server' stuff, if we have any new uid's to copy + across, we need to copy them to a new array 'cause of the way fetch_mail_free works */ + if (!fm->delete) { + char *cachename = mail_config_folder_to_cachename (folder, "cache-"); + + cache = camel_uid_cache_new (cachename); if (cache) { - /* save the cache for the next time we fetch mail! */ - camel_uid_cache_free_uids (uids); + GPtrArray *folder_uids, *cache_uids, *uids; - if (!camel_exception_is_set (ex)) - camel_uid_cache_save (cache); - camel_uid_cache_destroy (cache); - } else - camel_folder_free_uids (folder, uids); + folder_uids = camel_folder_get_uids(folder); + cache_uids = camel_uid_cache_get_new_uids(cache, folder_uids); + if (cache_uids) { + /* need to copy this, sigh */ + fm->source_uids = uids = g_ptr_array_new(); + g_ptr_array_set_size(uids, cache_uids->len); + for (i=0;i<cache_uids->len;i++) + uids->pdata[i] = g_strdup(cache_uids->pdata[i]); + camel_uid_cache_free_uids (cache_uids); + + filter_folder_filter(mm); + if (!camel_exception_is_set (&mm->ex)) + camel_uid_cache_save (cache); + camel_uid_cache_destroy (cache); + } + camel_folder_free_uids(folder, folder_uids); + } + g_free (cachename); } else { - data->empty = TRUE; + filter_folder_filter(mm); } - - /* sync and expunge */ - camel_folder_sync (folder, TRUE, ex); - - camel_object_unref (CAMEL_OBJECT (folder)); - } else { - data->empty = TRUE; } - } - - if (logfile) - fclose (logfile); - camel_folder_thaw (input->destination); + } - /*camel_object_unref (CAMEL_OBJECT (input->destination));*/ - gtk_object_unref (GTK_OBJECT (filter)); + if (m->cancel) + camel_cancel_unregister(m->cancel); } static void -cleanup_fetch_mail (gpointer in_data, gpointer op_data, CamelException *ex) +fetch_mail_fetched(struct _mail_msg *mm) { - fetch_mail_input_t *input = (fetch_mail_input_t *) in_data; - fetch_mail_data_t *data = (fetch_mail_data_t *) op_data; + struct _fetch_mail_msg *m = (struct _fetch_mail_msg *)mm; - camel_cancel_unregister(input->cancel); - camel_cancel_unref(input->cancel); + if (m->done) + m->done(m->source_uri, m->data); +} - if (data->empty && !camel_exception_is_set (ex)) - mail_op_set_message (_("There is no new mail at %s."), - input->source_url); - - if (data->update_infos) { - int i; - - for (i = 0; i < data->update_infos->len; i++) { - fetch_mail_update_info_t *update_info; - - update_info = (fetch_mail_update_info_t *) data->update_infos->pdata[i]; - evolution_storage_update_folder (data->storage, - update_info->name, - update_info->display, - update_info->new_messages); - g_free (update_info->name); - g_free (update_info->display); - g_free (update_info); - } +static void +fetch_mail_free(struct _mail_msg *mm) +{ + struct _fetch_mail_msg *m = (struct _fetch_mail_msg *)mm; - g_ptr_array_free (data->update_infos, TRUE); - } + g_free(m->source_uri); + if (m->cancel) + camel_cancel_unref(m->cancel); - g_free (input->source_url); - if (input->destination) - camel_object_unref (CAMEL_OBJECT (input->destination)); + filter_folder_free(mm); } -static const mail_operation_spec op_fetch_mail = { - describe_fetch_mail, - sizeof (fetch_mail_data_t), - setup_fetch_mail, - do_fetch_mail, - cleanup_fetch_mail +static struct _mail_msg_op fetch_mail_op = { + NULL, /* we do our own progress reporting */ + fetch_mail_fetch, + fetch_mail_fetched, + fetch_mail_free, }; -void -mail_do_fetch_mail (const gchar *source_url, gboolean keep_on_server, - CamelFolder *destination, - gpointer hook_func, gpointer hook_data) -{ - fetch_mail_input_t *input; - - g_return_if_fail (source_url != NULL); - g_return_if_fail (destination == NULL || - CAMEL_IS_FOLDER (destination)); +/* ouch, a 'do everything' interface ... */ +void mail_fetch_mail(const char *source, int keep, + FilterContext *fc, const char *type, + CamelCancel *cancel, + CamelFilterGetFolderFunc get_folder, void *get_data, + CamelFilterStatusFunc *status, void *status_data, + void (*done)(char *source, void *data), void *data) +{ + struct _fetch_mail_msg *m; + struct _filter_mail_msg *fm; + + m = mail_msg_new(&fetch_mail_op, NULL, sizeof(*m)); + fm = (struct _filter_mail_msg *)m; + m->source_uri = g_strdup(source); + fm->delete = !keep; + if (cancel) { + m->cancel = cancel; + camel_cancel_ref(cancel); + } + m->done = done; + m->data = data; - input = g_new (fetch_mail_input_t, 1); - input->source_url = g_strdup (source_url); - input->keep_on_server = keep_on_server; - input->destination = destination; - input->hook_func = hook_func; - input->hook_data = hook_data; - input->cancel = camel_cancel_new(); + fm->driver = camel_filter_driver_new(get_folder, get_data); + setup_filter_driver(fm->driver, fc, type); + if (status) + camel_filter_driver_set_status_func(fm->driver, status, status_data); - mail_operation_queue (&op_fetch_mail, input, TRUE); + e_thread_put(mail_thread_new, (EMsg *)m); } -/* ** FILTER ON DEMAND ********************************************************** */ -/* why do we have this separate code, it is basically a copy of the code above, - should be consolidated */ +/* updating of imap folders etc */ +struct _update_info { + EvolutionStorage *storage; -typedef struct filter_ondemand_input_s { - CamelFolder *source; - GPtrArray *uids; -} filter_ondemand_input_t; + void (*done)(CamelStore *, void *data); + void *data; +}; -static gchar * -describe_filter_ondemand (gpointer in_data, gboolean gerund) +static void do_update_subfolders_rec(CamelStore *store, CamelFolderInfo *info, EvolutionStorage *storage, const char *prefix) { - if (gerund) - return g_strdup_printf (_("Filtering email on demand")); + char *path, *name; + + path = g_strdup_printf("%s/%s", prefix, info->name); + if (info->unread_message_count > 0) + name = g_strdup_printf("%s (%d)", info->name, info->unread_message_count); else - return g_strdup_printf (_("Filter email on demand")); -} - -static void -setup_filter_ondemand (gpointer in_data, gpointer op_data, CamelException *ex) -{ - filter_ondemand_input_t *input = (filter_ondemand_input_t *) in_data; + name = g_strdup(info->name); - camel_object_ref (CAMEL_OBJECT (input->source)); + evolution_storage_update_folder(storage, path, name, info->unread_message_count > 0); + g_free(name); + if (info->child) + do_update_subfolders_rec(store, info->child, storage, path); + if (info->sibling) + do_update_subfolders_rec(store, info->sibling, storage, prefix); + g_free(path); } -static void -do_filter_ondemand (gpointer in_data, gpointer op_data, CamelException *ex) +static void do_update_subfolders(CamelStore *store, CamelFolderInfo *info, void *data) { - filter_ondemand_input_t *input = (filter_ondemand_input_t *) in_data; - FilterDriver *driver; - FilterContext *context; - FILE *logfile = NULL; - int i; + struct _update_info *uinfo = data; - mail_tool_camel_lock_up (); - if (camel_folder_get_message_count (input->source) == 0) { - mail_tool_camel_lock_down (); - return; + if (uinfo) { + do_update_subfolders_rec(store, info, uinfo->storage, ""); } - - /* create the filter context */ - context = mail_load_evolution_rule_context (); - - if (((RuleContext *)context)->error) { - gtk_object_unref (GTK_OBJECT (context)); - - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - "Cannot apply filters: failed to load filter rules."); - - mail_tool_camel_lock_down (); - return; - } - - /* setup filter driver - no default destination */ - driver = filter_driver_new (context, mail_tool_filter_get_folder_func, NULL); - - if (TRUE /* perform_logging */) { - char *filename; - - filename = g_strdup_printf ("%s/evolution-filter-log", evolution_dir); - logfile = fopen (filename, "a+"); - g_free (filename); - } - - filter_driver_set_logfile (driver, logfile); - filter_driver_set_status_func (driver, mail_op_report_status, NULL); - - for (i = 0; i < input->uids->len; i++) { - CamelMimeMessage *message; - CamelMessageInfo *info; - - message = camel_folder_get_message (input->source, input->uids->pdata[i], ex); - info = camel_folder_get_message_info (input->source, input->uids->pdata[i]); - - /* filter the message - use "incoming" rules since we don't want special "demand" filters? */ - filter_driver_filter_message (driver, message, info, "", FILTER_SOURCE_INCOMING, ex); - camel_folder_free_message_info(input->source, info); - } - - if (logfile) - fclose (logfile); - - /* sync the source folder */ - camel_folder_sync (input->source, FALSE, ex); - - gtk_object_unref (GTK_OBJECT (driver)); - mail_tool_camel_lock_down (); + if (uinfo->done) + uinfo->done(store, uinfo->data); + + gtk_object_unref((GtkObject *)uinfo->storage); + g_free(uinfo); } -static void -cleanup_filter_ondemand (gpointer in_data, gpointer op_data, CamelException *ex) +/* this interface is a little icky */ +int mail_update_subfolders(CamelStore *store, EvolutionStorage *storage, + void (*done)(CamelStore *, void *data), void *data) { - filter_ondemand_input_t *input = (filter_ondemand_input_t *) in_data; - int i; - - if (input->source) - camel_object_unref (CAMEL_OBJECT (input->source)); - - for (i = 0; i < input->uids->len; i++) - g_free (input->uids->pdata[i]); - g_ptr_array_free (input->uids, TRUE); + struct _update_info *info; + + /* FIXME: This wont actually work entirely right, as a failure may lose this data */ + /* however, this isn't a big problem ... */ + info = g_malloc0(sizeof(*info)); + info->storage = storage; + gtk_object_ref((GtkObject *)storage); + info->done = done; + info->data = data; + + return mail_get_folderinfo(store, do_update_subfolders, info); } -static const mail_operation_spec op_filter_ondemand = { - describe_filter_ondemand, - 0, - setup_filter_ondemand, - do_filter_ondemand, - cleanup_filter_ondemand -}; +/* ********************************************************************** */ +/* sending stuff */ +/* ** SEND MAIL *********************************************************** */ -void -mail_do_filter_ondemand (CamelFolder *source, GPtrArray *uids) +/* send 1 message to a specific transport */ +static void +mail_send_message(CamelMimeMessage *message, const char *destination, CamelFilterDriver *driver, CamelException *ex) { - filter_ondemand_input_t *input; + extern CamelFolder *sent_folder; /* FIXME */ + CamelMessageInfo *info; + CamelTransport *xport; + const char *version; + + if (SUB_VERSION[0] == '\0') + version = "Evolution (" VERSION " - Preview Release)"; + else + version = "Evolution (" VERSION "/" SUB_VERSION " - Preview Release)"; + camel_medium_add_header(CAMEL_MEDIUM (message), "X-Mailer", version); + camel_mime_message_set_date(message, CAMEL_MESSAGE_DATE_CURRENT, 0); + + xport = camel_session_get_transport(session, destination, ex); + if (camel_exception_is_set(ex)) + return; - g_return_if_fail (source == NULL || CAMEL_IS_FOLDER (source)); + camel_transport_send(xport, (CamelMedium *)message, ex); + camel_object_unref((CamelObject *)xport); + if (camel_exception_is_set(ex)) + return; - input = g_new (filter_ondemand_input_t, 1); - input->source = source; - input->uids = uids; + /* post-process */ + info = camel_message_info_new(); + info->flags = CAMEL_MESSAGE_SEEN; + + if (driver) + camel_filter_driver_filter_message(driver, message, info, "", ex); - mail_operation_queue (&op_filter_ondemand, input, TRUE); + if (sent_folder) + camel_folder_append_message(sent_folder, message, info, ex); + + camel_message_info_free(info); } -/* ** SEND MAIL *********************************************************** */ +/* ********************************************************************** */ struct _send_mail_msg { struct _mail_msg msg; - char *uri; + CamelFilterDriver *driver; + char *destination; CamelMimeMessage *message; void (*done)(char *uri, CamelMimeMessage *message, gboolean sent, void *data); @@ -568,59 +512,10 @@ static char *send_mail_desc(struct _mail_msg *mm, int done) static void send_mail_send(struct _mail_msg *mm) { struct _send_mail_msg *m = (struct _send_mail_msg *)mm; - extern CamelFolder *sent_folder; /* FIXME */ - CamelMessageInfo *info; - CamelTransport *xport; - FilterContext *context; - - set_x_mailer (m->message); - - camel_mime_message_set_date(m->message, CAMEL_MESSAGE_DATE_CURRENT, 0); - xport = camel_session_get_transport(session, m->uri, &mm->ex); - if (camel_exception_is_set(&mm->ex)) - return; - - mail_tool_send_via_transport(xport, (CamelMedium *)m->message, &mm->ex); - camel_object_unref((CamelObject *)xport); - if (camel_exception_is_set(&mm->ex)) - return; - - /* now lets run it through the outgoing filters */ - info = camel_message_info_new(); - info->flags = CAMEL_MESSAGE_SEEN; - - /* setup filter driver */ -#warning "Using a gtk object outside of the mian thread, joy" - context = mail_load_evolution_rule_context (); - - if (!((RuleContext *)context)->error) { - FilterDriver *driver; - FILE *logfile; - - driver = filter_driver_new (context, mail_tool_filter_get_folder_func, NULL); - - if (TRUE /* perform_logging */) { - char *filename; - - filename = g_strdup_printf ("%s/evolution-filter-log", evolution_dir); - logfile = fopen (filename, "a+"); - g_free (filename); - } - - filter_driver_filter_message (driver, m->message, info, "", FILTER_SOURCE_OUTGOING, &mm->ex); - - gtk_object_unref (GTK_OBJECT (driver)); - - if (logfile) - fclose (logfile); - } - - /* now to save the message in Sent */ - if (sent_folder) - camel_folder_append_message(sent_folder, m->message, info, &mm->ex); - - camel_message_info_free(info); + camel_cancel_register(mm->cancel); + mail_send_message(m->message, m->destination, m->driver, &mm->ex); + camel_cancel_unregister(mm->cancel); } static void send_mail_sent(struct _mail_msg *mm) @@ -628,7 +523,7 @@ static void send_mail_sent(struct _mail_msg *mm) struct _send_mail_msg *m = (struct _send_mail_msg *)mm; if (m->done) - m->done(m->uri, m->message, !camel_exception_is_set(&mm->ex), m->data); + m->done(m->destination, m->message, !camel_exception_is_set(&mm->ex), m->data); } static void send_mail_free(struct _mail_msg *mm) @@ -636,7 +531,7 @@ static void send_mail_free(struct _mail_msg *mm) struct _send_mail_msg *m = (struct _send_mail_msg *)mm; camel_object_unref((CamelObject *)m->message); - g_free(m->uri); + g_free(m->destination); } static struct _mail_msg_op send_mail_op = { @@ -647,164 +542,181 @@ static struct _mail_msg_op send_mail_op = { }; int -mail_send_mail_old(const char *uri, CamelMimeMessage *message, void (*done) (char *uri, CamelMimeMessage *message, gboolean sent, void *data), void *data) +mail_send_mail(const char *uri, CamelMimeMessage *message, void (*done) (char *uri, CamelMimeMessage *message, gboolean sent, void *data), void *data) { struct _send_mail_msg *m; int id; + FilterContext *fc; m = mail_msg_new(&send_mail_op, NULL, sizeof(*m)); - m->uri = g_strdup(uri); + m->destination = g_strdup(uri); m->message = message; camel_object_ref((CamelObject *)message); m->data = data; m->done = done; id = m->msg.seq; + + m->driver = camel_filter_driver_new(filter_get_folder, NULL); + fc = mail_load_filter_context(); + setup_filter_driver(m->driver, fc, FILTER_SOURCE_OUTGOING); + gtk_object_unref((GtkObject *)fc); + e_thread_put(mail_thread_new, (EMsg *)m); return id; } /* ** SEND MAIL QUEUE ***************************************************** */ -typedef struct send_queue_input_s -{ - CamelFolder *folder_queue; - gchar *xport_uri; -} -send_queue_input_t; +struct _send_queue_msg { + struct _mail_msg msg; -static gchar * -describe_send_queue (gpointer in_data, gboolean gerund) -{ - /*send_queue_input_t *input = (send_queue_input_t *) in_data;*/ - - if (gerund) { - return g_strdup_printf (_("Sending queue")); - } else { - return g_strdup_printf (_("Send queue")); - } -} + CamelFolder *queue; + char *destination; + + CamelFilterDriver *driver; + CamelCancel *cancel; + + /* we use camelfilterstatusfunc, even though its not the filter doing it */ + CamelFilterStatusFunc *status; + void *status_data; + + void (*done)(char *destination, void *data); + void *data; +}; static void -setup_send_queue (gpointer in_data, gpointer op_data, CamelException *ex) +report_status(struct _send_queue_msg *m, enum camel_filter_status_t status, int pc, const char *desc, ...) { - send_queue_input_t *input = (send_queue_input_t *) in_data; + va_list ap; + char *str; - camel_object_ref (CAMEL_OBJECT (input->folder_queue)); + if (m->status) { + va_start(ap, desc); + str = g_strdup_vprintf(desc, ap); + m->status(m->driver, status, pc, str, m->status_data); + g_free(str); + } } static void -do_send_queue (gpointer in_data, gpointer op_data, CamelException *ex) +send_queue_send(struct _mail_msg *mm) { - send_queue_input_t *input = (send_queue_input_t *) in_data; - extern CamelFolder *sent_folder; - CamelTransport *xport; + struct _send_queue_msg *m = (struct _send_queue_msg *)mm; GPtrArray *uids; - guint32 set; int i; - - uids = camel_folder_get_uids (input->folder_queue); - if (!uids) + extern CamelFolder *sent_folder; /* FIXME */ + + printf("sending queue\n"); + + uids = camel_folder_get_uids(m->queue); + if (uids == NULL || uids->len == 0) return; + + if (m->cancel) + camel_cancel_register(m->cancel); - for (i = 0; i < uids->len; i++) { + for (i=0; i<uids->len; i++) { CamelMimeMessage *message; - char *transport_url = NULL; + char *destination; + int pc = (100 * i)/uids->len; + + report_status(m, FILTER_STATUS_START, pc, "Sending message %d of %d", i+1, uids->len); - message = camel_folder_get_message (input->folder_queue, uids->pdata[i], ex); - if (camel_exception_is_set (ex)) + message = camel_folder_get_message(m->queue, uids->pdata[i], &mm->ex); + if (camel_exception_is_set(&mm->ex)) break; - - /* Remove the X-Evolution header */ - camel_medium_remove_header (CAMEL_MEDIUM (message), "X-Evolution"); - - set_x_mailer (message); - - camel_mime_message_set_date (message, CAMEL_MESSAGE_DATE_CURRENT, 0); - + /* Get the preferred transport URI */ - transport_url = (char *) camel_medium_get_header (CAMEL_MEDIUM (message), "X-Evolution-Transport"); - if (transport_url) { - transport_url = g_strdup (transport_url); - g_strstrip (transport_url); - camel_medium_remove_header (CAMEL_MEDIUM (message), "X-Evolution-Transport"); - } - - xport = camel_session_get_transport (session, transport_url ? transport_url : input->xport_uri, ex); - g_free (transport_url); - - if (camel_exception_is_set (ex)) - break; - - mail_tool_send_via_transport (xport, CAMEL_MEDIUM (message), ex); - camel_object_unref (CAMEL_OBJECT (xport)); - - if (camel_exception_is_set (ex)) + destination = (char *)camel_medium_get_header(CAMEL_MEDIUM(message), "X-Evolution-Transport"); + if (destination) { + destination = g_strdup(destination); + camel_medium_remove_header(CAMEL_MEDIUM(message), "X-Evolution-Transport"); + mail_send_message(message, g_strstrip(destination), m->driver, &mm->ex); + g_free(destination); + } else + mail_send_message(message, m->destination, m->driver, &mm->ex); + + if (camel_exception_is_set(&mm->ex)) break; - - set = camel_folder_get_message_flags (input->folder_queue, - uids->pdata[i]); - camel_folder_set_message_flags (input->folder_queue, - uids->pdata[i], - CAMEL_MESSAGE_DELETED, ~set); - - /* now to save the message in Sent */ - if (sent_folder) { - CamelMessageInfo *info; - - info = g_new0 (CamelMessageInfo, 1); - info->flags = CAMEL_MESSAGE_SEEN; - camel_folder_append_message (sent_folder, message, info, ex); - g_free (info); - } + + camel_folder_set_message_flags(m->queue, uids->pdata[i], CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_DELETED); } - - for (i = 0; i < uids->len; i++) - g_free (uids->pdata[i]); - g_ptr_array_free (uids, TRUE); - if (!camel_exception_is_set(ex)) - camel_folder_expunge(input->folder_queue, NULL); + if (camel_exception_is_set(&mm->ex)) + report_status(m, FILTER_STATUS_END, 100, "Failed on message %d of %d", i+1, uids->len); + else + report_status(m, FILTER_STATUS_END, 100, "Complete."); + + camel_folder_free_uids(m->queue, uids); + + if (!camel_exception_is_set(&mm->ex)) + camel_folder_expunge(m->queue, &mm->ex); if (sent_folder) - camel_folder_sync(sent_folder, FALSE, NULL); + camel_folder_sync(sent_folder, FALSE, &mm->ex); + + if (m->cancel) + camel_cancel_unregister(m->cancel); } static void -cleanup_send_queue (gpointer in_data, gpointer op_data, CamelException *ex) +send_queue_sent(struct _mail_msg *mm) { - send_queue_input_t *input = (send_queue_input_t *) in_data; - - camel_object_unref (CAMEL_OBJECT (input->folder_queue)); + struct _send_queue_msg *m = (struct _send_queue_msg *)mm; + + if (m->done) + m->done(m->destination, m->data); +} + +static void +send_queue_free(struct _mail_msg *mm) +{ + struct _send_queue_msg *m = (struct _send_queue_msg *)mm; - g_free (input->xport_uri); + camel_object_unref((CamelObject *)m->queue); + g_free(m->destination); + if (m->cancel) + camel_cancel_unref(m->cancel); } -static const mail_operation_spec op_send_queue = { - describe_send_queue, - 0, - setup_send_queue, - do_send_queue, - cleanup_send_queue +static struct _mail_msg_op send_queue_op = { + NULL, /* do our own reporting, as with fetch mail */ + send_queue_send, + send_queue_sent, + send_queue_free, }; +/* same interface as fetch_mail, just 'cause i'm lazy today (and we need to run it from the same spot?) */ void -mail_do_send_queue (CamelFolder *folder_queue, - const char *xport_uri) -{ - send_queue_input_t *input; +mail_send_queue(CamelFolder *queue, const char *destination, + FilterContext *fc, const char *type, + CamelCancel *cancel, + CamelFilterGetFolderFunc get_folder, void *get_data, + CamelFilterStatusFunc *status, void *status_data, + void (*done)(char *destination, void *data), void *data) +{ + struct _send_queue_msg *m; + + m = mail_msg_new(&send_queue_op, NULL, sizeof(*m)); + m->queue = queue; + camel_object_ref((CamelObject *)queue); + m->destination = g_strdup(destination); + if (cancel) { + m->cancel = cancel; + camel_cancel_ref(cancel); + } + m->status = status; + m->status_data = status_data; + m->done = done; + m->data = data; - g_return_if_fail (xport_uri != NULL); - g_return_if_fail (CAMEL_IS_FOLDER (folder_queue)); + m->driver = camel_filter_driver_new(get_folder, get_data); + setup_filter_driver(m->driver, fc, type); - input = g_new (send_queue_input_t, 1); - input->xport_uri = g_strdup (xport_uri); - input->folder_queue = folder_queue; - - mail_operation_queue (&op_send_queue, input, TRUE); + e_thread_put(mail_thread_new, (EMsg *)m); } - /* ** APPEND MESSAGE TO FOLDER ******************************************** */ typedef struct append_mail_input_s |