X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=pattern.c;h=7813d55ad5889d9b03e6182f6fc56296e4fcbec5;hp=f804c743046a8f59db8f3371b940b6007e826062;hb=616031722dea23d357d8b50d41ae7b40cfdd7d3c;hpb=ba5e3af4ea19e1d20c80941c077039871ec84258 diff --git a/pattern.c b/pattern.c index f804c74..7813d55 100644 --- a/pattern.c +++ b/pattern.c @@ -12,15 +12,25 @@ #endif #include "mutt.h" +#include "buffer.h" +#include "handler.h" +#include "enter.h" +#include "ascii.h" #include "mx.h" #include "mapping.h" #include "keymap.h" #include "copy.h" +#include "mime.h" #include "lib/mem.h" #include "lib/intl.h" #include "lib/str.h" +#ifdef USE_IMAP +#include "mx.h" +#include "imap/imap.h" +#endif + #include #include #include @@ -33,6 +43,7 @@ static int eat_regexp (pattern_t * pat, BUFFER *, BUFFER *); static int eat_date (pattern_t * pat, BUFFER *, BUFFER *); static int eat_range (pattern_t * pat, BUFFER *, BUFFER *); +static int patmatch (const pattern_t* pat, const char* buf); struct pattern_flags { int tag; /* character used to represent this op */ @@ -61,6 +72,7 @@ struct pattern_flags { 'L', M_ADDRESS, 0, eat_regexp}, { 'l', M_LIST, 0, NULL}, { 'm', M_MESSAGE, 0, eat_range}, { + 'M', M_MULTIPART, 0, NULL}, { 'n', M_SCORE, 0, eat_range}, { 'N', M_NEW, 0, NULL}, { 'O', M_OLD, 0, NULL}, { @@ -74,6 +86,7 @@ struct pattern_flags { 'T', M_TAG, 0, NULL}, { 't', M_TO, 0, eat_regexp}, { 'U', M_UNREAD, 0, NULL}, { + 'u', M_SUBSCRIBED_LIST, 0, NULL}, { 'v', M_COLLAPSED, 0, NULL}, { 'V', M_CRYPT_VERIFIED, 0, NULL}, #ifdef USE_NNTP @@ -132,8 +145,7 @@ int mutt_which_case (const char *s) } static int -msg_search (CONTEXT * ctx, regex_t * rx, char *buf, size_t blen, int op, - int msgno) +msg_search (CONTEXT *ctx, pattern_t* pat, int msgno) { char tempfile[_POSIX_PATH_MAX]; MESSAGE *msg = NULL; @@ -143,6 +155,8 @@ msg_search (CONTEXT * ctx, regex_t * rx, char *buf, size_t blen, int op, long lng = 0; int match = 0; HEADER *h = ctx->hdrs[msgno]; + char* buf; + size_t blen; if ((msg = mx_open_message (ctx, msgno)) != NULL) { if (option (OPTTHOROUGHSRC)) { @@ -156,10 +170,10 @@ msg_search (CONTEXT * ctx, regex_t * rx, char *buf, size_t blen, int op, return (0); } - if (op != M_BODY) + if (pat->op != M_BODY) mutt_copy_header (msg->fp, h, s.fpout, CH_FROM | CH_DECODE, NULL); - if (op != M_HEADER) { + if (pat->op != M_HEADER) { mutt_parse_mime_message (ctx, h); if (WithCrypto && (h->security & ENCRYPT) @@ -185,28 +199,36 @@ msg_search (CONTEXT * ctx, regex_t * rx, char *buf, size_t blen, int op, else { /* raw header / body */ fp = msg->fp; - if (op != M_BODY) { + if (pat->op != M_BODY) { fseek (fp, h->offset, 0); lng = h->content->offset - h->offset; } - if (op != M_HEADER) { - if (op == M_BODY) + if (pat->op != M_HEADER) { + if (pat->op == M_BODY) fseek (fp, h->content->offset, 0); lng += h->content->length; } } + blen = STRING; + buf = mem_malloc (blen); + /* search the file "fp" */ while (lng > 0) { - if (fgets (buf, blen - 1, fp) == NULL) + if (pat->op == M_HEADER) { + if (*(buf = mutt_read_rfc822_line (fp, buf, &blen)) == '\0') + break; + } else if (fgets (buf, blen - 1, fp) == NULL) break; /* don't loop forever */ - if (regexec (rx, buf, 0, NULL, 0) == 0) { + if (patmatch (pat, buf) == 0) { match = 1; break; } lng -= str_len (buf); } + mem_free (&buf); + mx_close_message (&msg); if (option (OPTTHOROUGHSRC)) { @@ -229,20 +251,37 @@ int eat_regexp (pattern_t * pat, BUFFER * s, BUFFER * err) snprintf (err->data, err->dsize, _("Error in expression: %s"), s->dptr); return (-1); } - pat->rx = mem_malloc (sizeof (regex_t)); - r = - REGCOMP (pat->rx, buf.data, - REG_NEWLINE | REG_NOSUB | mutt_which_case (buf.data)); - mem_free (&buf.data); - if (r) { - regerror (r, pat->rx, err->data, err->dsize); - regfree (pat->rx); - mem_free (&pat->rx); - return (-1); + +#if 0 + /* If there are no RE metacharacters, use simple search anyway */ + if (!pat->stringmatch && !strpbrk (buf.data, "|[{.*+?^$")) + pat->stringmatch = 1; +#endif + + if (pat->stringmatch) { + pat->str = str_dup (buf.data); + mem_free (&buf.data); + } else { + pat->rx = mem_malloc (sizeof (regex_t)); + r = REGCOMP (pat->rx, buf.data, REG_NEWLINE | REG_NOSUB | mutt_which_case (buf.data)); + mem_free (&buf.data); + if (r) { + regerror (r, pat->rx, err->data, err->dsize); + regfree (pat->rx); + mem_free (&pat->rx); + return (-1); + } } return 0; } +static int patmatch (const pattern_t* pat, const char* buf) { + if (pat->stringmatch) + return !strstr (buf, pat->str); + else + return regexec (pat->rx, buf, 0, NULL, 0); +} + int eat_range (pattern_t * pat, BUFFER * s, BUFFER * err) { char *tmp; @@ -645,6 +684,7 @@ void mutt_pattern_free (pattern_t ** pat) regfree (tmp->rx); mem_free (&tmp->rx); } + mem_free (&tmp->str); if (tmp->child) mutt_pattern_free (&tmp->child); mem_free (&tmp); @@ -704,6 +744,8 @@ pattern_t *mutt_pattern_comp ( /* const */ char *s, int flags, BUFFER * err) not = 0; alladdr = 0; break; + case '=': + /* fallthrough */ case '~': if (implicit && or) { /* A | B & C == (A | B) & C */ @@ -718,6 +760,7 @@ pattern_t *mutt_pattern_comp ( /* const */ char *s, int flags, BUFFER * err) tmp = new_pattern (); tmp->not = not; tmp->alladdr = alladdr; + tmp->stringmatch = (*ps.dptr == '=') ? 1 : 0; not = 0; alladdr = 0; @@ -823,7 +866,7 @@ perform_or (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT * ctx, return 0; } -static int match_adrlist (regex_t * rx, int match_personal, int alladdr, +static int match_adrlist (pattern_t* pat, int match_personal, int alladdr, int n, ...) { va_list ap; @@ -832,23 +875,23 @@ static int match_adrlist (regex_t * rx, int match_personal, int alladdr, va_start (ap, n); for (; n; n--) { for (a = va_arg (ap, ADDRESS *); a; a = a->next) { - if (alladdr ^ - ((a->mailbox && regexec (rx, a->mailbox, 0, NULL, 0) == 0) || + if (pat->alladdr ^ + ((a->mailbox && patmatch (pat, a->mailbox) == 0) || (match_personal && a->personal && - regexec (rx, a->personal, 0, NULL, 0) == 0))) { + patmatch (pat, a->personal) == 0))) { va_end (ap); - return (!alladdr); /* Found match, or non-match if alladdr */ + return (!pat->alladdr); /* Found match, or non-match if alladdr */ } } } va_end (ap); - return alladdr; /* No matches, or all matches if alladdr */ + return pat->alladdr; /* No matches, or all matches if alladdr */ } -static int match_reference (regex_t * rx, LIST * refs) +static int match_reference (pattern_t* pat, LIST * refs) { for (; refs; refs = refs->next) - if (regexec (rx, refs->data, 0, NULL, 0) == 0) + if (patmatch (pat, refs->data) == 0) return 1; return 0; } @@ -911,8 +954,6 @@ int mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT * ctx, HEADER * h) { - char buf[STRING]; - switch (pat->op) { case M_AND: return (pat->not ^ (perform_and (pat->child, flags, ctx, h) > 0)); @@ -952,30 +993,32 @@ mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, case M_BODY: case M_HEADER: case M_WHOLE_MSG: - return (pat-> - not ^ msg_search (ctx, pat->rx, buf, sizeof (buf), pat->op, - h->msgno)); +#ifdef USE_IMAP + /* IMAP search sets h->matched at search compile time */ + if (Context->magic == M_IMAP && pat->stringmatch) + return (h->matched); +#endif + return (pat->not ^ msg_search (ctx, pat, h->msgno)); case M_SENDER: - return (pat->not ^ match_adrlist (pat->rx, flags & M_MATCH_FULL_ADDRESS, + return (pat->not ^ match_adrlist (pat, flags & M_MATCH_FULL_ADDRESS, pat->alladdr, 1, h->env->sender)); case M_FROM: - return (pat->not ^ match_adrlist (pat->rx, flags & M_MATCH_FULL_ADDRESS, + return (pat->not ^ match_adrlist (pat, flags & M_MATCH_FULL_ADDRESS, pat->alladdr, 1, h->env->from)); case M_TO: - return (pat->not ^ match_adrlist (pat->rx, flags & M_MATCH_FULL_ADDRESS, + return (pat->not ^ match_adrlist (pat, flags & M_MATCH_FULL_ADDRESS, pat->alladdr, 1, h->env->to)); case M_CC: - return (pat->not ^ match_adrlist (pat->rx, flags & M_MATCH_FULL_ADDRESS, + return (pat->not ^ match_adrlist (pat, flags & M_MATCH_FULL_ADDRESS, pat->alladdr, 1, h->env->cc)); case M_SUBJECT: return (pat-> not ^ (h->env && h->env->subject - && regexec (pat->rx, h->env->subject, 0, NULL, 0) == 0)); + && patmatch (pat, h->env->subject) == 0)); case M_ID: return (pat-> not ^ (h->env && h->env->message_id - && regexec (pat->rx, h->env->message_id, 0, NULL, - 0) == 0)); + && patmatch (pat, h->env->message_id) == 0)); case M_SCORE: return (pat->not ^ (h->score >= pat->min && (pat->max == M_MAXRANGE || h->score <= pat->max))); @@ -985,21 +1028,26 @@ mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, && (pat->max == M_MAXRANGE || h->content->length <= pat->max))); case M_REFERENCE: - return (pat->not ^ match_reference (pat->rx, h->env->references)); + return (pat->not ^ match_reference (pat, h->env->references)); case M_ADDRESS: return (pat-> not ^ (h->env - && match_adrlist (pat->rx, flags & M_MATCH_FULL_ADDRESS, + && match_adrlist (pat, flags & M_MATCH_FULL_ADDRESS, pat->alladdr, 4, h->env->from, h->env->sender, h->env->to, h->env->cc))); case M_RECIPIENT: return (pat-> not ^ (h->env - && match_adrlist (pat->rx, flags & M_MATCH_FULL_ADDRESS, + && match_adrlist (pat, flags & M_MATCH_FULL_ADDRESS, pat->alladdr, 2, h->env->to, h->env->cc))); case M_LIST: + return (pat-> + not ^ (h->env + && mutt_is_list_cc (pat->alladdr, h->env->to, + h->env->cc))); + case M_SUBSCRIBED_LIST: return (pat-> not ^ (h->env && mutt_is_list_recipient (pat->alladdr, h->env->to, @@ -1033,16 +1081,17 @@ mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, case M_XLABEL: return (pat-> not ^ (h->env->x_label - && regexec (pat->rx, h->env->x_label, 0, NULL, 0) == 0)); + && patmatch (pat, h->env->x_label) == 0)); case M_HORMEL: return (pat-> not ^ (h->env->spam && h->env->spam->data - && regexec (pat->rx, h->env->spam->data, 0, NULL, - 0) == 0)); + && patmatch (pat, h->env->spam->data) == 0)); case M_DUPLICATED: return (pat->not ^ (h->thread && h->thread->duplicate_thread)); case M_UNREFERENCED: return (pat->not ^ (h->thread && !h->thread->child)); + case M_MULTIPART: + return (pat->not ^ (h->content && h->content->type == TYPEMULTIPART)); case M_REALNAME: /* realname filter: * we have a match if @@ -1065,8 +1114,7 @@ mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, case M_NEWSGROUPS: return (pat-> not ^ (h->env->newsgroups - && regexec (pat->rx, h->env->newsgroups, 0, NULL, - 0) == 0)); + && patmatch (pat, h->env->newsgroups) == 0)); #endif } mutt_error (_("error: unknown op %d (report this error)."), pat->op); @@ -1096,7 +1144,7 @@ void mutt_check_simple (char *s, size_t len, const char *simple) * equivalences? */ - if (!strchr (s, '~')) { /* yup, so spoof a real request */ + if (!strchr (s, '~') && !strchr (s, '=')) { /* yup, so spoof a real request */ /* convert old tokens into the new format */ if (ascii_strcasecmp ("all", s) == 0 || !str_cmp ("^", s) || !str_cmp (".", s)) /* ~A is more efficient */ strfcpy (s, "~A", len); @@ -1154,6 +1202,11 @@ int mutt_pattern_func (int op, char *prompt) return (-1); } +#ifdef USE_IMAP + if (Context->magic == M_IMAP && imap_search (Context, pat) < 0) + return -1; +#endif + mutt_message _("Executing command on matching messages..."); #define THIS_BODY Context->hdrs[i]->content @@ -1208,22 +1261,16 @@ int mutt_pattern_func (int op, char *prompt) mutt_clear_error (); if (op == M_LIMIT) { + /* drop previous limit pattern */ mem_free (&Context->pattern); if (Context->limit_pattern) mutt_pattern_free (&Context->limit_pattern); - if (!Context->vcount) { + if (Context->msgcount && !Context->vcount) { mutt_error _("No messages matched criteria."); - -#if 0 - Context->vcount = Context->msgcount; - /* restore full display */ - for (i = 0; i < Context->msgcount; i++) { - Context->hdrs[i]->virtual = i; - Context->v2r[i] = i; - } -#endif } - else if (str_ncmp (buf, "~A", 2) != 0) { + + /* record new limit pattern, unless match all */ + if (str_ncmp (buf, "~A", 2) != 0) { Context->pattern = simple; simple = NULL; /* don't clobber it */ Context->limit_pattern = mutt_pattern_comp (buf, M_FULL_MSG, &err); @@ -1286,6 +1333,10 @@ int mutt_search_command (int cur, int op) if (option (OPTSEARCHINVALID)) { for (i = 0; i < Context->msgcount; i++) Context->hdrs[i]->searched = 0; +#ifdef USE_IMAP + if (Context->magic == M_IMAP && imap_search (Context, SearchPattern) < 0) + return -1; +#endif unset_option (OPTSEARCHINVALID); }