From: Colin Leroy Date: Sun, 17 Oct 2010 19:12:44 +0000 (+0000) Subject: 2010-10-17 [colin] 3.7.6cvs55 X-Git-Tag: REL_3_7_7~12 X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=commitdiff_plain;h=7a1a6deffa9fc9e1637b701b0749ade84a3151ce 2010-10-17 [colin] 3.7.6cvs55 * src/main.c * src/gtk/authors.h * src/gtk/quicksearch.c * src/gtk/quicksearch.h Add ability to search from the command-line. Closes bug 2249, ' Making QuickSearch independent from the GUI' Patch by Sebastien Bigarret. --- diff --git a/ChangeLog b/ChangeLog index 575a448c2..9ea4cba91 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2010-10-17 [colin] 3.7.6cvs55 + + * src/main.c + * src/gtk/authors.h + * src/gtk/quicksearch.c + * src/gtk/quicksearch.h + Add ability to search from the command-line. + Closes bug 2249, ' Making QuickSearch independent from the GUI' + Patch by Sebastien Bigarret. + 2010-10-04 [mones] 3.7.6cvs54 * manual/dist/pdf/Makefile.am diff --git a/PATCHSETS b/PATCHSETS index 599797e48..b82fa0f2c 100644 --- a/PATCHSETS +++ b/PATCHSETS @@ -4050,3 +4050,4 @@ ( cvs diff -u -r 1.1.2.1 -r 1.1.2.2 manual/de/dist/html/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 manual/de/dist/pdf/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 manual/de/dist/ps/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 manual/de/dist/txt/Makefile.am; cvs diff -u -r 1.1.2.5 -r 1.1.2.6 manual/dist/html/Makefile.am; cvs diff -u -r 1.1.2.6 -r 1.1.2.7 manual/dist/pdf/Makefile.am; cvs diff -u -r 1.1.2.5 -r 1.1.2.6 manual/dist/ps/Makefile.am; cvs diff -u -r 1.1.2.5 -r 1.1.2.6 manual/dist/txt/Makefile.am; cvs diff -u -r 1.1.2.2 -r 1.1.2.3 manual/es/dist/html/Makefile.am; cvs diff -u -r 1.1.2.2 -r 1.1.2.3 manual/es/dist/pdf/Makefile.am; cvs diff -u -r 1.1.2.2 -r 1.1.2.3 manual/es/dist/ps/Makefile.am; cvs diff -u -r 1.1.2.2 -r 1.1.2.3 manual/es/dist/txt/Makefile.am; cvs diff -u -r 1.1.2.3 -r 1.1.2.4 manual/fr/dist/html/Makefile.am; cvs diff -u -r 1.1.2.4 -r 1.1.2.5 manual/fr/dist/pdf/Makefile.am; cvs diff -u -r 1.1.2.3 -r 1.1.2.4 manual/fr/dist/ps/Makefile.am; cvs diff -u -r 1.1.2.3 -r 1.1.2.4 manual/fr/dist/txt/Makefile.am; cvs diff -u -r 1.1.2.3 -r 1.1.2.4 manual/pl/dist/html/Makefile.am; cvs diff -u -r 1.1.2.4 -r 1.1.2.5 manual/pl/dist/pdf/Makefile.am; cvs diff -u -r 1.1.2.3 -r 1.1.2.4 manual/pl/dist/ps/Makefile.am; cvs diff -u -r 1.1.2.3 -r 1.1.2.4 manual/pl/dist/txt/Makefile.am; ) > 3.7.6cvs52.patchset ( cvs diff -u -r 1.213.2.196 -r 1.213.2.197 src/folder.c; cvs diff -u -r 1.87.2.61 -r 1.87.2.62 src/folder.h; cvs diff -u -r 1.179.2.251 -r 1.179.2.252 src/imap.c; cvs diff -u -r 1.79.2.69 -r 1.79.2.70 src/mh.c; cvs diff -u -r 1.150.2.115 -r 1.150.2.116 src/procmsg.c; ) > 3.7.6cvs53.patchset ( cvs diff -u -r 1.1.2.7 -r 1.1.2.8 manual/dist/pdf/Makefile.am; ) > 3.7.6cvs54.patchset +( cvs diff -u -r 1.115.2.230 -r 1.115.2.231 src/main.c; cvs diff -u -r 1.1.2.69 -r 1.1.2.70 src/gtk/authors.h; cvs diff -u -r 1.1.2.96 -r 1.1.2.97 src/gtk/quicksearch.c; cvs diff -u -r 1.1.2.19 -r 1.1.2.20 src/gtk/quicksearch.h; ) > 3.7.6cvs55.patchset diff --git a/configure.ac b/configure.ac index cce56821b..94a41fa07 100644 --- a/configure.ac +++ b/configure.ac @@ -12,7 +12,7 @@ MINOR_VERSION=7 MICRO_VERSION=6 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=54 +EXTRA_VERSION=55 EXTRA_RELEASE= EXTRA_GTK2_VERSION= diff --git a/src/gtk/authors.h b/src/gtk/authors.h index fb826e97c..6af07839c 100644 --- a/src/gtk/authors.h +++ b/src/gtk/authors.h @@ -91,6 +91,7 @@ static char *CONTRIBS_LIST[] = { "M. Benkmann", "Wilbert Berendsen", "Didier Barvaux", +"Sébastien Bigaret", "Laurent Bigonville", "Jean-Luc Biord", "Pavlo Bohmat", diff --git a/src/gtk/quicksearch.c b/src/gtk/quicksearch.c index 250146e02..5600f186c 100644 --- a/src/gtk/quicksearch.c +++ b/src/gtk/quicksearch.c @@ -44,6 +44,15 @@ #include "claws.h" #include "statusbar.h" +struct _QuickSearchRequest +{ + QuickSearchType type; + gchar *matchstring; + FolderItem *folderItem; + gboolean recursive; +}; +typedef struct _QuickSearchRequest QuickSearchRequest; + struct _QuickSearch { GtkWidget *hbox_search; @@ -58,6 +67,7 @@ struct _QuickSearch gchar *search_string; MatcherList *matcher_list; + QuickSearchRequest *request; QuickSearchExecuteCallback callback; gpointer callback_data; gboolean running; @@ -75,22 +85,38 @@ struct _QuickSearch /* dynamic and autorun qs settings are exclusive*/ GtkWidget *dynamic_menuitem; GtkWidget *autorun_menuitem; + + gboolean gui; }; static void quicksearch_set_running(QuickSearch *quicksearch, gboolean run); +static void quicksearch_set_matchstring(QuickSearch *quicksearch, const gchar *matchstring); static void quicksearch_set_active(QuickSearch *quicksearch, gboolean active); static void quicksearch_reset_folder_items(QuickSearch *quicksearch, FolderItem *folder_item); static gchar *expand_search_string(const gchar *str); static gchar *expand_tag_search_string(const gchar *str); +static gboolean quicksearch_from_gui(QuickSearch *quicksearch) +{ + return quicksearch->gui; +} + gboolean quicksearch_is_fast(QuickSearch *quicksearch) { return quicksearch->is_fast; } +void quicksearch_set_recursive(QuickSearch *quicksearch, gboolean recursive) +{ + quicksearch->request->recursive = recursive; +} + static void quicksearch_set_type(QuickSearch *quicksearch, gint type) { gint index; + quicksearch->request->type = type; + if (quicksearch->gui == FALSE) + return; index = menu_find_option_menu_index(GTK_CMOPTION_MENU(quicksearch->search_type_opt), GINT_TO_POINTER(type), NULL); @@ -121,7 +147,22 @@ static void quicksearch_set_popdown_strings(QuickSearch *quicksearch) static void prepare_matcher(QuickSearch *quicksearch) { - gchar *search_string = quicksearch_get_text(quicksearch); + /* param search_string is "matchstring" */ + const gchar *search_string; + QuickSearchType quicksearch_type; + + if (quicksearch == NULL) + return; + + /* When called from the GUI, reset type and matchstring */ + if (quicksearch_from_gui(quicksearch)) { + gchar *s = quicksearch_get_text(quicksearch); + quicksearch_set_matchstring(quicksearch, s); + g_free(s); + quicksearch->request->type = prefs_common.summary_quicksearch_type; + } + quicksearch_type = quicksearch->request->type; + search_string = quicksearch->request->matchstring; if (search_string == NULL || search_string[0] == '\0') { quicksearch_set_active(quicksearch, FALSE); @@ -130,7 +171,6 @@ static void prepare_matcher(QuickSearch *quicksearch) if (quicksearch->matcher_list != NULL) { if (quicksearch->matching) { quicksearch->deferred_free = TRUE; - g_free(search_string); return; } quicksearch->deferred_free = FALSE; @@ -139,11 +179,9 @@ static void prepare_matcher(QuickSearch *quicksearch) } if (search_string == NULL || search_string[0] == '\0') { - g_free(search_string); return; } - - if (prefs_common.summary_quicksearch_type == QUICK_SEARCH_EXTENDED) { + if (quicksearch_type == QUICK_SEARCH_EXTENDED) { char *newstr = NULL; newstr = expand_search_string(search_string); @@ -153,14 +191,13 @@ static void prepare_matcher(QuickSearch *quicksearch) } else { quicksearch->matcher_list = NULL; quicksearch_set_active(quicksearch, FALSE); - g_free(search_string); return; } - } else if (prefs_common.summary_quicksearch_type == QUICK_SEARCH_TAG) { + } else if (quicksearch_type == QUICK_SEARCH_TAG) { char *newstr = expand_tag_search_string(search_string); quicksearch->matcher_list = matcher_parser_get_cond(newstr, &quicksearch->is_fast); g_free(newstr); - } else if (prefs_common.summary_quicksearch_type == QUICK_SEARCH_MIXED) { + } else if (quicksearch_type == QUICK_SEARCH_MIXED) { char *newstr = expand_tag_search_string(search_string); quicksearch->matcher_list = matcher_parser_get_cond(newstr, &quicksearch->is_fast); g_free(newstr); @@ -171,8 +208,6 @@ static void prepare_matcher(QuickSearch *quicksearch) g_free(quicksearch->search_string); quicksearch->search_string = g_utf8_casefold(search_string, -1); } - - g_free(search_string); quicksearch_set_active(quicksearch, TRUE); } @@ -216,7 +251,7 @@ gboolean quicksearch_has_focus(QuickSearch *quicksearch) static void searchbar_run(QuickSearch *quicksearch, gboolean run_only_if_fast) { gchar *search_string = quicksearch_get_text(quicksearch); - + quicksearch_set_matchstring(quicksearch, search_string); prepare_matcher(quicksearch); /* add to history, for extended search add only correct matching rules */ @@ -345,6 +380,7 @@ static gboolean searchtype_changed(GtkMenuItem *widget, gpointer data) { QuickSearch *quicksearch = (QuickSearch *)data; gchar *search_string = quicksearch_get_text(quicksearch); + quicksearch_set_matchstring(quicksearch, search_string); prefs_common.summary_quicksearch_type = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(GTK_MENU_ITEM(gtk_menu_get_active( @@ -374,8 +410,11 @@ static gboolean searchtype_recursive_changed(GtkMenuItem *widget, gpointer data) QuickSearch *quicksearch = (QuickSearch *)data; gboolean checked = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); gchar *search_string = quicksearch_get_text(quicksearch); + /* not needed to quicksearch_set_matchstring(search_string); + wait for prepare_matcher() */ prefs_common.summary_quicksearch_recurse = checked; + quicksearch_set_recursive(quicksearch, checked); /* reselect the search type */ quicksearch_set_type(quicksearch, prefs_common.summary_quicksearch_type); @@ -598,6 +637,43 @@ static void quicksearch_set_button(GtkButton *button, const gchar *icon, const g gtk_widget_show_all(box); } +/* + * Builds a new QuickSearchRequest + */ +static QuickSearchRequest *quicksearchrequest_new(void) +{ + QuickSearchRequest *request; + request = g_new0(QuickSearchRequest, 1); + return request; +} + +/* + * Builds a new QuickSearch object independent from the GUI + */ +QuickSearch *quicksearch_new_nogui(void) +{ + QuickSearch *quicksearch; + QuickSearchRequest *request; + + request = quicksearchrequest_new(); + quicksearch = g_new0(QuickSearch, 1); + quicksearch->request = request; + quicksearch->gui = FALSE; + + /* init. values initally found in quicksearch_new(). + There's no need to init. all pointers to NULL since we use g_new0 + */ + quicksearch->matcher_list = NULL; + quicksearch->active = FALSE; + quicksearch->running = FALSE; + quicksearch->in_typing = FALSE; + quicksearch->press_timeout_id = -1; + quicksearch->normal_search_strings = NULL; + quicksearch->extended_search_strings = NULL; + + return quicksearch; +} + QuickSearch *quicksearch_new() { QuickSearch *quicksearch; @@ -614,7 +690,8 @@ QuickSearch *quicksearch_new() CLAWS_TIP_DECL(); GtkWidget *vbox; - quicksearch = g_new0(QuickSearch, 1); + quicksearch = quicksearch_new_nogui(); + quicksearch->gui = TRUE; /* quick search */ hbox_search = gtk_hbox_new(FALSE, 0); @@ -661,7 +738,7 @@ QuickSearch *quicksearch_new() gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), prefs_common.summary_quicksearch_recurse); - + quicksearch_set_recursive(quicksearch, prefs_common.summary_quicksearch_recurse); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(searchtype_recursive_changed), quicksearch); @@ -848,6 +925,19 @@ void quicksearch_hide(QuickSearch *quicksearch) gtk_widget_hide(quicksearch->hbox_search); } +/* + *\brief Sets the matchstring. + * + *\param quicksearch quicksearch to set + *\param matchstring the match string; it is duplicated, not stored + */ +static void quicksearch_set_matchstring(QuickSearch *quicksearch, + const gchar *matchstring) +{ + g_free(quicksearch->request->matchstring); + quicksearch->request->matchstring = g_strdup(matchstring); +} + void quicksearch_set(QuickSearch *quicksearch, QuickSearchType type, const gchar *matchstring) { @@ -856,12 +946,20 @@ void quicksearch_set(QuickSearch *quicksearch, QuickSearchType type, if (!matchstring || !(*matchstring)) quicksearch->in_typing = FALSE; + quicksearch_set_matchstring(quicksearch, matchstring); + + if (!quicksearch_from_gui(quicksearch)) { + prepare_matcher(quicksearch); + /* no callback */ + return; + } + g_signal_handlers_block_by_func(G_OBJECT(gtk_bin_get_child(GTK_BIN((quicksearch->search_string_entry)))), - G_CALLBACK(searchbar_changed_cb), quicksearch); + G_CALLBACK(searchbar_changed_cb), quicksearch); gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN((quicksearch->search_string_entry)))), matchstring); g_signal_handlers_unblock_by_func(G_OBJECT(gtk_bin_get_child(GTK_BIN((quicksearch->search_string_entry)))), - G_CALLBACK(searchbar_changed_cb), quicksearch); + G_CALLBACK(searchbar_changed_cb), quicksearch); prefs_common.summary_quicksearch_type = type; @@ -888,6 +986,11 @@ static void quicksearch_set_active(QuickSearch *quicksearch, gboolean active) static gboolean colors_initialised = FALSE; gboolean error = FALSE; + + quicksearch->active = active; + if (quicksearch->gui == FALSE) + return; + if (!colors_initialised) { gdk_color_parse("#f5f6be", &yellow); gdk_color_parse("#000000", &black); @@ -900,8 +1003,6 @@ static void quicksearch_set_active(QuickSearch *quicksearch, gboolean active) gdk_colormap_get_system(), &red, FALSE, TRUE); } - quicksearch->active = active; - if (active && (prefs_common.summary_quicksearch_type == QUICK_SEARCH_EXTENDED && quicksearch->matcher_list == NULL)) @@ -947,11 +1048,14 @@ gboolean quicksearch_match(QuickSearch *quicksearch, MsgInfo *msginfo) gchar *searched_header = NULL; gboolean result = FALSE; gchar *to = NULL, *from = NULL, *subject = NULL; + QuickSearchType quicksearch_type; if (!quicksearch->active) return TRUE; - switch (prefs_common.summary_quicksearch_type) { + quicksearch_type = quicksearch->request->type; + + switch (quicksearch_type) { case QUICK_SEARCH_SUBJECT: if (msginfo->subject) searched_header = g_utf8_casefold(msginfo->subject, -1); @@ -981,31 +1085,34 @@ gboolean quicksearch_match(QuickSearch *quicksearch, MsgInfo *msginfo) case QUICK_SEARCH_EXTENDED: break; default: - debug_print("unknown search type (%d)\n", prefs_common.summary_quicksearch_type); + debug_print("unknown search type (%d)\n", quicksearch_type); break; } quicksearch->matching = TRUE; - if (prefs_common.summary_quicksearch_type != QUICK_SEARCH_EXTENDED && - prefs_common.summary_quicksearch_type != QUICK_SEARCH_MIXED && - prefs_common.summary_quicksearch_type != QUICK_SEARCH_TAG && + if (quicksearch_type != QUICK_SEARCH_EXTENDED && + quicksearch_type != QUICK_SEARCH_MIXED && + quicksearch_type != QUICK_SEARCH_TAG && quicksearch->search_string && - searched_header && strstr(searched_header, quicksearch->search_string) != NULL) + searched_header && strstr(searched_header, quicksearch->search_string) != NULL) result = TRUE; - else if (prefs_common.summary_quicksearch_type == QUICK_SEARCH_MIXED && + else if (quicksearch_type == QUICK_SEARCH_MIXED && quicksearch->search_string && ( (to && strstr(to, quicksearch->search_string) != NULL) || (from && strstr(from, quicksearch->search_string) != NULL) || (subject && strstr(subject, quicksearch->search_string) != NULL) || ((quicksearch->matcher_list != NULL) && - matcherlist_match(quicksearch->matcher_list, msginfo)) )) + matcherlist_match(quicksearch->matcher_list, msginfo)) )) result = TRUE; else if ((quicksearch->matcher_list != NULL) && - matcherlist_match(quicksearch->matcher_list, msginfo)) + matcherlist_match(quicksearch->matcher_list, msginfo)) result = TRUE; quicksearch->matching = FALSE; - if (quicksearch->deferred_free) { + if (quicksearch_from_gui(quicksearch)==TRUE && quicksearch->deferred_free) { + /* Ref. http://lists.claws-mail.org/pipermail/users/2010-August/003063.html + See also 2.0.0cvs140 ChangeLog entry + and comment in search_msgs_in_folder() */ prepare_matcher(quicksearch); } @@ -1432,3 +1539,108 @@ void quicksearch_set_search_strings(QuickSearch *quicksearch) quicksearch_set_popdown_strings(quicksearch); } + +/* + * Searches in the supplied folderItem the messages (MessageInfo) matching a + * QuickSearchType + search string (ex.: QUICK_SEARCH_FROM and "foo@bar.com"). + * + * Found messages are appended to the array 'messages' and their ref.counts + * are incremented by 1 --so they need to be released (procmsg_msginfo_free()) + * before the array 'messages' is freed. + */ +void search_msgs_in_folder(GSList **messages, QuickSearch* quicksearch, + FolderItem* folderItem) +{ + /* from quicksearch_match_subfolder */ + GSList *msglist = NULL; + GSList *cur; + + /* The list is built w/ MsgInfo items whose ref.counts are incremented, + but they are decremented when the list is freed by + procmsg_msg_list_free(): we'll ask for a new ref., below + */ + msglist = folder_item_get_msg_list(folderItem); + + for (cur = msglist; cur != NULL; cur = cur->next) { + MsgInfo *msg = (MsgInfo *)cur->data; + if (quicksearch_match(quicksearch, msg)) { + /*debug_print("found: %s from:%s\n",procmsg_get_message_file_path(msg),msg->from);*/ + *messages = g_slist_prepend(*messages, procmsg_msginfo_new_ref(msg)); + } + /* See 2.0.0cvs140 ChangeLog entry for details + see also comments in quicksearch_match() */ + if (quicksearch_from_gui(quicksearch)==TRUE + && !quicksearch_is_active(quicksearch)) + break; + } + procmsg_msg_list_free(msglist); +} + +/* + * Searches within the folderItem and its sub-folders (if recursive is TRUE) + * the messages matching the search request. + * + * NB: search within a Folder can be done this way: + * search_msg_in_folders(messages, quicksearch, searchType, + * FOLDER_ITEM(folder->node->data), TRUE); + */ +void search_msgs_in_folders(GSList **messages, QuickSearch* quicksearch, + FolderItem* folderItem) +{ + FolderItem *cur = NULL; + + search_msgs_in_folder(messages, quicksearch, folderItem); + if (quicksearch->request->recursive == FALSE) + return; + + GNode *node = folderItem->node->children; + for (; node != NULL; node = node->next) { + cur = FOLDER_ITEM(node->data); + debug_print("in: %s\n",cur->path); + search_msgs_in_folder(messages, quicksearch, cur); + if (cur->node->children) + search_msgs_in_folders(messages, quicksearch, cur); + } + *messages = g_slist_reverse(*messages); +} + +/* +static void search_msg_folder(GSList **messages, QuickSearch* quicksearch, + QuickSearchType searchType, + Folder* folder) +{ + search_msgs_in_folders(messages, quicksearch, searchType, + FOLDER_ITEM(folder->node->data), TRUE); +} +*/ + + /* + * Returns the QuickSearchType associated to the supplied string. + */ +QuickSearchType quicksearch_type(const gchar* type) +{ + QuickSearchType searchType = QUICK_SEARCH_EXTENDED; + if (!type) + return searchType; + switch(toupper(*type)) { + case 'S': + searchType = QUICK_SEARCH_SUBJECT; + break; + case 'F': + searchType = QUICK_SEARCH_FROM; + break; + case 'T': + searchType = QUICK_SEARCH_TO; + break; + case 'E': + searchType = QUICK_SEARCH_EXTENDED; + break; + case 'M': + searchType = QUICK_SEARCH_MIXED; + break; + case 'G': + searchType = QUICK_SEARCH_TAG; + break; + } + return searchType; +} diff --git a/src/gtk/quicksearch.h b/src/gtk/quicksearch.h index 2f5e32188..5adc53ae3 100644 --- a/src/gtk/quicksearch.h +++ b/src/gtk/quicksearch.h @@ -31,16 +31,25 @@ typedef enum QUICK_SEARCH_TAG } QuickSearchType; + typedef struct _QuickSearch QuickSearch; typedef void (*QuickSearchExecuteCallback) (QuickSearch *quicksearch, gpointer data); #include "procmsg.h" +void search_msgs_in_folder(GSList **messages, QuickSearch* quicksearch, + FolderItem* folderItem); +void search_msgs_in_folders(GSList **messages, QuickSearch* quicksearch, + FolderItem* folderItem); +QuickSearchType quicksearch_type(const gchar *type); + QuickSearch *quicksearch_new(); +QuickSearch *quicksearch_new_nogui(); GtkWidget *quicksearch_get_widget(QuickSearch *quicksearch); void quicksearch_show(QuickSearch *quicksearch); void quicksearch_hide(QuickSearch *quicksearch); void quicksearch_set(QuickSearch *quicksearch, QuickSearchType type, const gchar *matchstring); +void quicksearch_set_recursive(QuickSearch *quicksearch, gboolean recursive); gboolean quicksearch_is_active(QuickSearch *quicksearch); void quicksearch_set_execute_callback(QuickSearch *quicksearch, QuickSearchExecuteCallback callback, diff --git a/src/main.c b/src/main.c index 30c26faa1..4b6e9b4d4 100644 --- a/src/main.c +++ b/src/main.c @@ -107,6 +107,7 @@ #include "tags.h" #include "hooks.h" #include "menu.h" +#include "quicksearch.h" #ifdef HAVE_LIBETPAN #include "imap-thread.h" @@ -191,6 +192,11 @@ static struct RemoteCmd { gboolean compose; const gchar *compose_mailto; GPtrArray *attach_files; + gboolean search; + const gchar *search_folder; + const gchar *search_type; + const gchar *search_request; + gboolean search_recursive; gboolean status; gboolean status_full; GPtrArray *status_folders; @@ -1093,7 +1099,7 @@ int main(int argc, char *argv[]) return 0; } - if (cmd.status || cmd.status_full) { + if (cmd.status || cmd.status_full || cmd.search) { puts("0 Claws Mail not running."); lock_socket_remove(); return 0; @@ -1152,7 +1158,9 @@ int main(int argc, char *argv[]) hildon_program = HILDON_PROGRAM(hildon_program_get_instance()); static_osso_context = osso_context; #endif - gtk_widget_set_default_colormap(gdk_rgb_get_colormap()); + gtk_widget_set_default_colormap( + gdk_screen_get_system_colormap( + gdk_screen_get_default())); gui_manager = gtkut_create_ui_manager(); @@ -1883,6 +1891,16 @@ static void parse_cmd_opt(int argc, char *argv[]) i++; p = (i+1 < argc)?argv[i+1]:NULL; } + } else if (!strncmp(argv[i], "--search", 8)) { + cmd.search_folder = (i+1 < argc)?argv[i+1]:NULL; + cmd.search_type = (i+2 < argc)?argv[i+2]:NULL; + cmd.search_request = (i+3 < argc)?argv[i+3]:NULL; + const char* rec = (i+4 < argc)?argv[i+4]:NULL; + cmd.search_recursive = TRUE; + if (rec && (tolower(*rec)=='n' || tolower(*rec)=='f' || *rec=='0')) + cmd.search_recursive = FALSE; + if (cmd.search_folder && cmd.search_type && cmd.search_request) + cmd.search = TRUE; } else if (!strncmp(argv[i], "--online", 8)) { cmd.online_mode = ONLINE_MODE_ONLINE; } else if (!strncmp(argv[i], "--offline", 9)) { @@ -1899,6 +1917,13 @@ static void parse_cmd_opt(int argc, char *argv[]) " attached")); g_print("%s\n", _(" --receive receive new messages")); g_print("%s\n", _(" --receive-all receive new messages of all accounts")); + g_print("%s\n", _(" --search folder type request [recursive]")); + g_print("%s\n", _(" searches mail")); + g_print("%s\n", _(" folder ex.: \"#mh/Mailbox/inbox\" or \"Mail\"")); + g_print("%s\n", _(" type: s[ubject],f[rom],t[o],e[xtended],m[ixed] or g: tag")); + g_print("%s\n", _(" request: search string")); + g_print("%s\n", _(" recursive: false iff arg. starts with 0, n, N, f or F")); + g_print("%s\n", _(" --send send all queued messages")); g_print("%s\n", _(" --status [folder]... show the total number of messages")); g_print("%s\n", _(" --status-full [folder]...\n" @@ -2252,6 +2277,19 @@ static gint prohibit_duplicate_launch(void) gchar *str = g_strdup_printf("select %s\n", cmd.target); fd_write_all(uxsock, str, strlen(str)); g_free(str); + } else if (cmd.search) { + gchar buf[BUFFSIZE]; + gchar *str = + g_strdup_printf("search %s\n%s\n%s\n%c\n", + cmd.search_folder, cmd.search_type, cmd.search_request, + (cmd.search_recursive==TRUE)?'1':'0'); + fd_write_all(uxsock, str, strlen(str)); + g_free(str); + for (;;) { + fd_gets(uxsock, buf, sizeof(buf)); + if (!strncmp(buf, ".\n", 2)) break; + fputs(buf, stdout); + } } else { #ifndef G_OS_WIN32 gchar buf[BUFSIZ]; @@ -2330,6 +2368,8 @@ static void lock_socket_input_cb(gpointer data, MainWindow *mainwin = (MainWindow *)data; gint sock; gchar buf[BUFFSIZE]; + /* re-use the same quicksearch (& avoid matcher_list mem.leaks) */ + static QuickSearch *quicksearch = NULL; sock = fd_accept(source); fd_gets(sock, buf, sizeof(buf)); @@ -2385,14 +2425,80 @@ static void lock_socket_input_cb(gpointer data, } else if (!strncmp(buf, "select ", 7)) { const gchar *target = buf+7; mainwindow_jump_to(target, TRUE); + } else if (!strncmp(buf, "search ", 7)) { + FolderItem* folderItem = NULL; + GSList *messages = NULL; + gchar *folder_name, *request; + QuickSearchType searchType = QUICK_SEARCH_EXTENDED; + gboolean recursive; + + if (quicksearch==NULL) + quicksearch = quicksearch_new_nogui(); + + folder_name = g_strdup(buf+7); + strretchomp(folder_name); + + if (fd_gets(sock, buf, sizeof(buf)) <= 0) { + g_free(folder_name); + folder_name=NULL; + } + searchType = quicksearch_type(buf); + if (fd_gets(sock, buf, sizeof(buf)) <= 0) { + g_free(folder_name); + folder_name=NULL; + } + request = g_strdup(buf); + strretchomp(request); + + recursive = TRUE; + if (fd_gets(sock, buf, sizeof(buf)) > 0) + if (buf[0]=='0') + recursive = FALSE; + + debug_print("search: %s %i %s %i\n",folder_name,searchType,request,recursive); + + if (folder_name) + folderItem = folder_find_item_from_identifier(folder_name); + if (folder_name && folderItem == NULL) { + debug_print("Unknow folder item : '%s', searching folder\n",folder_name); + Folder* folder = folder_find_from_path(folder_name); + if (folder != NULL) + folderItem = FOLDER_ITEM(folder->node->data); + else + debug_print("Unknown folder: '%s'\n",folder_name); + } else { + debug_print("%s %s\n",folderItem->name, folderItem->path); + } + if (folderItem != NULL) { + quicksearch_set(quicksearch, searchType, request); + quicksearch_set_recursive(quicksearch, recursive); + search_msgs_in_folders(&messages, quicksearch, folderItem); + } else { + g_print("Folder '%s' not found.\n'", folder_name); + } + + GSList *cur; + for (cur=messages; cur != NULL; cur = cur->next) { + MsgInfo* msg = (MsgInfo *)cur->data; + gchar *file = procmsg_get_message_file_path(msg); + fd_write_all(sock, file, strlen(file)); + fd_write_all(sock, "\n", 1); + g_free(file); + } + fd_write_all(sock, ".\n", 2); + + if (messages != NULL) + procmsg_msg_list_free(messages); + g_free(folder_name); + g_free(request); } else if (!strncmp(buf, "exit", 4)) { if (prefs_common.clean_on_exit && !prefs_common.ask_on_clean) { procmsg_empty_all_trash(); } app_will_exit(NULL, mainwin); } - fd_close(sock); + } static void open_compose_new(const gchar *address, GPtrArray *attach_files)