From 275ed94169994edbc9926d6231b758c7be271c53 Mon Sep 17 00:00:00 2001 From: Tristan Chabredier Date: Mon, 31 Jul 2006 12:03:02 +0000 Subject: [PATCH] 2006-07-31 [wwp] 2.4.0cvs3 * src/Makefile.am * src/addr_compl.c * src/addr_compl.h * src/addressbook.c * src/addressbook.h * src/addressbook_foldersel.c * src/addressbook_foldersel.h * src/addrindex.c * src/addrindex.h * src/matcher.c * src/matcher.h * src/matcher_parser_lex.l * src/matcher_parser_parse.y * src/prefs_common.c * src/prefs_common.h * src/prefs_filtering.c * src/prefs_matcher.c * src/prefs_matcher.h * src/summaryview.c introduce filtering against the address book. It's now possible to add matched conditions to determine if any email address in a message matches or doesn't match any or all books or folders in the address book. --- ChangeLog | 25 +++ PATCHSETS | 1 + configure.ac | 2 +- src/Makefile.am | 2 + src/addr_compl.c | 49 +++- src/addr_compl.h | 2 +- src/addressbook.c | 206 +++++++++++++++++ src/addressbook.h | 6 + src/addressbook_foldersel.c | 432 ++++++++++++++++++++++++++++++++++++ src/addressbook_foldersel.h | 32 +++ src/addrindex.c | 140 +++++++++--- src/addrindex.h | 3 +- src/matcher.c | 192 ++++++++++++---- src/matcher.h | 3 +- src/matcher_parser_lex.l | 2 + src/matcher_parser_parse.y | 36 ++- src/prefs_common.c | 5 + src/prefs_common.h | 2 + src/prefs_filtering.c | 2 +- src/prefs_matcher.c | 359 ++++++++++++++++++++++-------- src/prefs_matcher.h | 1 + src/summaryview.c | 2 +- 22 files changed, 1318 insertions(+), 186 deletions(-) create mode 100644 src/addressbook_foldersel.c create mode 100644 src/addressbook_foldersel.h diff --git a/ChangeLog b/ChangeLog index c0b587285..64717e1bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2006-07-31 [wwp] 2.4.0cvs3 + + * src/Makefile.am + * src/addr_compl.c + * src/addr_compl.h + * src/addressbook.c + * src/addressbook.h + * src/addressbook_foldersel.c + * src/addressbook_foldersel.h + * src/addrindex.c + * src/addrindex.h + * src/matcher.c + * src/matcher.h + * src/matcher_parser_lex.l + * src/matcher_parser_parse.y + * src/prefs_common.c + * src/prefs_common.h + * src/prefs_filtering.c + * src/prefs_matcher.c + * src/prefs_matcher.h + * src/summaryview.c + introduce filtering against the address book. It's now possible to add + matched conditions to determine if any email address in a message matches + or doesn't match any or all books or folders in the address book. + 2006-07-31 [wwp] 2.4.0cvs2 * src/account.c diff --git a/PATCHSETS b/PATCHSETS index c0d857a4a..2f680078a 100644 --- a/PATCHSETS +++ b/PATCHSETS @@ -1694,3 +1694,4 @@ ( cvs diff -u -r 1.1.2.9 -r 1.1.2.10 po/ca.po; ) > 2.3.1cvs91.patchset ( cvs diff -u -r 1.8.2.8 -r 1.8.2.9 src/quote_fmt.c; ) > 2.4.0cvs1.patchset ( cvs diff -u -r 1.61.2.48 -r 1.61.2.49 src/account.c; cvs diff -u -r 1.60.2.19 -r 1.60.2.20 src/filtering.c; cvs diff -u -r 1.21.2.7 -r 1.21.2.8 src/filtering.h; cvs diff -u -r 1.213.2.105 -r 1.213.2.106 src/folder.c; cvs diff -u -r 1.207.2.110 -r 1.207.2.111 src/folderview.c; cvs diff -u -r 1.149.2.54 -r 1.149.2.55 src/inc.c; cvs diff -u -r 1.274.2.127 -r 1.274.2.128 src/mainwindow.c; cvs diff -u -r 1.75.2.26 -r 1.75.2.27 src/matcher.c; cvs diff -u -r 1.16.2.6 -r 1.16.2.7 src/matcher_parser_lex.l; cvs diff -u -r 1.25.2.14 -r 1.25.2.15 src/matcher_parser_parse.y; cvs diff -u -r 1.28.2.22 -r 1.28.2.23 src/mbox.c; cvs diff -u -r 1.59.2.36 -r 1.59.2.37 src/prefs_filtering.c; cvs diff -u -r 1.6.2.4 -r 1.6.2.5 src/prefs_filtering.h; cvs diff -u -r 1.150.2.69 -r 1.150.2.70 src/procmsg.c; cvs diff -u -r 1.60.2.29 -r 1.60.2.30 src/procmsg.h; cvs diff -u -r 1.395.2.223 -r 1.395.2.224 src/summaryview.c; ) > 2.4.0cvs2.patchset +( cvs diff -u -r 1.155.2.39 -r 1.155.2.40 src/Makefile.am; cvs diff -u -r 1.27.2.18 -r 1.27.2.19 src/addr_compl.c; cvs diff -u -r 1.8.2.4 -r 1.8.2.5 src/addr_compl.h; cvs diff -u -r 1.60.2.59 -r 1.60.2.60 src/addressbook.c; cvs diff -u -r 1.18.2.2 -r 1.18.2.3 src/addressbook.h; diff -u /dev/null src/addressbook_foldersel.c; diff -u /dev/null src/addressbook_foldersel.h; cvs diff -u -r 1.28.2.17 -r 1.28.2.18 src/addrindex.c; cvs diff -u -r 1.9.2.6 -r 1.9.2.7 src/addrindex.h; cvs diff -u -r 1.75.2.27 -r 1.75.2.28 src/matcher.c; cvs diff -u -r 1.39.2.7 -r 1.39.2.8 src/matcher.h; cvs diff -u -r 1.16.2.7 -r 1.16.2.8 src/matcher_parser_lex.l; cvs diff -u -r 1.25.2.15 -r 1.25.2.16 src/matcher_parser_parse.y; cvs diff -u -r 1.204.2.92 -r 1.204.2.93 src/prefs_common.c; cvs diff -u -r 1.103.2.54 -r 1.103.2.55 src/prefs_common.h; cvs diff -u -r 1.59.2.37 -r 1.59.2.38 src/prefs_filtering.c; cvs diff -u -r 1.43.2.40 -r 1.43.2.41 src/prefs_matcher.c; cvs diff -u -r 1.4.2.3 -r 1.4.2.4 src/prefs_matcher.h; cvs diff -u -r 1.395.2.224 -r 1.395.2.225 src/summaryview.c; ) > 2.4.0cvs3.patchset diff --git a/configure.ac b/configure.ac index 611fa8e92..e95bee47b 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,7 @@ MINOR_VERSION=4 MICRO_VERSION=0 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=2 +EXTRA_VERSION=3 EXTRA_RELEASE= EXTRA_GTK2_VERSION= diff --git a/src/Makefile.am b/src/Makefile.am index bac640abf..867632a00 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,6 +20,7 @@ sylpheed_claws_SOURCES = \ addr_compl.c \ addressadd.c \ addressbook.c \ + addressbook_foldersel.c \ addrgather.c \ addrharvest.c \ addrindex.c \ @@ -157,6 +158,7 @@ sylpheed_clawsinclude_HEADERS = \ addrdefs.h \ addressadd.h \ addressbook.h \ + addressbook_foldersel.h \ addressitem.h \ addrgather.h \ addrharvest.h \ diff --git a/src/addr_compl.c b/src/addr_compl.c index 75bffcb2d..f2d398684 100644 --- a/src/addr_compl.c +++ b/src/addr_compl.c @@ -113,6 +113,8 @@ static gchar *g_completion_prefix; /* last prefix. (this is cached here * because the prefix passed to g_completion * is g_strdown()'ed */ +static gchar *completion_folder_path = NULL; + /*******************************************************************************/ /* @@ -259,8 +261,8 @@ static gint add_address(const gchar *name, const gchar *address, /** * Read address book, creating all entries in the completion index. */ -static void read_address_book(void) { - addrindex_load_completion( add_address ); +static void read_address_book(gchar *folderpath) { + addrindex_load_completion( add_address, folderpath ); g_address_list = g_list_reverse(g_address_list); g_completion_list = g_list_reverse(g_completion_list); } @@ -298,19 +300,42 @@ static void clear_completion_cache(void) * address completion. * \return The number of addresses in the completion list. */ -gint start_address_completion(void) +gint start_address_completion(gchar *folderpath) { clear_completion_cache(); + + if ((completion_folder_path == NULL && folderpath != NULL) || + (completion_folder_path != NULL && folderpath == NULL) || + (completion_folder_path != NULL && folderpath != NULL && + strcmp(completion_folder_path, folderpath) != 0)) { + + debug_print("start_address_completion: resetting\n"); + + /* TODO: wwp: optimize: only reset when the new folderpath is MORE restrictive than the old one + (the most easy case is when folderpath is NULL and completion_folder_path is != NULL */ + if (g_ref_count) { + free_all(); + g_ref_count = 0; + } + } + + g_free(completion_folder_path); + if (folderpath != NULL) + completion_folder_path = g_strdup(folderpath); + else + completion_folder_path = NULL; + if (!g_ref_count) { init_all(); /* open the address book */ - read_address_book(); + read_address_book(folderpath); /* merge the completion entry list into g_completion */ if (g_completion_list) g_completion_add_items(g_completion, g_completion_list); } g_ref_count++; - debug_print("start_address_completion ref count %d\n", g_ref_count); + debug_print("start_address_completion(%s) ref count %d\n", + folderpath, g_ref_count); return g_list_length(g_completion_list); } @@ -402,10 +427,11 @@ static void replace_address_in_edit(GtkEntry *entry, const gchar *newtext, */ guint complete_address(const gchar *str) { - GList *result; - gchar *d; - guint count, cpl; - completion_entry *ce; + GList *result = NULL; + gchar *d = NULL; + guint count = 0; + guint cpl = 0; + completion_entry *ce = NULL; g_return_val_if_fail(str != NULL, 0); @@ -524,7 +550,8 @@ gint invalidate_address_completion(void) debug_print("Invalidation request for address completion\n"); free_all(); init_all(); - read_address_book(); + read_address_book(completion_folder_path); + if (g_completion_list) g_completion_add_items(g_completion, g_completion_list); clear_completion_cache(); } @@ -949,7 +976,7 @@ static void completion_window_apply_selection(GtkTreeView *list_view, GtkEntry * */ void address_completion_start(GtkWidget *mainwindow) { - start_address_completion(); + start_address_completion(NULL); /* register focus change hook */ g_signal_connect(G_OBJECT(mainwindow), "set_focus", diff --git a/src/addr_compl.h b/src/addr_compl.h index cf2896499..10a4ebd17 100644 --- a/src/addr_compl.h +++ b/src/addr_compl.h @@ -23,7 +23,7 @@ #include -gint start_address_completion (void); +gint start_address_completion (gchar *folderpath); guint complete_address (const gchar *str); gchar *get_complete_address (gint index); gint invalidate_address_completion (void); diff --git a/src/addressbook.c b/src/addressbook.c index 8ae192846..60074e11a 100644 --- a/src/addressbook.c +++ b/src/addressbook.c @@ -69,6 +69,7 @@ #include "addrbook.h" #include "addrindex.h" #include "addressadd.h" +#include "addressbook_foldersel.h" #include "vcard.h" #include "editvcard.h" #include "editgroup.h" @@ -115,6 +116,19 @@ typedef enum N_LIST_COLS = 3 } AddressListColumns; +typedef struct { + AddressBookFile *book; + ItemFolder *folder; +} FolderInfo; + +typedef struct { + gchar **folder_path; + gboolean matched; + gint index; + AddressDataSource *book; + ItemFolder *folder; +} FolderPathMatch; + static gchar *list_titles[] = { N_("Name"), N_("Email Address"), N_("Remarks") }; @@ -4453,6 +4467,198 @@ gboolean addressbook_add_contact( return TRUE; } +/* *********************************************************************** + * Book/folder selection. + * *********************************************************************** + */ + +/* + * This function is used by the matcher dialog to select a book/folder. + */ +gboolean addressbook_folder_selection( gchar **folderpath ) +{ + AddressBookFile *book = NULL; + ItemFolder *folder = NULL; + gchar *path; + + g_return_val_if_fail( folderpath != NULL, FALSE); + + path = *folderpath; + *folderpath = NULL; + if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, path ) + && book != NULL ) { + if ( folder != NULL) { + gchar *tmp = NULL; + gchar *oldtmp = NULL; + AddrItemObject *obj = NULL; + + /* walk thru folder->parent to build the full folder path */ + /* TODO: wwp: optimize this */ + obj = &folder->obj; + tmp = g_strdup(obj->uid); + while ( obj->parent ) { + obj = obj->parent; + if ( obj->name != NULL ) { + oldtmp = g_strdup(tmp); + g_free(tmp); + tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp); + g_free(oldtmp); + } + } + *folderpath = g_strdup_printf("%s/%s", book->fileName, tmp); + g_free(tmp); + } else { + *folderpath = g_strdup_printf("%s", book->fileName); + } + debug_print( "addressbook_foldersel: %s\n", *folderpath); + return (*folderpath != NULL); + } + return FALSE; +} + +/* *********************************************************************** + * Book/folder checking. + * *********************************************************************** + */ + +static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder ) +{ + FolderInfo *fi = g_new0( FolderInfo, 1 ); + fi->book = abf; + fi->folder = folder; + return fi; +} + +static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder, + FolderInfo *fiParent, FolderPathMatch *match ) +{ + GList *list; + ItemFolder *folder; + gchar *fName; + FolderInfo *fi; + FolderPathMatch *nextmatch = NULL; + + list = parentFolder->listFolder; + while ( list ) { + folder = list->data; + fName = g_strdup( ADDRITEM_NAME(folder) ); + + /* match folder name, match pointer will be set to NULL if next recursive call + doesn't need to match subfolder name */ + if ( match != NULL && + match->matched == FALSE ) { + if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) { + /* folder name matches, prepare next subfolder match */ + debug_print("matched folder name '%s'\n", fName); + match->index++; + if ( match->folder_path[match->index] == NULL ) { + /* we've matched all elements */ + match->matched = TRUE; + match->folder = folder; + debug_print("book/folder path matched!\n"); + } else { + /* keep on matching */ + nextmatch = match; + } + } + } + + g_free( fName ); + + fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder ); + addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch ); + list = g_list_next( list ); + } +} + +/* + * This function is used by to check if a matcher book/folder path corresponds to an + existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid). + */ + +gboolean addressbook_peek_folder_exists( gchar *folderpath, + AddressDataSource **book, + ItemFolder **folder ) +{ + AddressDataSource *ds; + GList *list, *nodeDS; + ItemFolder *rootFolder; + AddressBookFile *abf; + FolderInfo *fi; + FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL }; + FolderPathMatch *nextmatch; + + if ( book ) + *book = NULL; + if ( folder ) + *folder = NULL; + + if ( folderpath == NULL ) + return FALSE; + + if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' ) + return TRUE; + + /* split the folder path we've received, we'll try to match this path, subpath by + subpath against the book/folder structure in order */ + folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 ); + + list = addrindex_get_interface_list( _addressIndex_ ); + while ( list ) { + AddressInterface *interface = list->data; + if ( interface->type == ADDR_IF_BOOK ) { + nodeDS = interface->listSource; + while ( nodeDS ) { + ds = nodeDS->data; + + /* Read address book */ + if( ! addrindex_ds_get_read_flag( ds ) ) { + addrindex_ds_read_data( ds ); + } + + /* Add node for address book */ + abf = ds->rawDataSource; + + /* try to match subfolders if this book is the right book + (and if there's smth to match, and not yet matched) */ + nextmatch = NULL; + if ( folder_path_match.folder_path != NULL && + folder_path_match.matched == FALSE && + strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) { + debug_print("matched book name '%s'\n", abf->fileName); + folder_path_match.index = 1; + if ( folder_path_match.folder_path[folder_path_match.index] == NULL ) { + /* we've matched all elements */ + folder_path_match.matched = TRUE; + folder_path_match.book = ds; + debug_print("book path matched!\n"); + } else { + /* keep on matching */ + nextmatch = &folder_path_match; + } + } + + fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL ); + + rootFolder = addrindex_ds_get_root_folder( ds ); + addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, nextmatch ); + + nodeDS = g_list_next( nodeDS ); + } + } + list = g_list_next( list ); + } + + g_strfreev( folder_path_match.folder_path ); + + if ( book ) + *book = folder_path_match.book; + if ( folder ) + *folder = folder_path_match.folder; + return folder_path_match.matched; +} + + /* ********************************************************************** * Address Import. * *********************************************************************** diff --git a/src/addressbook.h b/src/addressbook.h index 23c888df5..c83fcd10c 100644 --- a/src/addressbook.h +++ b/src/addressbook.h @@ -25,6 +25,7 @@ #include "compose.h" #include "addritem.h" +#include "addrindex.h" void addressbook_open ( Compose *target ); void addressbook_set_target_compose ( Compose *target ); @@ -39,6 +40,11 @@ gboolean addressbook_add_contact ( const gchar *name, const gchar *address, const gchar *remarks ); +gboolean addressbook_folder_selection( gchar **folderpath ); +gboolean addressbook_peek_folder_exists( gchar *folderpath, + AddressDataSource **book, + ItemFolder **folder ); + gboolean addressbook_load_completion (gint (*callBackFunc) (const gchar *, const gchar *, diff --git a/src/addressbook_foldersel.c b/src/addressbook_foldersel.c new file mode 100644 index 000000000..f33ae2dd1 --- /dev/null +++ b/src/addressbook_foldersel.c @@ -0,0 +1,432 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001-2006 Match Grun and the Sylpheed-Claws team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Add address to address book dialog. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "defs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtkutils.h" +#include "stock_pixmap.h" +#include "prefs_common.h" +#include "addressadd.h" +#include "addritem.h" +#include "addrbook.h" +#include "addrindex.h" +#include "manage_window.h" + +typedef struct { + AddressBookFile *book; + ItemFolder *folder; +} FolderInfo; + +typedef struct { + gchar **folder_path; + gboolean matched; + gint index; + GtkCTreeNode *node; +} FolderPathMatch; + +static struct _AddressBookFolderSel_dlg { + GtkWidget *window; + GtkWidget *tree_folder; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; + gint status_cid; + FolderInfo *fiSelected; +} addressbook_foldersel_dlg; + +static GdkPixmap *folderXpm; +static GdkBitmap *folderXpmMask; +static GdkPixmap *bookXpm; +static GdkBitmap *bookXpmMask; + +static gboolean addressbook_foldersel_cancelled; + +static FolderInfo *addressbook_foldersel_create_folderinfo( AddressBookFile *abf, ItemFolder *folder ) +{ + FolderInfo *fi = g_new0( FolderInfo, 1 ); + fi->book = abf; + fi->folder = folder; + return fi; +} + +static void addressbook_foldersel_free_folderinfo( FolderInfo *fi ) { + fi->book = NULL; + fi->folder = NULL; + g_free( fi ); +} + +static gint addressbook_foldersel_delete_event( GtkWidget *widget, GdkEventAny *event, gboolean *cancelled ) +{ + addressbook_foldersel_cancelled = TRUE; + gtk_main_quit(); + return TRUE; +} + +static gboolean addressbook_foldersel_key_pressed( GtkWidget *widget, GdkEventKey *event, gboolean *cancelled ) +{ + if ( event && event->keyval == GDK_Escape ) { + addressbook_foldersel_cancelled = TRUE; + gtk_main_quit(); + } + return FALSE; +} + +static void addressbook_foldersel_ok( GtkWidget *widget, gboolean *cancelled ) +{ + addressbook_foldersel_cancelled = FALSE; + gtk_main_quit(); +} + +static void addressbook_foldersel_cancel( GtkWidget *widget, gboolean *cancelled ) +{ + addressbook_foldersel_cancelled = TRUE; + gtk_main_quit(); +} + +static void addressbook_foldersel_folder_select( GtkCTree *ctree, gint row, gint column, + GdkEvent *event, gpointer data ) +{ + addressbook_foldersel_dlg.fiSelected = gtk_clist_get_row_data( GTK_CLIST(ctree), row ); +} + +static gboolean addressbook_foldersel_tree_button( GtkCTree *ctree, GdkEventButton *event, gpointer data ) +{ + if ( ! event ) + return FALSE; + if ( event->button == 1 ) { + /* Handle double click */ + if ( event->type == GDK_2BUTTON_PRESS ) { + addressbook_foldersel_cancelled = FALSE; + gtk_main_quit(); + } + } + + return FALSE; +} + +static void addressbook_foldersel_size_allocate_cb(GtkWidget *widget, + GtkAllocation *allocation) +{ + g_return_if_fail(allocation != NULL); + + prefs_common.addressbook_folderselwin_width = allocation->width; + prefs_common.addressbook_folderselwin_height = allocation->height; +} + +static void addressbook_foldersel_create( void ) +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *tree_folder; + GtkWidget *vlbox; + GtkWidget *tree_win; + GtkWidget *hbbox; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; + static GdkGeometry geometry; + + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_container_set_border_width( GTK_CONTAINER(window), 0 ); + gtk_window_set_title( GTK_WINDOW(window), _("Select Address Book Folder") ); + gtk_window_set_position( GTK_WINDOW(window), GTK_WIN_POS_MOUSE ); + gtk_window_set_modal( GTK_WINDOW(window), TRUE ); + g_signal_connect( G_OBJECT(window), "delete_event", + G_CALLBACK(addressbook_foldersel_delete_event), NULL ); + g_signal_connect( G_OBJECT(window), "key_press_event", + G_CALLBACK(addressbook_foldersel_key_pressed), NULL ); + g_signal_connect(G_OBJECT(window), "size_allocate", + G_CALLBACK(addressbook_foldersel_size_allocate_cb), NULL); + + vbox = gtk_vbox_new(FALSE, 8); + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_container_set_border_width( GTK_CONTAINER(vbox), 8 ); + + /* Address book/folder tree */ + vlbox = gtk_vbox_new(FALSE, 8); + gtk_box_pack_start(GTK_BOX(vbox), vlbox, TRUE, TRUE, 0); + gtk_container_set_border_width( GTK_CONTAINER(vlbox), 8 ); + + tree_win = gtk_scrolled_window_new( NULL, NULL ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(tree_win), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC ); + gtk_box_pack_start( GTK_BOX(vlbox), tree_win, TRUE, TRUE, 0 ); + + tree_folder = gtk_ctree_new( 1, 0 ); + gtk_container_add( GTK_CONTAINER(tree_win), tree_folder ); + gtk_clist_column_titles_show( GTK_CLIST(tree_folder) ); + gtk_clist_set_column_title( GTK_CLIST(tree_folder), 0, _( "Address Book" ) ); + gtk_ctree_set_line_style( GTK_CTREE(tree_folder), GTK_CTREE_LINES_DOTTED ); + gtk_clist_set_selection_mode( GTK_CLIST(tree_folder), GTK_SELECTION_BROWSE ); + gtk_ctree_set_expander_style( GTK_CTREE(tree_folder), GTK_CTREE_EXPANDER_SQUARE ); + gtk_ctree_set_indent( GTK_CTREE(tree_folder), CTREE_INDENT ); + gtk_clist_set_auto_sort( GTK_CLIST(tree_folder), TRUE ); + + /* Button panel */ + gtkut_stock_button_set_create( &hbbox, &cancel_btn, GTK_STOCK_CANCEL, + &ok_btn, GTK_STOCK_OK, + NULL, NULL ); + gtk_box_pack_end( GTK_BOX(vbox), hbbox, FALSE, FALSE, 0 ); + gtk_container_set_border_width( GTK_CONTAINER(hbbox), 0 ); + gtk_widget_grab_default( ok_btn ); + + g_signal_connect( G_OBJECT(ok_btn), "clicked", + G_CALLBACK(addressbook_foldersel_ok), NULL ); + g_signal_connect( G_OBJECT(cancel_btn), "clicked", + G_CALLBACK(addressbook_foldersel_cancel), NULL ); + g_signal_connect( G_OBJECT(tree_folder), "select_row", + G_CALLBACK(addressbook_foldersel_folder_select), NULL ); + g_signal_connect( G_OBJECT(tree_folder), "button_press_event", + G_CALLBACK(addressbook_foldersel_tree_button), NULL ); + + if ( !geometry.min_height ) { + geometry.min_width = 300; + geometry.min_height = 350; + } + + gtk_window_set_geometry_hints( GTK_WINDOW(window), NULL, &geometry, + GDK_HINT_MIN_SIZE ); + gtk_widget_set_size_request( window, prefs_common.addressbook_folderselwin_width, + prefs_common.addressbook_folderselwin_height ); + + gtk_widget_show_all( vbox ); + + addressbook_foldersel_dlg.window = window; + addressbook_foldersel_dlg.tree_folder = tree_folder; + addressbook_foldersel_dlg.ok_btn = ok_btn; + addressbook_foldersel_dlg.cancel_btn = cancel_btn; + + gtk_widget_show_all( window ); + + stock_pixmap_gdk( window, STOCK_PIXMAP_BOOK, &bookXpm, &bookXpmMask ); + stock_pixmap_gdk( window, STOCK_PIXMAP_DIR_OPEN, + &folderXpm, &folderXpmMask ); +} + +static void addressbook_foldersel_load_folder( GtkCTreeNode *parentNode, ItemFolder *parentFolder, + FolderInfo *fiParent, FolderPathMatch *match ) +{ + GtkCTree *tree = GTK_CTREE( addressbook_foldersel_dlg.tree_folder ); + GList *list; + ItemFolder *folder; + gchar *fName; + gchar **name; + GtkCTreeNode *node; + FolderInfo *fi; + FolderPathMatch *nextmatch = NULL; + + list = parentFolder->listFolder; + while ( list ) { + folder = list->data; + fName = g_strdup( ADDRITEM_NAME(folder) ); + + name = &fName; + node = gtk_sctree_insert_node( tree, parentNode, NULL, name, FOLDER_SPACING, + folderXpm, folderXpmMask, folderXpm, folderXpmMask, + FALSE, TRUE ); + + /* match folder name, match pointer will be set to NULL if next recursive call + doesn't need to match subfolder name */ + if ( match != NULL && + match->matched == FALSE ) { + if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) { + /* folder name matches, prepare next subfolder match */ + + debug_print("matched folder name '%s'\n", fName); + + match->index++; + + if ( match->folder_path[match->index] == NULL ) { + /* we've matched all elements */ + match->matched = TRUE; + match->node = node; + debug_print("book/folder path matched!\n"); + } else { + /* keep on matching */ + nextmatch = match; + } + } + } + + g_free( fName ); + + fi = addressbook_foldersel_create_folderinfo( fiParent->book, folder ); + gtk_ctree_node_set_row_data_full( tree, node, fi, + ( GtkDestroyNotify ) addressbook_foldersel_free_folderinfo ); + addressbook_foldersel_load_folder( node, folder, fi, nextmatch ); + list = g_list_next( list ); + } +} + +static void addressbook_foldersel_load_data( AddressIndex *addrIndex, gchar *path, FolderPathMatch* match ) +{ + AddressDataSource *ds; + GList *list, *nodeDS; + gchar **name; + gchar *dsName; + ItemFolder *rootFolder; + AddressBookFile *abf; + FolderInfo *fi; + GtkCTree *tree = GTK_CTREE( addressbook_foldersel_dlg.tree_folder ); + GtkCTreeNode *node; + FolderPathMatch *nextmatch; + + gtk_clist_clear( GTK_CLIST( tree ) ); + list = addrindex_get_interface_list( addrIndex ); + while ( list ) { + AddressInterface *interface = list->data; + if ( interface->type == ADDR_IF_BOOK ) { + nodeDS = interface->listSource; + while ( nodeDS ) { + ds = nodeDS->data; + dsName = g_strdup( addrindex_ds_get_name( ds ) ); + + /* Read address book */ + if( ! addrindex_ds_get_read_flag( ds ) ) { + addrindex_ds_read_data( ds ); + } + + /* Add node for address book */ + abf = ds->rawDataSource; + name = &dsName; + node = gtk_sctree_insert_node( tree, NULL, NULL, + name, FOLDER_SPACING, bookXpm, + bookXpmMask, bookXpm, bookXpmMask, + FALSE, TRUE ); + g_free( dsName ); + + /* try to match subfolders if this book is the right book + (and if there's smth to match, and not yet matched) */ + nextmatch = NULL; + if ( match->folder_path != NULL && + match->matched == FALSE && + match->folder_path[0] != NULL && + strcmp(match->folder_path[0], abf->fileName) == 0 ) { + + debug_print("matched book name '%s'\n", abf->fileName); + + match->index = 1; + + if ( match->folder_path[match->index] == NULL ) { + /* we've matched all elements */ + match->matched = TRUE; + match->node = node; + debug_print("book path matched!\n"); + } else { + /* keep on matching */ + nextmatch = match; + } + } + + fi = addressbook_foldersel_create_folderinfo( abf, NULL ); + gtk_ctree_node_set_row_data_full( tree, node, fi, + ( GtkDestroyNotify ) addressbook_foldersel_free_folderinfo ); + + rootFolder = addrindex_ds_get_root_folder( ds ); + addressbook_foldersel_load_folder( node, rootFolder, fi, nextmatch ); + + nodeDS = g_list_next( nodeDS ); + } + } + list = g_list_next( list ); + } +} + +gboolean addressbook_foldersel_selection( AddressIndex *addrIndex, + AddressBookFile **book, ItemFolder **folder, gchar* path) +{ + gboolean retVal = FALSE; + addressbook_foldersel_cancelled = FALSE; + FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL }; + + if ( ! addressbook_foldersel_dlg.window ) + addressbook_foldersel_create(); + gtk_widget_grab_focus(addressbook_foldersel_dlg.ok_btn); + gtk_widget_show(addressbook_foldersel_dlg.window); + manage_window_set_transient(GTK_WINDOW(addressbook_foldersel_dlg.window)); + + addressbook_foldersel_dlg.fiSelected = NULL; + + /* split the folder path we've received, we'll try to match this path, subpath by + subpath against the book/folder structure in order to select the folder that + corresponds to what we received */ + + if ( path != NULL ) { + if ( strcasecmp(path, _("Any")) == 0 || *path == '\0' ) + /* consider "Any" and "" as valid addressbook root */ + folder_path_match.matched = TRUE; + else + folder_path_match.folder_path = g_strsplit( path, "/", 256 ); + } + + addressbook_foldersel_load_data( addrIndex, path, &folder_path_match ); + + if ( folder_path_match.folder_path != NULL && folder_path_match.matched == FALSE) + g_warning("addressbook_foldersel_load_data: couldn't match book/folder path '%s'\n", path); + + g_strfreev( folder_path_match.folder_path ); + + if ( folder_path_match.node != NULL) + gtk_ctree_select( GTK_CTREE( addressbook_foldersel_dlg.tree_folder ), + GTK_CTREE_NODE( folder_path_match.node ) ); + else + gtk_clist_select_row( GTK_CLIST( addressbook_foldersel_dlg.tree_folder ), 0, 0 ); + gtk_widget_show(addressbook_foldersel_dlg.window); + + gtk_main(); + gtk_widget_hide( addressbook_foldersel_dlg.window ); + + if ( ! addressbook_foldersel_cancelled ) { + + *book = NULL; + *folder = NULL; + + if ( addressbook_foldersel_dlg.fiSelected ) { + *book = addressbook_foldersel_dlg.fiSelected->book; + *folder = addressbook_foldersel_dlg.fiSelected->folder; + retVal = TRUE; + } + } + + gtk_clist_clear( GTK_CLIST( addressbook_foldersel_dlg.tree_folder ) ); + + return retVal; +} + +/* +* End of Source. +*/ diff --git a/src/addressbook_foldersel.h b/src/addressbook_foldersel.h new file mode 100644 index 000000000..62023e5bd --- /dev/null +++ b/src/addressbook_foldersel.h @@ -0,0 +1,32 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001-2006 Match Grun and the Sylpheed-Claws team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Add address to address book dialog. + */ + +#ifndef __ADDRESSBOOK_FOLDERSEL_H__ +#define __ADDRESSBOOK_FOLDERSEL_H__ + +#include "addrindex.h" + +gboolean addressbook_foldersel_selection( AddressIndex *addrIndex, + AddressBookFile **book, ItemFolder **folder, gchar *path ); + +#endif /* __ADDRESSBOOK_FOLDERSEL_H__ */ diff --git a/src/addrindex.c b/src/addrindex.c index 0b7af02c4..f98ca944c 100644 --- a/src/addrindex.c +++ b/src/addrindex.c @@ -34,6 +34,7 @@ #include "addritem.h" #include "addrcache.h" #include "addrbook.h" +#include "addressbook.h" #include "addrindex.h" #include "xml.h" #include "addrquery.h" @@ -2788,39 +2789,15 @@ void addrindex_remove_results( AddressDataSource *ds, ItemFolder *folder ) { * *********************************************************************** */ -/** - * This function is used by the address completion function to load - * addresses for all non-external address book interfaces. - * - * \param callBackFunc Function to be called when an address is - * to be loaded. - * \return TRUE if data loaded, FALSE if address index not loaded. - */ -gboolean addrindex_load_completion( +static void addrindex_load_completion_load_persons( gint (*callBackFunc) ( const gchar *, const gchar *, - const gchar *, const gchar * ) ) + const gchar *, const gchar * ), + AddressDataSource *ds) { - AddressDataSource *ds; - GList *nodeIf, *nodeDS; GList *listP, *nodeP; GList *nodeM; gchar *sName; - nodeIf = addrindex_get_interface_list( _addressIndex_ ); - while( nodeIf ) { - AddressInterface *iface = nodeIf->data; - - nodeIf = g_list_next( nodeIf ); - if( ! iface->useInterface ) { - continue; - } - if( iface->externalQuery ) { - continue; - } - nodeDS = iface->listSource; - while( nodeDS ) { - ds = nodeDS->data; - /* Read address book */ if( addrindex_ds_get_modify_flag( ds ) ) { addrindex_ds_read_data( ds ); @@ -2856,10 +2833,111 @@ gboolean addrindex_load_completion( } /* Free up the list */ g_list_free( listP ); +} +/** + * This function is used by the address completion function to load + * addresses for all non-external address book interfaces. + * + * \param callBackFunc Function to be called when an address is + * to be loaded. + * \param folderpath Addressbook's Book/folder path to restrict to (if NULL or "" + * or "Any", assume the whole addressbook + * \return TRUE if data loaded, FALSE if address index not loaded. + */ + +gboolean addrindex_load_completion( + gint (*callBackFunc) ( const gchar *, const gchar *, + const gchar *, const gchar * ), + gchar *folderpath ) +{ + GList *nodeIf, *nodeDS; + + if( folderpath != NULL ) { + AddressDataSource *book; + ItemFolder* folder; + + /* split the folder path we've received, we'll try to match this path, subpath by + subpath against the book/folder structure in order and restrict loading of + addresses to that subpart (if matches). book/folder path must exist and + folderpath must not be empty or NULL */ + + if( ! addressbook_peek_folder_exists( folderpath, &book, &folder ) ) { + g_warning("addrindex_load_completion: folder path '%s' doesn't exist\n", folderpath); + return FALSE; + } + + if( book != NULL ) { + AddressBookFile *abf = book->rawDataSource; + + debug_print("addrindex_load_completion: book %p '%s'\n", book, abf->fileName); + + addrindex_load_completion_load_persons( callBackFunc, book ); + + return TRUE; + + } else { + + if( folder != NULL ) { + GList *items; + GList *nodeM; + gchar *sName; + ItemPerson *person; + + debug_print("addrindex_load_completion: folder %p '%s'\n", folder, folder->obj.name); + + /* Load email addresses */ + items = addritem_folder_get_person_list( folder ); + for( ; items != NULL; items = g_list_next( items ) ) { + person = items->data; + nodeM = person->listEMail; + + /* Figure out name to use */ + sName = ADDRITEM_NAME(person); + if( sName == NULL || *sName == '\0' ) { + sName = person->nickName; + } + + /* Process each E-Mail address */ + while( nodeM ) { + ItemEMail *email = nodeM->data; + + callBackFunc( sName, email->address, person->nickName, + ADDRITEM_NAME(email) ); + + nodeM = g_list_next( nodeM ); + } + } + /* Free up the list */ + mgu_clear_list( items ); + g_list_free( items ); + + return TRUE; + + } else { + g_warning("addrindex_load_completion: book/folder path is valid but got no pointer\n"); + } + } + return FALSE; + + } else { + + nodeIf = addrindex_get_interface_list( _addressIndex_ ); + while( nodeIf ) { + AddressInterface *iface = nodeIf->data; + + nodeIf = g_list_next( nodeIf ); + + if( ! iface->useInterface || iface->externalQuery ) + continue; + + nodeDS = iface->listSource; + while( nodeDS ) { + addrindex_load_completion_load_persons( callBackFunc, nodeDS->data ); nodeDS = g_list_next( nodeDS ); } } + } return TRUE; } @@ -2887,12 +2965,10 @@ gboolean addrindex_load_person_attribute( AddressInterface *iface = nodeIf->data; nodeIf = g_list_next( nodeIf ); - if( ! iface->useInterface ) { - continue; - } - if( iface->externalQuery ) { + + if( ! iface->useInterface || iface->externalQuery ) continue; - } + nodeDS = iface->listSource; while( nodeDS ) { ds = nodeDS->data; diff --git a/src/addrindex.h b/src/addrindex.h index 2eb5ff99b..31e089406 100644 --- a/src/addrindex.h +++ b/src/addrindex.h @@ -181,7 +181,8 @@ void addrindex_remove_results ( AddressDataSource *ds, gboolean addrindex_load_completion( gint (*callBackFunc) ( const gchar *, const gchar *, - const gchar *, const gchar * ) ); + const gchar *, const gchar * ), + gchar *folderpath ); gboolean addrindex_load_person_attribute( const gchar *attr, gint (*callBackFunc) diff --git a/src/matcher.c b/src/matcher.c index 3cbc7a8ec..44b6d9297 100644 --- a/src/matcher.c +++ b/src/matcher.c @@ -103,6 +103,8 @@ static const MatchParser matchparser_tab[] = { {MATCHCRITERIA_SCORE_EQUAL, "score_equal"}, {MATCHCRITERIA_PARTIAL, "partial"}, {MATCHCRITERIA_NOT_PARTIAL, "~partial"}, + {MATCHCRITERIA_FOUND_IN_ADDRESSBOOK, "found_in_addressbook"}, + {MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK, "~found_in_addressbook"}, {MATCHCRITERIA_SIZE_GREATER, "size_greater"}, {MATCHCRITERIA_SIZE_SMALLER, "size_smaller"}, @@ -125,8 +127,6 @@ static const MatchParser matchparser_tab[] = { {MATCHTYPE_MATCH, "match"}, {MATCHTYPE_REGEXPCASE, "regexpcase"}, {MATCHTYPE_REGEXP, "regexp"}, - {MATCHTYPE_ANY_IN_ADDRESSBOOK, "any_in_addressbook"}, - {MATCHTYPE_ALL_IN_ADDRESSBOOK, "all_in_addressbook"}, /* actions */ {MATCHACTION_SCORE, "score"}, /* for backward compatibility */ @@ -151,6 +151,12 @@ static const MatchParser matchparser_tab[] = { {MATCHACTION_IGNORE, "ignore"}, }; +enum { + MATCH_ANY = 0, + MATCH_ALL = 1, + MATCH_ONE = 2 +}; + /*! *\brief Look up table with keywords defined in \sa matchparser_tab */ @@ -213,7 +219,8 @@ gint get_matchparser_tab_id(const gchar *str) * "condition" (a matcher structure) * *\param criteria Criteria ID (MATCHCRITERIA_XXXX) - *\param header Header string (if criteria is MATCHCRITERIA_HEADER) + *\param header Header string (if criteria is MATCHCRITERIA_HEADER + or MATCHCRITERIA_FOUND_IN_ADDRESSBOOK) *\param matchtype Type of action (MATCHTYPE_XXX) *\param expr String value or expression to check *\param value Integer value to check @@ -280,38 +287,59 @@ MatcherProp *matcherprop_copy(const MatcherProp *src) /* ************** match ******************************/ static gboolean match_with_addresses_in_addressbook - (MatcherProp *prop, const gchar *str, gint type) + (MatcherProp *prop, GSList *address_list, gint type, + gchar* folderpath, gint match) { - GSList *address_list = NULL; - GSList *walk; - gboolean res = FALSE; + GSList *walk = NULL; + gboolean found = FALSE; + gchar *path = NULL; - if (str == NULL || *str == 0) - return FALSE; + g_return_val_if_fail(address_list != NULL, FALSE); + + debug_print("match_with_addresses_in_addressbook(%d, %s)\n", + g_slist_length(address_list), folderpath); + + if (folderpath == NULL || + strcasecmp(folderpath, _("Any")) == 0 || + *folderpath == '\0') + path = NULL; + else + path = folderpath; - /* XXX: perhaps complete with comments too */ - address_list = address_list_append(address_list, str); - if (!address_list) - return FALSE; + start_address_completion(path); - start_address_completion(); - res = FALSE; for (walk = address_list; walk != NULL; walk = walk->next) { - gboolean found = complete_address(walk->data) ? TRUE : FALSE; - + /* exact matching of email address */ + guint num_addr = complete_address(walk->data); + found = FALSE; + if (num_addr > 1) { + /* skip first item (this is the search string itself) */ + int i = 1; + for (; i < num_addr && !found; i++) { + gchar *addr = get_complete_address(i); + extract_address(addr); + if (strcasecmp(addr, walk->data) == 0) + found = TRUE; + g_free(addr); + } + } g_free(walk->data); - if (!found && type == MATCHTYPE_ALL_IN_ADDRESSBOOK) { - res = FALSE; + + if (match == MATCH_ALL) { + /* if matching all addresses, stop if one doesn't match */ + if (!found) break; - } else if (found) - res = TRUE; + } else if (match == MATCH_ANY) { + /* if matching any address, stop if one does match */ + if (found) + break; + } + /* MATCH_ONE: there should be only one loop iteration */ } - - g_slist_free(address_list); end_address_completion(); - return res; + return found; } /*! @@ -354,11 +382,6 @@ static gboolean matcherprop_string_match(MatcherProp *prop, const gchar *str) else return FALSE; - case MATCHTYPE_ALL_IN_ADDRESSBOOK: - case MATCHTYPE_ANY_IN_ADDRESSBOOK: - return match_with_addresses_in_addressbook - (prop, str, prop->matchtype); - case MATCHTYPE_MATCH: return (strstr(str, prop->expr) != NULL); @@ -624,7 +647,7 @@ gboolean matcherprop_match(MatcherProp *prop, case MATCHCRITERIA_NOT_TEST: return !matcherprop_match_test(prop, info); default: - return 0; + return FALSE; } } @@ -690,8 +713,8 @@ static void matcherlist_skip_headers(FILE *fp) static gboolean matcherprop_match_one_header(MatcherProp *matcher, gchar *buf) { - gboolean result; - Header *header; + gboolean result = FALSE; + Header *header = NULL; switch (matcher->criteria) { case MATCHCRITERIA_HEADER: @@ -720,7 +743,57 @@ static gboolean matcherprop_match_one_header(MatcherProp *matcher, return !matcherprop_string_decode_match(matcher, buf); case MATCHCRITERIA_NOT_HEADERS_PART: return !matcherprop_string_match(matcher, buf); + case MATCHCRITERIA_FOUND_IN_ADDRESSBOOK: + case MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK: + { + GSList *address_list = NULL; + gint match = MATCH_ONE; + gboolean found = FALSE; + + /* how many address headers are me trying to mach? */ + if (strcasecmp(matcher->header, _("Any")) == 0) + match = MATCH_ANY; + else if (strcasecmp(matcher->header, _("All")) == 0) + match = MATCH_ALL; + + if (match == MATCH_ONE) { + /* matching one address header exactly, is that the right one? */ + header = procheader_parse_header(buf); + if (!header || + !procheader_headername_equal(header->name, matcher->header)) + return FALSE; + address_list = address_list_append(address_list, header->body); + if (address_list == NULL) + return FALSE; + + } else { + header = procheader_parse_header(buf); + if (!header) + return FALSE; + /* address header is one of the headers we have to match when checking + for any address header or all address headers? */ + if (procheader_headername_equal(header->name, "From") || + procheader_headername_equal(header->name, "To") || + procheader_headername_equal(header->name, "Cc") || + procheader_headername_equal(header->name, "Reply-To") || + procheader_headername_equal(header->name, "Sender")) + address_list = address_list_append(address_list, header->body); + if (address_list == NULL) + return FALSE; + } + + found = match_with_addresses_in_addressbook + (matcher, address_list, matcher->criteria, + matcher->expr, match); + g_slist_free(address_list); + + if (matcher->criteria == MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK) + return !found; + else + return found; + } } + return FALSE; } @@ -740,6 +813,8 @@ static gboolean matcherprop_criteria_headers(const MatcherProp *matcher) case MATCHCRITERIA_NOT_HEADER: case MATCHCRITERIA_HEADERS_PART: case MATCHCRITERIA_NOT_HEADERS_PART: + case MATCHCRITERIA_FOUND_IN_ADDRESSBOOK: + case MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK: return TRUE; default: return FALSE; @@ -785,14 +860,46 @@ static gboolean matcherlist_match_headers(MatcherList *matchers, FILE *fp) while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1) { for (l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) { MatcherProp *matcher = (MatcherProp *) l->data; + gint match = MATCH_ANY; if (matcher->done) continue; - /* if the criteria is ~headers_part or ~message, ZERO lines - * must NOT match for the rule to match. */ + /* determine the match range (all, any are our concern here) */ if (matcher->criteria == MATCHCRITERIA_NOT_HEADERS_PART || matcher->criteria == MATCHCRITERIA_NOT_MESSAGE) { + match = MATCH_ALL; + + } else if (matcher->criteria == MATCHCRITERIA_FOUND_IN_ADDRESSBOOK || + matcher->criteria == MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK) { + Header *header = NULL; + + /* address header is one of the headers we have to match when checking + for any address header or all address headers? */ + header = procheader_parse_header(buf); + if (header && + (procheader_headername_equal(header->name, "From") || + procheader_headername_equal(header->name, "To") || + procheader_headername_equal(header->name, "Cc") || + procheader_headername_equal(header->name, "Reply-To") || + procheader_headername_equal(header->name, "Sender"))) { + + if (strcasecmp(matcher->header, _("Any")) == 0) + match = MATCH_ANY; + else if (strcasecmp(matcher->header, _("All")) == 0) + match = MATCH_ALL; + else + match = MATCH_ONE; + } else { + /* further call to matcherprop_match_one_header() can't match + and it irrelevant, so: don't alter the match result */ + continue; + } + } + + /* ZERO line must NOT match for the rule to match. + */ + if (match == MATCH_ALL) { if (matcherprop_match_one_header(matcher, buf)) { matcher->result = TRUE; } else { @@ -802,7 +909,7 @@ static gboolean matcherlist_match_headers(MatcherList *matchers, FILE *fp) /* else, just one line matching is enough for the rule to match */ } else if (matcherprop_criteria_headers(matcher) || - matcherprop_criteria_message(matcher)){ + matcherprop_criteria_message(matcher)) { if (matcherprop_match_one_header(matcher, buf)) { matcher->result = TRUE; matcher->done = TRUE; @@ -817,6 +924,7 @@ static gboolean matcherlist_match_headers(MatcherList *matchers, FILE *fp) } } } + return FALSE; } @@ -1180,6 +1288,7 @@ gchar *matcherprop_to_string(MatcherProp *matcher) const gchar *matchtype_str; int i; gchar * quoted_expr; + gchar * quoted_header; criteria_str = NULL; for (i = 0; i < (int) (sizeof(matchparser_tab) / sizeof(MatchParser)); i++) { @@ -1228,6 +1337,15 @@ gchar *matcherprop_to_string(MatcherProp *matcher) criteria_str, quoted_expr); g_free(quoted_expr); return matcher_str; + case MATCHCRITERIA_FOUND_IN_ADDRESSBOOK: + case MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK: + quoted_header = matcher_quote_str(matcher->header); + quoted_expr = matcher_quote_str(matcher->expr); + matcher_str = g_strdup_printf("%s \"%s\" in \"%s\"", + criteria_str, quoted_header, quoted_expr); + g_free(quoted_header); + g_free(quoted_expr); + return matcher_str; } matchtype_str = NULL; @@ -1244,12 +1362,8 @@ gchar *matcherprop_to_string(MatcherProp *matcher) case MATCHTYPE_MATCHCASE: case MATCHTYPE_REGEXP: case MATCHTYPE_REGEXPCASE: - case MATCHTYPE_ALL_IN_ADDRESSBOOK: - case MATCHTYPE_ANY_IN_ADDRESSBOOK: quoted_expr = matcher_quote_str(matcher->expr); if (matcher->header) { - gchar * quoted_header; - quoted_header = matcher_quote_str(matcher->header); matcher_str = g_strdup_printf ("%s \"%s\" %s \"%s\"", diff --git a/src/matcher.h b/src/matcher.h index 17e93f622..f0f407bf2 100644 --- a/src/matcher.h +++ b/src/matcher.h @@ -101,13 +101,12 @@ enum { MC_(SIZE_GREATER), MC_(SIZE_SMALLER), MC_(SIZE_EQUAL), + MC_(FOUND_IN_ADDRESSBOOK),MC_(NOT_FOUND_IN_ADDRESSBOOK), /* match type */ MT_(MATCHCASE), MT_(MATCH), MT_(REGEXPCASE), MT_(REGEXP), - MT_(ANY_IN_ADDRESSBOOK), - MT_(ALL_IN_ADDRESSBOOK), /* actions */ MA_(SCORE), MA_(EXECUTE), diff --git a/src/matcher_parser_lex.l b/src/matcher_parser_lex.l index 390490ee4..ef12ca921 100644 --- a/src/matcher_parser_lex.l +++ b/src/matcher_parser_lex.l @@ -57,6 +57,8 @@ void matcher_parser_init(void) %% +"in" return MATCHER_IN; + /* * a keyword consists of alpha and underscore * characters, possibly preceded by a tilde (~) diff --git a/src/matcher_parser_parse.y b/src/matcher_parser_parse.y index 5adbdd8a9..b9ca4a89b 100644 --- a/src/matcher_parser_parse.y +++ b/src/matcher_parser_parse.y @@ -310,7 +310,7 @@ int matcher_parserwrap(void) %token MATCHER_NOT_MESSAGE MATCHER_BODY_PART MATCHER_NOT_BODY_PART %token MATCHER_TEST MATCHER_NOT_TEST MATCHER_MATCHCASE MATCHER_MATCH %token MATCHER_REGEXPCASE MATCHER_REGEXP MATCHER_SCORE MATCHER_MOVE -%token MATCHER_ANY_IN_ADDRESSBOOK MATCHER_ALL_IN_ADDRESSBOOK +%token MATCHER_FOUND_IN_ADDRESSBOOK MATCHER_NOT_FOUND_IN_ADDRESSBOOK MATCHER_IN %token MATCHER_COPY MATCHER_DELETE MATCHER_MARK MATCHER_UNMARK %token MATCHER_LOCK MATCHER_UNLOCK %token MATCHER_EXECUTE @@ -546,14 +546,6 @@ MATCHER_MATCHCASE { match_type = MATCHTYPE_REGEXP; } -| MATCHER_ANY_IN_ADDRESSBOOK -{ - match_type = MATCHTYPE_ANY_IN_ADDRESSBOOK; -} -| MATCHER_ALL_IN_ADDRESSBOOK -{ - match_type = MATCHTYPE_ALL_IN_ADDRESSBOOK; -} ; condition: @@ -1000,6 +992,32 @@ MATCHER_ALL expr = $3; prop = matcherprop_new(criteria, NULL, match_type, expr, 0); } +| MATCHER_FOUND_IN_ADDRESSBOOK MATCHER_STRING +{ + header = g_strdup($2); +} MATCHER_IN MATCHER_STRING +{ + gint criteria = 0; + gchar *expr = NULL; + + criteria = MATCHCRITERIA_FOUND_IN_ADDRESSBOOK; + expr = $2; + prop = matcherprop_new(criteria, header, match_type, expr, 0); + g_free(header); +} +| MATCHER_NOT_FOUND_IN_ADDRESSBOOK MATCHER_STRING +{ + header = g_strdup($2); +} MATCHER_IN MATCHER_STRING +{ + gint criteria = 0; + gchar *expr = NULL; + + criteria = MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK; + expr = $2; + prop = matcherprop_new(criteria, header, match_type, expr, 0); + g_free(header); +} | MATCHER_MESSAGE match_type MATCHER_STRING { gint criteria = 0; diff --git a/src/prefs_common.c b/src/prefs_common.c index a519f0a65..0a83b2d11 100644 --- a/src/prefs_common.c +++ b/src/prefs_common.c @@ -749,6 +749,11 @@ static PrefParam param[] = { {"addressaddwin_height", "-1", &prefs_common.addressaddwin_height, P_INT, NULL, NULL, NULL}, + {"addressbook_folderselwin_width", "300", &prefs_common.addressbook_folderselwin_width, P_INT, + NULL, NULL, NULL}, + {"addressbook_folderselwin_height", "-1", &prefs_common.addressbook_folderselwin_height, P_INT, + NULL, NULL, NULL}, + /* Hidden */ {"warn_dnd", "1", &prefs_common.warn_dnd, P_INT, NULL, NULL, NULL}, diff --git a/src/prefs_common.h b/src/prefs_common.h index 95418f7f4..6283e2fd5 100644 --- a/src/prefs_common.h +++ b/src/prefs_common.h @@ -378,6 +378,8 @@ struct _PrefsCommon gint folderselwin_height; gint addressaddwin_width; gint addressaddwin_height; + gint addressbook_folderselwin_width; + gint addressbook_folderselwin_height; gint warn_dnd; gint broken_are_utf8; diff --git a/src/prefs_filtering.c b/src/prefs_filtering.c index cc2b5cf3d..177ce0914 100644 --- a/src/prefs_filtering.c +++ b/src/prefs_filtering.c @@ -210,7 +210,7 @@ void prefs_filtering_open(GSList ** p_processing, gtk_widget_show(filtering.window); - start_address_completion(); + start_address_completion(NULL); } static void prefs_filtering_size_allocate_cb(GtkWidget *widget, diff --git a/src/prefs_matcher.c b/src/prefs_matcher.c index 020089301..c06da8452 100644 --- a/src/prefs_matcher.c +++ b/src/prefs_matcher.c @@ -67,6 +67,7 @@ static struct Matcher { GtkWidget *predicate_combo; GtkWidget *predicate_flag_combo; GtkWidget *header_combo; + GtkWidget *header_addr_combo; GtkWidget *criteria_list; @@ -78,13 +79,18 @@ static struct Matcher { GtkWidget *header_entry; GtkWidget *header_label; + GtkWidget *header_addr_entry; + GtkWidget *header_addr_label; GtkWidget *value_entry; GtkWidget *value_label; + GtkWidget *addressbook_folder_label; + GtkWidget *addressbook_folder_combo; GtkWidget *case_chkbtn; GtkWidget *regexp_chkbtn; GtkWidget *color_optmenu; GtkWidget *test_btn; + GtkWidget *addressbook_select_btn; GtkWidget *cond_list_view; @@ -140,7 +146,9 @@ enum { CRITERIA_SIZE_SMALLER = 29, CRITERIA_SIZE_EQUAL = 30, - CRITERIA_PARTIAL = 31 + CRITERIA_PARTIAL = 31, + + CRITERIA_FOUND_IN_ADDRESSBOOK = 32 }; /*! @@ -165,7 +173,8 @@ static const gchar *criteria_text [] = { N_("Size greater than"), N_("Size smaller than"), N_("Size exactly"), - N_("Partially downloaded") + N_("Partially downloaded"), + N_("Found in addressbook") }; /*! @@ -202,6 +211,13 @@ static const gchar *predicate_text [] = { N_("contains"), N_("does not contain") }; +/*! + *\brief Preset addressbook book/folder items + */ +static const gchar *addressbook_folder_text [] = { + N_("Any") +}; + /*! *\brief Enabled predicate * @@ -348,11 +364,16 @@ static void prefs_matcher_create(void) GtkWidget *header_combo; GtkWidget *header_entry; GtkWidget *header_label; + GtkWidget *header_addr_combo; + GtkWidget *header_addr_entry; + GtkWidget *header_addr_label; GtkWidget *criteria_combo; GtkWidget *criteria_list; GtkWidget *criteria_label; GtkWidget *value_label; GtkWidget *value_entry; + GtkWidget *addressbook_folder_label; + GtkWidget *addressbook_folder_combo; GtkWidget *predicate_combo; GtkWidget *predicate_list; GtkWidget *predicate_flag_combo; @@ -381,6 +402,7 @@ static void prefs_matcher_create(void) GtkWidget *down_btn; GtkWidget *test_btn; + GtkWidget *addressbook_select_btn; GtkWidget *color_optmenu; @@ -485,6 +507,23 @@ static void prefs_matcher_create(void) header_entry = GTK_COMBO(header_combo)->entry; gtk_entry_set_editable(GTK_ENTRY(header_entry), TRUE); + /* address header name */ + + header_addr_label = gtk_label_new(_("Address header")); + gtk_misc_set_alignment(GTK_MISC(header_addr_label), 0, 0.5); + gtk_table_attach(GTK_TABLE(criteria_table), header_addr_label, 1, 2, 0, 1, + GTK_FILL, 0, 0, 0); + + header_addr_combo = gtk_combo_new(); + gtk_widget_set_size_request(header_addr_combo, 120, -1); + gtkut_combo_set_items(GTK_COMBO (header_addr_combo), + _("All"), _("Any"), "From", "To", "Cc", "Reply-To", "Sender", + NULL); + gtk_table_attach(GTK_TABLE(criteria_table), header_addr_combo, 1, 2, 1, 2, + 0, 0, 0, 0); + header_addr_entry = GTK_COMBO(header_addr_combo)->entry; + gtk_entry_set_editable(GTK_ENTRY(header_addr_entry), TRUE); + /* value */ value_label = gtk_label_new(_("Value")); @@ -499,6 +538,30 @@ static void prefs_matcher_create(void) gtk_table_attach(GTK_TABLE(criteria_table), value_entry, 2, 3, 1, 2, GTK_FILL | GTK_SHRINK | GTK_EXPAND, 0, 0, 0); + /* book/folder value */ + + addressbook_folder_label = gtk_label_new(_("Book/folder")); + gtk_misc_set_alignment(GTK_MISC (addressbook_folder_label), 0, 0.5); + gtk_table_attach(GTK_TABLE(criteria_table), addressbook_folder_label, 2, 3, 0, 1, + GTK_FILL | GTK_SHRINK | GTK_EXPAND, 0, 0, 0); + + addressbook_folder_combo = gtk_combo_new(); + gtk_widget_show(addressbook_folder_combo); + gtk_widget_set_size_request(addressbook_folder_combo, 200, -1); + gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(addressbook_folder_combo)->entry), + TRUE); + + combo_items = NULL; + for (i = 0; i < (gint) (sizeof(addressbook_folder_text) / sizeof(gchar *)); i++) { + combo_items = g_list_append(combo_items, + (gpointer) _(addressbook_folder_text[i])); + } + gtk_combo_set_popdown_strings(GTK_COMBO(addressbook_folder_combo), combo_items); + g_list_free(combo_items); + + gtk_table_attach(GTK_TABLE(criteria_table), addressbook_folder_combo, 2, 3, 1, 2, + GTK_FILL | GTK_SHRINK | GTK_EXPAND, 0, 0, 0); + #if GTK_CHECK_VERSION(2, 8, 0) test_btn = gtk_button_new_from_stock(GTK_STOCK_INFO); #else @@ -511,6 +574,13 @@ static void prefs_matcher_create(void) G_CALLBACK(prefs_matcher_test_info), NULL); + addressbook_select_btn = gtk_button_new_with_label(_(" Select... ")); + gtk_table_attach(GTK_TABLE (criteria_table), addressbook_select_btn, 3, 4, 1, 2, + 0, 0, 0, 0); + g_signal_connect(G_OBJECT (addressbook_select_btn), "clicked", + G_CALLBACK(prefs_matcher_addressbook_select), + NULL); + color_optmenu = gtk_option_menu_new(); gtk_option_menu_set_menu(GTK_OPTION_MENU(color_optmenu), colorlabel_create_color_menu()); @@ -684,6 +754,10 @@ static void prefs_matcher_create(void) prefs_common.matcherwin_height); gtk_widget_show_all(window); + gtk_widget_hide(header_addr_label); + gtk_widget_hide(header_addr_combo); + gtk_widget_hide(addressbook_select_btn); + gtk_widget_hide(addressbook_folder_label); matcher.window = window; @@ -693,8 +767,13 @@ static void prefs_matcher_create(void) matcher.header_combo = header_combo; matcher.header_entry = header_entry; matcher.header_label = header_label; + matcher.header_addr_combo = header_addr_combo; + matcher.header_addr_entry = header_addr_entry; + matcher.header_addr_label = header_addr_label; matcher.value_entry = value_entry; matcher.value_label = value_label; + matcher.addressbook_folder_label = addressbook_folder_label; + matcher.addressbook_folder_combo = addressbook_folder_combo; matcher.predicate_label = predicate_label; matcher.predicate_list = predicate_list; matcher.predicate_combo = predicate_combo; @@ -704,6 +783,7 @@ static void prefs_matcher_create(void) matcher.regexp_chkbtn = regexp_chkbtn; matcher.bool_op_list = bool_op_list; matcher.test_btn = test_btn; + matcher.addressbook_select_btn = addressbook_select_btn; matcher.color_optmenu = color_optmenu; matcher.criteria_table = criteria_table; @@ -751,7 +831,9 @@ static void prefs_matcher_reset_condition(void) gtk_list_select_item(GTK_LIST(matcher.criteria_list), 0); gtk_list_select_item(GTK_LIST(matcher.predicate_list), 0); gtk_entry_set_text(GTK_ENTRY(matcher.header_entry), ""); + gtk_entry_set_text(GTK_ENTRY(matcher.header_addr_entry), ""); gtk_entry_set_text(GTK_ENTRY(matcher.value_entry), ""); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(matcher.addressbook_folder_combo)->entry), ""); } /*! @@ -907,7 +989,6 @@ static gint prefs_matcher_get_criteria_from_matching(gint matching_id) case MATCHCRITERIA_NOT_MESSAGE: case MATCHCRITERIA_MESSAGE: return CRITERIA_MESSAGE; - break; case MATCHCRITERIA_NOT_HEADERS_PART: case MATCHCRITERIA_HEADERS_PART: return CRITERIA_HEADERS_PART; @@ -933,6 +1014,9 @@ static gint prefs_matcher_get_criteria_from_matching(gint matching_id) return CRITERIA_SIZE_SMALLER; case MATCHCRITERIA_SIZE_EQUAL: return CRITERIA_SIZE_EQUAL; + case MATCHCRITERIA_FOUND_IN_ADDRESSBOOK: + case MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK: + return CRITERIA_FOUND_IN_ADDRESSBOOK; default: return -1; } @@ -1013,6 +1097,8 @@ static gint prefs_matcher_get_matching_from_criteria(gint criteria_id) return MATCHCRITERIA_SIZE_SMALLER; case CRITERIA_SIZE_EQUAL: return MATCHCRITERIA_SIZE_EQUAL; + case CRITERIA_FOUND_IN_ADDRESSBOOK: + return MATCHCRITERIA_FOUND_IN_ADDRESSBOOK; default: return -1; } @@ -1075,6 +1161,8 @@ static gint prefs_matcher_not_criteria(gint matcher_criteria) return MATCHCRITERIA_NOT_TEST; case MATCHCRITERIA_BODY_PART: return MATCHCRITERIA_NOT_BODY_PART; + case MATCHCRITERIA_FOUND_IN_ADDRESSBOOK: + return MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK; default: return matcher_criteria; } @@ -1123,6 +1211,7 @@ static MatcherProp *prefs_matcher_dialog_to_matcher(void) case CRITERIA_TEST: case CRITERIA_COLORLABEL: case CRITERIA_IGNORE_THREAD: + case CRITERIA_FOUND_IN_ADDRESSBOOK: if (value_pred_flag == PREDICATE_FLAG_DISABLED) criteria = prefs_matcher_not_criteria(criteria); break; @@ -1206,7 +1295,6 @@ static MatcherProp *prefs_matcher_dialog_to_matcher(void) } value = atoi(value_str); - break; case CRITERIA_COLORLABEL: @@ -1216,7 +1304,6 @@ static MatcherProp *prefs_matcher_dialog_to_matcher(void) break; case CRITERIA_HEADER: - header = gtk_entry_get_text(GTK_ENTRY(matcher.header_entry)); expr = gtk_entry_get_text(GTK_ENTRY(matcher.value_entry)); @@ -1225,6 +1312,27 @@ static MatcherProp *prefs_matcher_dialog_to_matcher(void) return NULL; } break; + + case CRITERIA_FOUND_IN_ADDRESSBOOK: + header = gtk_entry_get_text(GTK_ENTRY(matcher.header_addr_entry)); + expr = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(matcher.addressbook_folder_combo)->entry)); + + if (*header == '\0') { + alertpanel_error(_("Header name is not set.")); + return NULL; + } + if (*expr == '\0') { + gchar *msg; + + msg = g_strdup_printf(_("Book/folder path is not set.\n\n" + "If you want to match the '%s' address against the whole address book, " + "you have to select 'Any' from the book/folder drop-down list."), + header); + alertpanel_error(msg); + g_free(msg); + return NULL; + } + break; } matcherprop = matcherprop_new(criteria, header, matchtype, @@ -1412,6 +1520,22 @@ static void prefs_matcher_set_value_widget(GtkWidget *old_widget, 0, 0, 0); } +static void prefs_matcher_disable_widget(GtkWidget* widget) +{ + g_return_if_fail( widget != NULL); + + gtk_widget_set_sensitive(widget, FALSE); + gtk_widget_hide(widget); +} + +static void prefs_matcher_enable_widget(GtkWidget* widget) +{ + g_return_if_fail( widget != NULL); + + gtk_widget_set_sensitive(widget, TRUE); + gtk_widget_show(widget); +} + /*! *\brief Change widgets depending on the selected condition * @@ -1444,18 +1568,21 @@ static void prefs_matcher_criteria_select(GtkList *list, switch (value) { case CRITERIA_ALL: - gtk_widget_set_sensitive(matcher.header_combo, FALSE); - gtk_widget_set_sensitive(matcher.header_label, FALSE); - gtk_widget_set_sensitive(matcher.value_label, FALSE); - gtk_widget_set_sensitive(matcher.value_entry, FALSE); - gtk_widget_set_sensitive(matcher.predicate_label, FALSE); - gtk_widget_set_sensitive(matcher.predicate_combo, FALSE); - gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE); - gtk_widget_hide(matcher.predicate_combo); - gtk_widget_show(matcher.predicate_flag_combo); - gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE); - gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE); - gtk_widget_set_sensitive(matcher.test_btn, FALSE); + prefs_matcher_disable_widget(matcher.header_combo); + prefs_matcher_disable_widget(matcher.header_label); + prefs_matcher_disable_widget(matcher.header_addr_combo); + prefs_matcher_disable_widget(matcher.header_addr_label); + prefs_matcher_disable_widget(matcher.value_label); + prefs_matcher_disable_widget(matcher.value_entry); + prefs_matcher_disable_widget(matcher.addressbook_folder_label); + prefs_matcher_disable_widget(matcher.addressbook_folder_combo); + prefs_matcher_disable_widget(matcher.predicate_label); + prefs_matcher_disable_widget(matcher.predicate_combo); + prefs_matcher_disable_widget(matcher.predicate_flag_combo); + prefs_matcher_disable_widget(matcher.case_chkbtn); + prefs_matcher_disable_widget(matcher.regexp_chkbtn); + prefs_matcher_disable_widget(matcher.test_btn); + prefs_matcher_disable_widget(matcher.addressbook_select_btn); break; case CRITERIA_UNREAD: @@ -1467,32 +1594,39 @@ static void prefs_matcher_criteria_select(GtkList *list, case CRITERIA_LOCKED: case CRITERIA_PARTIAL: case CRITERIA_IGNORE_THREAD: - gtk_widget_set_sensitive(matcher.header_combo, FALSE); - gtk_widget_set_sensitive(matcher.header_label, FALSE); - gtk_widget_set_sensitive(matcher.value_label, FALSE); - gtk_widget_set_sensitive(matcher.value_entry, FALSE); - gtk_widget_set_sensitive(matcher.predicate_label, TRUE); - gtk_widget_set_sensitive(matcher.predicate_combo, FALSE); - gtk_widget_set_sensitive(matcher.predicate_flag_combo, TRUE); - gtk_widget_hide(matcher.predicate_combo); - gtk_widget_show(matcher.predicate_flag_combo); - gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE); - gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE); - gtk_widget_set_sensitive(matcher.test_btn, FALSE); + prefs_matcher_disable_widget(matcher.header_combo); + prefs_matcher_disable_widget(matcher.header_label); + prefs_matcher_disable_widget(matcher.header_addr_combo); + prefs_matcher_disable_widget(matcher.header_addr_label); + prefs_matcher_disable_widget(matcher.value_label); + prefs_matcher_disable_widget(matcher.value_entry); + prefs_matcher_disable_widget(matcher.addressbook_folder_label); + prefs_matcher_disable_widget(matcher.addressbook_folder_combo); + prefs_matcher_enable_widget(matcher.predicate_label); + prefs_matcher_disable_widget(matcher.predicate_combo); + prefs_matcher_enable_widget(matcher.predicate_flag_combo); + prefs_matcher_disable_widget(matcher.case_chkbtn); + prefs_matcher_disable_widget(matcher.regexp_chkbtn); + prefs_matcher_disable_widget(matcher.test_btn); + prefs_matcher_disable_widget(matcher.addressbook_select_btn); break; case CRITERIA_COLORLABEL: - gtk_widget_set_sensitive(matcher.header_combo, FALSE); - gtk_widget_set_sensitive(matcher.header_label, FALSE); - gtk_widget_set_sensitive(matcher.value_label, TRUE); - gtk_widget_set_sensitive(matcher.predicate_label, TRUE); - gtk_widget_set_sensitive(matcher.predicate_combo, FALSE); - gtk_widget_set_sensitive(matcher.predicate_flag_combo, TRUE); - gtk_widget_hide(matcher.predicate_combo); - gtk_widget_show(matcher.predicate_flag_combo); - gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE); - gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE); - gtk_widget_set_sensitive(matcher.test_btn, FALSE); + prefs_matcher_disable_widget(matcher.header_combo); + prefs_matcher_disable_widget(matcher.header_label); + prefs_matcher_disable_widget(matcher.header_addr_combo); + prefs_matcher_disable_widget(matcher.header_addr_label); + prefs_matcher_enable_widget(matcher.value_label); + prefs_matcher_disable_widget(matcher.value_entry); + prefs_matcher_disable_widget(matcher.addressbook_folder_label); + prefs_matcher_disable_widget(matcher.addressbook_folder_combo); + prefs_matcher_enable_widget(matcher.predicate_label); + prefs_matcher_disable_widget(matcher.predicate_combo); + prefs_matcher_enable_widget(matcher.predicate_flag_combo); + prefs_matcher_disable_widget(matcher.case_chkbtn); + prefs_matcher_disable_widget(matcher.regexp_chkbtn); + prefs_matcher_disable_widget(matcher.test_btn); + prefs_matcher_disable_widget(matcher.addressbook_select_btn); break; case CRITERIA_SUBJECT: @@ -1506,33 +1640,39 @@ static void prefs_matcher_criteria_select(GtkList *list, case CRITERIA_HEADERS_PART: case CRITERIA_BODY_PART: case CRITERIA_MESSAGE: - gtk_widget_set_sensitive(matcher.header_combo, FALSE); - gtk_widget_set_sensitive(matcher.header_label, FALSE); - gtk_widget_set_sensitive(matcher.value_label, TRUE); - gtk_widget_set_sensitive(matcher.value_entry, TRUE); - gtk_widget_set_sensitive(matcher.predicate_label, TRUE); - gtk_widget_set_sensitive(matcher.predicate_combo, TRUE); - gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE); - gtk_widget_show(matcher.predicate_combo); - gtk_widget_hide(matcher.predicate_flag_combo); - gtk_widget_set_sensitive(matcher.case_chkbtn, TRUE); - gtk_widget_set_sensitive(matcher.regexp_chkbtn, TRUE); - gtk_widget_set_sensitive(matcher.test_btn, FALSE); + prefs_matcher_disable_widget(matcher.header_combo); + prefs_matcher_disable_widget(matcher.header_label); + prefs_matcher_disable_widget(matcher.header_addr_combo); + prefs_matcher_disable_widget(matcher.header_addr_label); + prefs_matcher_enable_widget(matcher.value_label); + prefs_matcher_enable_widget(matcher.value_entry); + prefs_matcher_disable_widget(matcher.addressbook_folder_label); + prefs_matcher_disable_widget(matcher.addressbook_folder_combo); + prefs_matcher_enable_widget(matcher.predicate_label); + prefs_matcher_enable_widget(matcher.predicate_combo); + prefs_matcher_disable_widget(matcher.predicate_flag_combo); + prefs_matcher_enable_widget(matcher.case_chkbtn); + prefs_matcher_enable_widget(matcher.regexp_chkbtn); + prefs_matcher_disable_widget(matcher.test_btn); + prefs_matcher_disable_widget(matcher.addressbook_select_btn); break; case CRITERIA_TEST: - gtk_widget_set_sensitive(matcher.header_combo, FALSE); - gtk_widget_set_sensitive(matcher.header_label, FALSE); - gtk_widget_set_sensitive(matcher.value_label, TRUE); - gtk_widget_set_sensitive(matcher.value_entry, TRUE); - gtk_widget_set_sensitive(matcher.predicate_label, TRUE); - gtk_widget_set_sensitive(matcher.predicate_combo, FALSE); - gtk_widget_set_sensitive(matcher.predicate_flag_combo, TRUE); - gtk_widget_hide(matcher.predicate_combo); - gtk_widget_show(matcher.predicate_flag_combo); - gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE); - gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE); - gtk_widget_set_sensitive(matcher.test_btn, TRUE); + prefs_matcher_disable_widget(matcher.header_combo); + prefs_matcher_disable_widget(matcher.header_label); + prefs_matcher_disable_widget(matcher.header_addr_combo); + prefs_matcher_disable_widget(matcher.header_addr_label); + prefs_matcher_enable_widget(matcher.value_label); + prefs_matcher_enable_widget(matcher.value_entry); + prefs_matcher_disable_widget(matcher.addressbook_folder_label); + prefs_matcher_disable_widget(matcher.addressbook_folder_combo); + prefs_matcher_enable_widget(matcher.predicate_label); + prefs_matcher_disable_widget(matcher.predicate_combo); + prefs_matcher_enable_widget(matcher.predicate_flag_combo); + prefs_matcher_disable_widget(matcher.case_chkbtn); + prefs_matcher_disable_widget(matcher.regexp_chkbtn); + prefs_matcher_enable_widget(matcher.test_btn); + prefs_matcher_disable_widget(matcher.addressbook_select_btn); break; case CRITERIA_AGE_GREATER: @@ -1543,33 +1683,57 @@ static void prefs_matcher_criteria_select(GtkList *list, case CRITERIA_SIZE_GREATER: case CRITERIA_SIZE_SMALLER: case CRITERIA_SIZE_EQUAL: - gtk_widget_set_sensitive(matcher.header_combo, FALSE); - gtk_widget_set_sensitive(matcher.header_label, FALSE); - gtk_widget_set_sensitive(matcher.value_label, TRUE); - gtk_widget_set_sensitive(matcher.value_entry, TRUE); - gtk_widget_set_sensitive(matcher.predicate_label, FALSE); - gtk_widget_set_sensitive(matcher.predicate_combo, FALSE); - gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE); - gtk_widget_show(matcher.predicate_combo); - gtk_widget_hide(matcher.predicate_flag_combo); - gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE); - gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE); - gtk_widget_set_sensitive(matcher.test_btn, FALSE); + prefs_matcher_disable_widget(matcher.header_combo); + prefs_matcher_disable_widget(matcher.header_label); + prefs_matcher_disable_widget(matcher.header_addr_combo); + prefs_matcher_disable_widget(matcher.header_addr_label); + prefs_matcher_enable_widget(matcher.value_label); + prefs_matcher_enable_widget(matcher.value_entry); + prefs_matcher_disable_widget(matcher.addressbook_folder_label); + prefs_matcher_disable_widget(matcher.addressbook_folder_combo); + prefs_matcher_disable_widget(matcher.predicate_label); + prefs_matcher_disable_widget(matcher.predicate_combo); + prefs_matcher_disable_widget(matcher.predicate_flag_combo); + prefs_matcher_disable_widget(matcher.case_chkbtn); + prefs_matcher_disable_widget(matcher.regexp_chkbtn); + prefs_matcher_disable_widget(matcher.test_btn); + prefs_matcher_disable_widget(matcher.addressbook_select_btn); break; case CRITERIA_HEADER: - gtk_widget_set_sensitive(matcher.header_combo, TRUE); - gtk_widget_set_sensitive(matcher.header_label, TRUE); - gtk_widget_set_sensitive(matcher.value_label, TRUE); - gtk_widget_set_sensitive(matcher.value_entry, TRUE); - gtk_widget_set_sensitive(matcher.predicate_label, TRUE); - gtk_widget_set_sensitive(matcher.predicate_combo, TRUE); - gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE); - gtk_widget_show(matcher.predicate_combo); - gtk_widget_hide(matcher.predicate_flag_combo); - gtk_widget_set_sensitive(matcher.case_chkbtn, TRUE); - gtk_widget_set_sensitive(matcher.regexp_chkbtn, TRUE); - gtk_widget_set_sensitive(matcher.test_btn, FALSE); + prefs_matcher_enable_widget(matcher.header_combo); + prefs_matcher_enable_widget(matcher.header_label); + prefs_matcher_disable_widget(matcher.header_addr_combo); + prefs_matcher_disable_widget(matcher.header_addr_label); + prefs_matcher_enable_widget(matcher.value_label); + prefs_matcher_enable_widget(matcher.value_entry); + prefs_matcher_disable_widget(matcher.addressbook_folder_label); + prefs_matcher_disable_widget(matcher.addressbook_folder_combo); + prefs_matcher_enable_widget(matcher.predicate_label); + prefs_matcher_enable_widget(matcher.predicate_combo); + prefs_matcher_disable_widget(matcher.predicate_flag_combo); + prefs_matcher_enable_widget(matcher.case_chkbtn); + prefs_matcher_enable_widget(matcher.regexp_chkbtn); + prefs_matcher_disable_widget(matcher.test_btn); + prefs_matcher_disable_widget(matcher.addressbook_select_btn); + break; + + case CRITERIA_FOUND_IN_ADDRESSBOOK: + prefs_matcher_disable_widget(matcher.header_combo); + prefs_matcher_disable_widget(matcher.header_label); + prefs_matcher_enable_widget(matcher.header_addr_combo); + prefs_matcher_enable_widget(matcher.header_addr_label); + prefs_matcher_disable_widget(matcher.value_label); + prefs_matcher_disable_widget(matcher.value_entry); + prefs_matcher_enable_widget(matcher.addressbook_folder_label); + prefs_matcher_enable_widget(matcher.addressbook_folder_combo); + prefs_matcher_enable_widget(matcher.predicate_label); + prefs_matcher_disable_widget(matcher.predicate_combo); + prefs_matcher_enable_widget(matcher.predicate_flag_combo); + prefs_matcher_disable_widget(matcher.case_chkbtn); + prefs_matcher_disable_widget(matcher.regexp_chkbtn); + prefs_matcher_disable_widget(matcher.test_btn); + prefs_matcher_enable_widget(matcher.addressbook_select_btn); break; } } @@ -1718,6 +1882,18 @@ void prefs_matcher_test_info(void) description_window_create(&test_desc_win); } +void prefs_matcher_addressbook_select(void) +{ + gchar *folderpath = NULL; + gboolean ret = FALSE; + + folderpath = (gchar *) gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(matcher.addressbook_folder_combo)->entry)); + ret = addressbook_folder_selection(&folderpath); + if ( ret != FALSE && folderpath != NULL) + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(matcher.addressbook_folder_combo)->entry), folderpath); +} + + /* * list view */ @@ -1857,6 +2033,7 @@ static gboolean prefs_matcher_selected(GtkTreeSelection *selector, case MATCHCRITERIA_NOT_MESSAGE: case MATCHCRITERIA_NOT_BODY_PART: case MATCHCRITERIA_NOT_TEST: + case MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK: negative_cond = TRUE; break; } @@ -1892,6 +2069,12 @@ static gboolean prefs_matcher_selected(GtkTreeSelection *selector, gtk_entry_set_text(GTK_ENTRY(matcher.value_entry), prop->expr); break; + case MATCHCRITERIA_FOUND_IN_ADDRESSBOOK: + case MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK: + gtk_entry_set_text(GTK_ENTRY(matcher.header_addr_entry), prop->header); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(matcher.addressbook_folder_combo)->entry), prop->expr); + break; + case MATCHCRITERIA_AGE_GREATER: case MATCHCRITERIA_AGE_LOWER: case MATCHCRITERIA_SCORE_GREATER: diff --git a/src/prefs_matcher.h b/src/prefs_matcher.h index 31693e628..05228d3bd 100644 --- a/src/prefs_matcher.h +++ b/src/prefs_matcher.h @@ -27,5 +27,6 @@ typedef void PrefsMatcherSignal (MatcherList *matchers); void prefs_matcher_open (MatcherList *matchers, PrefsMatcherSignal *cb); void prefs_matcher_test_info (void); +void prefs_matcher_addressbook_select (void); #endif /* __PREFS_FILTER_H__ */ diff --git a/src/summaryview.c b/src/summaryview.c index c107c2dd8..7c11a3210 100644 --- a/src/summaryview.c +++ b/src/summaryview.c @@ -2447,7 +2447,7 @@ static void summary_set_ctree_from_list(SummaryView *summaryview, summaryview->subject_table = subject_table; if (prefs_common.use_addr_book) - start_address_completion(); + start_address_completion(NULL); if (summaryview->threaded) { GNode *root, *gnode; -- 2.25.1