📄 pattern.c
字号:
/* * Copyright (C) 1996-2000,2006 Michael R. Elkins <me@mutt.org>, and others * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if HAVE_CONFIG_H# include "config.h"#endif#include "mutt.h"#include "mapping.h"#include "keymap.h"#include "mailbox.h"#include "copy.h"#include <string.h>#include <stdlib.h>#include <ctype.h>#include <sys/stat.h>#include <unistd.h>#include <stdarg.h>#include "mutt_crypt.h"#ifdef USE_IMAP#include "mx.h"#include "imap/imap.h"#endifstatic 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 */ int op; /* operation to perform */ int class; int (*eat_arg) (pattern_t *, BUFFER *, BUFFER *);}Flags[] ={ { 'A', M_ALL, 0, NULL }, { 'b', M_BODY, M_FULL_MSG, eat_regexp }, { 'B', M_WHOLE_MSG, M_FULL_MSG, eat_regexp }, { 'c', M_CC, 0, eat_regexp }, { 'C', M_RECIPIENT, 0, eat_regexp }, { 'd', M_DATE, 0, eat_date }, { 'D', M_DELETED, 0, NULL }, { 'e', M_SENDER, 0, eat_regexp }, { 'E', M_EXPIRED, 0, NULL }, { 'f', M_FROM, 0, eat_regexp }, { 'F', M_FLAG, 0, NULL }, { 'g', M_CRYPT_SIGN, 0, NULL }, { 'G', M_CRYPT_ENCRYPT, 0, NULL }, { 'h', M_HEADER, M_FULL_MSG, eat_regexp }, { 'H', M_HORMEL, 0, eat_regexp }, { 'i', M_ID, 0, eat_regexp }, { 'k', M_PGP_KEY, 0, NULL }, { 'l', M_LIST, 0, NULL }, { 'L', M_ADDRESS, 0, eat_regexp }, { 'm', M_MESSAGE, 0, eat_range }, { 'n', M_SCORE, 0, eat_range }, { 'N', M_NEW, 0, NULL }, { 'O', M_OLD, 0, NULL }, { 'p', M_PERSONAL_RECIP, 0, NULL }, { 'P', M_PERSONAL_FROM, 0, NULL }, { 'Q', M_REPLIED, 0, NULL }, { 'r', M_DATE_RECEIVED, 0, eat_date }, { 'R', M_READ, 0, NULL }, { 's', M_SUBJECT, 0, eat_regexp }, { 'S', M_SUPERSEDED, 0, NULL }, { 't', M_TO, 0, eat_regexp }, { 'T', M_TAG, 0, NULL }, { 'u', M_SUBSCRIBED_LIST, 0, NULL }, { 'U', M_UNREAD, 0, NULL }, { 'v', M_COLLAPSED, 0, NULL }, { 'V', M_CRYPT_VERIFIED, 0, NULL }, { 'x', M_REFERENCE, 0, eat_regexp }, { 'X', M_MIMEATTACH, 0, eat_range }, { 'y', M_XLABEL, 0, eat_regexp }, { 'z', M_SIZE, 0, eat_range }, { '=', M_DUPLICATED, 0, NULL }, { '$', M_UNREFERENCED, 0, NULL }, { 0 }};static pattern_t *SearchPattern = NULL; /* current search pattern */static char LastSearch[STRING] = { 0 }; /* last pattern searched for */static char LastSearchExpn[LONG_STRING] = { 0 }; /* expanded version of LastSearch */#define M_MAXRANGE -1/* constants for parse_date_range() */#define M_PDR_NONE 0x0000#define M_PDR_MINUS 0x0001#define M_PDR_PLUS 0x0002#define M_PDR_WINDOW 0x0004#define M_PDR_ABSOLUTE 0x0008#define M_PDR_DONE 0x0010#define M_PDR_ERROR 0x0100#define M_PDR_ERRORDONE (M_PDR_ERROR | M_PDR_DONE)int mutt_getvaluebychar (char ch, struct mapping_t *table){ int i; for (i = 0; table[i].name; i++) { if (ch == table[i].name[0]) return table[i].value; } return (-1);}/* if no uppercase letters are given, do a case-insensitive search */int mutt_which_case (const char *s){ while (*s) { if (isalpha ((unsigned char) *s) && isupper ((unsigned char) *s)) return 0; /* case-sensitive */ s++; } return REG_ICASE; /* case-insensitive */}static intmsg_search (CONTEXT *ctx, pattern_t* pat, int msgno){ char tempfile[_POSIX_PATH_MAX]; MESSAGE *msg = NULL; STATE s; struct stat st; FILE *fp = NULL; 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)) { /* decode the header / body */ memset (&s, 0, sizeof (s)); s.fpin = msg->fp; s.flags = M_CHARCONV; mutt_mktemp (tempfile); if ((s.fpout = safe_fopen (tempfile, "w+")) == NULL) { mutt_perror (tempfile); return (0); } if (pat->op != M_BODY) mutt_copy_header (msg->fp, h, s.fpout, CH_FROM | CH_DECODE, NULL); if (pat->op != M_HEADER) { mutt_parse_mime_message (ctx, h); if (WithCrypto && (h->security & ENCRYPT) && !crypt_valid_passphrase(h->security)) { mx_close_message (&msg); if (fp) { fclose (fp); unlink (tempfile); } return (0); } fseeko (msg->fp, h->offset, 0); mutt_body_handler (h->content, &s); } fp = s.fpout; fflush (fp); fseek (fp, 0, 0); fstat (fileno (fp), &st); lng = (long) st.st_size; } else { /* raw header / body */ fp = msg->fp; if (pat->op != M_BODY) { fseeko (fp, h->offset, 0); lng = h->content->offset - h->offset; } if (pat->op != M_HEADER) { if (pat->op == M_BODY) fseeko (fp, h->content->offset, 0); lng += h->content->length; } } blen = STRING; buf = safe_malloc (blen); /* search the file "fp" */ while (lng > 0) { 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 (patmatch (pat, buf) == 0) { match = 1; break; } lng -= mutt_strlen (buf); } FREE (&buf); mx_close_message (&msg); if (option (OPTTHOROUGHSRC)) { fclose (fp); unlink (tempfile); } } return match;}int eat_regexp (pattern_t *pat, BUFFER *s, BUFFER *err){ BUFFER buf; int r; memset (&buf, 0, sizeof (buf)); if (mutt_extract_token (&buf, s, M_TOKEN_PATTERN | M_TOKEN_COMMENT) != 0 || !buf.data) { snprintf (err->data, err->dsize, _("Error in expression: %s"), s->dptr); return (-1); } if (!*buf.data) { snprintf (err->data, err->dsize, _("Empty expression")); 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->p.str = safe_strdup (buf.data); FREE (&buf.data); } else if (pat->groupmatch) { pat->p.g = mutt_pattern_group (buf.data); FREE (&buf.data); } else { pat->p.rx = safe_malloc (sizeof (regex_t)); r = REGCOMP (pat->p.rx, buf.data, REG_NEWLINE | REG_NOSUB | mutt_which_case (buf.data)); FREE (&buf.data); if (r) { regerror (r, pat->p.rx, err->data, err->dsize); regfree (pat->p.rx); FREE (&pat->p.rx); return (-1); } } return 0;}int eat_range (pattern_t *pat, BUFFER *s, BUFFER *err){ char *tmp; int do_exclusive = 0; int skip_quote = 0; /* * If simple_search is set to "~m %s", the range will have double quotes * around it... */ if (*s->dptr == '"') { s->dptr++; skip_quote = 1; } if (*s->dptr == '<') do_exclusive = 1; if ((*s->dptr != '-') && (*s->dptr != '<')) { /* range minimum */ if (*s->dptr == '>') { pat->max = M_MAXRANGE; pat->min = strtol (s->dptr + 1, &tmp, 0) + 1; /* exclusive range */ } else pat->min = strtol (s->dptr, &tmp, 0); if (toupper ((unsigned char) *tmp) == 'K') /* is there a prefix? */ { pat->min *= 1024; tmp++; } else if (toupper ((unsigned char) *tmp) == 'M') { pat->min *= 1048576; tmp++; } if (*s->dptr == '>') { s->dptr = tmp; return 0; } if (*tmp != '-') { /* exact value */ pat->max = pat->min; s->dptr = tmp; return 0; } tmp++; } else { s->dptr++; tmp = s->dptr; } if (isdigit ((unsigned char) *tmp)) { /* range maximum */ pat->max = strtol (tmp, &tmp, 0); if (toupper ((unsigned char) *tmp) == 'K') { pat->max *= 1024; tmp++; } else if (toupper ((unsigned char) *tmp) == 'M') { pat->max *= 1048576; tmp++; } if (do_exclusive) (pat->max)--; } else pat->max = M_MAXRANGE; if (skip_quote && *tmp == '"') tmp++; SKIPWS (tmp); s->dptr = tmp; return 0;}static const char *getDate (const char *s, struct tm *t, BUFFER *err){ char *p; time_t now = time (NULL); struct tm *tm = localtime (&now); t->tm_mday = strtol (s, &p, 10); if (t->tm_mday < 1 || t->tm_mday > 31) { snprintf (err->data, err->dsize, _("Invalid day of month: %s"), s); return NULL; } if (*p != '/') { /* fill in today's month and year */ t->tm_mon = tm->tm_mon; t->tm_year = tm->tm_year; return p; } p++; t->tm_mon = strtol (p, &p, 10) - 1; if (t->tm_mon < 0 || t->tm_mon > 11) { snprintf (err->data, err->dsize, _("Invalid month: %s"), p); return NULL; } if (*p != '/') { t->tm_year = tm->tm_year; return p; } p++; t->tm_year = strtol (p, &p, 10); if (t->tm_year < 70) /* year 2000+ */ t->tm_year += 100; else if (t->tm_year > 1900) t->tm_year -= 1900; return p;}/* Ny years Nm months Nw weeks Nd days */static const char *get_offset (struct tm *tm, const char *s, int sign){ char *ps; int offset = strtol (s, &ps, 0); if ((sign < 0 && offset > 0) || (sign > 0 && offset < 0)) offset = -offset; switch (*ps) { case 'y': tm->tm_year += offset; break; case 'm': tm->tm_mon += offset; break; case 'w': tm->tm_mday += 7 * offset; break; case 'd': tm->tm_mday += offset; break; default: return s; } mutt_normalize_time (tm); return (ps + 1);}static void adjust_date_range (struct tm *min, struct tm *max){ if (min->tm_year > max->tm_year || (min->tm_year == max->tm_year && min->tm_mon > max->tm_mon) || (min->tm_year == max->tm_year && min->tm_mon == max->tm_mon && min->tm_mday > max->tm_mday)) { int tmp; tmp = min->tm_year; min->tm_year = max->tm_year; max->tm_year = tmp; tmp = min->tm_mon;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -