pattern.c
来自「mutt-1.5.12 源代码。linux 下邮件接受的工具。」· C语言 代码 · 共 1,426 行 · 第 1/3 页
C
1,426 行
va_list ap; ADDRESS *a; va_start (ap, n); for ( ; n ; n --) { for (a = va_arg (ap, ADDRESS *) ; a ; a = a->next) { if (pat->alladdr ^ ((a->mailbox && patmatch (pat, a->mailbox) == 0) || (match_personal && a->personal && patmatch (pat, a->personal) == 0))) { va_end (ap); return (! pat->alladdr); /* Found match, or non-match if alladdr */ } } } va_end (ap); return pat->alladdr; /* No matches, or all matches if alladdr */}static int match_reference (pattern_t *pat, LIST *refs){ for (; refs; refs = refs->next) if (patmatch (pat, refs->data) == 0) return 1; return 0;}/* * Matches subscribed mailing lists */int mutt_is_list_recipient (int alladdr, ADDRESS *a1, ADDRESS *a2){ for (; a1 ; a1 = a1->next) if (alladdr ^ mutt_is_subscribed_list (a1)) return (! alladdr); for (; a2 ; a2 = a2->next) if (alladdr ^ mutt_is_subscribed_list (a2)) return (! alladdr); return alladdr;}/* * Matches known mailing lists * The function name may seem a little bit misleading: It checks all * recipients in To and Cc for known mailing lists, subscribed or not. */int mutt_is_list_cc (int alladdr, ADDRESS *a1, ADDRESS *a2){ for (; a1 ; a1 = a1->next) if (alladdr ^ mutt_is_mail_list (a1)) return (! alladdr); for (; a2 ; a2 = a2->next) if (alladdr ^ mutt_is_mail_list (a2)) return (! alladdr); return alladdr;}static int match_user (int alladdr, ADDRESS *a1, ADDRESS *a2){ for (; a1 ; a1 = a1->next) if (alladdr ^ mutt_addr_is_user (a1)) return (! alladdr); for (; a2 ; a2 = a2->next) if (alladdr ^ mutt_addr_is_user (a2)) return (! alladdr); return alladdr;}/* flags M_MATCH_FULL_ADDRESS match both personal and machine address */intmutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx, HEADER *h){ switch (pat->op) { case M_AND: return (pat->not ^ (perform_and (pat->child, flags, ctx, h) > 0)); case M_OR: return (pat->not ^ (perform_or (pat->child, flags, ctx, h) > 0)); case M_ALL: return (!pat->not); case M_EXPIRED: return (pat->not ^ h->expired); case M_SUPERSEDED: return (pat->not ^ h->superseded); case M_FLAG: return (pat->not ^ h->flagged); case M_TAG: return (pat->not ^ h->tagged); case M_NEW: return (pat->not ? h->old || h->read : !(h->old || h->read)); case M_UNREAD: return (pat->not ? h->read : !h->read); case M_REPLIED: return (pat->not ^ h->replied); case M_OLD: return (pat->not ? (!h->old || h->read) : (h->old && !h->read)); case M_READ: return (pat->not ^ h->read); case M_DELETED: return (pat->not ^ h->deleted); case M_MESSAGE: return (pat->not ^ (h->msgno >= pat->min - 1 && (pat->max == M_MAXRANGE || h->msgno <= pat->max - 1))); case M_DATE: return (pat->not ^ (h->date_sent >= pat->min && h->date_sent <= pat->max)); case M_DATE_RECEIVED: return (pat->not ^ (h->received >= pat->min && h->received <= pat->max)); case M_BODY: case M_HEADER: case M_WHOLE_MSG:#ifdef USE_IMAP /* IMAP search sets h->matched at search compile time */ if (ctx->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, flags & M_MATCH_FULL_ADDRESS, 1, h->env->sender)); case M_FROM: return (pat->not ^ match_adrlist (pat, flags & M_MATCH_FULL_ADDRESS, 1, h->env->from)); case M_TO: return (pat->not ^ match_adrlist (pat, flags & M_MATCH_FULL_ADDRESS, 1, h->env->to)); case M_CC: return (pat->not ^ match_adrlist (pat, flags & M_MATCH_FULL_ADDRESS, 1, h->env->cc)); case M_SUBJECT: return (pat->not ^ (h->env->subject && patmatch (pat, h->env->subject) == 0)); case M_ID: return (pat->not ^ (h->env->message_id && 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))); case M_SIZE: return (pat->not ^ (h->content->length >= pat->min && (pat->max == M_MAXRANGE || h->content->length <= pat->max))); case M_REFERENCE: return (pat->not ^ match_reference (pat, h->env->references)); case M_ADDRESS: return (pat->not ^ match_adrlist (pat, flags & M_MATCH_FULL_ADDRESS, 4, h->env->from, h->env->sender, h->env->to, h->env->cc)); case M_RECIPIENT: return (pat->not ^ match_adrlist (pat, flags & M_MATCH_FULL_ADDRESS, 2, h->env->to, h->env->cc)); case M_LIST: /* known list, subscribed or not */ return (pat->not ^ mutt_is_list_cc (pat->alladdr, h->env->to, h->env->cc)); case M_SUBSCRIBED_LIST: return (pat->not ^ mutt_is_list_recipient (pat->alladdr, h->env->to, h->env->cc)); case M_PERSONAL_RECIP: return (pat->not ^ match_user (pat->alladdr, h->env->to, h->env->cc)); case M_PERSONAL_FROM: return (pat->not ^ match_user (pat->alladdr, h->env->from, NULL)); case M_COLLAPSED: return (pat->not ^ (h->collapsed && h->num_hidden > 1)); case M_CRYPT_SIGN: if (!WithCrypto) break; return (pat->not ^ ((h->security & SIGN) ? 1 : 0)); case M_CRYPT_VERIFIED: if (!WithCrypto) break; return (pat->not ^ ((h->security & GOODSIGN) ? 1 : 0)); case M_CRYPT_ENCRYPT: if (!WithCrypto) break; return (pat->not ^ ((h->security & ENCRYPT) ? 1 : 0)); case M_PGP_KEY: if (!(WithCrypto & APPLICATION_PGP)) break; return (pat->not ^ ((h->security & APPLICATION_PGP) && (h->security & PGPKEY))); case M_XLABEL: return (pat->not ^ (h->env->x_label && patmatch (pat, h->env->x_label) == 0)); case M_HORMEL: return (pat->not ^ (h->env->spam && h->env->spam->data && patmatch (pat, h->env->spam->data) == 0)); case M_DUPLICATED: return (pat->not ^ (h->thread && h->thread->duplicate_thread)); case M_MIMEATTACH: { int count = mutt_count_body_parts (ctx, h); return (pat->not ^ (count >= pat->min && (pat->max == M_MAXRANGE || count <= pat->max))); } case M_UNREFERENCED: return (pat->not ^ (h->thread && !h->thread->child)); } mutt_error (_("error: unknown op %d (report this error)."), pat->op); return (-1);}static void quote_simple(char *tmp, size_t len, const char *p){ int i = 0; tmp[i++] = '"'; while (*p && i < len - 3) { if (*p == '\\' || *p == '"') tmp[i++] = '\\'; tmp[i++] = *p++; } tmp[i++] = '"'; tmp[i] = 0;} /* convert a simple search into a real request */void mutt_check_simple (char *s, size_t len, const char *simple){ char tmp[LONG_STRING]; /* XXX - is ascii_strcasecmp() right here, or should we use locale's * equivalences? */ if (!strchr (s, '~') && !strchr (s, '=') && !strchr (s, '%')) /* yup, so spoof a real request */ { /* convert old tokens into the new format */ if (ascii_strcasecmp ("all", s) == 0 || !mutt_strcmp ("^", s) || !mutt_strcmp (".", s)) /* ~A is more efficient */ strfcpy (s, "~A", len); else if (ascii_strcasecmp ("del", s) == 0) strfcpy (s, "~D", len); else if (ascii_strcasecmp ("flag", s) == 0) strfcpy (s, "~F", len); else if (ascii_strcasecmp ("new", s) == 0) strfcpy (s, "~N", len); else if (ascii_strcasecmp ("old", s) == 0) strfcpy (s, "~O", len); else if (ascii_strcasecmp ("repl", s) == 0) strfcpy (s, "~Q", len); else if (ascii_strcasecmp ("read", s) == 0) strfcpy (s, "~R", len); else if (ascii_strcasecmp ("tag", s) == 0) strfcpy (s, "~T", len); else if (ascii_strcasecmp ("unread", s) == 0) strfcpy (s, "~U", len); else { quote_simple (tmp, sizeof(tmp), s); mutt_expand_fmt (s, len, simple, tmp); } }}int mutt_pattern_func (int op, char *prompt){ pattern_t *pat; char buf[LONG_STRING] = "", *simple, error[STRING]; BUFFER err; int i; strfcpy (buf, NONULL (Context->pattern), sizeof (buf)); if (mutt_get_field (prompt, buf, sizeof (buf), M_PATTERN | M_CLEAR) != 0 || !buf[0]) return (-1); mutt_message _("Compiling search pattern..."); simple = safe_strdup (buf); mutt_check_simple (buf, sizeof (buf), NONULL (SimpleSearch)); err.data = error; err.dsize = sizeof (error); if ((pat = mutt_pattern_comp (buf, M_FULL_MSG, &err)) == NULL) { FREE (&simple); mutt_error ("%s", err.data); 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 if (op == M_LIMIT) { Context->vcount = 0; Context->vsize = 0; Context->collapsed = 0; for (i = 0; i < Context->msgcount; i++) { /* new limit pattern implicitly uncollapses all threads */ Context->hdrs[i]->virtual = -1; Context->hdrs[i]->limited = 0; Context->hdrs[i]->collapsed = 0; Context->hdrs[i]->num_hidden = 0; if (mutt_pattern_exec (pat, M_MATCH_FULL_ADDRESS, Context, Context->hdrs[i])) { Context->hdrs[i]->virtual = Context->vcount; Context->hdrs[i]->limited = 1; Context->v2r[Context->vcount] = i; Context->vcount++; Context->vsize+=THIS_BODY->length + THIS_BODY->offset - THIS_BODY->hdr_offset; } } } else { for (i = 0; i < Context->vcount; i++) { if (mutt_pattern_exec (pat, M_MATCH_FULL_ADDRESS, Context, Context->hdrs[Context->v2r[i]])) { switch (op) { case M_DELETE: case M_UNDELETE: mutt_set_flag (Context, Context->hdrs[Context->v2r[i]], M_DELETE, (op == M_DELETE)); break; case M_TAG: case M_UNTAG: mutt_set_flag (Context, Context->hdrs[Context->v2r[i]], M_TAG, (op == M_TAG)); break; } } } }#undef THIS_BODY mutt_clear_error (); if (op == M_LIMIT) { /* drop previous limit pattern */ FREE (&Context->pattern); if (Context->limit_pattern) mutt_pattern_free (&Context->limit_pattern); if (Context->msgcount && !Context->vcount) mutt_error _("No messages matched criteria."); /* record new limit pattern, unless match all */ if (mutt_strcmp (buf, "~A") != 0) { Context->pattern = simple; simple = NULL; /* don't clobber it */ Context->limit_pattern = mutt_pattern_comp (buf, M_FULL_MSG, &err); } } FREE (&simple); mutt_pattern_free (&pat); return 0;}int mutt_search_command (int cur, int op){ int i, j; char buf[STRING]; char temp[LONG_STRING]; char error[STRING]; BUFFER err; int incr; HEADER *h; if (op != OP_SEARCH_NEXT && op != OP_SEARCH_OPPOSITE) { strfcpy (buf, LastSearch, sizeof (buf)); if (mutt_get_field ((op == OP_SEARCH) ? _("Search for: ") : _("Reverse search for: "), buf, sizeof (buf), M_CLEAR | M_PATTERN) != 0 || !buf[0]) return (-1); if (op == OP_SEARCH) unset_option (OPTSEARCHREVERSE); else set_option (OPTSEARCHREVERSE); /* compare the *expanded* version of the search pattern in case $simple_search has changed while we were searching */ strfcpy (temp, buf, sizeof (temp)); mutt_check_simple (temp, sizeof (temp), NONULL (SimpleSearch)); if (!SearchPattern || mutt_strcmp (temp, LastSearchExpn)) { set_option (OPTSEARCHINVALID); strfcpy (LastSearch, buf, sizeof (LastSearch)); mutt_message _("Compiling search pattern..."); mutt_pattern_free (&SearchPattern); err.data = error; err.dsize = sizeof (error); if ((SearchPattern = mutt_pattern_comp (temp, M_FULL_MSG, &err)) == NULL) { mutt_error ("%s", error); return (-1); } mutt_clear_error (); } } else if (!SearchPattern) { mutt_error _("No search pattern."); return (-1); } 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); } incr = (option (OPTSEARCHREVERSE)) ? -1 : 1; if (op == OP_SEARCH_OPPOSITE) incr = -incr; for (i = cur + incr, j = 0 ; j != Context->vcount; j++) { if (i > Context->vcount - 1) { i = 0; if (option (OPTWRAPSEARCH)) mutt_message _("Search wrapped to top."); else { mutt_message _("Search hit bottom without finding match"); return (-1); } } else if (i < 0) { i = Context->vcount - 1; if (option (OPTWRAPSEARCH)) mutt_message _("Search wrapped to bottom."); else { mutt_message _("Search hit top without finding match"); return (-1); } } h = Context->hdrs[Context->v2r[i]]; if (h->searched) { /* if we've already evaulated this message, use the cached value */ if (h->matched) return i; } else { /* remember that we've already searched this message */ h->searched = 1; if ((h->matched = (mutt_pattern_exec (SearchPattern, M_MATCH_FULL_ADDRESS, Context, h) > 0))) return i; } if (SigInt) { mutt_error _("Search interrupted."); SigInt = 0; return (-1); } i += incr; } mutt_error _("Not found."); return (-1);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?