NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
hook.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <limits.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include "mutt/lib.h"
37 #include "address/lib.h"
38 #include "config/lib.h"
39 #include "email/lib.h"
40 #include "core/lib.h"
41 #include "alias/lib.h"
42 #include "mutt.h"
43 #include "hook.h"
44 #include "ncrypt/lib.h"
45 #include "pattern/lib.h"
46 #include "context.h"
47 #include "format_flags.h"
48 #include "hdrline.h"
49 #include "init.h"
50 #include "mutt_attach.h"
51 #include "mutt_commands.h"
52 #include "mutt_globals.h"
53 #include "muttlib.h"
54 #include "mx.h"
55 #ifdef USE_COMP_MBOX
56 #include "compmbox/lib.h"
57 #endif
58 
62 struct Hook
63 {
65  struct Regex regex;
66  char *command;
67  struct PatternList *pattern;
68  TAILQ_ENTRY(Hook) entries;
69 };
70 TAILQ_HEAD(HookList, Hook);
71 
72 static struct HookList Hooks = TAILQ_HEAD_INITIALIZER(Hooks);
73 
74 static struct HashTable *IdxFmtHooks = NULL;
76 
82 enum CommandResult mutt_parse_hook(struct Buffer *buf, struct Buffer *s,
83  intptr_t data, struct Buffer *err)
84 {
85  struct Hook *hook = NULL;
86  int rc = MUTT_CMD_ERROR;
87  bool pat_not = false;
88  bool use_regex = true;
89  regex_t *rx = NULL;
90  struct PatternList *pat = NULL;
91  const bool folder_or_mbox = (data & (MUTT_FOLDER_HOOK | MUTT_MBOX_HOOK));
92 
93  struct Buffer *cmd = mutt_buffer_pool_get();
95 
96  if (~data & MUTT_GLOBAL_HOOK) /* NOT a global hook */
97  {
98  if (*s->dptr == '!')
99  {
100  s->dptr++;
101  SKIPWS(s->dptr);
102  pat_not = true;
103  }
104 
106  if (folder_or_mbox &&
107  mutt_str_equal(mutt_buffer_string(pattern), "-noregex"))
108  {
109  use_regex = false;
110  if (!MoreArgs(s))
111  {
112  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
113  rc = MUTT_CMD_WARNING;
114  goto cleanup;
115  }
117  }
118 
119  if (!MoreArgs(s))
120  {
121  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
122  rc = MUTT_CMD_WARNING;
123  goto cleanup;
124  }
125  }
126 
127  mutt_extract_token(cmd, s,
132 
133  if (mutt_buffer_is_empty(cmd))
134  {
135  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
136  rc = MUTT_CMD_WARNING;
137  goto cleanup;
138  }
139 
140  if (MoreArgs(s))
141  {
142  mutt_buffer_printf(err, _("%s: too many arguments"), buf->data);
143  rc = MUTT_CMD_WARNING;
144  goto cleanup;
145  }
146 
147  const char *const c_default_hook =
148  cs_subset_string(NeoMutt->sub, "default_hook");
149  if (folder_or_mbox)
150  {
151  /* Accidentally using the ^ mailbox shortcut in the .neomuttrc is a
152  * common mistake */
153  if ((pattern->data[0] == '^') && !CurrentFolder)
154  {
155  mutt_buffer_strcpy(err, _("current mailbox shortcut '^' is unset"));
156  goto cleanup;
157  }
158 
159  struct Buffer *tmp = mutt_buffer_pool_get();
160  mutt_buffer_copy(tmp, pattern);
161  mutt_buffer_expand_path_regex(tmp, use_regex);
162 
163  /* Check for other mailbox shortcuts that expand to the empty string.
164  * This is likely a mistake too */
165  if (mutt_buffer_is_empty(tmp) && !mutt_buffer_is_empty(pattern))
166  {
167  mutt_buffer_strcpy(err, _("mailbox shortcut expanded to empty regex"));
169  goto cleanup;
170  }
171 
172  if (use_regex)
173  {
174  mutt_buffer_copy(pattern, tmp);
175  }
176  else
177  {
179  }
181  }
182 #ifdef USE_COMP_MBOX
183  else if (data & (MUTT_APPEND_HOOK | MUTT_OPEN_HOOK | MUTT_CLOSE_HOOK))
184  {
186  {
187  mutt_buffer_strcpy(err, _("badly formatted command string"));
188  goto cleanup;
189  }
190  }
191 #endif
192  else if (c_default_hook && (~data & MUTT_GLOBAL_HOOK) &&
194  (!WithCrypto || !(data & MUTT_CRYPT_HOOK)))
195  {
196  /* At this stage remain only message-hooks, reply-hooks, send-hooks,
197  * send2-hooks, save-hooks, and fcc-hooks: All those allowing full
198  * patterns. If given a simple regex, we expand $default_hook. */
199  mutt_check_simple(pattern, c_default_hook);
200  }
201 
203  {
205  }
206 
207  /* check to make sure that a matching hook doesn't already exist */
208  TAILQ_FOREACH(hook, &Hooks, entries)
209  {
210  if (data & MUTT_GLOBAL_HOOK)
211  {
212  /* Ignore duplicate global hooks */
213  if (mutt_str_equal(hook->command, mutt_buffer_string(cmd)))
214  {
215  rc = MUTT_CMD_SUCCESS;
216  goto cleanup;
217  }
218  }
219  else if ((hook->type == data) && (hook->regex.pat_not == pat_not) &&
221  {
223  MUTT_ACCOUNT_HOOK | MUTT_REPLY_HOOK | MUTT_CRYPT_HOOK |
225  {
226  /* these hooks allow multiple commands with the same
227  * pattern, so if we've already seen this pattern/command pair, just
228  * ignore it instead of creating a duplicate */
229  if (mutt_str_equal(hook->command, mutt_buffer_string(cmd)))
230  {
231  rc = MUTT_CMD_SUCCESS;
232  goto cleanup;
233  }
234  }
235  else
236  {
237  /* other hooks only allow one command per pattern, so update the
238  * entry with the new command. this currently does not change the
239  * order of execution of the hooks, which i think is desirable since
240  * a common action to perform is to change the default (.) entry
241  * based upon some other information. */
242  FREE(&hook->command);
243  hook->command = mutt_buffer_strdup(cmd);
244  rc = MUTT_CMD_SUCCESS;
245  goto cleanup;
246  }
247  }
248  }
249 
250  if (data & (MUTT_CHARSET_HOOK | MUTT_ICONV_HOOK))
251  {
252  /* These are managed separately by the charset code */
254  if (mutt_ch_lookup_add(type, mutt_buffer_string(pattern), mutt_buffer_string(cmd), err))
255  rc = MUTT_CMD_SUCCESS;
256  goto cleanup;
257  }
258  else if (data & (MUTT_SEND_HOOK | MUTT_SEND2_HOOK | MUTT_SAVE_HOOK |
260  {
261  PatternCompFlags comp_flags;
262 
263  if (data & (MUTT_SEND2_HOOK))
264  comp_flags = MUTT_PC_SEND_MODE_SEARCH;
265  else if (data & (MUTT_SEND_HOOK | MUTT_FCC_HOOK))
266  comp_flags = MUTT_PC_NO_FLAGS;
267  else
268  comp_flags = MUTT_PC_FULL_MSG;
269 
271  mutt_buffer_string(pattern), comp_flags, err);
272  if (!pat)
273  goto cleanup;
274  }
275  else if (~data & MUTT_GLOBAL_HOOK) /* NOT a global hook */
276  {
277  /* Hooks not allowing full patterns: Check syntax of regex */
278  rx = mutt_mem_malloc(sizeof(regex_t));
279  int rc2 = REG_COMP(rx, NONULL(mutt_buffer_string(pattern)),
280  ((data & MUTT_CRYPT_HOOK) ? REG_ICASE : 0));
281  if (rc2 != 0)
282  {
283  regerror(rc2, rx, err->data, err->dsize);
284  FREE(&rx);
285  goto cleanup;
286  }
287  }
288 
289  hook = mutt_mem_calloc(1, sizeof(struct Hook));
290  hook->type = data;
291  hook->command = mutt_buffer_strdup(cmd);
292  hook->pattern = pat;
293  hook->regex.pattern = mutt_buffer_strdup(pattern);
294  hook->regex.regex = rx;
295  hook->regex.pat_not = pat_not;
296  TAILQ_INSERT_TAIL(&Hooks, hook, entries);
297  rc = MUTT_CMD_SUCCESS;
298 
299 cleanup:
301  mutt_buffer_pool_release(&pattern);
302  return rc;
303 }
304 
309 static void delete_hook(struct Hook *h)
310 {
311  FREE(&h->command);
312  FREE(&h->regex.pattern);
313  if (h->regex.regex)
314  {
315  regfree(h->regex.regex);
316  FREE(&h->regex.regex);
317  }
319  FREE(&h);
320 }
321 
329 {
330  struct Hook *h = NULL;
331  struct Hook *tmp = NULL;
332 
333  TAILQ_FOREACH_SAFE(h, &Hooks, entries, tmp)
334  {
335  if ((type == MUTT_HOOK_NO_FLAGS) || (type == h->type))
336  {
337  TAILQ_REMOVE(&Hooks, h, entries);
338  delete_hook(h);
339  }
340  }
341 }
342 
346 static void idxfmt_hashelem_free(int type, void *obj, intptr_t data)
347 {
348  struct HookList *hl = obj;
349  struct Hook *h = NULL;
350  struct Hook *tmp = NULL;
351 
352  TAILQ_FOREACH_SAFE(h, hl, entries, tmp)
353  {
354  TAILQ_REMOVE(hl, h, entries);
355  delete_hook(h);
356  }
357 
358  FREE(&hl);
359 }
360 
364 static void delete_idxfmt_hooks(void)
365 {
366  mutt_hash_free(&IdxFmtHooks);
367 }
368 
372 enum CommandResult mutt_parse_idxfmt_hook(struct Buffer *buf, struct Buffer *s,
373  intptr_t data, struct Buffer *err)
374 {
375  enum CommandResult rc = MUTT_CMD_ERROR;
376  bool pat_not = false;
377 
378  struct Buffer *name = mutt_buffer_pool_get();
379  struct Buffer *pattern = mutt_buffer_pool_get();
380  struct Buffer *fmtstring = mutt_buffer_pool_get();
381 
382  if (!IdxFmtHooks)
383  {
384  IdxFmtHooks = mutt_hash_new(30, MUTT_HASH_STRDUP_KEYS);
386  }
387 
388  if (!MoreArgs(s))
389  {
390  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
391  goto out;
392  }
394  struct HookList *hl = mutt_hash_find(IdxFmtHooks, mutt_buffer_string(name));
395 
396  if (*s->dptr == '!')
397  {
398  s->dptr++;
399  SKIPWS(s->dptr);
400  pat_not = true;
401  }
403 
404  if (!MoreArgs(s))
405  {
406  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
407  goto out;
408  }
410 
411  if (MoreArgs(s))
412  {
413  mutt_buffer_printf(err, _("%s: too many arguments"), buf->data);
414  goto out;
415  }
416 
417  const char *const c_default_hook =
418  cs_subset_string(NeoMutt->sub, "default_hook");
419  if (c_default_hook)
420  mutt_check_simple(pattern, c_default_hook);
421 
422  /* check to make sure that a matching hook doesn't already exist */
423  struct Hook *hook = NULL;
424  if (hl)
425  {
426  TAILQ_FOREACH(hook, hl, entries)
427  {
428  if ((hook->regex.pat_not == pat_not) &&
430  {
431  mutt_str_replace(&hook->command, mutt_buffer_string(fmtstring));
432  rc = MUTT_CMD_SUCCESS;
433  goto out;
434  }
435  }
436  }
437 
438  /* MUTT_PC_PATTERN_DYNAMIC sets so that date ranges are regenerated during
439  * matching. This of course is slower, but index-format-hook is commonly
440  * used for date ranges, and they need to be evaluated relative to "now", not
441  * the hook compilation time. */
442  struct PatternList *pat =
444  mutt_buffer_string(pattern),
446  if (!pat)
447  goto out;
448 
449  hook = mutt_mem_calloc(1, sizeof(struct Hook));
450  hook->type = MUTT_IDXFMTHOOK;
451  hook->command = mutt_buffer_strdup(fmtstring);
452  hook->pattern = pat;
453  hook->regex.pattern = mutt_buffer_strdup(pattern);
454  hook->regex.regex = NULL;
455  hook->regex.pat_not = pat_not;
456 
457  if (!hl)
458  {
459  hl = mutt_mem_calloc(1, sizeof(*hl));
460  TAILQ_INIT(hl);
461  mutt_hash_insert(IdxFmtHooks, mutt_buffer_string(name), hl);
462  }
463 
464  TAILQ_INSERT_TAIL(hl, hook, entries);
465  rc = MUTT_CMD_SUCCESS;
466 
467 out:
469  mutt_buffer_pool_release(&pattern);
470  mutt_buffer_pool_release(&fmtstring);
471 
472  return rc;
473 }
474 
478 enum CommandResult mutt_parse_unhook(struct Buffer *buf, struct Buffer *s,
479  intptr_t data, struct Buffer *err)
480 {
481  while (MoreArgs(s))
482  {
484  if (mutt_str_equal("*", buf->data))
485  {
487  {
488  mutt_buffer_printf(err, "%s", _("unhook: Can't do unhook * from within a hook"));
489  return MUTT_CMD_WARNING;
490  }
494  }
495  else
496  {
498 
499  if (type == MUTT_HOOK_NO_FLAGS)
500  {
501  mutt_buffer_printf(err, _("unhook: unknown hook type: %s"), buf->data);
502  return MUTT_CMD_ERROR;
503  }
504  if (type & (MUTT_CHARSET_HOOK | MUTT_ICONV_HOOK))
505  {
507  return MUTT_CMD_SUCCESS;
508  }
509  if (current_hook_type == type)
510  {
511  mutt_buffer_printf(err, _("unhook: Can't delete a %s from within a %s"),
512  buf->data, buf->data);
513  return MUTT_CMD_WARNING;
514  }
515  if (type == MUTT_IDXFMTHOOK)
517  else
518  mutt_delete_hooks(type);
519  }
520  }
521  return MUTT_CMD_SUCCESS;
522 }
523 
529 void mutt_folder_hook(const char *path, const char *desc)
530 {
531  if (!path && !desc)
532  return;
533 
534  struct Hook *hook = NULL;
535  struct Buffer *err = mutt_buffer_pool_get();
536 
538 
539  TAILQ_FOREACH(hook, &Hooks, entries)
540  {
541  if (!hook->command)
542  continue;
543 
544  if (!(hook->type & MUTT_FOLDER_HOOK))
545  continue;
546 
547  const char *match = NULL;
548  if (mutt_regex_match(&hook->regex, path))
549  match = path;
550  else if (mutt_regex_match(&hook->regex, desc))
551  match = desc;
552 
553  if (match)
554  {
555  mutt_debug(LL_DEBUG1, "folder-hook '%s' matches '%s'\n", hook->regex.pattern, match);
556  mutt_debug(LL_DEBUG5, " %s\n", hook->command);
557  if (mutt_parse_rc_line(hook->command, err) == MUTT_CMD_ERROR)
558  {
559  mutt_error("%s", mutt_buffer_string(err));
560  break;
561  }
562  }
563  }
565 
567 }
568 
577 char *mutt_find_hook(HookFlags type, const char *pat)
578 {
579  struct Hook *tmp = NULL;
580 
581  TAILQ_FOREACH(tmp, &Hooks, entries)
582  {
583  if (tmp->type & type)
584  {
585  if (mutt_regex_match(&tmp->regex, pat))
586  return tmp->command;
587  }
588  }
589  return NULL;
590 }
591 
598 void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
599 {
600  struct Hook *hook = NULL;
601  struct PatternCache cache = { 0 };
602  struct Buffer *err = mutt_buffer_pool_get();
603 
605 
606  TAILQ_FOREACH(hook, &Hooks, entries)
607  {
608  if (!hook->command)
609  continue;
610 
611  if (hook->type & type)
612  {
613  if ((mutt_pattern_exec(SLIST_FIRST(hook->pattern), 0, m, e, &cache) > 0) ^
614  hook->regex.pat_not)
615  {
616  if (mutt_parse_rc_line(hook->command, err) == MUTT_CMD_ERROR)
617  {
618  mutt_error("%s", mutt_buffer_string(err));
621 
622  return;
623  }
624  /* Executing arbitrary commands could affect the pattern results,
625  * so the cache has to be wiped */
626  memset(&cache, 0, sizeof(cache));
627  }
628  }
629  }
631 
633 }
634 
645 static int addr_hook(char *path, size_t pathlen, HookFlags type,
646  struct Mailbox *m, struct Email *e)
647 {
648  struct Hook *hook = NULL;
649  struct PatternCache cache = { 0 };
650 
651  /* determine if a matching hook exists */
652  TAILQ_FOREACH(hook, &Hooks, entries)
653  {
654  if (!hook->command)
655  continue;
656 
657  if (hook->type & type)
658  {
659  if ((mutt_pattern_exec(SLIST_FIRST(hook->pattern), 0, m, e, &cache) > 0) ^
660  hook->regex.pat_not)
661  {
662  mutt_make_string(path, pathlen, 0, hook->command, m, -1, e, MUTT_FORMAT_PLAIN, NULL);
663  return 0;
664  }
665  }
666  }
667 
668  return -1;
669 }
670 
677 void mutt_default_save(char *path, size_t pathlen, struct Email *e)
678 {
679  *path = '\0';
680  if (addr_hook(path, pathlen, MUTT_SAVE_HOOK, ctx_mailbox(Context), e) == 0)
681  return;
682 
683  struct Envelope *env = e->env;
684  const struct Address *from = TAILQ_FIRST(&env->from);
685  const struct Address *reply_to = TAILQ_FIRST(&env->reply_to);
686  const struct Address *to = TAILQ_FIRST(&env->to);
687  const struct Address *cc = TAILQ_FIRST(&env->cc);
688  const struct Address *addr = NULL;
689  bool from_me = mutt_addr_is_user(from);
690 
691  if (!from_me && reply_to && reply_to->mailbox)
692  addr = reply_to;
693  else if (!from_me && from && from->mailbox)
694  addr = from;
695  else if (to && to->mailbox)
696  addr = to;
697  else if (cc && cc->mailbox)
698  addr = cc;
699  else
700  addr = NULL;
701  if (addr)
702  {
703  struct Buffer *tmp = mutt_buffer_pool_get();
704  mutt_safe_path(tmp, addr);
705  snprintf(path, pathlen, "=%s", mutt_buffer_string(tmp));
707  }
708 }
709 
715 void mutt_select_fcc(struct Buffer *path, struct Email *e)
716 {
718 
719  if (addr_hook(path->data, path->dsize, MUTT_FCC_HOOK, NULL, e) != 0)
720  {
721  const struct Address *to = TAILQ_FIRST(&e->env->to);
722  const struct Address *cc = TAILQ_FIRST(&e->env->cc);
723  const struct Address *bcc = TAILQ_FIRST(&e->env->bcc);
724  const bool c_save_name = cs_subset_bool(NeoMutt->sub, "save_name");
725  const bool c_force_name = cs_subset_bool(NeoMutt->sub, "force_name");
726  const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
727  if ((c_save_name || c_force_name) && (to || cc || bcc))
728  {
729  const struct Address *addr = to ? to : (cc ? cc : bcc);
730  struct Buffer *buf = mutt_buffer_pool_get();
731  mutt_safe_path(buf, addr);
732  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
733  mutt_buffer_concat_path(path, NONULL(c_folder), mutt_buffer_string(buf));
735  if (!c_force_name && (mx_access(mutt_buffer_string(path), W_OK) != 0))
736  mutt_buffer_strcpy(path, c_record);
737  }
738  else
739  mutt_buffer_strcpy(path, c_record);
740  }
741  else
742  mutt_buffer_fix_dptr(path);
743 
745 }
746 
753 static void list_hook(struct ListHead *matches, const char *match, HookFlags hook)
754 {
755  struct Hook *tmp = NULL;
756 
757  TAILQ_FOREACH(tmp, &Hooks, entries)
758  {
759  if ((tmp->type & hook) && mutt_regex_match(&tmp->regex, match))
760  {
762  }
763  }
764 }
765 
773 void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
774 {
775  list_hook(list, addr->mailbox, MUTT_CRYPT_HOOK);
776 }
777 
782 void mutt_account_hook(const char *url)
783 {
784  /* parsing commands with URLs in an account hook can cause a recursive
785  * call. We just skip processing if this occurs. Typically such commands
786  * belong in a folder-hook -- perhaps we should warn the user. */
787  static bool inhook = false;
788  if (inhook)
789  return;
790 
791  struct Hook *hook = NULL;
792  struct Buffer *err = mutt_buffer_pool_get();
793 
794  TAILQ_FOREACH(hook, &Hooks, entries)
795  {
796  if (!(hook->command && (hook->type & MUTT_ACCOUNT_HOOK)))
797  continue;
798 
799  if (mutt_regex_match(&hook->regex, url))
800  {
801  inhook = true;
802  mutt_debug(LL_DEBUG1, "account-hook '%s' matches '%s'\n", hook->regex.pattern, url);
803  mutt_debug(LL_DEBUG5, " %s\n", hook->command);
804 
805  if (mutt_parse_rc_line(hook->command, err) == MUTT_CMD_ERROR)
806  {
807  mutt_error("%s", mutt_buffer_string(err));
809 
810  inhook = false;
811  goto done;
812  }
813 
814  inhook = false;
815  }
816  }
817 done:
819 }
820 
828 {
829  struct Hook *hook = NULL;
830  struct Buffer err;
831  char buf[256];
832 
833  mutt_buffer_init(&err);
834  err.data = buf;
835  err.dsize = sizeof(buf);
836 
837  TAILQ_FOREACH(hook, &Hooks, entries)
838  {
839  if (!(hook->command && (hook->type & MUTT_TIMEOUT_HOOK)))
840  continue;
841 
842  if (mutt_parse_rc_line(hook->command, &err) == MUTT_CMD_ERROR)
843  {
844  mutt_error("%s", err.data);
845  mutt_buffer_reset(&err);
846 
847  /* The hooks should be independent of each other, so even though this on
848  * failed, we'll carry on with the others. */
849  }
850  }
851 
852  /* Delete temporary attachment files */
854 }
855 
864 {
865  struct Hook *hook = NULL;
866  struct Buffer err = mutt_buffer_make(0);
867  char buf[256];
868 
869  err.data = buf;
870  err.dsize = sizeof(buf);
871 
872  TAILQ_FOREACH(hook, &Hooks, entries)
873  {
874  if (!(hook->command && (hook->type & type)))
875  continue;
876 
877  if (mutt_parse_rc_line(hook->command, &err) == MUTT_CMD_ERROR)
878  {
879  mutt_error("%s", err.data);
880  mutt_buffer_reset(&err);
881  }
882  }
883 }
884 
893 const char *mutt_idxfmt_hook(const char *name, struct Mailbox *m, struct Email *e)
894 {
895  if (!IdxFmtHooks)
896  return NULL;
897 
898  struct HookList *hl = mutt_hash_find(IdxFmtHooks, name);
899  if (!hl)
900  return NULL;
901 
903 
904  struct PatternCache cache = { 0 };
905  const char *fmtstring = NULL;
906  struct Hook *hook = NULL;
907 
908  TAILQ_FOREACH(hook, hl, entries)
909  {
910  struct Pattern *pat = SLIST_FIRST(hook->pattern);
911  if ((mutt_pattern_exec(pat, 0, m, e, &cache) > 0) ^ hook->regex.pat_not)
912  {
913  fmtstring = hook->command;
914  break;
915  }
916  }
917 
919 
920  return fmtstring;
921 }
#define MUTT_SEND_HOOK
send-hook: when composing a new email
Definition: hook.h:41
#define MUTT_PC_PATTERN_DYNAMIC
Enable runtime date range evaluation.
Definition: lib.h:62
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:354
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
The "current" mailbox.
Definition: context.h:37
enum CommandResult mutt_parse_idxfmt_hook(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;index-format-hook&#39; command - Implements Command::parse() -.
Definition: hook.c:372
struct HashElem * mutt_hash_insert(struct HashTable *table, const char *strkey, void *data)
Add a new element to the Hash Table (with string keys)
Definition: hash.c:327
static struct HookList Hooks
Definition: hook.c:72
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define WithCrypto
Definition: lib.h:113
The envelope/body of an email.
Definition: email.h:37
A Hash Table.
Definition: hash.h:87
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define TAILQ_FIRST(head)
Definition: queue.h:723
CommandResult
Error codes for command_t parse functions.
Definition: mutt_commands.h:34
#define MUTT_SHUTDOWN_HOOK
shutdown-hook: run when leaving NeoMutt
Definition: hook.h:59
Config/command parsing.
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:444
Error: Can&#39;t help the user.
Definition: mutt_commands.h:36
Structs that make up an email.
String processing routines to generate the mail index.
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer&#39;s contents to another Buffer.
Definition: buffer.c:445
#define mutt_error(...)
Definition: logging.h:88
The "currently-open" mailbox.
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
HookFlags type
Hook type.
Definition: hook.c:64
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:449
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
regex_t * regex
compiled expression
Definition: regex3.h:92
static void delete_idxfmt_hooks(void)
Delete all the index-format-hooks.
Definition: hook.c:364
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
HookFlags mutt_get_hook_type(const char *name)
Find a hook by name.
Definition: init.c:693
static HookFlags current_hook_type
Definition: hook.c:75
String manipulation buffer.
Definition: buffer.h:33
bool pat_not
do not match
Definition: regex3.h:93
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
A list of user hooks.
Definition: hook.c:62
enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: init.c:1039
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
enum CommandResult mutt_parse_hook(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;hook&#39; family of commands - Implements Command::parse() -This is used by &#39;account-hook&#39;...
Definition: hook.c:82
#define _(a)
Definition: message.h:28
void mutt_delete_hooks(HookFlags type)
Delete matching hooks.
Definition: hook.c:328
#define MUTT_CHARSET_HOOK
charset-hook: create a charset alias for malformed emails
Definition: hook.h:44
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:54
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
static void list_hook(struct ListHead *matches, const char *match, HookFlags hook)
Find hook strings matching.
Definition: hook.c:753
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:46
void mutt_check_simple(struct Buffer *s, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:113
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1275
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
uint32_t HookFlags
Flags for mutt_parse_hook(), e.g. MUTT_FOLDER_HOOK.
Definition: hook.h:35
#define MUTT_IDXFMTHOOK
index-format-hook: customise the format of the index
Definition: hook.h:56
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:677
Flags to control mutt_expando_format()
Container for Accounts, Notifications.
Definition: neomutt.h:36
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:603
#define MUTT_CRYPT_HOOK
crypt-hook: automatically select a PGP/SMIME key
Definition: hook.h:47
A simple (non-regex) pattern.
Definition: lib.h:68
void mutt_ch_lookup_remove(void)
Remove all the character set lookups.
Definition: charset.c:521
Convenience wrapper for the config headers.
Email Address Handling.
void mutt_buffer_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:134
Character set conversion.
Definition: charset.h:68
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
char * command
Filename, command or pattern to execute.
Definition: hook.c:66
Some miscellaneous functions.
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:529
size_t dsize
Length of data.
Definition: buffer.h:37
#define MoreArgs(buf)
Definition: buffer.h:40
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:863
Parse and execute user-defined hooks.
Many unsorted constants and some structs.
API for mailboxes.
static void idxfmt_hashelem_free(int type, void *obj, intptr_t data)
Delete an index-format-hook from the Hash Table - Implements hash_hdata_free_t.
Definition: hook.c:346
#define MUTT_ICONV_HOOK
iconv-hook: create a system charset alias
Definition: hook.h:45
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
void mutt_make_string(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1409
struct Envelope * env
Envelope information.
Definition: email.h:90
Convenience wrapper for the core headers.
#define SKIPWS(ch)
Definition: string2.h:46
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:773
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
#define MUTT_PC_SEND_MODE_SEARCH
Allow send-mode body searching.
Definition: lib.h:63
#define TAILQ_INIT(head)
Definition: queue.h:765
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:45
struct Regex regex
Regular expression.
Definition: hook.c:65
Email Aliases.
Compressed mbox local mailbox type.
#define MUTT_APPEND_HOOK
append-hook: append to a compressed mailbox
Definition: hook.h:53
#define MUTT_MBOX_HOOK
mbox-hook: move messages after reading them
Definition: hook.h:40
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
#define MUTT_GLOBAL_HOOK
Hooks which don&#39;t take a regex.
Definition: hook.h:60
void mutt_safe_path(struct Buffer *dest, const struct Address *a)
Make a safe filename from an email address.
Definition: muttlib.c:761
Alias for another character set.
Definition: charset.h:67
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
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
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition: file.c:637
void mutt_hash_set_destructor(struct HashTable *table, hash_hdata_free_t fn, intptr_t fn_data)
Set the destructor for a Hash Table.
Definition: hash.c:293
const char * mutt_idxfmt_hook(const char *name, struct Mailbox *m, struct Email *e)
Get index-format-hook format string.
Definition: hook.c:893
#define MUTT_SAVE_HOOK
save-hook: set a default folder when saving an email
Definition: hook.h:43
#define SLIST_FIRST(head)
Definition: queue.h:229
void mutt_account_hook(const char *url)
Perform an account hook.
Definition: hook.c:782
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:40
char * mutt_find_hook(HookFlags type, const char *pat)
Find a matching hook.
Definition: hook.c:577
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:395
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define MUTT_CLOSE_HOOK
close-hook: write to a compressed mailbox
Definition: hook.h:54
void mutt_select_fcc(struct Buffer *path, struct Email *e)
Select the FCC path for an email.
Definition: hook.c:715
char * dptr
Current read/write position.
Definition: buffer.h:36
#define MUTT_TOKEN_SPACE
Don&#39;t treat whitespace as a term.
Definition: mutt.h:69
#define MUTT_PC_NO_FLAGS
No flags are set.
Definition: lib.h:60
Match patterns to emails.
char * data
Pointer to data.
Definition: buffer.h:35
int mutt_comp_valid_command(const char *cmd)
Is this command string allowed?
Definition: compress.c:408
Definitions of NeoMutt commands.
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
API for encryption/signing of emails.
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
Handling of email attachments.
#define MUTT_OPEN_HOOK
open-hook: to read a compressed mailbox
Definition: hook.h:52
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
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
#define MUTT_TIMEOUT_HOOK
timeout-hook: run a command periodically
Definition: hook.h:57
#define TAILQ_ENTRY(type)
Definition: queue.h:640
Success: Command worked.
Definition: mutt_commands.h:38
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
Log at debug level 1.
Definition: logging.h:40
Warning: Help given to the user.
Definition: mutt_commands.h:37
#define MUTT_FORMAT_PLAIN
Do not prepend DISP_TO, DISP_CC ...
Definition: format_flags.h:38
#define MUTT_SEND2_HOOK
send2-hook: when changing fields in the compose menu
Definition: hook.h:50
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
Cached regular expression.
Definition: regex3.h:89
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:50
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:613
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:827
#define MUTT_REPLY_HOOK
reply-hook: when replying to an email
Definition: hook.h:49
#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:562
size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:374
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition: mx.c:184
TAILQ_HEAD(HookList, Hook)
#define MUTT_HOOK_NO_FLAGS
No flags are set.
Definition: hook.h:38
enum CommandResult mutt_parse_unhook(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unhook&#39; command - Implements Command::parse() -.
Definition: hook.c:478
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
Hundreds of global variables to back the user variables.
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:598
static int addr_hook(char *path, size_t pathlen, HookFlags type, struct Mailbox *m, struct Email *e)
Perform an address hook (get a path)
Definition: hook.c:645
static void delete_hook(struct Hook *h)
Delete a Hook.
Definition: hook.c:309
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
char * pattern
printable version
Definition: regex3.h:91
Cache commonly-used patterns.
Definition: lib.h:105
#define MUTT_HASH_STRDUP_KEYS
make a copy of the keys
Definition: hash.h:102
Log at debug level 5.
Definition: logging.h:44
#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
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition: hash.c:251
#define MUTT_STARTUP_HOOK
startup-hook: run when starting NeoMutt
Definition: hook.h:58
LookupType
Types of character set lookups.
Definition: charset.h:65
#define MUTT_FCC_HOOK
fcc-hook: to save outgoing email
Definition: hook.h:42
struct PatternList * pattern
Used for fcc,save,send-hook.
Definition: hook.c:67
uint8_t PatternCompFlags
Flags for mutt_pattern_comp(), e.g. MUTT_PC_FULL_MSG.
Definition: lib.h:59
#define MUTT_ACCOUNT_HOOK
account-hook: when changing between accounts
Definition: hook.h:48
The header of an Email.
Definition: envelope.h:54
bool mutt_ch_lookup_add(enum LookupType type, const char *pat, const char *replace, struct Buffer *err)
Add a new character set lookup.
Definition: charset.c:489
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:66
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
#define MUTT_FOLDER_HOOK
folder-hook: when entering a mailbox
Definition: hook.h:39