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 + -
显示快捷键?