aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mail/ChangeLog20
-rw-r--r--mail/folder-browser.c108
-rw-r--r--mail/mail-vfolder.c152
-rw-r--r--mail/mail-vfolder.h22
-rw-r--r--mail/message-thread.c5
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);