NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
pattern.c
Go to the documentation of this file.
1 
31 #include "config.h"
32 #include <stddef.h>
33 #include <stdbool.h>
34 #include "private.h"
35 #include "mutt/lib.h"
36 #include "config/lib.h"
37 #include "email/lib.h"
38 #include "core/lib.h"
39 #include "alias/gui.h" // IWYU pragma: keep
40 #include "alias/lib.h"
41 #include "gui/lib.h"
42 #include "mutt.h"
43 #include "lib.h"
44 #include "menu/lib.h"
45 #include "progress/lib.h"
46 #include "context.h"
47 #include "mutt_globals.h"
48 #include "mutt_logging.h"
49 #include "mx.h"
50 #include "opcodes.h"
51 #include "options.h"
52 #include "protos.h"
53 #ifndef USE_FMEMOPEN
54 #include <sys/stat.h>
55 #endif
56 #ifdef USE_IMAP
57 #include "imap/lib.h"
58 #endif
59 
60 // clang-format off
66 struct RangeRegex range_regexes[] = {
67  [RANGE_K_REL] = { RANGE_REL_RX, 1, 3, 0, { 0 } },
68  [RANGE_K_ABS] = { RANGE_ABS_RX, 1, 3, 0, { 0 } },
69  [RANGE_K_LT] = { RANGE_LT_RX, 1, 2, 0, { 0 } },
70  [RANGE_K_GT] = { RANGE_GT_RX, 2, 1, 0, { 0 } },
71  [RANGE_K_BARE] = { RANGE_BARE_RX, 1, 1, 0, { 0 } },
72 };
73 // clang-format on
74 
83 bool (*eat_arg_t)(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s,
84  struct Buffer *err);
85 
86 static struct PatternList *SearchPattern = NULL;
87 static char LastSearch[256] = { 0 };
88 static char LastSearchExpn[1024] = { 0 };
89 
95 static void quote_simple(const char *str, struct Buffer *buf)
96 {
97  mutt_buffer_reset(buf);
98  mutt_buffer_addch(buf, '"');
99  while (*str)
100  {
101  if ((*str == '\\') || (*str == '"'))
102  mutt_buffer_addch(buf, '\\');
103  mutt_buffer_addch(buf, *str++);
104  }
105  mutt_buffer_addch(buf, '"');
106 }
107 
113 void mutt_check_simple(struct Buffer *buf, const char *simple)
114 {
115  bool do_simple = true;
116 
117  for (const char *p = mutt_buffer_string(buf); p && (p[0] != '\0'); p++)
118  {
119  if ((p[0] == '\\') && (p[1] != '\0'))
120  p++;
121  else if ((p[0] == '~') || (p[0] == '=') || (p[0] == '%'))
122  {
123  do_simple = false;
124  break;
125  }
126  }
127 
128  /* XXX - is mutt_istr_cmp() right here, or should we use locale's
129  * equivalences? */
130 
131  if (do_simple) /* yup, so spoof a real request */
132  {
133  /* convert old tokens into the new format */
134  if (mutt_istr_equal("all", mutt_buffer_string(buf)) ||
135  mutt_str_equal("^", mutt_buffer_string(buf)) ||
136  mutt_str_equal(".", mutt_buffer_string(buf))) /* ~A is more efficient */
137  {
138  mutt_buffer_strcpy(buf, "~A");
139  }
140  else if (mutt_istr_equal("del", mutt_buffer_string(buf)))
141  mutt_buffer_strcpy(buf, "~D");
142  else if (mutt_istr_equal("flag", mutt_buffer_string(buf)))
143  mutt_buffer_strcpy(buf, "~F");
144  else if (mutt_istr_equal("new", mutt_buffer_string(buf)))
145  mutt_buffer_strcpy(buf, "~N");
146  else if (mutt_istr_equal("old", mutt_buffer_string(buf)))
147  mutt_buffer_strcpy(buf, "~O");
148  else if (mutt_istr_equal("repl", mutt_buffer_string(buf)))
149  mutt_buffer_strcpy(buf, "~Q");
150  else if (mutt_istr_equal("read", mutt_buffer_string(buf)))
151  mutt_buffer_strcpy(buf, "~R");
152  else if (mutt_istr_equal("tag", mutt_buffer_string(buf)))
153  mutt_buffer_strcpy(buf, "~T");
154  else if (mutt_istr_equal("unread", mutt_buffer_string(buf)))
155  mutt_buffer_strcpy(buf, "~U");
156  else
157  {
158  struct Buffer *tmp = mutt_buffer_pool_get();
159  quote_simple(mutt_buffer_string(buf), tmp);
160  mutt_file_expand_fmt(buf, simple, mutt_buffer_string(tmp));
162  }
163  }
164 }
165 
172 static struct MuttThread *top_of_thread(struct Email *e)
173 {
174  if (!e)
175  return NULL;
176 
177  struct MuttThread *t = e->thread;
178 
179  while (t && t->parent)
180  t = t->parent;
181 
182  return t;
183 }
184 
192 bool mutt_limit_current_thread(struct Context *ctx, struct Email *e)
193 {
194  if (!ctx || !ctx->mailbox || !e)
195  return false;
196 
197  struct Mailbox *m = ctx->mailbox;
198 
199  struct MuttThread *me = top_of_thread(e);
200  if (!me)
201  return false;
202 
203  m->vcount = 0;
204  ctx->vsize = 0;
205  ctx->collapsed = false;
206 
207  for (int i = 0; i < m->msg_count; i++)
208  {
209  e = m->emails[i];
210  if (!e)
211  break;
212 
213  e->vnum = -1;
214  e->visible = false;
215  e->collapsed = false;
216  e->num_hidden = 0;
217 
218  if (top_of_thread(e) == me)
219  {
220  struct Body *body = e->body;
221 
222  e->vnum = m->vcount;
223  e->visible = true;
224  m->v2r[m->vcount] = i;
225  m->vcount++;
226  ctx->vsize += (body->length + body->offset - body->hdr_offset);
227  }
228  }
229  return true;
230 }
231 
241 int mutt_pattern_alias_func(int op, char *prompt, struct AliasMenuData *mdata,
242  struct Menu *menu)
243 {
244  int rc = -1;
245  struct Progress *progress = NULL;
246  struct Buffer *buf = mutt_buffer_pool_get();
247 
248  mutt_buffer_strcpy(buf, mdata->str);
249  if (prompt)
250  {
251  if ((mutt_buffer_get_field(prompt, buf, MUTT_PATTERN | MUTT_CLEAR, false,
252  NULL, NULL, NULL) != 0) ||
254  {
256  return -1;
257  }
258  }
259 
260  mutt_message(_("Compiling search pattern..."));
261 
262  bool match_all = false;
263  struct PatternList *pat = NULL;
264  char *simple = mutt_buffer_strdup(buf);
265  if (simple)
266  {
268  const char *pbuf = buf->data;
269  while (*pbuf == ' ')
270  pbuf++;
271  match_all = mutt_str_equal(pbuf, "~A");
272 
273  struct Buffer err = mutt_buffer_make(0);
274  pat = mutt_pattern_comp(NULL, menu, buf->data, MUTT_PC_FULL_MSG, &err);
275  if (!pat)
276  {
277  mutt_error("%s", mutt_buffer_string(&err));
278  mutt_buffer_dealloc(&err);
279  goto bail;
280  }
281  }
282  else
283  {
284  match_all = true;
285  }
286 
287  progress = progress_new(_("Executing command on matching messages..."),
288  MUTT_PROGRESS_READ, ARRAY_SIZE(&mdata->ava));
289 
290  int vcounter = 0;
291  struct AliasView *avp = NULL;
292  ARRAY_FOREACH(avp, &mdata->ava)
293  {
294  progress_update(progress, ARRAY_FOREACH_IDX, -1);
295 
296  if (match_all ||
298  {
299  avp->is_visible = true;
300  vcounter++;
301  }
302  else
303  {
304  avp->is_visible = false;
305  }
306  }
307  progress_free(&progress);
308 
309  FREE(&mdata->str);
310  if (!match_all)
311  {
312  mdata->str = simple;
313  simple = NULL;
314  }
315 
316  if (menu)
317  {
318  menu->max = vcounter;
319  menu_set_index(menu, 0);
320  }
321 
323 
324  rc = 0;
325 
326 bail:
328  FREE(&simple);
329  mutt_pattern_free(&pat);
330 
331  return rc;
332 }
333 
342 int mutt_pattern_func(struct Context *ctx, int op, char *prompt)
343 {
344  if (!ctx || !ctx->mailbox)
345  return -1;
346 
347  struct Mailbox *m = ctx->mailbox;
348 
349  struct Buffer err;
350  int rc = -1;
351  struct Progress *progress = NULL;
352  struct Buffer *buf = mutt_buffer_pool_get();
353 
354  mutt_buffer_strcpy(buf, NONULL(ctx->pattern));
355  if (prompt || (op != MUTT_LIMIT))
356  {
357  if ((mutt_buffer_get_field(prompt, buf, MUTT_PATTERN | MUTT_CLEAR, false,
358  NULL, NULL, NULL) != 0) ||
360  {
362  return -1;
363  }
364  }
365 
366  mutt_message(_("Compiling search pattern..."));
367 
368  char *simple = mutt_buffer_strdup(buf);
369  const char *const c_simple_search =
370  cs_subset_string(NeoMutt->sub, "simple_search");
371  mutt_check_simple(buf, NONULL(c_simple_search));
372  const char *pbuf = buf->data;
373  while (*pbuf == ' ')
374  pbuf++;
375  const bool match_all = mutt_str_equal(pbuf, "~A");
376 
377  mutt_buffer_init(&err);
378  err.dsize = 256;
379  err.data = mutt_mem_malloc(err.dsize);
380  struct PatternList *pat =
381  mutt_pattern_comp(m, ctx->menu, buf->data, MUTT_PC_FULL_MSG, &err);
382  if (!pat)
383  {
384  mutt_error("%s", err.data);
385  goto bail;
386  }
387 
388 #ifdef USE_IMAP
389  if ((m->type == MUTT_IMAP) && (!imap_search(m, pat)))
390  goto bail;
391 #endif
392 
393  progress = progress_new(_("Executing command on matching messages..."), MUTT_PROGRESS_READ,
394  (op == MUTT_LIMIT) ? m->msg_count : m->vcount);
395 
396  if (op == MUTT_LIMIT)
397  {
398  m->vcount = 0;
399  ctx->vsize = 0;
400  ctx->collapsed = false;
401  int padding = mx_msg_padding_size(m);
402 
403  for (int i = 0; i < m->msg_count; i++)
404  {
405  struct Email *e = m->emails[i];
406  if (!e)
407  break;
408 
409  progress_update(progress, i, -1);
410  /* new limit pattern implicitly uncollapses all threads */
411  e->vnum = -1;
412  e->visible = false;
413  e->collapsed = false;
414  e->num_hidden = 0;
415  if (match_all ||
417  {
418  e->vnum = m->vcount;
419  e->visible = true;
420  m->v2r[m->vcount] = i;
421  m->vcount++;
422  struct Body *b = e->body;
423  ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
424  }
425  }
426  }
427  else
428  {
429  for (int i = 0; i < m->vcount; i++)
430  {
431  struct Email *e = mutt_get_virt_email(m, i);
432  if (!e)
433  continue;
434  progress_update(progress, i, -1);
436  {
437  switch (op)
438  {
439  case MUTT_UNDELETE:
440  mutt_set_flag(m, e, MUTT_PURGE, false);
441  /* fallthrough */
442  case MUTT_DELETE:
443  mutt_set_flag(m, e, MUTT_DELETE, (op == MUTT_DELETE));
444  break;
445  case MUTT_TAG:
446  case MUTT_UNTAG:
447  mutt_set_flag(m, e, MUTT_TAG, (op == MUTT_TAG));
448  break;
449  }
450  }
451  }
452  }
453  progress_free(&progress);
454 
456 
457  if (op == MUTT_LIMIT)
458  {
459  /* drop previous limit pattern */
460  FREE(&ctx->pattern);
462 
463  if (m->msg_count && !m->vcount)
464  mutt_error(_("No messages matched criteria"));
465 
466  /* record new limit pattern, unless match all */
467  if (!match_all)
468  {
469  ctx->pattern = simple;
470  simple = NULL; /* don't clobber it */
471  ctx->limit_pattern =
472  mutt_pattern_comp(m, ctx->menu, buf->data, MUTT_PC_FULL_MSG, &err);
473  }
474  }
475 
476  rc = 0;
477 
478 bail:
480  FREE(&simple);
481  mutt_pattern_free(&pat);
482  FREE(&err.data);
483 
484  return rc;
485 }
486 
496 int mutt_search_command(struct Mailbox *m, struct Menu *menu, int cur, int op)
497 {
498  struct Progress *progress = NULL;
499  int rc = -1;
500 
501  if ((*LastSearch == '\0') || ((op != OP_SEARCH_NEXT) && (op != OP_SEARCH_OPPOSITE)))
502  {
503  char buf[256];
504  mutt_str_copy(buf, (LastSearch[0] != '\0') ? LastSearch : "", sizeof(buf));
505  if ((mutt_get_field(
506  ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ? _("Search for: ") : _("Reverse search for: "),
507  buf, sizeof(buf), MUTT_CLEAR | MUTT_PATTERN, false, NULL, NULL) != 0) ||
508  (buf[0] == '\0'))
509  {
510  return -1;
511  }
512 
513  if ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT))
514  OptSearchReverse = false;
515  else
516  OptSearchReverse = true;
517 
518  /* compare the *expanded* version of the search pattern in case
519  * $simple_search has changed while we were searching */
520  struct Buffer *tmp = mutt_buffer_pool_get();
521  mutt_buffer_strcpy(tmp, buf);
522  const char *const c_simple_search =
523  cs_subset_string(NeoMutt->sub, "simple_search");
524  mutt_check_simple(tmp, NONULL(c_simple_search));
525 
527  {
528  struct Buffer err;
529  mutt_buffer_init(&err);
530  OptSearchInvalid = true;
531  mutt_str_copy(LastSearch, buf, sizeof(LastSearch));
533  mutt_message(_("Compiling search pattern..."));
535  err.dsize = 256;
536  err.data = mutt_mem_malloc(err.dsize);
537  SearchPattern = mutt_pattern_comp(m, menu, tmp->data, MUTT_PC_FULL_MSG, &err);
538  if (!SearchPattern)
539  {
541  mutt_error("%s", err.data);
542  FREE(&err.data);
543  LastSearch[0] = '\0';
544  LastSearchExpn[0] = '\0';
545  return -1;
546  }
547  FREE(&err.data);
549  }
550 
552  }
553 
554  if (OptSearchInvalid)
555  {
556  for (int i = 0; i < m->msg_count; i++)
557  m->emails[i]->searched = false;
558 #ifdef USE_IMAP
559  if ((m->type == MUTT_IMAP) && (!imap_search(m, SearchPattern)))
560  return -1;
561 #endif
562  OptSearchInvalid = false;
563  }
564 
565  int incr = OptSearchReverse ? -1 : 1;
566  if (op == OP_SEARCH_OPPOSITE)
567  incr = -incr;
568 
569  progress = progress_new(_("Searching..."), MUTT_PROGRESS_READ, m->vcount);
570 
571  for (int i = cur + incr, j = 0; j != m->vcount; j++)
572  {
573  const char *msg = NULL;
574  progress_update(progress, j, -1);
575  const bool c_wrap_search = cs_subset_bool(NeoMutt->sub, "wrap_search");
576  if (i > m->vcount - 1)
577  {
578  i = 0;
579  if (c_wrap_search)
580  msg = _("Search wrapped to top");
581  else
582  {
583  mutt_message(_("Search hit bottom without finding match"));
584  goto done;
585  }
586  }
587  else if (i < 0)
588  {
589  i = m->vcount - 1;
590  if (c_wrap_search)
591  msg = _("Search wrapped to bottom");
592  else
593  {
594  mutt_message(_("Search hit top without finding match"));
595  goto done;
596  }
597  }
598 
599  struct Email *e = mutt_get_virt_email(m, i);
600  if (e->searched)
601  {
602  /* if we've already evaluated this message, use the cached value */
603  if (e->matched)
604  {
606  if (msg && *msg)
607  mutt_message(msg);
608  rc = i;
609  goto done;
610  }
611  }
612  else
613  {
614  /* remember that we've already searched this message */
615  e->searched = true;
617  MUTT_MATCH_FULL_ADDRESS, m, e, NULL);
618  if (e->matched > 0)
619  {
621  if (msg && *msg)
622  mutt_message(msg);
623  rc = i;
624  goto done;
625  }
626  }
627 
628  if (SigInt)
629  {
630  mutt_error(_("Search interrupted"));
631  SigInt = false;
632  goto done;
633  }
634 
635  i += incr;
636  }
637 
638  mutt_error(_("Not found"));
639 done:
640  progress_free(&progress);
641  return rc;
642 }
643 
652 int mutt_search_alias_command(struct Menu *menu, int cur, int op)
653 {
654  struct Progress *progress = NULL;
655  const struct AliasMenuData *mdata = menu->mdata;
656  const struct AliasViewArray *ava = &mdata->ava;
657  int rc = -1;
658 
659  if ((*LastSearch == '\0') || ((op != OP_SEARCH_NEXT) && (op != OP_SEARCH_OPPOSITE)))
660  {
661  char buf[256];
662  mutt_str_copy(buf, (LastSearch[0] != '\0') ? LastSearch : "", sizeof(buf));
663  if ((mutt_get_field(
664  ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ? _("Search for: ") : _("Reverse search for: "),
665  buf, sizeof(buf), MUTT_CLEAR | MUTT_PATTERN, false, NULL, NULL) != 0) ||
666  (buf[0] == '\0'))
667  {
668  return -1;
669  }
670 
671  if ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT))
672  OptSearchReverse = false;
673  else
674  OptSearchReverse = true;
675 
676  /* compare the *expanded* version of the search pattern in case
677  * $simple_search has changed while we were searching */
678  struct Buffer *tmp = mutt_buffer_pool_get();
679  mutt_buffer_strcpy(tmp, buf);
681 
683  {
684  struct Buffer err;
685  mutt_buffer_init(&err);
686  OptSearchInvalid = true;
687  mutt_str_copy(LastSearch, buf, sizeof(LastSearch));
689  mutt_message(_("Compiling search pattern..."));
691  err.dsize = 256;
692  err.data = mutt_mem_malloc(err.dsize);
693  SearchPattern = mutt_pattern_comp(NULL, menu, tmp->data, MUTT_PC_FULL_MSG, &err);
694  if (!SearchPattern)
695  {
697  mutt_error("%s", err.data);
698  FREE(&err.data);
699  LastSearch[0] = '\0';
700  LastSearchExpn[0] = '\0';
701  return -1;
702  }
703  FREE(&err.data);
705  }
706 
708  }
709 
710  if (OptSearchInvalid)
711  {
712  struct AliasView *av = NULL;
713  ARRAY_FOREACH(av, ava)
714  {
715  av->is_searched = false;
716  }
717 
718  OptSearchInvalid = false;
719  }
720 
721  int incr = OptSearchReverse ? -1 : 1;
722  if (op == OP_SEARCH_OPPOSITE)
723  incr = -incr;
724 
725  progress = progress_new(_("Searching..."), MUTT_PROGRESS_READ, ARRAY_SIZE(ava));
726 
727  for (int i = cur + incr, j = 0; j != ARRAY_SIZE(ava); j++)
728  {
729  const char *msg = NULL;
730  progress_update(progress, j, -1);
731  const bool c_wrap_search = cs_subset_bool(NeoMutt->sub, "wrap_search");
732  if (i > ARRAY_SIZE(ava) - 1)
733  {
734  i = 0;
735  if (c_wrap_search)
736  msg = _("Search wrapped to top");
737  else
738  {
739  mutt_message(_("Search hit bottom without finding match"));
740  goto done;
741  }
742  }
743  else if (i < 0)
744  {
745  i = ARRAY_SIZE(ava) - 1;
746  if (c_wrap_search)
747  msg = _("Search wrapped to bottom");
748  else
749  {
750  mutt_message(_("Search hit top without finding match"));
751  goto done;
752  }
753  }
754 
755  struct AliasView *av = ARRAY_GET(ava, i);
756  if (av->is_searched)
757  {
758  /* if we've already evaluated this message, use the cached value */
759  if (av->is_matched)
760  {
762  if (msg && *msg)
763  mutt_message(msg);
764  rc = i;
765  goto done;
766  }
767  }
768  else
769  {
770  /* remember that we've already searched this message */
771  av->is_searched = true;
773  MUTT_MATCH_FULL_ADDRESS, av, NULL);
774  if (av->is_matched > 0)
775  {
777  if (msg && *msg)
778  mutt_message(msg);
779  rc = i;
780  goto done;
781  }
782  }
783 
784  if (SigInt)
785  {
786  mutt_error(_("Search interrupted"));
787  SigInt = false;
788  goto done;
789  }
790 
791  i += incr;
792  }
793 
794  mutt_error(_("Not found"));
795 done:
796  progress_free(&progress);
797  return rc;
798 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
Convenience wrapper for the gui headers.
bool imap_search(struct Mailbox *m, const struct PatternList *pat)
Find messages in mailbox matching a pattern.
Definition: search.c:229
The "current" mailbox.
Definition: context.h:37
int mutt_pattern_alias_func(int op, char *prompt, struct AliasMenuData *mdata, struct Menu *menu)
Perform some Pattern matching for Alias.
Definition: pattern.c:241
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define NONULL(x)
Definition: string2.h:37
Relative range.
Definition: private.h:76
int msg_count
Total number of messages.
Definition: mailbox.h:91
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:66
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
IMAP network mailbox.
The envelope/body of an email.
Definition: email.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:58
Less-than range.
Definition: private.h:78
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:412
#define RANGE_REL_RX
Definition: private.h:88
Definition: lib.h:67
struct Body * body
List of MIME parts.
Definition: email.h:91
Structs that make up an email.
#define mutt_error(...)
Definition: logging.h:88
The "currently-open" mailbox.
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:268
static void quote_simple(const char *str, struct Buffer *buf)
Apply simple quoting to a string.
Definition: pattern.c:95
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:67
AliasView array wrapper with Pattern information -.
Definition: gui.h:52
void mutt_check_simple(struct Buffer *buf, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:113
int mutt_get_field(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:335
struct MuttThread * thread
Thread of Emails.
Definition: email.h:95
Messages in limited view.
Definition: mutt.h:101
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:206
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:105
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
String manipulation buffer.
Definition: buffer.h:33
Messages to be un-deleted.
Definition: mutt.h:95
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
static char LastSearch[256]
last pattern searched for
Definition: pattern.c:87
Progress tracks elements, according to $read_inc
Definition: lib.h:46
bool is_matched
Search matches this Alias.
Definition: gui.h:40
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
Messages to be purged (bypass trash)
Definition: mutt.h:96
int mutt_search_alias_command(struct Menu *menu, int cur, int op)
Perform a search.
Definition: pattern.c:652
int mutt_search_command(struct Mailbox *m, struct Menu *menu, int cur, int op)
Perform a search.
Definition: pattern.c:496
GUI data wrapping an Alias.
Definition: gui.h:35
#define RANGE_LT_RX
Definition: private.h:95
bool searched
Email has been searched.
Definition: email.h:67
Single symbol.
Definition: private.h:80
All user-callable functions.
Container for Accounts, Notifications.
Definition: neomutt.h:36
A Progress Bar.
Definition: progress.c:47
#define MUTT_PATTERN
Pattern mode - only used for history classes.
Definition: mutt.h:60
#define RANGE_BARE_RX
Definition: private.h:99
int vcount
The number of virtual messages.
Definition: mailbox.h:102
The body of an email.
Definition: body.h:34
A simple (non-regex) pattern.
Definition: lib.h:68
Convenience wrapper for the config headers.
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
Progress bar.
size_t dsize
Length of data.
Definition: buffer.h:37
struct Mailbox * mailbox
Definition: context.h:49
Many unsorted constants and some structs.
API for mailboxes.
Convenience wrapper for the core headers.
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:45
char * str
String representing the limit being used.
Definition: gui.h:54
Email Aliases.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
#define RANGE_GT_RX
Definition: private.h:96
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
struct PatternList * mutt_pattern_comp(struct Mailbox *m, struct Menu *menu, const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: compile.c:1092
off_t vsize
Size (in bytes) of the messages shown.
Definition: context.h:39
Regular expression representing a range.
Definition: private.h:62
bool is_visible
Is visible?
Definition: gui.h:43
Prototypes for many functions.
bool visible
Is this message part of the view?
Definition: email.h:74
static char LastSearchExpn[1024]
expanded version of LastSearch
Definition: pattern.c:88
void * mdata
Private data.
Definition: lib.h:155
#define SLIST_FIRST(head)
Definition: queue.h:229
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
Messages to be deleted.
Definition: mutt.h:94
A mailbox.
Definition: mailbox.h:81
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:1120
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
static struct MuttThread * top_of_thread(struct Email *e)
Find the first email in the current thread.
Definition: pattern.c:172
size_t num_hidden
Number of hidden messages in this view (only valid when collapsed is set)
Definition: email.h:75
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: context.h:41
bool(* eat_arg_t)(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
Function to parse a pattern.
Definition: pattern.c:83
void mutt_file_expand_fmt(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1450
Tagged messages.
Definition: mutt.h:99
char * data
Pointer to data.
Definition: buffer.h:35
Greater-than range.
Definition: private.h:79
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
bool is_searched
Alias has been searched.
Definition: gui.h:39
int vnum
Virtual message number.
Definition: email.h:88
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:51
Absolute range.
Definition: private.h:77
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:228
void progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:175
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
int max
Number of entries in the menu.
Definition: lib.h:71
An Email conversation.
Definition: thread.h:34
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:1097
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
static struct PatternList * SearchPattern
current search pattern
Definition: pattern.c:86
#define MUTT_ALIAS_SIMPLESEARCH
Definition: lib.h:57
Shared constants/structs that are private to libpattern.
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
bool collapsed
Are all threads collapsed?
Definition: context.h:47
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:246
int mutt_pattern_func(struct Context *ctx, int op, char *prompt)
Perform some Pattern matching.
Definition: pattern.c:342
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
#define RANGE_ABS_RX
Definition: private.h:92
struct AliasViewArray ava
Array of AliasView.
Definition: gui.h:55
Messages to be un-tagged.
Definition: mutt.h:100
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1540
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:1038
#define MUTT_PC_FULL_MSG
Enable body and header matching.
Definition: lib.h:61
Convenience wrapper for the library headers.
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
char * pattern
Limit pattern string.
Definition: context.h:40
Shared code for the Alias and Query Dialogs.
static unsigned char * pbuf
Cache PGP data packet.
Definition: pgppacket.c:38
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:95
WHERE bool OptSearchReverse
(pseudo) used by ci_search_command
Definition: options.h:52
bool mutt_limit_current_thread(struct Context *ctx, struct Email *e)
Limit the email view to the current thread.
Definition: pattern.c:192
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:83
uint8_t PatternCompFlags
Flags for mutt_pattern_comp(), e.g. MUTT_PC_FULL_MSG.
Definition: lib.h:59
bool matched
Search matches this Email.
Definition: email.h:68