Allow Mutt-like patterns in quick search.
authorDarko Koruga <darko@users.sourceforge.net>
Thu, 5 Dec 2002 10:31:11 +0000 (10:31 +0000)
committerDarko Koruga <darko@users.sourceforge.net>
Thu, 5 Dec 2002 10:31:11 +0000 (10:31 +0000)
ChangeLog.claws
README.claws
configure.in
src/common/utils.c
src/common/utils.h
src/summaryview.c

index 337da46..54b4eae 100644 (file)
@@ -1,3 +1,15 @@
+2002-12-05 [darko]     0.8.6claws62
+
+       * src/utils.[ch]
+               expand_search_string(): new function
+               converts Mutt-like patterns to Sylpheed's
+               filtering engine
+       * src/summaryview.c
+               use expand_search_string() to allow Mutt-like
+               patterns in extended search
+       * README.claws
+               document extended option in quick search
+
 2002-12-05 [paul]      0.8.6claws61
 
        * sync with 0.8.6cvs16
index 9241332..878dae0 100644 (file)
@@ -19,6 +19,7 @@ Summary:
    * spell checking (with installation instructions)
    * new cache
    * selective download, delete messages on server
+   * extended search in quick search
 4. How to contribute
 5. How to request features
 6. Installing Claws from CVS
@@ -470,6 +471,67 @@ mention it.
                - select "Dillo: dillo %p&" from drop down list
                - choose an icon and click ok
        
+* quick search
+---------------------------------
+    This feature allows one to define criteria that messages have
+    to match in order to be displayed in the summary view pane.
+    Search types titled From, Subject and To are self explanatory.
+    Search type extended allows one to use Sylpheed's powerful
+    filtering engine to select messages. Examples:
+    from regexpcase "foo"
+    subject regexp "Bug" & to regexp "sylpheed-claws"
+
+    Additionally, it is possible to use simpler yet equally
+    powerfull patterns for message selections. Mutt users will
+    immediately recognize most of the available patterns:
+
+    Pattern  Parameter  Selects
+    ----------------------------------------------------
+    a                   all messages
+    ag       #          messages whose age is greater than #
+    al       #          messages whose age is lower than #
+    b        S          messages which contain S in the message body
+    B        S          messages which contain S in the whole message
+    c        S          messages carbon-copied to S
+    C        S          message is either to: or cc: to S
+    D                   deleted messages
+    e        S          messages which contain S in the Sender field
+    E        S          true if execute "S" succeeds
+    f        S          messages originating from user S
+    F                   forwarded messages
+    h        S          messages which contain header S
+    i        S          messages which contain S in Message-Id header
+    I        S          messages which contain S in inreplyto header
+    n        S          messages which are in newsgroup S
+    N                   new messages
+    O                   old messages
+    r                   messages which have been replied to
+    R                   read messages
+    s        S          messages which contain S in subject
+    se       #          messages whose score is equal to #
+    sg       #          messages whose score is greater than #
+    sl       #          messages whose score is lower than #
+    Se       #          messages whose size is equal to #
+    Sg       #          messages whose size is greater than #
+    Ss       #          messages whose size is smaller than #
+    t        S          messages which have been sent to S
+    T                   marked marked
+    U                   unread messages
+    x        S          messages which contain S in References header
+    y        S          messages which contain S in X-Label header
+
+    # means number
+    S means regexp string
+
+    It is possible to use logical operators AND (&), OR (|) and
+    NOT (! or ~). Case sensitive search is achieved with %.
+    Examples:
+    T                  marked messages
+    U                  unread messages
+    f "john beavis"    messages from john beavis
+    %f "John Beavis"   messages from John Beavis (case sensitive)
+    ~s foo             messages which do not have foo in the subject
+    f foo & s bar      messages from foo that do not have bar in thesubject
 
 
 4. How to contribute
index 1dcd57d..884ac94 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=8
 MICRO_VERSION=6
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=claws61
+EXTRA_VERSION=claws62
 VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION$EXTRA_VERSION
 
 dnl set $target
index 7016e41..b0491f5 100644 (file)
@@ -3026,3 +3026,205 @@ FILE *get_tmpfile_in_dir(const gchar *dir, gchar **filename)
 
        return fdopen(fd, "w+");
 }
