Added locked pattern to extended search.
[claws.git] / src / common / utils.c
index 7016e41..3ce408a 100644 (file)
@@ -470,52 +470,29 @@ wchar_t *wcscasestr(const wchar_t *haystack, const wchar_t *needle)
 }
 
 /* Examine if next block is non-ASCII string */
-gboolean is_next_nonascii(const wchar_t *s)
+gboolean is_next_nonascii(const guchar *s)
 {
-       const wchar_t *wp;
+       const guchar *p;
 
        /* skip head space */
-       for (wp = s; *wp != (wchar_t)0 && iswspace(*wp); wp++)
+       for (p = s; *p != '\0' && isspace(*p); p++)
                ;
-       for (; *wp != (wchar_t)0 && !iswspace(*wp); wp++) {
-               if (*wp > 127)
+       for (; *p != '\0' && !isspace(*p); p++) {
+               if (*p > 127 || *p < 32)
                        return TRUE;
        }
 
        return FALSE;
 }
 
-/* Examine if next block is multi-byte string */
-gboolean is_next_mbs(const wchar_t *s)
+gint get_next_word_len(const gchar *s)
 {
-       gint mbl;
-       const wchar_t *wp;
-       gchar tmp[MB_LEN_MAX];
+       gint len = 0;
 
-       /* skip head space */
-       for (wp = s; *wp != (wchar_t)0 && iswspace(*wp); wp++)
-               ;
-       for (; *wp != (wchar_t)0 && !iswspace(*wp); wp++) {
-               mbl = wctomb(tmp, *wp);
-               if (mbl > 1)
-                       return TRUE;
-       }
-
-       return FALSE;
-}
-
-wchar_t *find_wspace(const wchar_t *s)
-{
-       const wchar_t *wp;
-
-       for (wp = s; *wp != (wchar_t)0 && iswspace(*wp); wp++)
+       for (; *s != '\0' && !isspace(*s); s++, len++)
                ;
-       for (; *wp != (wchar_t)0; wp++) {
-               if (iswspace(*wp))
-                       return (wchar_t *)wp;
-       }
 
-       return NULL;
+       return len;
 }
 
 /* compare subjects */
@@ -2086,7 +2063,7 @@ gint copy_file(const gchar *src, const gchar *dest)
                while (len > 0) {
                        n_write = write(dest_fd, bufp, len);
                        if (n_write <= 0) {
-                               g_warning(_("writing to %s failed.\n"), dest);
+                               g_warning("writing to %s failed.\n", dest);
                                close(dest_fd);
                                close(src_fd);
                                unlink(dest);
@@ -2106,7 +2083,7 @@ gint copy_file(const gchar *src, const gchar *dest)
        close(dest_fd);
 
        if (n_read < 0 || get_file_size(src) != get_file_size(dest)) {
-               g_warning(_("File copy from %s to %s failed.\n"), src, dest);
+               g_warning("File copy from %s to %s failed.\n", src, dest);
                unlink(dest);
                if (dest_bak) {
                        if (rename(dest_bak, dest) < 0)
@@ -2147,14 +2124,14 @@ gint append_file(const gchar *src, const gchar *dest, gboolean keep_backup)
 
        if (change_file_mode_rw(dest_fp, dest) < 0) {
                FILE_OP_ERROR(dest, "chmod");
-               g_warning(_("can't change file mode\n"));
+               g_warning("can't change file mode\n");
        }
 
        while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), src_fp)) > 0) {
                if (n_read < sizeof(buf) && ferror(src_fp))
                        break;
                if (fwrite(buf, n_read, 1, dest_fp) < 1) {
-                       g_warning(_("writing to %s failed.\n"), dest);
+                       g_warning("writing to %s failed.\n", dest);
                        fclose(dest_fp);
                        fclose(src_fp);
                        unlink(dest);
@@ -2215,14 +2192,14 @@ gint copy_file(const gchar *src, const gchar *dest, gboolean keep_backup)
 
        if (change_file_mode_rw(dest_fp, dest) < 0) {
                FILE_OP_ERROR(dest, "chmod");
-               g_warning(_("can't change file mode\n"));
+               g_warning("can't change file mode\n");
        }
 
        while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), src_fp)) > 0) {
                if (n_read < sizeof(buf) && ferror(src_fp))
                        break;
                if (fwrite(buf, n_read, 1, dest_fp) < 1) {
-                       g_warning(_("writing to %s failed.\n"), dest);
+                       g_warning("writing to %s failed.\n", dest);
                        fclose(dest_fp);
                        fclose(src_fp);
                        unlink(dest);
@@ -2314,7 +2291,7 @@ gint copy_file_part(FILE *fp, off_t offset, size_t length, const gchar *dest)
                if (n_read < to_read && ferror(fp))
                        break;
                if (fwrite(buf, n_read, 1, dest_fp) < 1) {
-                       g_warning(_("writing to %s failed.\n"), dest);
+                       g_warning("writing to %s failed.\n", dest);
                        fclose(dest_fp);
                        unlink(dest);
                        return -1;
@@ -2774,7 +2751,6 @@ void decode_uri(gchar *decoded_uri, const gchar *encoded_uri)
 
 gint open_uri(const gchar *uri, const gchar *cmdline)
 {
-       static gchar *default_cmdline = "netscape -remote openURL(%s,raise)";
        gchar buf[BUFFSIZE];
        gchar *p;
        gchar encoded_uri[BUFFSIZE];
@@ -2790,9 +2766,9 @@ gint open_uri(const gchar *uri, const gchar *cmdline)
                g_snprintf(buf, sizeof(buf), cmdline, encoded_uri);
        else {
                if (cmdline)
-                       g_warning(_("Open URI command line is invalid: `%s'"),
+                       g_warning("Open URI command line is invalid: `%s'",
                                  cmdline);
-               g_snprintf(buf, sizeof(buf), default_cmdline, encoded_uri);
+               g_snprintf(buf, sizeof(buf), DEFAULT_BROWSER_CMD, encoded_uri);
        }
        
        execute_command_line(buf, TRUE);
@@ -3026,3 +3002,190 @@ 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 = 0;
+       gchar term_char, save_char;
+       gchar *cmd_start, *cmd_end;
+       GString *matcherstr;
+       gchar *returnstr = 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  },
+               { "L",  "locked",                       0,      FALSE,  FALSE },
+               { "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 (search_string == 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++) {
+               const gchar *tmp_search_string = search_string;
+               cmd_start = cmds[i].command;
+               /* allow logical NOT */
+               if (*tmp_search_string == '~')
+                       tmp_search_string++;
+               if (!strncmp(tmp_search_string, cmd_start, strlen(cmd_start)))
+                       break;
+       }
+       if (cmds[i].command)
+               return copy_str;
+
+       matcherstr = g_string_sized_new(16);
+       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;
+
+                               /* copy command */
+                               if (matcherstr->len > 0) {
+                                       g_string_append(matcherstr, " ");
+                               }
+                               if (dontmatch)
+                                       g_string_append(matcherstr, "~");
+                               g_string_append(matcherstr, cmds[i].command);
+                               g_string_append(matcherstr, " ");
+
+                               /* 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';
+
+                               if (cmds[i].qualifier) {
+                                       if (casesens)
+                                               g_string_append(matcherstr, "regexp ");
+                                       else
+                                               g_string_append(matcherstr, "regexpcase ");
+                               }
+
+                               /* do we need to add quotes ? */
+                               if (cmds[i].quotes && term_char != '"')
+                                       g_string_append(matcherstr, "\"");
+
+                               /* copy actual parameter */
+                               g_string_append(matcherstr, cmd_start);
+
+                               /* do we need to add quotes ? */
+                               if (cmds[i].quotes && term_char != '"')
+                                       g_string_append(matcherstr, "\"");
+
+                               /* restore original character */
+                               *cmd_end = save_char;
+
+                               break;
+                       }
+               }
+
+               if (*cmd_end) {
+                       cmd_end++;
+                       cmd_start = cmd_end;
+               }
+       }
+
+       g_free(copy_str);
+       returnstr = matcherstr->str;
+       g_string_free(matcherstr, FALSE);
+       return returnstr;
+}
+