aboutsummaryrefslogtreecommitdiffstats
path: root/mail
diff options
context:
space:
mode:
Diffstat (limited to 'mail')
-rw-r--r--mail/ChangeLog6
-rw-r--r--mail/Makefile.am1
-rw-r--r--mail/folder-browser-factory.c6
-rw-r--r--mail/mail-send-recv.c604
4 files changed, 617 insertions, 0 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog
index 37bf886b41..6bb1be5091 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,3 +1,9 @@
+2001-01-19 Not Zed <NotZed@Ximian.com>
+
+ * mail-send-recv.c: New swanky send/recieve thingy, well it so far
+ only receives (pop/mbox). Ignore all the warnings for now, and
+ the ugly 'button' to run it.
+
2001-01-18 Jeffrey Stedfast <fejj@ximian.com>
* folder-browser-factory.c: Added the next/previous toolbar
diff --git a/mail/Makefile.am b/mail/Makefile.am
index af0fb7a073..75409686fd 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -77,6 +77,7 @@ evolution_mail_SOURCES = \
mail-ops.h \
mail-search-dialogue.c \
mail-search-dialogue.h \
+ mail-send-recv.c \
mail-summary.c \
mail-summary.h \
mail-threads.c \
diff --git a/mail/folder-browser-factory.c b/mail/folder-browser-factory.c
index 13b62080bd..e924ca0256 100644
--- a/mail/folder-browser-factory.c
+++ b/mail/folder-browser-factory.c
@@ -33,6 +33,9 @@
/* The FolderBrowser BonoboControls we have. */
static EList *control_list = NULL;
+/* this is temporary, remove later -Z */
+void mail_receive(void);
+
/*
* Add with 'folder_browser'
*/
@@ -97,6 +100,9 @@ BonoboUIVerb verbs [] = {
BONOBO_UI_UNSAFE_VERB ("MailPrevious", previous_msg),
BONOBO_UI_UNSAFE_VERB ("MailNext", next_msg),
+ /* This is just very temporary - !Z */
+ BONOBO_UI_UNSAFE_VERB ("MailGetNew", mail_receive),
+
BONOBO_UI_VERB_END
};
diff --git a/mail/mail-send-recv.c b/mail/mail-send-recv.c
new file mode 100644
index 0000000000..ee080f8dd2
--- /dev/null
+++ b/mail/mail-send-recv.c
@@ -0,0 +1,604 @@
+
+#include <stdio.h>
+#include <string.h>
+
+#include "filter/filter-context.h"
+#include "filter/filter-filter.h"
+#include "camel/camel-filter-driver.h"
+#include "camel/camel-folder.h"
+#include "camel/camel-session.h"
+#include "camel/camel-uid-cache.h"
+
+#include "mail-mt.h"
+#include "mail-config.h"
+
+/* for the dialogue stuff */
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <libgnomeui/gnome-stock.h>
+#include <libgnomeui/gnome-dialog.h>
+
+/* send/receive email */
+
+extern char *evolution_dir;
+extern CamelFolder *mail_tool_filter_get_folder_func (CamelFilterDriver *d, const char *uri, void *data);
+
+static FilterContext *
+load_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
+setup_filter_driver(CamelFilterDriver *driver, FilterContext *fc, const char *source)
+{
+ GString *fsearch, *faction;
+ FilterFilter *rule = NULL;
+
+ if (TRUE /* perform_logging */) {
+ char *filename = g_strdup_printf("%s/evolution-filter-log", evolution_dir);
+ FILE *logfile = fopen(filename, "a+");
+ g_free(filename);
+ if (logfile)
+ camel_filter_driver_set_logfile(driver, logfile);
+ }
+
+ 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);
+}
+
+/* used for both just filtering a folder + uid's, and for filtering a whole folder */
+struct _fetch_mail_msg {
+ struct _mail_msg msg;
+
+ char *source_uri;
+ CamelFolder *source_folder;
+ GPtrArray *source_uids;
+ CamelCancel *cancel;
+ CamelFolder *destination;
+ CamelFilterDriver *driver;
+ int keep;
+
+ void (*done)(char *source, void *data);
+ void *data;
+};
+
+/* filter a folder, or a subset thereof, uses source_folder/source_uids */
+static void
+fetch_mail_filter_folder(struct _mail_msg *mm)
+{
+ struct _fetch_mail_msg *m = (struct _fetch_mail_msg *)mm;
+ CamelFolder *folder;
+ CamelUIDCache *cache = NULL;
+ GPtrArray *uids, *folder_uids = NULL, *cache_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 (folder == NULL || camel_folder_get_message_count (folder) == 0) {
+ return;
+ }
+
+ camel_folder_freeze(folder);
+
+ if (m->source_uids)
+ uids = m->source_uids;
+ else
+ 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);
+ }
+
+ 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);
+}
+
+static void
+fetch_mail_fetch(struct _mail_msg *mm)
+{
+ struct _fetch_mail_msg *m = (struct _fetch_mail_msg *)mm;
+
+ 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;
+ }
+ }
+
+ 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);
+
+ /* ok? zap the output file */
+ if (!camel_exception_is_set (&mm->ex)) {
+ unlink (path);
+ }
+ }
+ g_free (path);
+ } else {
+ fetch_mail_filter_folder(mm);
+ }
+
+ camel_folder_thaw (m->destination);
+
+ if (m->cancel)
+ camel_cancel_unregister(m->cancel);
+}
+
+static void
+fetch_mail_fetched(struct _mail_msg *mm)
+{
+ struct _fetch_mail_msg *m = (struct _fetch_mail_msg *)mm;
+
+ if (m->done)
+ m->done(m->source_uri, m->data);
+}
+
+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;i<m->source_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);
+}
+
+static struct _mail_msg_op fetch_mail_op = {
+ NULL, /* we do our own progress reporting */
+ fetch_mail_fetch,
+ fetch_mail_fetched,
+ fetch_mail_free,
+};
+
+/* 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)
+{
+ struct _fetch_mail_msg *m;
+
+ m = mail_msg_new(&fetch_mail_op, NULL, sizeof(*m));
+ m->source_uri = g_strdup(source);
+ m->keep = keep;
+ m->cancel = cancel;
+ camel_cancel_ref(cancel);
+ 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 */
+struct _folder_info {
+ char *uri;
+ CamelFolder *folder;
+ time_t update;
+ int count; /* how many times updated, to slow it down as we go, if we have lots */
+};
+
+struct _send_data {
+ GList *infos;
+
+ int active; /* how many still active */
+
+ GnomeDialog *gd;
+ int cancelled;
+
+ CamelFolder *inbox; /* since w'ere never asked to uypdate this one, do it ourselves */
+ time_t inbox_update;
+
+ GMutex *lock;
+ GHashTable *folders;
+};
+
+struct _send_info {
+ CamelCancel *cancel;
+ char *uri;
+ int keep;
+ int cancelled;
+ GtkProgressBar *bar;
+ GtkButton *stop;
+ time_t update;
+ struct _send_data *data;
+};
+
+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;
+ gtk_widget_set_sensitive((GtkWidget *)info->stop, FALSE);
+}
+
+static void
+free_folder_info(void *key, struct _folder_info *info, void *data)
+{
+ camel_object_unref((CamelObject *)info->folder);
+ g_free(info->uri);
+}
+
+static void
+free_info_data(void *datain)
+{
+ struct _send_data *data = datain;
+ GList *list = data->infos;
+
+ while (list) {
+ struct _send_info *info = list->data;
+ g_free(info->uri);
+ camel_cancel_unref(info->cancel);
+ list = list->next;
+ }
+
+ g_list_free(data->infos);
+ g_hash_table_foreach(data->folders, (GHFunc)free_folder_info, NULL);
+ g_hash_table_destroy(data->folders);
+ g_mutex_free(data->lock);
+ if (data->inbox)
+ camel_object_unref((CamelObject *)data->inbox);
+ g_free(data);
+}
+
+static void
+dialogue_clicked(GnomeDialog *gd, int button, struct _send_data *data)
+{
+ GList *scan;
+
+ switch(button) {
+ case 0: /* ok */
+ gnome_dialog_close(gd);
+ break;
+ case 1:
+ printf("cancelled whole thing\n");
+ if (!data->cancelled) {
+ data->cancelled = TRUE;
+ scan = data->infos;
+ while (scan) {
+ struct _send_info *info = scan->data;
+ receive_cancel(info->stop, info);
+ scan = scan->next;
+ }
+ }
+ gnome_dialog_set_sensitive(gd, 1, FALSE);
+ break;
+ }
+}
+
+static struct _send_data *build_dialogue(GSList *sources)
+{
+ GnomeDialog *gd;
+ GtkFrame *frame;
+ GtkTable *table;
+ int row;
+ GList *list = NULL;
+ struct _send_data *data;
+
+ data = g_malloc0(sizeof(*data));
+ data->lock = g_mutex_new();
+ data->folders = g_hash_table_new(g_str_hash, g_str_equal);
+ data->inbox = mail_tool_get_local_inbox(NULL);
+
+ 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"));
+ 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);
+ gtk_widget_show((GtkWidget *)frame);
+
+ 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));
+ 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);
+
+ 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(source->url);
+ info->keep = source->keep_on_server;
+ info->cancel = camel_cancel_new();
+ info->stop = stop;
+ info->data = data;
+ data->active++;
+
+ list = g_list_prepend(list, info);
+
+ gtk_signal_connect((GtkObject *)stop, "clicked", receive_cancel, info);
+ sources = sources->next;
+ row++;
+ }
+
+ gtk_widget_show_all((GtkWidget *)table);
+ gtk_widget_show((GtkWidget *)gd);
+
+ gtk_signal_connect((GtkObject *)gd, "clicked", dialogue_clicked, data);
+
+ data->infos = list;
+ data->gd = gd;
+ gtk_object_set_data_full((GtkObject *)gd, "info_data", data, free_info_data);
+
+ return data;
+}
+
+static void
+update_folders(char *uri, struct _folder_info *info, void *data)
+{
+ time_t now = *((time_t *)data);
+
+ printf("checking update for folder: %s\n", info->uri);
+
+ /* let it flow through to the folders every 10 seconds */
+ /* we back off slowly as we progress */
+ if (now > info->update+10+info->count*5) {
+ printf("upating a folder: %s\n", info->uri);
+ camel_folder_thaw(info->folder);
+ camel_folder_freeze(info->folder);
+ info->update = now;
+ info->count++;
+ }
+}
+
+/* for forwarding stuff to the gui thread */
+struct _status_msg {
+ struct _mail_msg msg;
+ char *desc;
+ int pc;
+ struct _send_info *info;
+};
+
+static void
+do_show_status(struct _mail_msg *mm)
+{
+ struct _status_msg *m = (struct _status_msg *)mm;
+
+ gtk_progress_set_percentage((GtkProgress *)m->info->bar, (gfloat)(m->pc/100.0));
+ gtk_progress_set_format_string((GtkProgress *)m->info->bar, m->desc);
+}
+
+static void
+do_free_status(struct _mail_msg *mm)
+{
+ struct _status_msg *m = (struct _status_msg *)mm;
+
+ g_free(m->desc);
+}
+
+struct _mail_msg_op status_op = {
+ NULL,
+ do_show_status,
+ NULL,
+ do_free_status,
+};
+
+static void
+receive_status (CamelFilterDriver *driver, enum camel_filter_status_t status, int pc, const char *desc, void *data)
+{
+ struct _send_info *info = data;
+ time_t now;
+ struct _status_msg *m;
+
+ /* only update every second */
+ now = time(0);
+ if (now <= info->update)
+ return;
+
+ info->update = now;
+
+ /* let it flow through to the folder, every now and then too? */
+ g_hash_table_foreach(info->data->folders, (GHFunc)update_folders, &now);
+
+ if (info->data->inbox && now > info->data->inbox_update+20) {
+ printf("updating inbox too\n");
+ /* this doesn't seem to work right :( */
+ camel_folder_thaw(info->data->inbox);
+ camel_folder_freeze(info->data->inbox);
+ info->data->inbox_update = now;
+ }
+
+ /* we just pile them onto the port, assuming it can handle it.
+ We could also have a receiver port and see if they've been processed
+ yet, so if this is necessary its not too hard to add */
+ /* the mail_gui_port receiver will free everything for us */
+ switch (status) {
+ case FILTER_STATUS_START:
+ case FILTER_STATUS_END:
+ m = mail_msg_new(&status_op, NULL, sizeof(*m));
+ m->desc = g_strdup(desc);
+ m->pc = pc;
+ m->info = info;
+ e_msgport_put(mail_gui_port, (EMsg *)m);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+receive_done (char *uri, void *data)
+{
+ struct _send_info *info = data;
+
+ if (info->cancelled)
+ gtk_progress_set_format_string((GtkProgress *)info->bar, _("Cancelled."));
+ else
+ gtk_progress_set_format_string((GtkProgress *)info->bar, _("Complete."));
+
+ gtk_widget_set_sensitive((GtkWidget *)info->stop, FALSE);
+
+ info->data->active--;
+ if (info->data->active == 0) {
+ gnome_dialog_set_sensitive(info->data->gd, 0, TRUE);
+ gnome_dialog_set_sensitive(info->data->gd, 1, FALSE);
+ }
+}
+
+/* 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)
+{
+ struct _send_info *info = data;
+ CamelFolder *mail_tool_uri_to_folder_noex (const char *uri);
+ CamelFolder *folder;
+ struct _folder_info *oldinfo;
+ char *oldkey;
+
+ g_mutex_lock(info->data->lock);
+ folder = g_hash_table_lookup(info->data->folders, uri);
+ g_mutex_unlock(info->data->lock);
+ if (folder) {
+ camel_object_ref((CamelObject *)folder);
+ return folder;
+ }
+ folder = mail_tool_uri_to_folder_noex(uri);
+ /* 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);
+ if (g_hash_table_lookup_extended(info->data->folders, uri, (void **)&oldkey, (void **)&oldinfo)) {
+ camel_object_unref((CamelObject *)oldinfo->folder);
+ oldinfo->folder = folder;
+ } else {
+ oldinfo = g_malloc0(sizeof(*oldinfo));
+ oldinfo->folder = folder;
+ oldinfo->uri = g_strdup(uri);
+ g_hash_table_insert(info->data->folders, oldinfo->uri, oldinfo);
+ }
+ g_mutex_unlock(info->data->lock);
+
+ return folder;
+}
+
+void mail_receive(void)
+{
+ GSList *sources;
+ GList *scan;
+ FilterContext *fc;
+ struct _send_data *data;
+
+ sources = mail_config_get_sources ();
+ if (!sources)
+ return;
+
+ fc = load_context();
+
+ data = build_dialogue(sources);
+ 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);
+ scan = scan->next;
+ }
+
+ gtk_object_unref((GtkObject *)fc);
+}
+