Configurable vfolder sources, and a button to save a search
as a new vfolder. 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. svn path=/trunk/; revision=4422
This commit is contained in:
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
22
mail/mail-vfolder.h
Normal file
22
mail/mail-vfolder.h
Normal file
@ -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
|
||||
@ -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);
|
||||
|
||||
Reference in New Issue
Block a user