+
+/* allow Mutt-like patterns in quick search */
+gchar *expand_search_string(const gchar *search_string)
+{
+       int i, len, new_len = 0;
+       gchar term_char, save_char;
+       gchar *cmd_start, *cmd_end;
+       gchar *new_str = NULL;
+       gchar *copy_str;
+       gboolean casesens, dontmatch;
+       /* list of allowed pattern abbreviations */
+       struct {
+               gchar           *abbreviated;   /* abbreviation */
+               gchar           *command;       /* actual matcher command */ 
+               gint            numparams;      /* number of params for cmd */
+               gboolean        qualifier;      /* do we append regexpcase */
+               gboolean        quotes;         /* do we need quotes */
+       }
+       cmds[] = {
+               { "a",  "all",                          0,      FALSE,  FALSE },
+               { "ag", "age_greater",                  1,      FALSE,  FALSE },
+               { "al", "age_lower",                    1,      FALSE,  FALSE },
+               { "b",  "body_part",                    1,      TRUE,   TRUE  },
+               { "B",  "message",                      1,      TRUE,   TRUE  },
+               { "c",  "cc",                           1,      TRUE,   TRUE  },
+               { "C",  "to_or_cc",                     1,      TRUE,   TRUE  },
+               { "D",  "deleted",                      0,      FALSE,  FALSE },
+               { "e",  "header \"Sender\"",            1,      TRUE,   TRUE  },
+               { "E",  "execute",                      1,      FALSE,  TRUE  },
+               { "f",  "from",                         1,      TRUE,   TRUE  },
+               { "F",  "forwarded",                    0,      FALSE,  FALSE },
+               { "h",  "headers_part",                 1,      TRUE,   TRUE  },
+               { "i",  "header \"Message-Id\"",        1,      TRUE,   TRUE  },
+               { "I",  "inreplyto",                    1,      TRUE,   TRUE  },
+               { "n",  "newsgroups",                   1,      TRUE,   TRUE  },
+               { "N",  "new",                          0,      FALSE,  FALSE },
+               { "O",  "~new",                         0,      FALSE,  FALSE },
+               { "r",  "replied",                      0,      FALSE,  FALSE },
+               { "R",  "~unread",                      0,      FALSE,  FALSE },
+               { "s",  "subject",                      1,      TRUE,   TRUE  },
+               { "se", "score_equal",                  1,      FALSE,  FALSE },
+               { "sg", "score_greater",                1,      FALSE,  FALSE },
+               { "sl", "score_lower",                  1,      FALSE,  FALSE },
+               { "Se", "size_equal",                   1,      FALSE,  FALSE },
+               { "Sg", "size_greater",                 1,      FALSE,  FALSE },
+               { "Ss", "size_smaller",                 1,      FALSE,  FALSE },
+               { "t",  "to",                           1,      TRUE,   TRUE  },
+               { "T",  "marked",                       0,      FALSE,  FALSE },
+               { "U",  "unread",                       0,      FALSE,  FALSE },
+               { "x",  "header \"References\"",        1,      TRUE,   TRUE  },
+               { "y",  "header \"X-Label\"",           1,      TRUE,   TRUE  },
+               { "&",  "&",                            0,      FALSE,  FALSE },
+               { "|",  "|",                            0,      FALSE,  FALSE },
+               { NULL, NULL,                           0,      FALSE,  FALSE }
+       };
+
+       if (copy_str == NULL)
+               return NULL;
+
+       copy_str = g_strdup(search_string);
+
+       /* if it's a full command don't process it so users
+          can still do something like from regexpcase "foo" */
+       for (i = 0; cmds[i].command; i++) {
+               cmd_start = cmds[i].command;
+               /* allow logical NOT */
+               if (*cmd_start == '~')
+                       cmd_start++;
+               if (!strncmp(copy_str, cmd_start, strlen(cmd_start)))
+                       break;
+       }
+       if (cmds[i].command)
+               return copy_str;
+
+       cmd_start = cmd_end = copy_str;
+       while (cmd_end && *cmd_end) {
+               /* skip all white spaces */
+               while (*cmd_end && isspace(*cmd_end))
+                       cmd_end++;
+
+               /* extract a command */
+               while (*cmd_end && !isspace(*cmd_end))
+                       cmd_end++;
+
+               /* save character */
+               save_char = *cmd_end;
+               *cmd_end = '\0';
+
+               dontmatch = FALSE;
+               casesens = FALSE;
+
+               /* ~ and ! mean logical NOT */
+               if (*cmd_start == '~' || *cmd_start == '!')
+               {
+                       dontmatch = TRUE;
+                       cmd_start++;
+               }
+               /* % means case sensitive match */
+               if (*cmd_start == '%')
+               {
+                       casesens = TRUE;
+                       cmd_start++;
+               }
+
+               /* find matching abbreviation */
+               for (i = 0; cmds[i].command; i++) {
+                       if (!strcmp(cmd_start, cmds[i].abbreviated)) {
+                               /* restore character */
+                               *cmd_end = save_char;
+                               len = strlen(cmds[i].command) + 1;
+                               if (dontmatch)
+                                       len++;
+                               if (casesens)
+                                       len++;
+
+                               /* copy command */
+                               if (new_str) {
+                                       new_len += 1;
+                                       new_str = g_realloc(new_str, new_len);
+                                       strcat(new_str, " ");
+                               }
+                               new_len += (len + 1);
+                               new_str = g_realloc(new_str, new_len);
+                               if (new_len == len + 1)
+                                       *new_str = '\0';
+                               if (dontmatch)
+                                       strcat(new_str, "~");
+                               strcat(new_str, cmds[i].command);
+                               strcat(new_str, " ");
+
+                               /* stop if no params required */
+                               if (cmds[i].numparams == 0)
+                                       break;
+
+                               /* extract a parameter, allow quotes */
+                               cmd_end++;
+                               cmd_start = cmd_end;
+                               if (*cmd_start == '"') {
+                                       term_char = '"';
+                                       cmd_end++;
+                               }
+                               else
+                                       term_char = ' ';
+
+                               /* extract actual parameter */
+                               while ((*cmd_end) && (*cmd_end != term_char))
+                                       cmd_end++;
+
+                               if (*cmd_end && (*cmd_end != term_char))
+                                       break;
+
+                               if (*cmd_end == '"')
+                                       cmd_end++;
+
+                               save_char = *cmd_end;
+                               *cmd_end = '\0';
+
+                               new_len += strlen(cmd_start);
+
+                               /* do we need to add regexpcase ? */
+                               if (cmds[i].qualifier)
+                                       new_len += 10; /* "regexpcase " */
+
+                               if (term_char != '"')
+                                       new_len += 2;
+                               new_str = g_realloc(new_str, new_len);
+
+                               if (cmds[i].qualifier) {
+                                       if (casesens)
+                                               strcat(new_str, "regexp ");
+                                       else
+                                               strcat(new_str, "regexpcase ");
+                               }
+
+                               /* do we need to add quotes ? */
+                               if (cmds[i].quotes && term_char != '"')
+                                       strcat(new_str, "\"");
+
+                               /* copy actual parameter */
+                               strcat(new_str, cmd_start);
+
+                               /* do we need to add quotes ? */
+                               if (cmds[i].quotes && term_char != '"')
+                                       strcat(new_str, "\"");
+
+                               /* restore original character */
+                               *cmd_end = save_char;
+
+                               break;
+                       }
+               }
+
+               if (*cmd_end) {
+                       cmd_end++;
+                       cmd_start = cmd_end;
+               }
+       }
+
+       g_free(copy_str);
+       return new_str;
+}
+
index 260fbb3..c33f201 100644 (file)
@@ -401,5 +401,7 @@ const gchar * line_has_quote_char   (const gchar *str,
 const gchar * line_has_quote_char_last (const gchar *str,
                                         const gchar *quote_chars);
 
+/* used in extended search */
+gchar * expand_search_string   (const gchar *str);
 
 #endif /* __UTILS_H__ */
index ff87ecc..a4ea7db 100644 (file)
@@ -921,8 +921,17 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                gchar *searched_header = NULL;
                MatcherList * tmp_list = NULL;
                
-               if (search_type == S_SEARCH_EXTENDED)
-                       tmp_list = matcher_parser_get_cond(search_string);
+               if (search_type == S_SEARCH_EXTENDED) {
+                       char *newstr;
+
+                       newstr = expand_search_string(search_string);
+                       if (newstr) {
+                               tmp_list = matcher_parser_get_cond(newstr);
+                               g_free(newstr);
+                       }
+                       else
+                               tmp_list = NULL;
+               }
 
                not_killed = NULL;
                for (cur = mlist ; cur != NULL ; cur = g_slist_next(cur)) {