diff options
Diffstat (limited to 'mail/mail-local.c')
-rw-r--r-- | mail/mail-local.c | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/mail/mail-local.c b/mail/mail-local.c new file mode 100644 index 0000000000..b326a15cac --- /dev/null +++ b/mail/mail-local.c @@ -0,0 +1,413 @@ + +/* + code for handling local mail boxes +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <bonobo.h> +#include <gnome.h> +#include <glade/glade.h> + +#include "Evolution.h" +#include "evolution-storage.h" + +#include "evolution-shell-component.h" +#include "folder-browser.h" + +#include "camel/camel.h" + +#include "filter/vfolder-context.h" +#include "filter/vfolder-rule.h" +#include "filter/vfolder-editor.h" + +#include "mail.h" +#include "mail-local.h" + +#define d(x) + +struct _local_meta { + char *path; /* path of metainfo file */ + + char *format; /* format of mailbox */ + char *name; /* name of mbox itself */ +}; + +static struct _local_meta * +load_metainfo(const char *path) +{ + xmlDocPtr doc; + xmlNodePtr node; + struct _local_meta *meta; + + meta = g_malloc0(sizeof(*meta)); + meta->path = g_strdup(path); + + printf("Loading folder metainfo from : %s\n", meta->path); + + doc = xmlParseFile(meta->path); + if (doc == NULL) { + goto dodefault; + } + node = doc->root; + if (strcmp(node->name, "folderinfo")) { + goto dodefault; + } + node = node->childs; + while (node) { + if (!strcmp(node->name, "folder")) { + meta->format = xmlGetProp(node, "type"); + meta->name = xmlGetProp(node, "name"); + } + node = node->next; + } + xmlFreeDoc(doc); + return meta; + +dodefault: + meta->format = g_strdup("mbox"); /* defaults */ + meta->name = g_strdup("mbox"); + if (doc) + xmlFreeDoc(doc); + return meta; +} + +static void +free_metainfo(struct _local_meta *meta) +{ + g_free(meta->path); + g_free(meta->format); + g_free(meta->name); + g_free(meta); +} + +static int +save_metainfo(struct _local_meta *meta) +{ + xmlDocPtr doc; + xmlNodePtr root, node; + int ret; + + printf("Saving folder metainfo to : %s\n", meta->path); + + doc = xmlNewDoc("1.0"); + root = xmlNewDocNode(doc, NULL, "folderinfo", NULL); + xmlDocSetRootElement(doc, root); + + node = xmlNewChild(root, NULL, "folder", NULL); + xmlSetProp(node, "type", meta->format); + xmlSetProp(node, "name", meta->name); + + ret = xmlSaveFile(meta->path, doc); + xmlFreeDoc(doc); + return ret; +} + +CamelFolder * +local_uri_to_folder(const char *uri, CamelException *ex) +{ + CamelURL *url; + char *metapath; + char *storename; + CamelStore *store; + CamelFolder *folder = NULL; + struct _local_meta *meta; + + if (strncmp(uri, "file:", 5)) { + return NULL; + } + + printf("opening local folder %s\n", uri); + + /* get the actual location of the mailbox */ + url = camel_url_new(uri, ex); + if (camel_exception_is_set(ex)) { + return NULL; + } + + metapath = g_strdup_printf("%s/local-metadata.xml", url->path); + meta = load_metainfo(metapath); + g_free(metapath); + + /* change file: to format: */ + camel_url_set_protocol(url, meta->format); + storename = camel_url_to_string(url, TRUE); + + printf("store name is %s\n", storename); + + store = camel_session_get_store(session, storename, ex); + g_free(storename); + if (store) { + folder = camel_store_get_folder(store, meta->name, FALSE, ex); + gtk_object_unref((GtkObject *)store); + } + camel_url_free(url); + free_metainfo(meta); + + return folder; +} + +/* + open new + copy old->new + close old + rename old oldsave + rename new old + open oldsave + delete oldsave + + close old + rename oldtmp + open new + open oldtmp + copy oldtmp new + close oldtmp + close oldnew + +*/ + +static void update_progress(GtkProgress *progress, char *fmt, float percent) +{ + if (fmt) + gtk_progress_set_format_string(progress, fmt); + gtk_progress_set_percentage(progress, percent); + while( gtk_events_pending() ) + gtk_main_iteration(); +} + +static void +do_local_reconfigure_folder(FolderBrowser *fb, char *newtype, GtkProgress *progress, CamelException *ex) +{ + CamelStore *fromstore, *tostore; + char *fromurl, *tourl, *uri; + CamelFolder *fromfolder, *tofolder; + GPtrArray *uids; + int i; + char *metapath; + char *tmpname; + CamelURL *url; + struct _local_meta *meta; + + printf("reconfiguring folder: %s to type %s\n", fb->uri, newtype); + + /* get the actual location of the mailbox */ + url = camel_url_new(fb->uri, ex); + if (url == NULL || camel_exception_is_set(ex)) { + camel_exception_free(ex); + g_warning("%s is not a workable url!", fb->uri); + return; + } + + metapath = g_strdup_printf("%s/local-metadata.xml", url->path); + meta = load_metainfo(metapath); + g_free(metapath); + + /* first, 'close' the old folder */ + if (fb->folder != NULL) { + update_progress(progress, "Closing current folder", 0.0); + printf("Closing old folder ...\n"); + camel_folder_sync(fb->folder, FALSE, ex); + gtk_object_unref (GTK_OBJECT (fb->folder)); + fb->folder = NULL; + } + + camel_url_set_protocol(url, meta->format); + fromurl = camel_url_to_string(url, TRUE); + camel_url_set_protocol(url, newtype); + tourl = camel_url_to_string(url, TRUE); + + printf("opening stores %s and %s\n", fromurl, tourl); + fromstore = camel_session_get_store(session, fromurl, ex); + if (camel_exception_is_set(ex)) { + return; + } + tostore = camel_session_get_store(session, tourl, ex); + if (camel_exception_is_set(ex)) { + return; + } + + /* rename the old mbox and open it again */ + tmpname = g_strdup_printf("%s_reconfig", meta->name); + printf("renaming mbox to mboxtmp, and opening it\n"); + update_progress(progress, "Renaming old folder and opening", 0.0); + camel_store_rename_folder(fromstore, meta->name, tmpname, ex); + if (camel_exception_is_set(ex)) { + return; + } + fromfolder = camel_store_get_folder(fromstore, tmpname, TRUE, ex); + if (fromfolder == NULL || camel_exception_is_set(ex)) { + /* try and recover ... */ + camel_store_rename_folder(fromstore, tmpname, meta->name, ex); + return; + } + + /* create a new mbox */ + printf("Creating the destination mbox\n"); + update_progress(progress, "Creating new folder", 0.0); + tofolder = camel_store_get_folder(tostore, meta->name, TRUE, ex); + if (tofolder == NULL || camel_exception_is_set(ex)) { + printf("cannot open destination folder\n"); + /* try and recover ... */ + camel_store_rename_folder(fromstore, tmpname, meta->name, ex); + return; + } + + /* copy the messages across */ + uids = camel_folder_get_uids (fromfolder); + printf("got %d messages in source\n", uids->len); + update_progress(progress, "Copying messages", 0.0); + for (i = 0; i < uids->len; i++) { + CamelMimeMessage *msg; + char *uid = uids->pdata[i]; + + update_progress(progress, NULL, i/uids->len); + + printf("copying message %s\n", uid); + msg = camel_folder_get_message(fromfolder, uid, ex); + if (camel_exception_is_set(ex)) { + /* we're fucked a bit ... */ + /* need to: delete new folder + rename old back again */ + g_warning("cannot get message"); + return; + } + camel_folder_append_message(tofolder, msg, + camel_folder_get_message_flags(fromfolder, uid), + ex); + if (camel_exception_is_set(ex)) { + /* we're fucked a bit ... */ + /* need to: delete new folder + rename old back again */ + g_warning("cannot append message"); + return; + } + gtk_object_unref((GtkObject *)msg); +#warning "because flags were removed from the message" +#warning "we can't keep them when converting mail storage format" + } + update_progress(progress, "Synchronising", 0.0); + + /* sync while we're doing i/o, just to make sure */ + camel_folder_sync(tofolder, FALSE, ex); + if (camel_exception_is_set(ex)) { + /* same again */ + } + + /* delete everything in the old mailbox */ + printf("deleting old mbox contents\n"); + for (i = 0; i < uids->len; i++) { + char *uid = uids->pdata[i]; + camel_folder_delete_message(fromfolder, uid); + } + camel_folder_sync(fromfolder, TRUE, ex); + gtk_object_unref((GtkObject *)fromfolder); + printf("and old mbox ...\n"); + camel_store_delete_folder(fromstore, tmpname, ex); + + /* switch format */ + g_free(meta->format); + meta->format = g_strdup(newtype); + if (save_metainfo(meta) == -1) { + g_warning("Cannot save folder metainfo, you'll probably find you can't\n" + "open this folder anymore: %s", tourl); + } + free_metainfo(meta); + + /* force a reload of the newly formatted folder */ + printf("opening new source\n"); + uri = g_strdup(fb->uri); + folder_browser_set_uri(fb, uri); + g_free(uri); + + /* and unref our copy of the new folder ... */ + gtk_object_unref((GtkObject *)tofolder); + g_free(fromurl); + g_free(tourl); +} + +struct _reconfig_data { + FolderBrowser *fb; + GtkProgress *progress; + GtkWidget *frame; + GtkWidget *apply; + GtkWidget *cancel; + GtkOptionMenu *optionlist; +}; + +static void +reconfigure_clicked(GnomeDialog *d, int button, struct _reconfig_data *data) +{ + if (button == 0) { + GtkMenu *menu; + int type; + char *types[] = { "mh", "mbox" }; + CamelException *ex; + + ex = camel_exception_new(); + + menu = (GtkMenu *)gtk_option_menu_get_menu(data->optionlist); + type = g_list_index(GTK_MENU_SHELL(menu)->children, gtk_menu_get_active(menu)); + if (type < 0 || type > 1) + type = 1; + + gtk_progress_set_percentage(data->progress, 0.0); + gtk_widget_set_sensitive(data->frame, FALSE); + gtk_widget_set_sensitive(data->apply, FALSE); + gtk_widget_set_sensitive(data->cancel, FALSE); + + do_local_reconfigure_folder(data->fb, types[type], data->progress, ex); + if (camel_exception_is_set(ex)) { + GtkWidget *win = gtk_widget_get_ancestor((GtkWidget *)d, GTK_TYPE_WINDOW); + char *error; + + error = g_strdup_printf("A failure occured:\n %s\n\n" + "If you can no longer open this mailbox, then\n" + "you may need to repair it manually.", + camel_exception_get_description(ex)); + gnome_error_dialog_parented(error, GTK_WINDOW (win)); + g_free(error); + } + camel_exception_free(ex); + } + if (button != -1) { + gnome_dialog_close(d); + } +} + +void +local_reconfigure_folder(FolderBrowser *fb) +{ + CamelStore *store; + GladeXML *gui; + GnomeDialog *gd; + struct _reconfig_data *data; + + if (fb->folder == NULL) { + g_warning("Trying to reconfigure nonexistant folder"); + return; + } + + data = g_malloc0(sizeof(*data)); + + store = camel_folder_get_parent_store(fb->folder); + + gui = glade_xml_new(EVOLUTION_GLADEDIR "/local-config.glade", "dialog_format"); + gd = (GnomeDialog *)glade_xml_get_widget (gui, "dialog_format"); + + data->progress = (GtkProgress *)glade_xml_get_widget (gui, "progress_format"); + gtk_progress_set_show_text(data->progress, TRUE); + data->frame = glade_xml_get_widget (gui, "frame_format"); + data->apply = glade_xml_get_widget (gui, "apply_format"); + data->cancel = glade_xml_get_widget (gui, "cancel_format"); + data->optionlist = (GtkOptionMenu *)glade_xml_get_widget (gui, "option_format"); + data->fb = fb; + + gtk_label_set_text((GtkLabel *)glade_xml_get_widget (gui, "label_format"), + ((CamelService *)store)->url->protocol); + + gtk_signal_connect((GtkObject *)gd, "clicked", reconfigure_clicked, data); + gtk_object_set_data_full((GtkObject *)gd, "data", data, g_free); + gtk_widget_show((GtkWidget *)gd); + gtk_object_unref((GtkObject *)gui); +} |