From 50ef085e18b3cd54f1cea88ceb20156a56fb050d Mon Sep 17 00:00:00 2001 From: Not Zed Date: Sun, 21 Jan 2001 04:19:30 +0000 Subject: Init a cancel field in the message. (mail_msg_free): Free it. 2001-01-21 Not Zed * mail-mt.c (mail_msg_new): Init a cancel field in the message. (mail_msg_free): Free it. (mail_msg_cancel): New function to attempt to cancel an operation by id. Impelementation functions can still be uncancellable by not registering for cancellation, etc, or do it themselves as well. * mail-send-recv.c (fetch_mail_filter_folder): set folder_uid's properly, so we can save it later. (filter_folder_filter): Renamed from fetch_mail_filter_folder, since its going to be used for all filtering. (mail_fetch_mail): Changed from mail_filter_mail. (mail_filter_folder): New function, replaces mail_do_filter_ondemand functionality. (mail_filter_on_demand): New function, actually replaces mail_do_filter_ondemand. (receive_get_folder): Added an exception arg. (mail_send_message): New function to just send a message. (send_mail_send): Use mail_send_message. (send_queue_send): New send qeue code, use mail_send_message, and clean up some stuff. (mail_send_receive): Changed from mail_receive. (build_dialogue): Setup the sending data, as well. (mail_update_subfolders): New function to update folder info. (send_mail_send): hook into cancellation if we want. svn path=/trunk/; revision=7672 --- mail/ChangeLog | 28 ++ mail/folder-browser-factory.c | 4 +- mail/mail-mt.c | 16 + mail/mail-mt.h | 3 + mail/mail-ops.c | 2 +- mail/mail-send-recv.c | 782 ++++++++++++++++++++++++++++++++++++------ 6 files changed, 722 insertions(+), 113 deletions(-) (limited to 'mail') diff --git a/mail/ChangeLog b/mail/ChangeLog index 30bf75932e..64cbe1c166 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,31 @@ +2001-01-21 Not Zed + + * mail-mt.c (mail_msg_new): Init a cancel field in the message. + (mail_msg_free): Free it. + (mail_msg_cancel): New function to attempt to cancel an + operation by id. Impelementation functions can still be + uncancellable by not registering for cancellation, etc, or do it + themselves as well. + + * mail-send-recv.c (fetch_mail_filter_folder): set folder_uid's + properly, so we can save it later. + (filter_folder_filter): Renamed from fetch_mail_filter_folder, + since its going to be used for all filtering. + (mail_fetch_mail): Changed from mail_filter_mail. + (mail_filter_folder): New function, replaces + mail_do_filter_ondemand functionality. + (mail_filter_on_demand): New function, actually replaces + mail_do_filter_ondemand. + (receive_get_folder): Added an exception arg. + (mail_send_message): New function to just send a message. + (send_mail_send): Use mail_send_message. + (send_queue_send): New send qeue code, use mail_send_message, and + clean up some stuff. + (mail_send_receive): Changed from mail_receive. + (build_dialogue): Setup the sending data, as well. + (mail_update_subfolders): New function to update folder info. + (send_mail_send): hook into cancellation if we want. + 2001-01-20 Jeffrey Stedfast * mail-ops.c (do_send_queue): Strip leading space from the diff --git a/mail/folder-browser-factory.c b/mail/folder-browser-factory.c index e924ca0256..aac2e5fedc 100644 --- a/mail/folder-browser-factory.c +++ b/mail/folder-browser-factory.c @@ -34,7 +34,7 @@ static EList *control_list = NULL; /* this is temporary, remove later -Z */ -void mail_receive(void); +void mail_send_receive(void); /* * Add with 'folder_browser' @@ -101,7 +101,7 @@ BonoboUIVerb verbs [] = { BONOBO_UI_UNSAFE_VERB ("MailNext", next_msg), /* This is just very temporary - !Z */ - BONOBO_UI_UNSAFE_VERB ("MailGetNew", mail_receive), + BONOBO_UI_UNSAFE_VERB ("MailGetNew", mail_send_receive), BONOBO_UI_VERB_END }; diff --git a/mail/mail-mt.c b/mail/mail-mt.c index b18f78c06e..1735432070 100644 --- a/mail/mail-mt.c +++ b/mail/mail-mt.c @@ -40,6 +40,7 @@ void *mail_msg_new(mail_msg_op_t *ops, EMsgPort *reply_port, size_t size) msg->ops = ops; msg->seq = mail_msg_seq++; msg->msg.reply_port = reply_port; + msg->cancel = camel_cancel_new(); camel_exception_init(&msg->ex); g_hash_table_insert(mail_msg_active, (void *)msg->seq, msg); @@ -63,6 +64,7 @@ void mail_msg_free(void *msg) MAIL_MT_UNLOCK(mail_msg_lock); + camel_cancel_unref(m->cancel); camel_exception_clear(&m->ex); g_free(m); } @@ -91,6 +93,20 @@ void mail_msg_check_error(void *msg) g_free(text); } +void mail_msg_cancel(unsigned int msgid) +{ + struct _mail_msg *m; + + MAIL_MT_LOCK(mail_msg_lock); + m = g_hash_table_lookup(mail_msg_active, (void *)msgid); + + if (m) + camel_cancel_cancel(m->cancel); + + MAIL_MT_UNLOCK(mail_msg_lock); +} + + /* waits for a message to be finished processing (freed) the messageid is from struct _mail_msg->seq */ void mail_msg_wait(unsigned int msgid) diff --git a/mail/mail-mt.h b/mail/mail-mt.h index 6ef4119f4c..de2f91d81b 100644 --- a/mail/mail-mt.h +++ b/mail/mail-mt.h @@ -26,11 +26,13 @@ #include "camel/camel-exception.h" #include "e-util/e-msgport.h" #include "camel/camel-object.h" +#include "camel/camel-session.h" typedef struct _mail_msg { EMsg msg; /* parent type */ struct _mail_msg_op *ops; /* operation functions */ unsigned int seq; /* seq number for synchronisation */ + CamelCancel *cancel; /* a cancellation handle */ CamelException ex; /* an initialised camel exception, upto the caller to use this */ } mail_msg_t; @@ -50,6 +52,7 @@ void mail_msg_init(void); void *mail_msg_new(mail_msg_op_t *ops, EMsgPort *reply_port, size_t size); void mail_msg_free(void *msg); void mail_msg_check_error(void *msg); +void mail_msg_cancel(unsigned int msgid); void mail_msg_wait(unsigned int msgid); /* set the status-bar message */ diff --git a/mail/mail-ops.c b/mail/mail-ops.c index 8cd874f042..c6db157afb 100644 --- a/mail/mail-ops.c +++ b/mail/mail-ops.c @@ -647,7 +647,7 @@ static struct _mail_msg_op send_mail_op = { }; int -mail_send_mail(const char *uri, CamelMimeMessage *message, void (*done) (char *uri, CamelMimeMessage *message, gboolean sent, void *data), void *data) +mail_send_mail_old(const char *uri, CamelMimeMessage *message, void (*done) (char *uri, CamelMimeMessage *message, gboolean sent, void *data), void *data) { struct _send_mail_msg *m; int id; diff --git a/mail/mail-send-recv.c b/mail/mail-send-recv.c index ee080f8dd2..18cd0d5a51 100644 --- a/mail/mail-send-recv.c +++ b/mail/mail-send-recv.c @@ -9,8 +9,11 @@ #include "camel/camel-session.h" #include "camel/camel-uid-cache.h" +#include "evolution-storage.h" + #include "mail-mt.h" #include "mail-config.h" +#include "mail-session.h" /* for the dialogue stuff */ #include @@ -22,6 +25,7 @@ extern char *evolution_dir; extern CamelFolder *mail_tool_filter_get_folder_func (CamelFilterDriver *d, const char *uri, void *data); +extern CamelFolder *mail_tool_uri_to_folder(const char *uri, CamelException *ex); static FilterContext * load_context(void) @@ -71,115 +75,213 @@ setup_filter_driver(CamelFilterDriver *driver, FilterContext *fc, const char *so g_string_free (faction, TRUE); } +static CamelFolder * +filter_get_folder(CamelFilterDriver *d, const char *uri, void *data, CamelException *ex) +{ + CamelFolder *folder; + + folder = mail_tool_uri_to_folder(uri, ex); + + return folder; +} + /* used for both just filtering a folder + uid's, and for filtering a whole folder */ -struct _fetch_mail_msg { +/* used both for fetching mail, and for filtering mail */ +struct _filter_mail_msg { struct _mail_msg msg; - char *source_uri; - CamelFolder *source_folder; - GPtrArray *source_uids; + CamelFolder *source_folder; /* where they come from */ + GPtrArray *source_uids; /* uids to copy, or NULL == copy all */ CamelCancel *cancel; - CamelFolder *destination; CamelFilterDriver *driver; - int keep; + int delete; /* delete messages after filtering them? */ + CamelFolder *destination; /* default destination for any messages, NULL for none */ +}; + +/* 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 -fetch_mail_filter_folder(struct _mail_msg *mm) +filter_folder_filter(struct _mail_msg *mm) { - struct _fetch_mail_msg *m = (struct _fetch_mail_msg *)mm; + struct _filter_mail_msg *m = (struct _filter_mail_msg *)mm; CamelFolder *folder; - CamelUIDCache *cache = NULL; - GPtrArray *uids, *folder_uids = NULL, *cache_uids = NULL; + GPtrArray *uids, *folder_uids = NULL; - if (m->source_folder) - folder = m->source_folder; - else - folder = m->source_folder = mail_tool_get_inbox (m->source_uri, &mm->ex); + if (m->cancel) + camel_cancel_register(m->cancel); + + folder = m->source_folder; if (folder == NULL || camel_folder_get_message_count (folder) == 0) { + if (m->cancel) + camel_cancel_unregister(m->cancel); return; } + if (m->destination) { + camel_folder_freeze(m->destination); + camel_filter_driver_set_default_folder(m->driver, m->destination); + } + camel_folder_freeze(folder); if (m->source_uids) uids = m->source_uids; else - uids = camel_folder_get_uids (folder); + folder_uids = uids = camel_folder_get_uids (folder); - if (m->keep) { - char *cachename = mail_config_folder_to_cachename (folder, "cache-"); - - cache = camel_uid_cache_new (cachename); - if (cache) { - cache_uids = camel_uid_cache_get_new_uids (cache, uids); - uids = cache_uids; - } - - g_free (cachename); - } - - camel_filter_driver_filter_folder(m->driver, folder, FILTER_SOURCE_INCOMING, uids, !m->keep, &mm->ex); - - if (cache) { - if (!camel_exception_is_set (&mm->ex)) - camel_uid_cache_save (cache); - camel_uid_cache_destroy (cache); - } + camel_filter_driver_filter_folder(m->driver, folder, uids, m->delete, &mm->ex); if (folder_uids) camel_folder_free_uids(folder, folder_uids); - if (cache_uids) - camel_uid_cache_free_uids (cache_uids); /* sync and expunge */ camel_folder_sync (folder, TRUE, &mm->ex); camel_folder_thaw(folder); + + 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;isource_uids->len;i++) + g_free(m->source_uids->pdata[i]); + g_ptr_array_free(m->source_uids, TRUE); + } + 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); + } + + 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 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; + if (m->cancel) camel_cancel_register(m->cancel); - if (m->destination == NULL) { - if ( (m->destination = mail_tool_get_local_inbox(&mm->ex)) == NULL) { - if (m->cancel) - camel_cancel_unregister(m->cancel); - return; - } + if ( (fm->destination = mail_tool_get_local_inbox(&mm->ex)) == NULL) { + if (m->cancel) + camel_cancel_unregister(m->cancel); + return; } - camel_folder_freeze (m->destination); - camel_filter_driver_set_default_folder(m->driver, m->destination); - /* 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 (&mm->ex)) { - camel_filter_driver_filter_mbox(m->driver, path, FILTER_SOURCE_INCOMING, &mm->ex); + camel_filter_driver_filter_mbox(fm->driver, path, &mm->ex); - /* ok? zap the output file */ - if (!camel_exception_is_set (&mm->ex)) { + if (!camel_exception_is_set (&mm->ex)) unlink (path); - } } g_free (path); } else { - fetch_mail_filter_folder(mm); - } + CamelFolder *folder = fm->source_folder = mail_tool_get_inbox(m->source_uri, &mm->ex); + CamelUIDCache *cache = NULL; + + if (folder) { + /* 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) { + GPtrArray *folder_uids, *cache_uids, *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;ilen;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 { + filter_folder_filter(mm); + } + } - camel_folder_thaw (m->destination); + } if (m->cancel) camel_cancel_unregister(m->cancel); @@ -198,20 +300,12 @@ static void fetch_mail_free(struct _mail_msg *mm) { struct _fetch_mail_msg *m = (struct _fetch_mail_msg *)mm; - int i; g_free(m->source_uri); - if (m->source_folder) - camel_object_unref((CamelObject *)m->source_folder); - if (m->source_uids) { - for (i=0;isource_uids->len;i++) - g_free(m->source_uids->pdata[i]); - g_ptr_array_free(m->source_uids, TRUE); - } - camel_cancel_unref(m->cancel); - if (m->destination) - camel_object_unref((CamelObject *)m->destination); - camel_object_unref((CamelObject *)m->driver); + if (m->cancel) + camel_cancel_unref(m->cancel); + + filter_folder_free(mm); } static struct _mail_msg_op fetch_mail_op = { @@ -222,33 +316,376 @@ static struct _mail_msg_op fetch_mail_op = { }; /* ouch, a 'do everything' interface ... */ -void mail_filter_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) +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); - m->keep = keep; - m->cancel = cancel; - camel_cancel_ref(cancel); + fm->delete = !keep; + if (cancel) { + m->cancel = cancel; + camel_cancel_ref(cancel); + } + m->done = done; + m->data = data; + + 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); + + e_thread_put(mail_thread_new, (EMsg *)m); +} + + +/* updating of imap folders etc */ +struct _update_info { + EvolutionStorage *storage; + + void (*done)(CamelStore *, void *data); + void *data; +}; + +static void do_update_subfolders_rec(CamelStore *store, CamelFolderInfo *info, EvolutionStorage *storage, const char *prefix) +{ + 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 + name = g_strdup(info->name); + + 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_update_subfolders(CamelStore *store, CamelFolderInfo *info, void *data) +{ + struct _update_info *uinfo = data; + + if (uinfo) { + do_update_subfolders_rec(store, info, uinfo->storage, ""); + } + + if (uinfo->done) + uinfo->done(store, uinfo->data); + + gtk_object_unref((GtkObject *)uinfo->storage); + g_free(uinfo); +} + +/* this interface is a little icky */ +int mail_update_subfolders(CamelStore *store, EvolutionStorage *storage, + void (*done)(CamelStore *, void *data), void *data) +{ + 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); +} + +/* ********************************************************************** */ +/* sending stuff */ +/* ** SEND MAIL *********************************************************** */ + +/* send 1 message to a specific transport */ +static void +mail_send_message(CamelMimeMessage *message, const char *destination, CamelFilterDriver *driver, CamelException *ex) +{ + 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; + + mail_tool_send_via_transport(xport, (CamelMedium *)message, ex); + camel_object_unref((CamelObject *)xport); + if (camel_exception_is_set(ex)) + return; + + /* post-process */ + info = camel_message_info_new(); + info->flags = CAMEL_MESSAGE_SEEN; + + if (driver) + camel_filter_driver_filter_message(driver, message, info, "", ex); + + if (sent_folder) + camel_folder_append_message(sent_folder, message, info, ex); + + camel_message_info_free(info); +} + +/* ********************************************************************** */ + +struct _send_mail_msg { + struct _mail_msg msg; + + CamelFilterDriver *driver; + char *destination; + CamelMimeMessage *message; + + void (*done)(char *uri, CamelMimeMessage *message, gboolean sent, void *data); + void *data; +}; + +static char *send_mail_desc(struct _mail_msg *mm, int done) +{ + struct _send_mail_msg *m = (struct _send_mail_msg *)mm; + const char *subject; + + subject = camel_mime_message_get_subject(m->message); + if (subject && subject[0]) + return g_strdup_printf (_("Sending \"%s\""), subject); + else + return g_strdup(_("Sending message")); +} + +static void send_mail_send(struct _mail_msg *mm) +{ + struct _send_mail_msg *m = (struct _send_mail_msg *)mm; + + 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) +{ + struct _send_mail_msg *m = (struct _send_mail_msg *)mm; + + if (m->done) + m->done(m->destination, m->message, !camel_exception_is_set(&mm->ex), m->data); +} + +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->destination); +} + +static struct _mail_msg_op send_mail_op = { + send_mail_desc, + send_mail_send, + send_mail_sent, + send_mail_free, +}; + +int +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->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 = load_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 ***************************************************** */ + +struct _send_queue_msg { + struct _mail_msg msg; + + 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 +report_status(struct _send_queue_msg *m, enum camel_filter_status_t status, int pc, const char *desc, ...) +{ + va_list ap; + char *str; + + 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 +send_queue_send(struct _mail_msg *mm) +{ + struct _send_queue_msg *m = (struct _send_queue_msg *)mm; + GPtrArray *uids; + int i; + 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; ilen; i++) { + CamelMimeMessage *message; + 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(m->queue, uids->pdata[i], &mm->ex); + if (camel_exception_is_set(&mm->ex)) + break; + + /* Get the preferred transport URI */ + 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; + + camel_folder_set_message_flags(m->queue, uids->pdata[i], CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_DELETED); + } + + 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, &mm->ex); + + if (m->cancel) + camel_cancel_unregister(m->cancel); +} + +static void +send_queue_sent(struct _mail_msg *mm) +{ + 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; + + camel_object_unref((CamelObject *)m->queue); + g_free(m->destination); + if (m->cancel) + camel_cancel_unref(m->cancel); +} + +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_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; m->driver = camel_filter_driver_new(get_folder, get_data); setup_filter_driver(m->driver, fc, type); - if (status) - camel_filter_driver_set_status_func(m->driver, status, status_data); e_thread_put(mail_thread_new, (EMsg *)m); } -/* this is not used yet, will be used to keep track of which folders were - filtering to, and to let them refresh once in a while */ + +/* ********************************************************************** */ +/* This stuff below is independent of the stuff above */ + +/* this stuff is used to keep track of which folders filters have accessed, and + what not. the thaw/refreeze thing doesn't really seem to work though */ struct _folder_info { char *uri; CamelFolder *folder; @@ -271,11 +708,24 @@ struct _send_data { GHashTable *folders; }; +typedef enum { + SEND_RECEIVE, /* receiver */ + SEND_SEND, /* sender */ + SEND_UPDATE, /* imap-like 'just update folder info' */ +} send_info_t ; + +typedef enum { + SEND_ACTIVE, + SEND_CANCELLED, + SEND_COMPLETE +} send_state_t; + struct _send_info { + send_info_t type; /* 0 = fetch, 1 = send */ CamelCancel *cancel; char *uri; int keep; - int cancelled; + send_state_t state; GtkProgressBar *bar; GtkButton *stop; time_t update; @@ -285,9 +735,11 @@ struct _send_info { static void receive_cancel(GtkButton *button, struct _send_info *info) { - camel_cancel_cancel(info->cancel); - gtk_progress_set_format_string((GtkProgress *)info->bar, _("Cancelling ...")); - info->cancelled = TRUE; + if (info->state == SEND_ACTIVE) { + camel_cancel_cancel(info->cancel); + gtk_progress_set_format_string((GtkProgress *)info->bar, _("Cancelling ...")); + info->state = SEND_CANCELLED; + } gtk_widget_set_sensitive((GtkWidget *)info->stop, FALSE); } @@ -345,7 +797,7 @@ dialogue_clicked(GnomeDialog *gd, int button, struct _send_data *data) } } -static struct _send_data *build_dialogue(GSList *sources) +static struct _send_data *build_dialogue(GSList *sources, CamelFolder *outbox, const char *destination) { GnomeDialog *gd; GtkFrame *frame; @@ -353,7 +805,11 @@ static struct _send_data *build_dialogue(GSList *sources) int row; GList *list = NULL; struct _send_data *data; - + GtkLabel *label; + GtkProgressBar *bar; + GtkButton *stop; + struct _send_info *info; + data = g_malloc0(sizeof(*data)); data->lock = g_mutex_new(); data->folders = g_hash_table_new(g_str_hash, g_str_equal); @@ -362,7 +818,7 @@ static struct _send_data *build_dialogue(GSList *sources) gd = (GnomeDialog *)gnome_dialog_new(_("Send & Receive mail"), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_set_sensitive(gd, 0, FALSE); - frame= (GtkFrame *)gtk_frame_new(_("Receive list")); + frame= (GtkFrame *)gtk_frame_new(_("Receiving")); gtk_box_pack_start((GtkBox *)gd->vbox, (GtkWidget *)frame, TRUE, TRUE, 0); table = (GtkTable *)gtk_table_new(g_slist_length(sources), 3, FALSE); gtk_container_add((GtkContainer *)frame, (GtkWidget *)table); @@ -371,26 +827,25 @@ static struct _send_data *build_dialogue(GSList *sources) row = 0; while (sources) { MailConfigService *source = sources->data; - GtkLabel *label; - GtkProgressBar *bar; - GtkButton *stop; - struct _send_info *info; - - /* imap is handled differently */ - if (!strncmp(source->url, "imap:", 5)) { - sources = sources->next; - continue; - } info = g_malloc0(sizeof(*info)); + /* imap is handled differently */ + if (!strncmp(source->url, "imap:", 5)) + info->type = SEND_UPDATE; + else + info->type = SEND_RECEIVE; printf("adding source %s\n", source->url); label = (GtkLabel *)gtk_label_new(source->url); bar = (GtkProgressBar *)gtk_progress_bar_new(); stop = (GtkButton *)gnome_stock_button(GNOME_STOCK_BUTTON_CANCEL); - gtk_progress_set_format_string((GtkProgress *)bar, _("Waiting ...")); gtk_progress_set_show_text((GtkProgress *)bar, TRUE); + if (info->type == SEND_UPDATE) { + gtk_progress_set_format_string((GtkProgress *)bar, _("Updating ...")); + } else { + gtk_progress_set_format_string((GtkProgress *)bar, _("Waiting ...")); + } gtk_table_attach(table, (GtkWidget *)label, 0, 1, row, row+1, GTK_EXPAND|GTK_FILL, 0, 3, 1); gtk_table_attach(table, (GtkWidget *)bar, 1, 2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 3, 1); @@ -402,6 +857,7 @@ static struct _send_data *build_dialogue(GSList *sources) info->cancel = camel_cancel_new(); info->stop = stop; info->data = data; + info->state = SEND_ACTIVE; data->active++; list = g_list_prepend(list, info); @@ -412,6 +868,44 @@ static struct _send_data *build_dialogue(GSList *sources) } gtk_widget_show_all((GtkWidget *)table); + + if (outbox) { + frame= (GtkFrame *)gtk_frame_new(_("Sending")); + gtk_box_pack_start((GtkBox *)gd->vbox, (GtkWidget *)frame, TRUE, TRUE, 0); + table = (GtkTable *)gtk_table_new(1, 3, FALSE); + gtk_container_add((GtkContainer *)frame, (GtkWidget *)table); + gtk_widget_show((GtkWidget *)frame); + + info = g_malloc0(sizeof(*info)); + info->type = SEND_SEND; + printf("adding dest %s\n", destination); + + label = (GtkLabel *)gtk_label_new(destination); + bar = (GtkProgressBar *)gtk_progress_bar_new(); + stop = (GtkButton *)gnome_stock_button(GNOME_STOCK_BUTTON_CANCEL); + + gtk_progress_set_format_string((GtkProgress *)bar, _("Waiting ...")); + gtk_progress_set_show_text((GtkProgress *)bar, TRUE); + + gtk_table_attach(table, (GtkWidget *)label, 0, 1, row, row+1, GTK_EXPAND|GTK_FILL, 0, 3, 1); + gtk_table_attach(table, (GtkWidget *)bar, 1, 2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 3, 1); + gtk_table_attach(table, (GtkWidget *)stop, 2, 3, row, row+1, GTK_EXPAND|GTK_FILL, 0, 3, 1); + + info->bar = bar; + info->uri = g_strdup(destination); + info->keep = FALSE; + info->cancel = camel_cancel_new(); + info->stop = stop; + info->data = data; + info->state = SEND_ACTIVE; + data->active++; + + list = g_list_prepend(list, info); + + gtk_signal_connect((GtkObject *)stop, "clicked", receive_cancel, info); + gtk_widget_show_all((GtkWidget *)table); + } + gtk_widget_show((GtkWidget *)gd); gtk_signal_connect((GtkObject *)gd, "clicked", dialogue_clicked, data); @@ -516,15 +1010,22 @@ receive_status (CamelFilterDriver *driver, enum camel_filter_status_t status, in } } +/* when receive/send is complete */ static void receive_done (char *uri, void *data) { struct _send_info *info = data; - if (info->cancelled) + gtk_progress_set_percentage((GtkProgress *)info->bar, (gfloat)1.0); + + switch(info->state) { + case SEND_CANCELLED: gtk_progress_set_format_string((GtkProgress *)info->bar, _("Cancelled.")); - else + break; + default: + info->state = SEND_COMPLETE; gtk_progress_set_format_string((GtkProgress *)info->bar, _("Complete.")); + } gtk_widget_set_sensitive((GtkWidget *)info->stop, FALSE); @@ -535,15 +1036,21 @@ receive_done (char *uri, void *data) } } +/* same for updating */ +static void +receive_update_done(CamelStore *store, void *data) +{ + receive_done("", data); +} + /* although we dont do anythign smart here yet, there is no need for this interface to be available to anyone else. This can also be used to hook into which folders are being updated, and occasionally let them refresh */ static CamelFolder * -receive_get_folder(CamelFilterDriver *d, const char *uri, void *data) +receive_get_folder(CamelFilterDriver *d, const char *uri, void *data, CamelException *ex) { struct _send_info *info = data; - CamelFolder *mail_tool_uri_to_folder_noex (const char *uri); CamelFolder *folder; struct _folder_info *oldinfo; char *oldkey; @@ -555,7 +1062,10 @@ receive_get_folder(CamelFilterDriver *d, const char *uri, void *data) camel_object_ref((CamelObject *)folder); return folder; } - folder = mail_tool_uri_to_folder_noex(uri); + folder = mail_tool_uri_to_folder(uri, ex); + if (!folder) + return NULL; + /* we recheck that the folder hasn't snuck in while we were loading it ... */ /* and we assume the newer one is the same, but unref the old one anyway */ g_mutex_lock(info->data->lock); @@ -573,32 +1083,84 @@ receive_get_folder(CamelFilterDriver *d, const char *uri, void *data) return folder; } -void mail_receive(void) +void mail_send_receive(void) { GSList *sources; GList *scan; FilterContext *fc; struct _send_data *data; + extern CamelFolder *outbox_folder; + const MailConfigAccount *account; + CamelStore *store; + CamelException *ex; - sources = mail_config_get_sources (); + sources = mail_config_get_sources(); if (!sources) return; + account = mail_config_get_default_account(); + if (!account || !account->transport) + return; fc = load_context(); - data = build_dialogue(sources); + /* what to do about pop before smtp ? + Well, probably hook into receive_done or receive_status on + the right pop account, and when it is, then kick off the + smtp one. */ + data = build_dialogue(sources, outbox_folder, account->transport->url); scan = data->infos; while (scan) { struct _send_info *info = scan->data; - mail_filter_mail(info->uri, info->keep, - fc, FILTER_SOURCE_INCOMING, - info->cancel, - receive_get_folder, info, - receive_status, info, - receive_done, info); + + switch(info->type) { + case SEND_RECEIVE: + mail_fetch_mail(info->uri, info->keep, + fc, FILTER_SOURCE_INCOMING, + info->cancel, + receive_get_folder, info, + receive_status, info, + receive_done, info); + break; + case SEND_SEND: + /* todo, store the folder in info? */ + mail_send_queue(outbox_folder, info->uri, + fc, FILTER_SOURCE_OUTGOING, + info->cancel, + receive_get_folder, info, + receive_status, info, + receive_done, info); + break; + case SEND_UPDATE: + /* FIXME: error reporting? */ + ex = camel_exception_new(); + store = camel_session_get_store(session, info->uri, ex); + if (store) { + EvolutionStorage *storage = mail_lookup_storage(store); + if (storage) { + mail_update_subfolders(store, storage, receive_update_done, info); + gtk_object_unref((GtkObject *)storage); + } else { + receive_done("", info); + } + camel_object_unref((CamelObject *)store); + } else { + receive_done("", info); + } + camel_exception_free(ex); + break; + } scan = scan->next; } gtk_object_unref((GtkObject *)fc); } +void mail_filter_on_demand(CamelFolder *folder, GPtrArray *uids) +{ + FilterContext *fc; + + fc = load_context(); + mail_filter_folder(folder, uids, fc, FILTER_SOURCE_INCOMING, NULL); + gtk_object_unref((GtkObject *)fc); +} + -- cgit