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