NeoMutt  2020-11-20
Teaching an old dog new tricks
DOXYGEN
exec.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <stdarg.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include "private.h"
39 #include "mutt/lib.h"
40 #include "address/lib.h"
41 #include "email/lib.h"
42 #include "core/lib.h"
43 #include "alias/alias.h"
44 #include "alias/gui.h"
45 #include "alias/lib.h"
46 #include "mutt.h"
47 #include "lib.h"
48 #include "ncrypt/lib.h"
49 #include "send/lib.h"
50 #include "copy.h"
51 #include "handler.h"
52 #include "maillist.h"
53 #include "mutt_parse.h"
54 #include "muttlib.h"
55 #include "mx.h"
56 #include "state.h"
57 
65 static bool patmatch(const struct Pattern *pat, const char *buf)
66 {
67  if (pat->is_multi)
68  return (mutt_list_find(&pat->p.multi_cases, buf) != NULL);
69  if (pat->string_match)
70  return pat->ign_case ? strcasestr(buf, pat->p.str) : strstr(buf, pat->p.str);
71  if (pat->group_match)
72  return mutt_group_match(pat->p.group, buf);
73  return (regexec(pat->p.regex, buf, 0, NULL, 0) == 0);
74 }
75 
80 static void print_crypt_pattern_op_error(int op)
81 {
82  const struct PatternFlags *entry = lookup_op(op);
83  if (entry)
84  {
85  /* L10N: One of the crypt pattern operators: ~g, ~G, ~k, ~V
86  was invoked when NeoMutt was compiled without crypto support.
87  %c is the pattern character, i.e. "g". */
88  mutt_error(_("Pattern operator '~%c' is disabled"), entry->tag);
89  }
90  else
91  {
92  /* L10N: An unknown pattern operator was somehow invoked.
93  This shouldn't be possible unless there is a bug. */
94  mutt_error(_("error: unknown op %d (report this error)"), op);
95  }
96 }
97 
106 static bool msg_search(struct Mailbox *m, struct Pattern *pat, int msgno)
107 {
108  bool match = false;
109  struct Message *msg = mx_msg_open(m, msgno);
110  if (!msg)
111  {
112  return match;
113  }
114 
115  FILE *fp = NULL;
116  long len = 0;
117  struct Email *e = m->emails[msgno];
118 #ifdef USE_FMEMOPEN
119  char *temp = NULL;
120  size_t tempsize = 0;
121 #else
122  struct stat st;
123 #endif
124 
125  if (C_ThoroughSearch)
126  {
127  /* decode the header / body */
128  struct State s = { 0 };
129  s.fp_in = msg->fp;
130  s.flags = MUTT_CHARCONV;
131 #ifdef USE_FMEMOPEN
132  s.fp_out = open_memstream(&temp, &tempsize);
133  if (!s.fp_out)
134  {
135  mutt_perror(_("Error opening 'memory stream'"));
136  return false;
137  }
138 #else
140  if (!s.fp_out)
141  {
142  mutt_perror(_("Can't create temporary file"));
143  return false;
144  }
145 #endif
146 
147  if (pat->op != MUTT_PAT_BODY)
148  mutt_copy_header(msg->fp, e, s.fp_out, CH_FROM | CH_DECODE, NULL, 0);
149 
150  if (pat->op != MUTT_PAT_HEADER)
151  {
153 
154  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) &&
156  {
157  mx_msg_close(m, &msg);
158  if (s.fp_out)
159  {
161 #ifdef USE_FMEMOPEN
162  FREE(&temp);
163 #endif
164  }
165  return false;
166  }
167 
168  fseeko(msg->fp, e->offset, SEEK_SET);
169  mutt_body_handler(e->body, &s);
170  }
171 
172 #ifdef USE_FMEMOPEN
174  len = tempsize;
175 
176  if (tempsize != 0)
177  {
178  fp = fmemopen(temp, tempsize, "r");
179  if (!fp)
180  {
181  mutt_perror(_("Error re-opening 'memory stream'"));
182  FREE(&temp);
183  return false;
184  }
185  }
186  else
187  { /* fmemopen can't handle empty buffers */
188  fp = mutt_file_fopen("/dev/null", "r");
189  if (!fp)
190  {
191  mutt_perror(_("Error opening /dev/null"));
192  return false;
193  }
194  }
195 #else
196  fp = s.fp_out;
197  fflush(fp);
198  fseek(fp, 0, SEEK_SET);
199  fstat(fileno(fp), &st);
200  len = (long) st.st_size;
201 #endif
202  }
203  else
204  {
205  /* raw header / body */
206  fp = msg->fp;
207  if (pat->op != MUTT_PAT_BODY)
208  {
209  fseeko(fp, e->offset, SEEK_SET);
210  len = e->body->offset - e->offset;
211  }
212  if (pat->op != MUTT_PAT_HEADER)
213  {
214  if (pat->op == MUTT_PAT_BODY)
215  fseeko(fp, e->body->offset, SEEK_SET);
216  len += e->body->length;
217  }
218  }
219 
220  size_t blen = 256;
221  char *buf = mutt_mem_malloc(blen);
222 
223  /* search the file "fp" */
224  while (len > 0)
225  {
226  if (pat->op == MUTT_PAT_HEADER)
227  {
228  buf = mutt_rfc822_read_line(fp, buf, &blen);
229  if (*buf == '\0')
230  break;
231  }
232  else if (!fgets(buf, blen - 1, fp))
233  break; /* don't loop forever */
234  if (patmatch(pat, buf))
235  {
236  match = true;
237  break;
238  }
239  len -= mutt_str_len(buf);
240  }
241 
242  FREE(&buf);
243 
244  mx_msg_close(m, &msg);
245 
246  if (C_ThoroughSearch)
247  mutt_file_fclose(&fp);
248 
249 #ifdef USE_FMEMOPEN
250  FREE(&temp);
251 #endif
252  return match;
253 }
254 
264 static bool perform_and(struct PatternList *pat, PatternExecFlags flags,
265  struct Mailbox *m, struct Email *e, struct PatternCache *cache)
266 {
267  struct Pattern *p = NULL;
268 
269  SLIST_FOREACH(p, pat, entries)
270  {
271  if (mutt_pattern_exec(p, flags, m, e, cache) <= 0)
272  return false;
273  }
274  return true;
275 }
276 
285 static bool perform_alias_and(struct PatternList *pat, PatternExecFlags flags,
286  struct AliasView *av, struct PatternCache *cache)
287 {
288  struct Pattern *p = NULL;
289 
290  SLIST_FOREACH(p, pat, entries)
291  {
292  if (mutt_pattern_alias_exec(p, flags, av, cache) <= 0)
293  return false;
294  }
295  return true;
296 }
297 
307 static int perform_or(struct PatternList *pat, PatternExecFlags flags,
308  struct Mailbox *m, struct Email *e, struct PatternCache *cache)
309 {
310  struct Pattern *p = NULL;
311 
312  SLIST_FOREACH(p, pat, entries)
313  {
314  if (mutt_pattern_exec(p, flags, m, e, cache) > 0)
315  return true;
316  }
317  return false;
318 }
319 
328 static int perform_alias_or(struct PatternList *pat, PatternExecFlags flags,
329  struct AliasView *av, struct PatternCache *cache)
330 {
331  struct Pattern *p = NULL;
332 
333  SLIST_FOREACH(p, pat, entries)
334  {
335  if (mutt_pattern_alias_exec(p, flags, av, cache) > 0)
336  return true;
337  }
338  return false;
339 }
340 
351 static int match_addrlist(struct Pattern *pat, bool match_personal, int n, ...)
352 {
353  va_list ap;
354 
355  va_start(ap, n);
356  for (; n; n--)
357  {
358  struct AddressList *al = va_arg(ap, struct AddressList *);
359  struct Address *a = NULL;
360  TAILQ_FOREACH(a, al, entries)
361  {
362  if (pat->all_addr ^ ((!pat->is_alias || alias_reverse_lookup(a)) &&
363  ((a->mailbox && patmatch(pat, a->mailbox)) ||
364  (match_personal && a->personal && patmatch(pat, a->personal)))))
365  {
366  va_end(ap);
367  return !pat->all_addr; /* Found match, or non-match if all_addr */
368  }
369  }
370  }
371  va_end(ap);
372  return pat->all_addr; /* No matches, or all matches if all_addr */
373 }
374 
381 static bool match_reference(struct Pattern *pat, struct ListHead *refs)
382 {
383  struct ListNode *np = NULL;
384  STAILQ_FOREACH(np, refs, entries)
385  {
386  if (patmatch(pat, np->data))
387  return true;
388  }
389  return false;
390 }
391 
403 static int mutt_is_predicate_recipient(bool all_addr, struct Envelope *e, addr_predicate_t p)
404 {
405  struct AddressList *als[] = { &e->to, &e->cc };
406  for (size_t i = 0; i < mutt_array_size(als); ++i)
407  {
408  struct AddressList *al = als[i];
409  struct Address *a = NULL;
410  TAILQ_FOREACH(a, al, entries)
411  {
412  if (all_addr ^ p(a))
413  return !all_addr;
414  }
415  }
416  return all_addr;
417 }
418 
427 int mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *e)
428 {
430 }
431 
440 int mutt_is_list_recipient(bool all_addr, struct Envelope *e)
441 {
442  return mutt_is_predicate_recipient(all_addr, e, &mutt_is_mail_list);
443 }
444 
454 static int match_user(int all_addr, struct AddressList *al1, struct AddressList *al2)
455 {
456  struct Address *a = NULL;
457  if (al1)
458  {
459  TAILQ_FOREACH(a, al1, entries)
460  {
461  if (all_addr ^ mutt_addr_is_user(a))
462  return !all_addr;
463  }
464  }
465 
466  if (al2)
467  {
468  TAILQ_FOREACH(a, al2, entries)
469  {
470  if (all_addr ^ mutt_addr_is_user(a))
471  return !all_addr;
472  }
473  }
474  return all_addr;
475 }
476 
490 static int match_threadcomplete(struct PatternList *pat, PatternExecFlags flags,
491  struct Mailbox *m, struct MuttThread *t,
492  int left, int up, int right, int down)
493 {
494  if (!t)
495  return 0;
496 
497  int a;
498  struct Email *e = t->message;
499  if (e)
500  if (mutt_pattern_exec(SLIST_FIRST(pat), flags, m, e, NULL))
501  return 1;
502 
503  if (up && (a = match_threadcomplete(pat, flags, m, t->parent, 1, 1, 1, 0)))
504  return a;
505  if (right && t->parent && (a = match_threadcomplete(pat, flags, m, t->next, 0, 0, 1, 1)))
506  {
507  return a;
508  }
509  if (left && t->parent && (a = match_threadcomplete(pat, flags, m, t->prev, 1, 0, 0, 1)))
510  {
511  return a;
512  }
513  if (down && (a = match_threadcomplete(pat, flags, m, t->child, 1, 0, 1, 1)))
514  return a;
515  return 0;
516 }
517 
528 static int match_threadparent(struct PatternList *pat, PatternExecFlags flags,
529  struct Mailbox *m, struct MuttThread *t)
530 {
531  if (!t || !t->parent || !t->parent->message)
532  return 0;
533 
534  return mutt_pattern_exec(SLIST_FIRST(pat), flags, m, t->parent->message, NULL);
535 }
536 
547 static int match_threadchildren(struct PatternList *pat, PatternExecFlags flags,
548  struct Mailbox *m, struct MuttThread *t)
549 {
550  if (!t || !t->child)
551  return 0;
552 
553  for (t = t->child; t; t = t->next)
554  if (t->message && mutt_pattern_exec(SLIST_FIRST(pat), flags, m, t->message, NULL))
555  return 1;
556 
557  return 0;
558 }
559 
567 static bool match_content_type(const struct Pattern *pat, struct Body *b)
568 {
569  if (!b)
570  return false;
571 
572  char buf[256];
573  snprintf(buf, sizeof(buf), "%s/%s", TYPE(b), b->subtype);
574 
575  if (patmatch(pat, buf))
576  return true;
577  if (match_content_type(pat, b->parts))
578  return true;
579  if (match_content_type(pat, b->next))
580  return true;
581  return false;
582 }
583 
592 static bool match_mime_content_type(const struct Pattern *pat,
593  struct Mailbox *m, struct Email *e)
594 {
596  return match_content_type(pat, e->body);
597 }
598 
605 static bool match_update_dynamic_date(struct Pattern *pat)
606 {
607  struct Buffer *err = mutt_buffer_pool_get();
608 
609  bool rc = eval_date_minmax(pat, pat->p.str, err);
611 
612  return rc;
613 }
614 
622 static void set_pattern_cache_value(int *cache_entry, int value)
623 {
624  *cache_entry = (value != 0) ? 2 : 1;
625 }
626 
633 static int get_pattern_cache_value(int cache_entry)
634 {
635  return cache_entry == 2;
636 }
637 
643 static int is_pattern_cache_set(int cache_entry)
644 {
645  return cache_entry != 0;
646 }
647 
656 static int msg_search_sendmode(struct Email *e, struct Pattern *pat)
657 {
658  bool match = false;
659  char *buf = NULL;
660  size_t blen = 0;
661  FILE *fp = NULL;
662 
663  if ((pat->op == MUTT_PAT_HEADER) || (pat->op == MUTT_PAT_WHOLE_MSG))
664  {
665  struct Buffer *tempfile = mutt_buffer_pool_get();
666  mutt_buffer_mktemp(tempfile);
667  fp = mutt_file_fopen(mutt_b2s(tempfile), "w+");
668  if (!fp)
669  {
670  mutt_perror(mutt_b2s(tempfile));
671  mutt_buffer_pool_release(&tempfile);
672  return 0;
673  }
674 
676  false, false, NeoMutt->sub);
677  fflush(fp);
678  fseek(fp, 0, 0);
679 
680  while ((buf = mutt_file_read_line(buf, &blen, fp, NULL, 0)) != NULL)
681  {
682  if (patmatch(pat, buf) == 0)
683  {
684  match = true;
685  break;
686  }
687  }
688 
689  FREE(&buf);
690  mutt_file_fclose(&fp);
691  unlink(mutt_b2s(tempfile));
692  mutt_buffer_pool_release(&tempfile);
693 
694  if (match)
695  return match;
696  }
697 
698  if ((pat->op == MUTT_PAT_BODY) || (pat->op == MUTT_PAT_WHOLE_MSG))
699  {
700  fp = mutt_file_fopen(e->body->filename, "r");
701  if (!fp)
702  {
704  return 0;
705  }
706 
707  while ((buf = mutt_file_read_line(buf, &blen, fp, NULL, 0)) != NULL)
708  {
709  if (patmatch(pat, buf) == 0)
710  {
711  match = true;
712  break;
713  }
714  }
715 
716  FREE(&buf);
717  mutt_file_fclose(&fp);
718  }
719 
720  return match;
721 }
722 
739  struct Mailbox *m, struct Email *e, struct PatternCache *cache)
740 {
741  switch (pat->op)
742  {
743  case MUTT_PAT_AND:
744  return pat->pat_not ^ (perform_and(pat->child, flags, m, e, cache) > 0);
745  case MUTT_PAT_OR:
746  return pat->pat_not ^ (perform_or(pat->child, flags, m, e, cache) > 0);
747  case MUTT_PAT_THREAD:
748  return pat->pat_not ^
749  match_threadcomplete(pat->child, flags, m, e->thread, 1, 1, 1, 1);
750  case MUTT_PAT_PARENT:
751  return pat->pat_not ^ match_threadparent(pat->child, flags, m, e->thread);
752  case MUTT_PAT_CHILDREN:
753  return pat->pat_not ^ match_threadchildren(pat->child, flags, m, e->thread);
754  case MUTT_ALL:
755  return !pat->pat_not;
756  case MUTT_EXPIRED:
757  return pat->pat_not ^ e->expired;
758  case MUTT_SUPERSEDED:
759  return pat->pat_not ^ e->superseded;
760  case MUTT_FLAG:
761  return pat->pat_not ^ e->flagged;
762  case MUTT_TAG:
763  return pat->pat_not ^ e->tagged;
764  case MUTT_NEW:
765  return pat->pat_not ? e->old || e->read : !(e->old || e->read);
766  case MUTT_UNREAD:
767  return pat->pat_not ? e->read : !e->read;
768  case MUTT_REPLIED:
769  return pat->pat_not ^ e->replied;
770  case MUTT_OLD:
771  return pat->pat_not ? (!e->old || e->read) : (e->old && !e->read);
772  case MUTT_READ:
773  return pat->pat_not ^ e->read;
774  case MUTT_DELETED:
775  return pat->pat_not ^ e->deleted;
776  case MUTT_PAT_MESSAGE:
777  return pat->pat_not ^ ((EMSG(e) >= pat->min) && (EMSG(e) <= pat->max));
778  case MUTT_PAT_DATE:
779  if (pat->dynamic)
781  return pat->pat_not ^ (e->date_sent >= pat->min && e->date_sent <= pat->max);
783  if (pat->dynamic)
785  return pat->pat_not ^ (e->received >= pat->min && e->received <= pat->max);
786  case MUTT_PAT_BODY:
787  case MUTT_PAT_HEADER:
788  case MUTT_PAT_WHOLE_MSG:
789  if (pat->sendmode)
790  {
791  if (!e->body || !e->body->filename)
792  return 0;
793  return pat->pat_not ^ msg_search_sendmode(e, pat);
794  }
795  /* m can be NULL in certain cases, such as when replying to a message
796  * from the attachment menu and the user has a reply-hook using "~e".
797  * This is also the case when message scoring. */
798  if (!m)
799  return 0;
800 #ifdef USE_IMAP
801  /* IMAP search sets e->matched at search compile time */
802  if ((m->type == MUTT_IMAP) && pat->string_match)
803  return e->matched;
804 #endif
805  return pat->pat_not ^ msg_search(m, pat, e->msgno);
807 #ifdef USE_IMAP
808  if (!m)
809  return 0;
810  if (m->type == MUTT_IMAP)
811  {
812  if (pat->string_match)
813  return e->matched;
814  return 0;
815  }
816  mutt_error(_("error: server custom search only supported with IMAP"));
817  return 0;
818 #else
819  mutt_error(_("error: server custom search only supported with IMAP"));
820  return -1;
821 #endif
822  case MUTT_PAT_SENDER:
823  if (!e->env)
824  return 0;
825  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
826  1, &e->env->sender);
827  case MUTT_PAT_FROM:
828  if (!e->env)
829  return 0;
830  return pat->pat_not ^
831  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->from);
832  case MUTT_PAT_TO:
833  if (!e->env)
834  return 0;
835  return pat->pat_not ^
836  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->to);
837  case MUTT_PAT_CC:
838  if (!e->env)
839  return 0;
840  return pat->pat_not ^
841  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->cc);
842  case MUTT_PAT_SUBJECT:
843  if (!e->env)
844  return 0;
845  return pat->pat_not ^ (e->env->subject && patmatch(pat, e->env->subject));
846  case MUTT_PAT_ID:
848  if (!e->env)
849  return 0;
850  return pat->pat_not ^ (e->env->message_id && patmatch(pat, e->env->message_id));
851  case MUTT_PAT_SCORE:
852  return pat->pat_not ^ (e->score >= pat->min &&
853  (pat->max == MUTT_MAXRANGE || e->score <= pat->max));
854  case MUTT_PAT_SIZE:
855  return pat->pat_not ^ (e->body->length >= pat->min &&
856  (pat->max == MUTT_MAXRANGE || e->body->length <= pat->max));
857  case MUTT_PAT_REFERENCE:
858  if (!e->env)
859  return 0;
860  return pat->pat_not ^ (match_reference(pat, &e->env->references) ||
861  match_reference(pat, &e->env->in_reply_to));
862  case MUTT_PAT_ADDRESS:
863  if (!e->env)
864  return 0;
865  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
866  4, &e->env->from, &e->env->sender,
867  &e->env->to, &e->env->cc);
868  case MUTT_PAT_RECIPIENT:
869  if (!e->env)
870  return 0;
871  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
872  2, &e->env->to, &e->env->cc);
873  case MUTT_PAT_LIST: /* known list, subscribed or not */
874  {
875  if (!e->env)
876  return 0;
877 
878  int result;
879  if (cache)
880  {
881  int *cache_entry = pat->all_addr ? &cache->list_all : &cache->list_one;
882  if (!is_pattern_cache_set(*cache_entry))
883  {
884  set_pattern_cache_value(cache_entry,
886  }
887  result = get_pattern_cache_value(*cache_entry);
888  }
889  else
890  result = mutt_is_list_recipient(pat->all_addr, e->env);
891  return pat->pat_not ^ result;
892  }
894  {
895  if (!e->env)
896  return 0;
897 
898  int result;
899  if (cache)
900  {
901  int *cache_entry = pat->all_addr ? &cache->sub_all : &cache->sub_one;
902  if (!is_pattern_cache_set(*cache_entry))
903  {
905  cache_entry, mutt_is_subscribed_list_recipient(pat->all_addr, e->env));
906  }
907  result = get_pattern_cache_value(*cache_entry);
908  }
909  else
911  return pat->pat_not ^ result;
912  }
914  {
915  if (!e->env)
916  return 0;
917 
918  int result;
919  if (cache)
920  {
921  int *cache_entry = pat->all_addr ? &cache->pers_recip_all : &cache->pers_recip_one;
922  if (!is_pattern_cache_set(*cache_entry))
923  {
925  cache_entry, match_user(pat->all_addr, &e->env->to, &e->env->cc));
926  }
927  result = get_pattern_cache_value(*cache_entry);
928  }
929  else
930  result = match_user(pat->all_addr, &e->env->to, &e->env->cc);
931  return pat->pat_not ^ result;
932  }
934  {
935  if (!e->env)
936  return 0;
937 
938  int result;
939  if (cache)
940  {
941  int *cache_entry = pat->all_addr ? &cache->pers_from_all : &cache->pers_from_one;
942  if (!is_pattern_cache_set(*cache_entry))
943  {
944  set_pattern_cache_value(cache_entry,
945  match_user(pat->all_addr, &e->env->from, NULL));
946  }
947  result = get_pattern_cache_value(*cache_entry);
948  }
949  else
950  result = match_user(pat->all_addr, &e->env->from, NULL);
951  return pat->pat_not ^ result;
952  }
953  case MUTT_PAT_COLLAPSED:
954  return pat->pat_not ^ (e->collapsed && e->num_hidden > 1);
955  case MUTT_PAT_CRYPT_SIGN:
956  if (!WithCrypto)
957  {
959  return 0;
960  }
961  return pat->pat_not ^ ((e->security & SEC_SIGN) ? 1 : 0);
963  if (!WithCrypto)
964  {
966  return 0;
967  }
968  return pat->pat_not ^ ((e->security & SEC_GOODSIGN) ? 1 : 0);
970  if (!WithCrypto)
971  {
973  return 0;
974  }
975  return pat->pat_not ^ ((e->security & SEC_ENCRYPT) ? 1 : 0);
976  case MUTT_PAT_PGP_KEY:
977  if (!(WithCrypto & APPLICATION_PGP))
978  {
980  return 0;
981  }
982  return pat->pat_not ^ ((e->security & PGP_KEY) == PGP_KEY);
983  case MUTT_PAT_XLABEL:
984  if (!e->env)
985  return 0;
986  return pat->pat_not ^ (e->env->x_label && patmatch(pat, e->env->x_label));
988  {
989  char *tags = driver_tags_get(&e->tags);
990  bool rc = (pat->pat_not ^ (tags && patmatch(pat, tags)));
991  FREE(&tags);
992  return rc;
993  }
994  case MUTT_PAT_HORMEL:
995  if (!e->env)
996  return 0;
997  return pat->pat_not ^ (e->env->spam.data && patmatch(pat, e->env->spam.data));
998  case MUTT_PAT_DUPLICATED:
999  return pat->pat_not ^ (e->thread && e->thread->duplicate_thread);
1000  case MUTT_PAT_MIMEATTACH:
1001  if (!m)
1002  return 0;
1003  {
1004  int count = mutt_count_body_parts(m, e);
1005  return pat->pat_not ^ (count >= pat->min &&
1006  (pat->max == MUTT_MAXRANGE || count <= pat->max));
1007  }
1008  case MUTT_PAT_MIMETYPE:
1009  if (!m)
1010  return 0;
1011  return pat->pat_not ^ match_mime_content_type(pat, m, e);
1012  case MUTT_PAT_UNREFERENCED:
1013  return pat->pat_not ^ (e->thread && !e->thread->child);
1014  case MUTT_PAT_BROKEN:
1015  return pat->pat_not ^ (e->thread && e->thread->fake_thread);
1016 #ifdef USE_NNTP
1017  case MUTT_PAT_NEWSGROUPS:
1018  if (!e->env)
1019  return 0;
1020  return pat->pat_not ^ (e->env->newsgroups && patmatch(pat, e->env->newsgroups));
1021 #endif
1022  }
1023  mutt_error(_("error: unknown op %d (report this error)"), pat->op);
1024  return 0;
1025 }
1026 
1042  struct AliasView *av, struct PatternCache *cache)
1043 {
1044  switch (pat->op)
1045  {
1046  case MUTT_PAT_FROM: /* alias */
1047  if (!av->alias)
1048  return 0;
1049  return pat->pat_not ^ (av->alias->name && patmatch(pat, av->alias->name));
1050  case MUTT_PAT_CC: /* comment */
1051  if (!av->alias)
1052  return 0;
1053  return pat->pat_not ^ (av->alias->comment && patmatch(pat, av->alias->comment));
1054  case MUTT_PAT_TO: /* alias address list */
1055  if (!av->alias)
1056  return 0;
1057  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
1058  1, &av->alias->addr);
1059  case MUTT_PAT_AND:
1060  return pat->pat_not ^ (perform_alias_and(pat->child, flags, av, cache) > 0);
1061  case MUTT_PAT_OR:
1062  return pat->pat_not ^ (perform_alias_or(pat->child, flags, av, cache) > 0);
1063  }
1064 
1065  return 0;
1066 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
struct MuttThread * next
Next sibling Thread.
Definition: thread.h:47
Pattern matches message number.
Definition: lib.h:151
struct PatternList * child
Arguments to logical operation.
Definition: lib.h:85
Deleted messages.
Definition: mutt.h:101
static int match_threadparent(struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct MuttThread *t)
Match Pattern against an email&#39;s parent.
Definition: exec.c:528
char * name
Short name.
Definition: alias.h:35
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: lib.h:87
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
Miscellaneous email parsing routines.
Pattern matches email&#39;s Message-Id.
Definition: lib.h:144
#define WithCrypto
Definition: lib.h:123
Pattern matches email&#39;s body.
Definition: lib.h:146
bool group_match
Check a group of Addresses.
Definition: lib.h:77
The envelope/body of an email.
Definition: email.h:37
static int get_pattern_cache_value(int cache_entry)
Get pattern cache value.
Definition: exec.c:633
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_perror(...)
Definition: logging.h:85
Message is signed.
Definition: lib.h:161
A postponed Email, just the envelope info.
Definition: header.h:42
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
struct Body * body
List of MIME parts.
Definition: email.h:91
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
Structs that make up an email.
static int msg_search_sendmode(struct Email *e, struct Pattern *pat)
Search in send-mode.
Definition: exec.c:656
static int match_user(int all_addr, struct AddressList *al1, struct AddressList *al2)
Matches the user&#39;s email Address.
Definition: exec.c:454
Convenience wrapper for the send headers.
int pers_recip_all
^~p
Definition: lib.h:114
struct MuttThread * thread
Thread of Emails.
Definition: email.h:95
Email is on mailing list.
Definition: lib.h:156
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t.
Definition: maillist.c:45
Pattern matches &#39;To:&#39; field.
Definition: lib.h:134
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
static void set_pattern_cache_value(int *cache_entry, int value)
Sets a value in the PatternCache cache entry.
Definition: exec.c:622
String manipulation buffer.
Definition: buffer.h:33
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:49
Flagged messages.
Definition: mutt.h:102
#define EMSG(e)
Definition: private.h:119
Pattern matches date received.
Definition: lib.h:140
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:55
#define _(a)
Definition: message.h:28
bool mutt_is_subscribed_list(const struct Address *addr)
Is this the email address of a user-subscribed mailing list? - Implements addr_predicate_t.
Definition: maillist.c:57
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:667
struct Body * next
next attachment in the list
Definition: body.h:53
An email address.
Definition: address.h:34
Pattern matches &#39;References:&#39; or &#39;In-Reply-To:&#39; field.
Definition: lib.h:154
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
FILE * fp_out
File to write to.
Definition: state.h:47
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool is_multi
Multiple case (only for ~I pattern now)
Definition: lib.h:82
GUI data wrapping an Alias.
Definition: gui.h:36
bool mutt_group_match(struct Group *g, const char *s)
Does a string match an entry in a Group?
Definition: group.c:324
bool expired
Already expired?
Definition: email.h:52
static int match_threadcomplete(struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct MuttThread *t, int left, int up, int right, int down)
Match a Pattern against an email thread.
Definition: exec.c:490
int mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *e)
Matches subscribed mailing lists.
Definition: exec.c:427
Container for Accounts, Notifications.
Definition: neomutt.h:36
Message is unreferenced in the thread.
Definition: lib.h:142
FILE * fp_in
File to read from.
Definition: state.h:46
Representation of a single alias to an email address.
static int match_addrlist(struct Pattern *pat, bool match_personal, int n,...)
Match a Pattern against an Address list.
Definition: exec.c:351
Messages that have been replied to.
Definition: mutt.h:95
The body of an email.
Definition: body.h:34
A simple (non-regex) pattern.
Definition: lib.h:71
int sub_all
^~u
Definition: lib.h:112
Pattern matches &#39;From:&#39; field.
Definition: lib.h:138
Email Address Handling.
Pattern matches email&#39;s header.
Definition: lib.h:147
Some miscellaneous functions.
Server-side pattern matches.
Definition: lib.h:166
#define mutt_array_size(x)
Definition: memory.h:33
bool is_alias
Is there an alias for this Address?
Definition: lib.h:79
Message is encrypted.
Definition: lib.h:163
static bool msg_search(struct Mailbox *m, struct Pattern *pat, int msgno)
Search an email.
Definition: exec.c:106
static bool match_update_dynamic_date(struct Pattern *pat)
Update a dynamic date pattern.
Definition: exec.c:605
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1204
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:134
All messages.
Definition: mutt.h:91
bool tagged
Email is tagged.
Definition: email.h:44
bool read
Email is read.
Definition: email.h:51
bool dynamic
Evaluate date ranges at run time.
Definition: lib.h:80
Message is crypographically verified.
Definition: lib.h:162
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
char * message_id
Message ID.
Definition: envelope.h:69
bool all_addr
All Addresses in the list must match.
Definition: lib.h:75
bool(* addr_predicate_t)(const struct Address *a)
Test an Address for some condition.
Definition: address.h:69
bool eval_date_minmax(struct Pattern *pat, const char *s, struct Buffer *err)
Evaluate a date-range pattern against &#39;now&#39;.
Definition: compile.c:487
struct MuttThread * prev
Previous sibling Thread.
Definition: thread.h:48
static int mutt_is_predicate_recipient(bool all_addr, struct Envelope *e, addr_predicate_t p)
Test an Envelopes Addresses using a predicate function.
Definition: exec.c:403
Many unsorted constants and some structs.
API for mailboxes.
bool old
Email is seen, but unread.
Definition: email.h:50
static bool match_content_type(const struct Pattern *pat, struct Body *b)
Match a Pattern against an Attachment&#39;s Content-Type.
Definition: exec.c:567
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
static int match_threadchildren(struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct MuttThread *t)
Match Pattern against an email&#39;s children.
Definition: exec.c:547
Pattern matches sender.
Definition: lib.h:150
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: exec.c:65
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
Pattern matches keyword/label.
Definition: lib.h:165
Email is addressed to the user.
Definition: lib.h:158
struct Envelope * env
Envelope information.
Definition: email.h:90
Convenience wrapper for the core headers.
Email is from the user.
Definition: lib.h:159
struct ListNode * mutt_list_find(const struct ListHead *h, const char *data)
Find a string in a List.
Definition: list.c:102
Pattern matches newsgroup.
Definition: lib.h:171
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
struct Address * alias_reverse_lookup(const struct Address *addr)
Does the user have an alias for the given address.
Definition: reverse.c:105
bool pat_not
Pattern should be inverted (not)
Definition: lib.h:74
bool string_match
Check a string for a match.
Definition: lib.h:76
bool superseded
Got superseded?
Definition: email.h:53
Email Aliases.
int min
Minimum for range checks.
Definition: lib.h:83
bool ign_case
Ignore case for local string_match searches.
Definition: lib.h:78
Pattern matches any address field.
Definition: lib.h:160
struct TagList tags
For drivers that support server tagging.
Definition: email.h:109
Message is part of a broken thread.
Definition: lib.h:143
Email is on subscribed mailing list.
Definition: lib.h:157
int score
Message score.
Definition: email.h:89
char * subtype
content-type subtype
Definition: body.h:37
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:82
Old messages.
Definition: mutt.h:94
#define mutt_b2s(buf)
Definition: buffer.h:41
int pers_from_one
~P
Definition: lib.h:117
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
bool duplicate_thread
Duplicated Email in Thread.
Definition: thread.h:37
const struct PatternFlags * lookup_op(int op)
Lookup the Pattern Flags for an op.
Definition: flags.c:210
struct Alias * alias
Alias.
Definition: gui.h:45
int pers_recip_one
~p
Definition: lib.h:115
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
#define SLIST_FIRST(head)
Definition: queue.h:228
A local copy of an email.
Definition: mx.h:82
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
Pattern matches MIME type.
Definition: lib.h:169
bool fake_thread
Emails grouped by Subject.
Definition: thread.h:36
A mailbox.
Definition: mailbox.h:81
int mutt_is_list_recipient(bool all_addr, struct Envelope *e)
Matches known mailing lists.
Definition: exec.c:440
int mutt_pattern_alias_exec(struct Pattern *pat, PatternExecFlags flags, struct AliasView *av, struct PatternCache *cache)
Match a pattern against an alias.
Definition: exec.c:1041
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
Message-Id is among results from an external query.
Definition: lib.h:145
static bool perform_and(struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Perform a logical AND on a set of Patterns.
Definition: exec.c:264
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:142
union Pattern::@1 p
size_t num_hidden
Number of hidden messages in this view (only valid when collapsed is set)
Definition: email.h:75
bool C_ThoroughSearch
Config: Decode headers and messages before searching them.
Definition: config.c:38
Superseded messages.
Definition: mutt.h:107
Tagged messages.
Definition: mutt.h:103
char * data
Pointer to data.
Definition: buffer.h:35
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:53
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
int list_all
^~l
Definition: lib.h:110
New messages.
Definition: mutt.h:93
Messages that have been read.
Definition: mutt.h:96
Pattern matches number of attachments.
Definition: lib.h:168
#define mutt_file_mkstemp()
Definition: file.h:106
API for encryption/signing of emails.
char * comment
Free-form comment string.
Definition: alias.h:37
static int is_pattern_cache_set(int cache_entry)
Is a given Pattern cached?
Definition: exec.c:643
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: lib.h:73
#define MUTT_MAXRANGE
Definition: private.h:121
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
static int perform_alias_or(struct PatternList *pat, PatternExecFlags flags, struct AliasView *av, struct PatternCache *cache)
Perform a logical OR on a set of Patterns.
Definition: exec.c:328
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
Handle mailing lists.
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:84
Expired messages.
Definition: mutt.h:106
int pers_from_all
^~P
Definition: lib.h:116
An Email conversation.
Definition: thread.h:34
#define SEC_SIGN
Email is signed.
Definition: lib.h:86
int mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: exec.c:738
char * personal
Real name of address.
Definition: address.h:36
Unread messages.
Definition: mutt.h:97
Keep track when processing files.
#define TYPE(body)
Definition: mime.h:89
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
int tag
Character used to represent this operation, e.g. &#39;A&#39; for &#39;~A&#39;.
Definition: private.h:53
Pattern matches &#39;Date:&#39; field.
Definition: lib.h:139
Thread is collapsed.
Definition: lib.h:136
char * data
String.
Definition: list.h:36
char * subject
Email&#39;s subject.
Definition: envelope.h:66
Pattern matches &#39;Cc:&#39; field.
Definition: lib.h:135
Duplicate message.
Definition: lib.h:141
Duplicate the structure of an entire email.
Both patterns must match.
Definition: lib.h:129
#define PGP_KEY
Definition: lib.h:106
Shared constants/structs that are private to libpattern.
static bool perform_alias_and(struct PatternList *pat, PatternExecFlags flags, struct AliasView *av, struct PatternCache *cache)
Perform a logical AND on a set of Patterns.
Definition: exec.c:285
bool flagged
Marked important?
Definition: email.h:43
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
char * str
String, if string_match is set.
Definition: lib.h:89
bool deleted
Email is deleted.
Definition: email.h:45
Either pattern can match.
Definition: lib.h:130
int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy Email header.
Definition: copy.c:405
bool sendmode
Evaluate searches in send-mode.
Definition: lib.h:81
#define mutt_error(...)
Definition: logging.h:84
bool replied
Email has been replied to.
Definition: email.h:54
struct Group * group
Address group if group_match is set.
Definition: lib.h:88
static void print_crypt_pattern_op_error(int op)
Print an error for a disabled crypto pattern.
Definition: exec.c:80
Pattern matches parent.
Definition: lib.h:132
FILE * fp
pointer to the message data
Definition: mx.h:84
Pattern matches email&#39;s spam score.
Definition: lib.h:148
User is a recipient of the email.
Definition: lib.h:155
static bool match_reference(struct Pattern *pat, struct ListHead *refs)
Match references against a Pattern.
Definition: exec.c:381
#define FREE(x)
Definition: memory.h:40
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:547
int max
Maximum for range checks.
Definition: lib.h:84
Keep track when processing files.
Definition: state.h:44
#define SLIST_FOREACH(var, head, field)
Definition: queue.h:230
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
struct AddressList sender
Email&#39;s sender.
Definition: envelope.h:61
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: lib.h:90
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1593
Pattern matches raw email text.
Definition: lib.h:149
Pattern matches a child email.
Definition: lib.h:133
int mutt_count_body_parts(struct Mailbox *m, struct Email *e)
Count the MIME Body parts.
Definition: mutt_parse.c:206
Mapping between user character and internal constant.
Definition: private.h:51
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
static int perform_or(struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Perform a logical OR on a set of Patterns.
Definition: exec.c:307
Cache commonly-used patterns.
Definition: lib.h:108
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:36
Pattern matches message tags.
Definition: lib.h:167
Pattern matches email thread.
Definition: lib.h:131
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
A List node for strings.
Definition: list.h:34
Decide how to display email content.
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
char * x_label
X-Label.
Definition: envelope.h:72
Shared code for the Alias and Query Dialogs.
#define SEC_GOODSIGN
Email has a valid signature.
Definition: lib.h:87
int list_one
~l
Definition: lib.h:111
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:98
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1158
Message has PGP key.
Definition: lib.h:164
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:573
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
Pattern matches email&#39;s score.
Definition: lib.h:152
uint8_t PatternExecFlags
Flags for mutt_pattern_exec(), e.g. MUTT_MATCH_FULL_ADDRESS.
Definition: lib.h:96
The header of an Email.
Definition: envelope.h:54
Pattern matches email&#39;s size.
Definition: lib.h:153
struct Buffer spam
Spam header.
Definition: envelope.h:80
bool matched
Search matches this Email.
Definition: email.h:68
int msgno
Number displayed to the user.
Definition: email.h:87
int sub_one
~u
Definition: lib.h:113
Pattern matches &#39;Subject:&#39; field.
Definition: lib.h:137
char * mutt_rfc822_read_line(FILE *fp, char *line, size_t *linelen)
Read a header line from a file.
Definition: parse.c:1036
static bool match_mime_content_type(const struct Pattern *pat, struct Mailbox *m, struct Email *e)
Match a Pattern against an email&#39;s Content-Type.
Definition: exec.c:592