diff options
-rw-r--r-- | mail/ChangeLog | 20 | ||||
-rw-r--r-- | mail/folder-browser.c | 108 | ||||
-rw-r--r-- | mail/mail-vfolder.c | 152 | ||||
-rw-r--r-- | mail/mail-vfolder.h | 22 | ||||
-rw-r--r-- | mail/message-thread.c | 5 |
5 files changed, 265 insertions, 42 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index 637f43efc2..9619a906fa 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,23 @@ +2000-07-31 Not Zed <NotZed@HelixCode.com> + + * mail-vfolder.h: Header for vfolder functions. + + * folder-browser.c (mail_uri_to_folder): Use new scheme to open + vfolders. + (search_save): New button/function to save a search as a vfolder. + + * mail-vfolder.c (vfolder_edit): Made asynchronous. + (vfolder_uri_to_folder): New function for loading vfolders and + setting up their source folders. + (vfolder_refresh): Change shell vfolder uri's to indirect + references rather than the real vfolder uri. + (vfolder_gui_add_rule): Add a rule with user confirmation. + (vfolder_create_part): Get a new part by name, for creating rules + in code. + + * message-thread.c (thread_messages): Check for uid lookup + failure, which indicates an error in the folder or calling code. + 2000-07-29 Not Zed <NotZed@HelixCode.com> * component-factory.c (create_view): Remove hack to pass the diff --git a/mail/folder-browser.c b/mail/folder-browser.c index 9268c65df8..6768f0318f 100644 --- a/mail/folder-browser.c +++ b/mail/folder-browser.c @@ -17,6 +17,12 @@ #include "message-list.h" #include <widgets/e-paned/e-vpaned.h> +#include "mail-vfolder.h" +#include "filter/vfolder-rule.h" +#include "filter/vfolder-context.h" +#include "filter/filter-option.h" +#include "filter/filter-input.h" + #define PARENT_TYPE (gtk_table_get_type ()) static GtkObjectClass *folder_browser_parent_class; @@ -68,37 +74,7 @@ mail_uri_to_folder (const char *name) ex = camel_exception_new (); if (!strncmp (name, "vfolder:", 8)) { - char *query, *newquery; - store_name = g_strdup (name); - query = strchr (store_name, '?'); - if (query) { - *query++ = 0; - } else { - query = ""; - } - newquery = g_strdup_printf("mbox?%s", query); - store = camel_session_get_store (session, store_name, ex); - - if (store) { - folder = camel_store_get_folder (store, newquery, TRUE, ex); - /* FIXME: do this properly rather than hardcoding */ -#warning "Find a way not to hardcode vfolder source" - { - char *source_name; - CamelFolder *source_folder; - extern char *evolution_dir; - - source_name = g_strdup_printf ("file://%s/local/Inbox", evolution_dir); - source_folder = mail_uri_to_folder (source_name); - g_free (source_name); -#warning "Not Good (tm). It might be better to have some sort of high level Camel interface for this" - if (source_folder) - camel_vee_folder_add_folder (folder, source_folder); - } - } - g_free (newquery); - g_free (store_name); - + folder = vfolder_uri_to_folder(name); } else if (!strncmp (name, "imap:", 5)) { char *service, *ptr; @@ -227,6 +203,7 @@ static char * search_options[] = { NULL }; +/* NOTE: If this is changed, then change the search_save() function to match! */ /* %s is replaced by the whole search string in quotes ... possibly could split the search string into words as well ? */ static char * search_string[] = { @@ -315,6 +292,70 @@ search_activate(GtkEntry *entry, FolderBrowser *fb) search_set(fb); } +static void +search_save(GtkWidget *w, FolderBrowser *fb) +{ + GtkWidget *widget; + int index; + char *text; + FilterElement *element; + VfolderRule *rule; + FilterPart *part; + + text = gtk_entry_get_text((GtkEntry *)fb->search_entry); + + if (text == NULL || text[0] == 0) { + return; + } + + widget = gtk_menu_get_active (GTK_MENU(GTK_OPTION_MENU(fb->search_menu)->menu)); + index = (int)gtk_object_get_data((GtkObject *)widget, "search_option"); + rule = vfolder_rule_new(); + ((FilterRule *)rule)->grouping = FILTER_GROUP_ANY; + vfolder_rule_add_source(rule, fb->uri); + filter_rule_set_name((FilterRule *)rule, text); + switch(index) { + default: /* header or body contains */ + index = 0; + case 1: case 2: + if (index == 0 || index == 1) { /* body-contains */ + part = vfolder_create_part("body"); + filter_rule_add_part((FilterRule *)rule, part); + element = filter_part_find_element(part, "body-type"); + filter_option_set_current((FilterOption *)element, "contains"); + element = filter_part_find_element(part, "word"); + filter_input_set_value((FilterInput *)element, text); + } + if (index == 0 || index == 2) { /* subject contains */ + part = vfolder_create_part("subject"); + filter_rule_add_part((FilterRule *)rule, part); + element = filter_part_find_element(part, "subject-type"); + filter_option_set_current((FilterOption *)element, "contains"); + element = filter_part_find_element(part, "subject"); + filter_input_set_value((FilterInput *)element, text); + } + break; + case 3: /* not body contains */ + part = vfolder_create_part("body"); + filter_rule_add_part((FilterRule *)rule, part); + element = filter_part_find_element(part, "body-type"); + filter_option_set_current((FilterOption *)element, "not contains"); + element = filter_part_find_element(part, "word"); + filter_input_set_value((FilterInput *)element, text); + break; + case 4: /* not header contains */ + part = vfolder_create_part("subject"); + filter_rule_add_part((FilterRule *)rule, part); + element = filter_part_find_element(part, "subject-type"); + filter_option_set_current((FilterOption *)element, "not contains"); + element = filter_part_find_element(part, "subject"); + filter_input_set_value((FilterInput *)element, text); + break; + } + + vfolder_gui_add_rule(rule); +} + void folder_browser_clear_search (FolderBrowser *fb) { @@ -373,6 +414,7 @@ static void folder_browser_gui_init (FolderBrowser *fb) { GtkWidget *hbox, *label; + GtkButton *button; /* * The panned container @@ -397,6 +439,10 @@ folder_browser_gui_init (FolderBrowser *fb) label = gtk_label_new("Search"); gtk_widget_show(label); fb->search_menu = create_option_menu(search_options, 0, fb); + button = (GtkButton *)gtk_button_new_with_label("Save"); + gtk_widget_show((GtkWidget *)button); + gtk_signal_connect((GtkObject *)button, "clicked", search_save, fb); + gtk_box_pack_end((GtkBox *)hbox, (GtkWidget *)button, FALSE, FALSE, 3); gtk_box_pack_end((GtkBox *)hbox, fb->search_entry, FALSE, FALSE, 3); gtk_box_pack_end((GtkBox *)hbox, fb->search_menu, FALSE, FALSE, 3); gtk_box_pack_end((GtkBox *)hbox, label, FALSE, FALSE, 3); diff --git a/mail/mail-vfolder.c b/mail/mail-vfolder.c index cef814082a..cd613040b1 100644 --- a/mail/mail-vfolder.c +++ b/mail/mail-vfolder.c @@ -18,11 +18,16 @@ #include "evolution-shell-component.h" #include "folder-browser.h" +#include "mail-vfolder.h" + +#include "camel/camel.h" #include "filter/vfolder-context.h" -#include "filter/filter-rule.h" +#include "filter/vfolder-rule.h" #include "filter/vfolder-editor.h" +#define d(x) x + struct _vfolder_info { char *name; char *query; @@ -35,10 +40,13 @@ static EvolutionStorage *vfolder_storage; /* GROSS HACK: for passing to other parts of the program */ EvolutionShellClient *global_shell_client = NULL; + +/* more globals ... */ extern char *evolution_dir; +extern CamelSession *session; static struct _vfolder_info * -vfolder_find(char *name) +vfolder_find(const char *name) { GList *l = available_vfolders; struct _vfolder_info *info; @@ -74,11 +82,12 @@ vfolder_refresh(void) /* check if the rule has changed ... otherwise, leave it */ if (strcmp(expr->str, info->query)) { - printf("Must reconfigure vfolder with new rule?\n"); + d(printf("Must reconfigure vfolder with new rule?\n")); g_free(info->query); info->query = g_strdup(expr->str); - uri = g_strdup_printf("vfolder:%s/vfolder/%s?%s", evolution_dir, info->name, info->query); + /*uri = g_strdup_printf("vfolder:%s/vfolder/%s?%s", evolution_dir, info->name, info->query);*/ + uri = g_strdup_printf("vfolder:%s", info->name); path = g_strdup_printf("/%s", info->name); evolution_storage_removed_folder(vfolder_storage, path); evolution_storage_new_folder (vfolder_storage, path, @@ -92,9 +101,10 @@ vfolder_refresh(void) info = g_malloc(sizeof(*info)); info->name = g_strdup(rule->name); info->query = g_strdup(expr->str); - printf("Adding new vfolder: %s %s\n", rule->name, expr->str); + d(printf("Adding new vfolder: %s %s\n", rule->name, expr->str)); - uri = g_strdup_printf("vfolder:%s/vfolder/%s?%s", evolution_dir, info->name, info->query); + /*uri = g_strdup_printf("vfolder:%s/vfolder/%s?%s", evolution_dir, info->name, info->query);*/ + uri = g_strdup_printf("vfolder:%s", info->name); path = g_strdup_printf("/%s", info->name); evolution_storage_new_folder (vfolder_storage, path, "mail", @@ -109,7 +119,7 @@ vfolder_refresh(void) l = available_vfolders; while (l) { info = l->data; - printf("removing vfolders %s %s\n", info->name, info->query); + d(printf("removing vfolders %s %s\n", info->name, info->query)); path = g_strdup_printf("/%s", info->name); evolution_storage_removed_folder(vfolder_storage, path); g_free(path); @@ -160,17 +170,137 @@ vfolder_create_storage(EvolutionShellComponent *shell_component) vfolder_refresh(); } +/* maps the shell's uri to the real vfolder uri and open the folder */ +CamelFolder * +vfolder_uri_to_folder(const char *uri) +{ + CamelFolder *mail_uri_to_folder(const char *); + void camel_vee_folder_add_folder(CamelFolder *, CamelFolder *); + + struct _vfolder_info *info; + char *storeuri, *foldername; + VfolderRule *rule; + CamelStore *store = NULL; + CamelFolder *folder = NULL, *sourcefolder; + CamelException *ex; + const char *sourceuri; + int sources; + + if (strncmp (uri, "vfolder:", 8)) + return NULL; + + info = vfolder_find(uri+8); + if (info == NULL) { + g_warning("Shell trying to open unknown vFolder: %s", uri); + return NULL; + } + + d(printf("Opening vfolder: %s\n", uri)); + + rule = (VfolderRule *)rule_context_find_rule((RuleContext *)context, info->name); + + storeuri = g_strdup_printf("vfolder:%s/vfolder/%s", evolution_dir, info->name); + foldername = g_strdup_printf("mbox?%s", info->query); + ex = camel_exception_new (); + store = camel_session_get_store (session, storeuri, ex); + if (store == NULL) + goto cleanup; + + folder = camel_store_get_folder (store, foldername, TRUE, ex); + if (folder == NULL) + goto cleanup; + + sourceuri = NULL; + sources = 0; + while ( (sourceuri = vfolder_rule_next_source(rule, sourceuri)) ) { + d(printf("adding vfolder source: %s\n", sourceuri)); + sourcefolder = mail_uri_to_folder(sourceuri); + if (sourcefolder) { + sources++; + camel_vee_folder_add_folder(folder, sourcefolder); + } + } + /* if we didn't have any sources, just use Inbox as the default */ + if (sources == 0) { + char *defaulturi; + + defaulturi = g_strdup_printf("file://%s/local/Inbox", evolution_dir); + d(printf("No sources configured/found, using default: %s\n", defaulturi)); + sourcefolder = mail_uri_to_folder(defaulturi); + g_free(defaulturi); + if (sourcefolder) + camel_vee_folder_add_folder(folder, sourcefolder); + } +cleanup: + g_free(foldername); + g_free(storeuri); + + return folder; +} + +static void +vfolder_editor_clicked(GtkWidget *w, int button, void *data) +{ + if (button == 0) { + char *user; + + user = g_strdup_printf("%s/vfolders.xml", evolution_dir); + rule_context_save((RuleContext *)context, user); + g_free(user); + vfolder_refresh(); + } + if (button != -1) { + gnome_dialog_close((GnomeDialog *)w); + } +} + void vfolder_edit(void) { GtkWidget *w; - char *user; w = vfolder_editor_construct(context); - if (gnome_dialog_run_and_close((GnomeDialog *)w) == 0) { - user = g_strdup_printf ("%s/vfolders.xml", evolution_dir); - rule_context_save(context, user); + gtk_signal_connect((GtkObject *)w, "clicked", vfolder_editor_clicked, NULL); + gtk_widget_show(w); +} + +static void +new_rule_clicked(GtkWidget *w, int button, void *data) +{ + if (button == 0) { + char *user; + FilterRule *rule = gtk_object_get_data((GtkObject *)w, "rule"); + + gtk_object_ref((GtkObject *)rule); + rule_context_add_rule((RuleContext *)context, rule); + user = g_strdup_printf("%s/vfolders.xml", evolution_dir); + rule_context_save((RuleContext *)context, user); g_free(user); vfolder_refresh(); } + if (button != -1) { + gnome_dialog_close((GnomeDialog *)w); + } +} + +FilterPart * +vfolder_create_part(const char *name) +{ + return rule_context_create_part((RuleContext *)context, name); +} + +/* adds a rule with a gui */ +void +vfolder_gui_add_rule(VfolderRule *rule) +{ + GtkWidget *w; + GnomeDialog *gd; + + w = filter_rule_get_widget((FilterRule *)rule, (RuleContext *)context); + gd = (GnomeDialog *)gnome_dialog_new("New VFolder", "Ok", "Cancel", NULL); + gtk_box_pack_start((GtkBox *)gd->vbox, w, FALSE, TRUE, 0); + gtk_widget_show((GtkWidget *)gd); + gtk_object_set_data_full((GtkObject *)gd, "rule", rule, (GtkDestroyNotify)gtk_object_unref); + gtk_signal_connect((GtkObject *)gd, "clicked", new_rule_clicked, NULL); + gtk_widget_show((GtkWidget *)gd); } diff --git a/mail/mail-vfolder.h b/mail/mail-vfolder.h new file mode 100644 index 0000000000..10f20777d2 --- /dev/null +++ b/mail/mail-vfolder.h @@ -0,0 +1,22 @@ + +#ifndef _MAIL_VFOLDER_H +#define _MAIL_VFOLDER_H + +#include <bonobo.h> + +#include "Evolution.h" +#include "evolution-storage.h" +#include "evolution-shell-component.h" + +#include "camel/camel-folder.h" +#include "filter/vfolder-rule.h" +#include "filter/filter-part.h" + +void vfolder_create_storage(EvolutionShellComponent *shell_component); + +CamelFolder *vfolder_uri_to_folder(const char *uri); +void vfolder_edit(void); +FilterPart *vfolder_create_part(const char *name); +void vfolder_gui_add_rule(VfolderRule *rule); + +#endif diff --git a/mail/message-thread.c b/mail/message-thread.c index 3218d7ff28..c35e39f470 100644 --- a/mail/message-thread.c +++ b/mail/message-thread.c @@ -421,6 +421,11 @@ thread_messages(CamelFolder *folder, GPtrArray *uids) const CamelMessageInfo *mi; mi = camel_folder_get_message_info (folder, uids->pdata[i]); + if (mi == NULL) { + g_warning("Folder doesn't contain uid %s", uids->pdata[i]); + continue; + } + if (mi->message_id) { d(printf("doing : %s\n", mi->message_id)); c = g_hash_table_lookup(id_table, mi->message_id); |