NeoMutt  2020-09-25
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 "email/lib.h"
39 #include "alias/lib.h"
40 #include "mutt.h"
41 #include "hook.h"
42 #include "ncrypt/lib.h"
43 #include "pattern/lib.h"
44 #include "context.h"
45 #include "format_flags.h"
46 #include "hdrline.h"
47 #include "init.h"
48 #include "mutt_attach.h"
49 #include "mutt_commands.h"
50 #include "mutt_globals.h"
51 #include "muttlib.h"
52 #include "mx.h"
53 #ifdef USE_COMP_MBOX
54 #include "compmbox/lib.h"
55 #endif
56 
57 /* These Config Variables are only used in hook.c */
60 bool C_SaveName;
61 
65 struct Hook
66 {
68  struct Regex regex;
69  char *command;
70  struct PatternList *pattern;
71  TAILQ_ENTRY(Hook) entries;
72 };
73 TAILQ_HEAD(HookList, Hook);
74 
75 static struct HookList Hooks = TAILQ_HEAD_INITIALIZER(Hooks);
76 
77 static struct HashTable *IdxFmtHooks = NULL;
79 
85 enum CommandResult mutt_parse_hook(struct Buffer *buf, struct Buffer *s,
86  intptr_t data, struct Buffer *err)
87 {
88  struct Hook *hook = NULL;
89  int rc = MUTT_CMD_ERROR;
90  bool pat_not = false;
91  regex_t *rx = NULL;
92  struct PatternList *pat = NULL;
93 
94  struct Buffer *cmd = mutt_buffer_pool_get();
96 
97  if (~data & MUTT_GLOBAL_HOOK) /* NOT a global hook */
98  {
99  if (*s->dptr == '!')
100  {
101  s->dptr++;
102  SKIPWS(s->dptr);
103  pat_not = true;
104  }
105 
107 
108  if (!MoreArgs(s))
109  {
110  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
111  rc = MUTT_CMD_WARNING;
112  goto cleanup;
113  }
114  }
115 
116  mutt_extract_token(cmd, s,
121 
122  if (mutt_buffer_is_empty(cmd))
123  {
124  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
125  rc = MUTT_CMD_WARNING;
126  goto cleanup;
127  }
128 
129  if (MoreArgs(s))
130  {
131  mutt_buffer_printf(err, _("%s: too many arguments"), buf->data);
132  rc = MUTT_CMD_WARNING;
133  goto cleanup;
134  }
135 
136  if (data & (MUTT_FOLDER_HOOK | MUTT_MBOX_HOOK))
137  {
138  /* Accidentally using the ^ mailbox shortcut in the .neomuttrc is a
139  * common mistake */
140  if ((pattern->data[0] == '^') && !CurrentFolder)
141  {
142  mutt_buffer_strcpy(err, _("current mailbox shortcut '^' is unset"));
143  goto cleanup;
144  }
145 
146  struct Buffer *tmp = mutt_buffer_pool_get();
147  mutt_buffer_copy(tmp, pattern);
149 
150  /* Check for other mailbox shortcuts that expand to the empty string.
151  * This is likely a mistake too */
152  if (mutt_buffer_is_empty(tmp) && !mutt_buffer_is_empty(pattern))
153  {
154  mutt_buffer_strcpy(err, _("mailbox shortcut expanded to empty regex"));
156  goto cleanup;
157  }
158 
159  mutt_buffer_copy(pattern, tmp);
161  }
162 #ifdef USE_COMP_MBOX
163  else if (data & (MUTT_APPEND_HOOK | MUTT_OPEN_HOOK | MUTT_CLOSE_HOOK))
164  {
165  if (mutt_comp_valid_command(mutt_b2s(cmd)) == 0)
166  {
167  mutt_buffer_strcpy(err, _("badly formatted command string"));
168  goto cleanup;
169  }
170  }
171 #endif
172  else if (C_DefaultHook && (~data & MUTT_GLOBAL_HOOK) &&
174  (!WithCrypto || !(data & MUTT_CRYPT_HOOK)))
175  {
176  /* At this stage remain only message-hooks, reply-hooks, send-hooks,
177  * send2-hooks, save-hooks, and fcc-hooks: All those allowing full
178  * patterns. If given a simple regex, we expand $default_hook. */
180  }
181 
183  {
185  }
186 
187  /* check to make sure that a matching hook doesn't already exist */
188  TAILQ_FOREACH(hook, &Hooks, entries)
189  {
190  if (data & MUTT_GLOBAL_HOOK)
191  {
192  /* Ignore duplicate global hooks */
193  if (mutt_str_equal(hook->command, mutt_b2s(cmd)))
194  {
195  rc = MUTT_CMD_SUCCESS;
196  goto cleanup;
197  }
198  }
199  else if ((hook->type == data) && (hook->regex.pat_not == pat_not) &&
200  mutt_str_equal(mutt_b2s(pattern), hook->regex.pattern))
201  {
203  MUTT_ACCOUNT_HOOK | MUTT_REPLY_HOOK | MUTT_CRYPT_HOOK |
205  {
206  /* these hooks allow multiple commands with the same
207  * pattern, so if we've already seen this pattern/command pair, just
208  * ignore it instead of creating a duplicate */
209  if (mutt_str_equal(hook->command, mutt_b2s(cmd)))
210  {
211  rc = MUTT_CMD_SUCCESS;
212  goto cleanup;
213  }
214  }
215  else
216  {
217  /* other hooks only allow one command per pattern, so update the
218  * entry with the new command. this currently does not change the
219  * order of execution of the hooks, which i think is desirable since
220  * a common action to perform is to change the default (.) entry
221  * based upon some other information. */
222  FREE(&hook->command);
223  hook->command = mutt_buffer_strdup(cmd);
224  rc = MUTT_CMD_SUCCESS;
225  goto cleanup;
226  }
227  }
228  }
229 
230  if (data & (MUTT_CHARSET_HOOK | MUTT_ICONV_HOOK))
231  {
232  /* These are managed separately by the charset code */
234  if (mutt_ch_lookup_add(type, mutt_b2s(pattern), mutt_b2s(cmd), err))
235  rc = MUTT_CMD_SUCCESS;
236  goto cleanup;
237  }
238  else if (data & (MUTT_SEND_HOOK | MUTT_SEND2_HOOK | MUTT_SAVE_HOOK |
240  {
241  PatternCompFlags comp_flags;
242 
243  if (data & (MUTT_SEND2_HOOK))
244  comp_flags = MUTT_PC_SEND_MODE_SEARCH;
245  else if (data & (MUTT_SEND_HOOK | MUTT_FCC_HOOK))
246  comp_flags = MUTT_PC_NO_FLAGS;
247  else
248  comp_flags = MUTT_PC_FULL_MSG;
249 
250  pat = mutt_pattern_comp(mutt_b2s(pattern), comp_flags, err);
251  if (!pat)
252  goto cleanup;
253  }
254  else if (~data & MUTT_GLOBAL_HOOK) /* NOT a global hook */
255  {
256  /* Hooks not allowing full patterns: Check syntax of regex */
257  rx = mutt_mem_malloc(sizeof(regex_t));
258  int rc2 = REG_COMP(rx, NONULL(mutt_b2s(pattern)),
259  ((data & MUTT_CRYPT_HOOK) ? REG_ICASE : 0));
260  if (rc2 != 0)
261  {
262  regerror(rc2, rx, err->data, err->dsize);
263  FREE(&rx);
264  goto cleanup;
265  }
266  }
267 
268  hook = mutt_mem_calloc(1, sizeof(struct Hook));
269  hook->type = data;
270  hook->command = mutt_buffer_strdup(cmd);
271  hook->pattern = pat;
272  hook->regex.pattern = mutt_buffer_strdup(pattern);
273  hook->regex.regex = rx;
274  hook->regex.pat_not = pat_not;
275  TAILQ_INSERT_TAIL(&Hooks, hook, entries);
276  rc = MUTT_CMD_SUCCESS;
277 
278 cleanup:
280  mutt_buffer_pool_release(&pattern);
281  return rc;
282 }
283 
288 static void delete_hook(struct Hook *h)
289 {
290  FREE(&h->command);
291  FREE(&h->regex.pattern);
292  if (h->regex.regex)
293  {
294  regfree(h->regex.regex);
295  FREE(&h->regex.regex);
296  }
298  FREE(&h);
299 }
300 
308 {
309  struct Hook *h = NULL;
310  struct Hook *tmp = NULL;
311 
312  TAILQ_FOREACH_SAFE(h, &Hooks, entries, tmp)
313  {
314  if ((type == MUTT_HOOK_NO_FLAGS) || (type == h->type))
315  {
316  TAILQ_REMOVE(&Hooks, h, entries);
317  delete_hook(h);
318  }
319  }
320 }
321 
325 static void delete_idxfmt_hooklist(int type, void *obj, intptr_t data)
326 {
327  struct HookList *hl = obj;
328  struct Hook *h = NULL;
329  struct Hook *tmp = NULL;
330 
331  TAILQ_FOREACH_SAFE(h, hl, entries, tmp)
332  {
333  TAILQ_REMOVE(hl, h, entries);
334  delete_hook(h);
335  }
336 
337  FREE(&hl);
338 }
339 
343 static void delete_idxfmt_hooks(void)
344 {
345  mutt_hash_free(&IdxFmtHooks);
346 }
347 
351 enum CommandResult mutt_parse_idxfmt_hook(struct Buffer *buf, struct Buffer *s,
352  intptr_t data, struct Buffer *err)
353 {
354  enum CommandResult rc = MUTT_CMD_ERROR;
355  bool pat_not = false;
356 
357  struct Buffer *name = mutt_buffer_pool_get();
358  struct Buffer *pattern = mutt_buffer_pool_get();
359  struct Buffer *fmtstring = mutt_buffer_pool_get();
360 
361  if (!IdxFmtHooks)
362  {
363  IdxFmtHooks = mutt_hash_new(30, MUTT_HASH_STRDUP_KEYS);
365  }
366 
367  if (!MoreArgs(s))
368  {
369  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
370  goto out;
371  }
373  struct HookList *hl = mutt_hash_find(IdxFmtHooks, mutt_b2s(name));
374 
375  if (*s->dptr == '!')
376  {
377  s->dptr++;
378  SKIPWS(s->dptr);
379  pat_not = true;
380  }
382 
383  if (!MoreArgs(s))
384  {
385  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
386  goto out;
387  }
389 
390  if (MoreArgs(s))
391  {
392  mutt_buffer_printf(err, _("%s: too many arguments"), buf->data);
393  goto out;
394  }
395 
396  if (C_DefaultHook)
398 
399  /* check to make sure that a matching hook doesn't already exist */
400  struct Hook *hook = NULL;
401  if (hl)
402  {
403  TAILQ_FOREACH(hook, hl, entries)
404  {
405  if ((hook->regex.pat_not == pat_not) &&
406  mutt_str_equal(mutt_b2s(pattern), hook->regex.pattern))
407  {
408  mutt_str_replace(&hook->command, mutt_b2s(fmtstring));
409  rc = MUTT_CMD_SUCCESS;
410  goto out;
411  }
412  }
413  }
414 
415  /* MUTT_PC_PATTERN_DYNAMIC sets so that date ranges are regenerated during
416  * matching. This of course is slower, but index-format-hook is commonly
417  * used for date ranges, and they need to be evaluated relative to "now", not
418  * the hook compilation time. */
419  struct PatternList *pat = mutt_pattern_comp(
421  if (!pat)
422  goto out;
423 
424  hook = mutt_mem_calloc(1, sizeof(struct Hook));
425  hook->type = MUTT_IDXFMTHOOK;
426  hook->command = mutt_buffer_strdup(fmtstring);
427  hook->pattern = pat;
428  hook->regex.pattern = mutt_buffer_strdup(pattern);
429  hook->regex.regex = NULL;
430  hook->regex.pat_not = pat_not;
431 
432  if (!hl)
433  {
434  hl = mutt_mem_calloc(1, sizeof(*hl));
435  TAILQ_INIT(hl);
436  mutt_hash_insert(IdxFmtHooks, mutt_b2s(name), hl);
437  }
438 
439  TAILQ_INSERT_TAIL(hl, hook, entries);
440  rc = MUTT_CMD_SUCCESS;
441 
442 out:
444  mutt_buffer_pool_release(&pattern);
445  mutt_buffer_pool_release(&fmtstring);
446 
447  return rc;
448 }
449 
453 enum CommandResult mutt_parse_unhook(struct Buffer *buf, struct Buffer *s,
454  intptr_t data, struct Buffer *err)
455 {
456  while (MoreArgs(s))
457  {
459  if (mutt_str_equal("*", buf->data))
460  {
462  {
463  mutt_buffer_printf(err, "%s", _("unhook: Can't do unhook * from within a hook"));
464  return MUTT_CMD_WARNING;
465  }
469  }
470  else
471  {
473 
474  if (type == MUTT_HOOK_NO_FLAGS)
475  {
476  mutt_buffer_printf(err, _("unhook: unknown hook type: %s"), buf->data);
477  return MUTT_CMD_ERROR;
478  }
479  if (type & (MUTT_CHARSET_HOOK | MUTT_ICONV_HOOK))
480  {
482  return MUTT_CMD_SUCCESS;
483  }
484  if (current_hook_type == type)
485  {
486  mutt_buffer_printf(err, _("unhook: Can't delete a %s from within a %s"),
487  buf->data, buf->data);
488  return MUTT_CMD_WARNING;
489  }
490  if (type == MUTT_IDXFMTHOOK)
492  else
493  mutt_delete_hooks(type);
494  }
495  }
496  return MUTT_CMD_SUCCESS;
497 }
498 
504 void mutt_folder_hook(const char *path, const char *desc)
505 {
506  if (!path && !desc)
507  return;
508 
509  struct Hook *hook = NULL;
510  struct Buffer *err = mutt_buffer_pool_get();
511 
513 
514  TAILQ_FOREACH(hook, &Hooks, entries)
515  {
516  if (!hook->command)
517  continue;
518 
519  if (!(hook->type & MUTT_FOLDER_HOOK))
520  continue;
521 
522  const char *match = NULL;
523  if (mutt_regex_match(&hook->regex, path))
524  match = path;
525  else if (mutt_regex_match(&hook->regex, desc))
526  match = desc;
527 
528  if (match)
529  {
530  mutt_debug(LL_DEBUG1, "folder-hook '%s' matches '%s'\n", hook->regex.pattern, match);
531  mutt_debug(LL_DEBUG5, " %s\n", hook->command);
532  if (mutt_parse_rc_line(hook->command, err) == MUTT_CMD_ERROR)
533  {
534  mutt_error("%s", mutt_b2s(err));
535  break;
536  }
537  }
538  }
540 
542 }
543 
552 char *mutt_find_hook(HookFlags type, const char *pat)
553 {
554  struct Hook *tmp = NULL;
555 
556  TAILQ_FOREACH(tmp, &Hooks, entries)
557  {
558  if (tmp->type & type)
559  {
560  if (mutt_regex_match(&tmp->regex, pat))
561  return tmp->command;
562  }
563  }
564  return NULL;
565 }
566 
573 void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
574 {
575  struct Hook *hook = NULL;
576  struct PatternCache cache = { 0 };
577  struct Buffer *err = mutt_buffer_pool_get();
578 
580 
581  TAILQ_FOREACH(hook, &Hooks, entries)
582  {
583  if (!hook->command)
584  continue;
585 
586  if (hook->type & type)
587  {
588  if ((mutt_pattern_exec(SLIST_FIRST(hook->pattern), 0, m, e, &cache) > 0) ^
589  hook->regex.pat_not)
590  {
591  if (mutt_parse_rc_line(hook->command, err) == MUTT_CMD_ERROR)
592  {
593  mutt_error("%s", mutt_b2s(err));
596 
597  return;
598  }
599  /* Executing arbitrary commands could affect the pattern results,
600  * so the cache has to be wiped */
601  memset(&cache, 0, sizeof(cache));
602  }
603  }
604  }
606 
608 }
609 
620 static int addr_hook(char *path, size_t pathlen, HookFlags type,
621  struct Context *ctx, struct Email *e)
622 {
623  struct Hook *hook = NULL;
624  struct PatternCache cache = { 0 };
625 
626  /* determine if a matching hook exists */
627  TAILQ_FOREACH(hook, &Hooks, entries)
628  {
629  if (!hook->command)
630  continue;
631 
632  if (hook->type & type)
633  {
634  struct Mailbox *m = ctx ? ctx->mailbox : NULL;
635  if ((mutt_pattern_exec(SLIST_FIRST(hook->pattern), 0, m, e, &cache) > 0) ^
636  hook->regex.pat_not)
637  {
638  mutt_make_string_flags(path, pathlen, 0, hook->command, m,
639  ctx ? ctx->msg_in_pager : -1, e, MUTT_FORMAT_PLAIN);
640  return 0;
641  }
642  }
643  }
644 
645  return -1;
646 }
647 
654 void mutt_default_save(char *path, size_t pathlen, struct Email *e)
655 {
656  *path = '\0';
657  if (addr_hook(path, pathlen, MUTT_SAVE_HOOK, Context, e) == 0)
658  return;
659 
660  struct Envelope *env = e->env;
661  const struct Address *from = TAILQ_FIRST(&env->from);
662  const struct Address *reply_to = TAILQ_FIRST(&env->reply_to);
663  const struct Address *to = TAILQ_FIRST(&env->to);
664  const struct Address *cc = TAILQ_FIRST(&env->cc);
665  const struct Address *addr = NULL;
666  bool from_me = mutt_addr_is_user(from);
667 
668  if (!from_me && reply_to && reply_to->mailbox)
669  addr = reply_to;
670  else if (!from_me && from && from->mailbox)
671  addr = from;
672  else if (to && to->mailbox)
673  addr = to;
674  else if (cc && cc->mailbox)
675  addr = cc;
676  else
677  addr = NULL;
678  if (addr)
679  {
680  struct Buffer *tmp = mutt_buffer_pool_get();
681  mutt_safe_path(tmp, addr);
682  snprintf(path, pathlen, "=%s", mutt_b2s(tmp));
684  }
685 }
686 
692 void mutt_select_fcc(struct Buffer *path, struct Email *e)
693 {
695 
696  if (addr_hook(path->data, path->dsize, MUTT_FCC_HOOK, NULL, e) != 0)
697  {
698  const struct Address *to = TAILQ_FIRST(&e->env->to);
699  const struct Address *cc = TAILQ_FIRST(&e->env->cc);
700  const struct Address *bcc = TAILQ_FIRST(&e->env->bcc);
701  if ((C_SaveName || C_ForceName) && (to || cc || bcc))
702  {
703  const struct Address *addr = to ? to : (cc ? cc : bcc);
704  struct Buffer *buf = mutt_buffer_pool_get();
705  mutt_safe_path(buf, addr);
708  if (!C_ForceName && (mx_access(mutt_b2s(path), W_OK) != 0))
710  }
711  else
713  }
714  else
715  mutt_buffer_fix_dptr(path);
716 
718 }
719 
726 static void list_hook(struct ListHead *matches, const char *match, HookFlags hook)
727 {
728  struct Hook *tmp = NULL;
729 
730  TAILQ_FOREACH(tmp, &Hooks, entries)
731  {
732  if ((tmp->type & hook) && mutt_regex_match(&tmp->regex, match))
733  {
735  }
736  }
737 }
738 
746 void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
747 {
748  list_hook(list, addr->mailbox, MUTT_CRYPT_HOOK);
749 }
750 
755 void mutt_account_hook(const char *url)
756 {
757  /* parsing commands with URLs in an account hook can cause a recursive
758  * call. We just skip processing if this occurs. Typically such commands
759  * belong in a folder-hook -- perhaps we should warn the user. */
760  static bool inhook = false;
761  if (inhook)
762  return;
763 
764  struct Hook *hook = NULL;
765  struct Buffer *err = mutt_buffer_pool_get();
766 
767  TAILQ_FOREACH(hook, &Hooks, entries)
768  {
769  if (!(hook->command && (hook->type & MUTT_ACCOUNT_HOOK)))
770  continue;
771 
772  if (mutt_regex_match(&hook->regex, url))
773  {
774  inhook = true;
775  mutt_debug(LL_DEBUG1, "account-hook '%s' matches '%s'\n", hook->regex.pattern, url);
776  mutt_debug(LL_DEBUG5, " %s\n", hook->command);
777 
778  if (mutt_parse_rc_line(hook->command, err) == MUTT_CMD_ERROR)
779  {
780  mutt_error("%s", mutt_b2s(err));
782 
783  inhook = false;
784  goto done;
785  }
786 
787  inhook = false;
788  }
789  }
790 done:
792 }
793 
801 {
802  struct Hook *hook = NULL;
803  struct Buffer err;
804  char buf[256];
805 
806  mutt_buffer_init(&err);
807  err.data = buf;
808  err.dsize = sizeof(buf);
809 
810  TAILQ_FOREACH(hook, &Hooks, entries)
811  {
812  if (!(hook->command && (hook->type & MUTT_TIMEOUT_HOOK)))
813  continue;
814 
815  if (mutt_parse_rc_line(hook->command, &err) == MUTT_CMD_ERROR)
816  {
817  mutt_error("%s", err.data);
818  mutt_buffer_reset(&err);
819 
820  /* The hooks should be independent of each other, so even though this on
821  * failed, we'll carry on with the others. */
822  }
823  }
824 
825  /* Delete temporary attachment files */
827 }
828 
837 {
838  struct Hook *hook = NULL;
839  struct Buffer err = mutt_buffer_make(0);
840  char buf[256];
841 
842  err.data = buf;
843  err.dsize = sizeof(buf);
844 
845  TAILQ_FOREACH(hook, &Hooks, entries)
846  {
847  if (!(hook->command && (hook->type & type)))
848  continue;
849 
850  if (mutt_parse_rc_line(hook->command, &err) == MUTT_CMD_ERROR)
851  {
852  mutt_error("%s", err.data);
853  mutt_buffer_reset(&err);
854  }
855  }
856 }
857 
866 const char *mutt_idxfmt_hook(const char *name, struct Mailbox *m, struct Email *e)
867 {
868  if (!IdxFmtHooks)
869  return NULL;
870 
871  struct HookList *hl = mutt_hash_find(IdxFmtHooks, name);
872  if (!hl)
873  return NULL;
874 
876 
877  struct PatternCache cache = { 0 };
878  const char *fmtstring = NULL;
879  struct Hook *hook = NULL;
880 
881  TAILQ_FOREACH(hook, hl, entries)
882  {
883  struct Pattern *pat = SLIST_FIRST(hook->pattern);
884  if ((mutt_pattern_exec(pat, 0, m, e, &cache) > 0) ^ hook->regex.pat_not)
885  {
886  fmtstring = hook->command;
887  break;
888  }
889  }
890 
892 
893  return fmtstring;
894 }
#define MUTT_SEND_HOOK
send-hook: when composing a new email
Definition: hook.h:47
#define MUTT_PC_PATTERN_DYNAMIC
Enable runtime date range evaluation.
Definition: lib.h:61
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:871
The "current" mailbox.
Definition: context.h:38
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:75
#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
#define WithCrypto
Definition: lib.h:123
void mutt_make_string_flags(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1403
int msg_in_pager
Message currently shown in the pager.
Definition: context.h:44
The envelope/body of an email.
Definition: email.h:37
A Hash Table.
Definition: hash.h:84
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define TAILQ_FIRST(head)
Definition: queue.h:716
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:65
Config/command parsing.
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
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
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
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()
Definition: hook.c:85
HookFlags type
Hook type.
Definition: hook.c:67
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:447
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
static int addr_hook(char *path, size_t pathlen, HookFlags type, struct Context *ctx, struct Email *e)
Perform an address hook (get a path)
Definition: hook.c:620
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:91
static void delete_idxfmt_hooks(void)
Delete all the index-format-hooks.
Definition: hook.c:343
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:695
static HookFlags current_hook_type
Definition: hook.c:78
String manipulation buffer.
Definition: buffer.h:33
bool pat_not
do not match
Definition: regex3.h:92
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:728
A list of user hooks.
Definition: hook.c:65
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
#define _(a)
Definition: message.h:28
void mutt_delete_hooks(HookFlags type)
Delete matching hooks.
Definition: hook.c:307
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: compile.c:1056
#define MUTT_CHARSET_HOOK
charset-hook: create a charset alias for malformed emails
Definition: hook.h:50
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
An email address.
Definition: address.h:34
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:453
char * mailbox
Mailbox and host address.
Definition: address.h:37
static void list_hook(struct ListHead *matches, const char *match, HookFlags hook)
Find hook strings matching.
Definition: hook.c:726
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:52
void mutt_check_simple(struct Buffer *s, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:109
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1258
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:43
#define MUTT_IDXFMTHOOK
index-format-hook: customise the format of the index
Definition: hook.h:62
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:654
Flags to control mutt_expando_format()
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:598
#define MUTT_CRYPT_HOOK
crypt-hook: automatically select a PGP/SMIME key
Definition: hook.h:53
A simple (non-regex) pattern.
Definition: lib.h:67
void mutt_ch_lookup_remove(void)
Remove all the character set lookups.
Definition: charset.c:517
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:140
Character set conversion.
Definition: charset.h:69
char * command
Filename, command or pattern to execute.
Definition: hook.c:69
Some miscellaneous functions.
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:504
size_t dsize
Length of data.
Definition: buffer.h:37
#define MoreArgs(buf)
Definition: buffer.h:43
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:836
struct Mailbox * mailbox
Definition: context.h:50
Parse and execute user-defined hooks.
Many unsorted constants and some structs.
API for mailboxes.
#define MUTT_ICONV_HOOK
iconv-hook: create a system charset alias
Definition: hook.h:51
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
struct Envelope * env
Envelope information.
Definition: email.h:90
#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:746
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:62
#define TAILQ_INIT(head)
Definition: queue.h:758
bool C_ForceName
Config: Save outgoing mail in a folder of their name.
Definition: hook.c:59
struct Regex regex
Regular expression.
Definition: hook.c:68
Email Aliases.
Compressed mbox local mailbox type.
#define MUTT_APPEND_HOOK
append-hook: append to a compressed mailbox
Definition: hook.h:59
#define MUTT_MBOX_HOOK
mbox-hook: move messages after reading them
Definition: hook.h:46
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
static void delete_idxfmt_hooklist(int type, void *obj, intptr_t data)
Delete a index-format-hook from the Hash Table - Implements hash_hdata_free_t.
Definition: hook.c:325
#define MUTT_GLOBAL_HOOK
Hooks which don&#39;t take a regex.
Definition: hook.h:66
void mutt_safe_path(struct Buffer *dest, const struct Address *a)
Make a safe filename from an email address.
Definition: muttlib.c:753
Alias for another character set.
Definition: charset.h:68
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
#define mutt_b2s(buf)
Definition: buffer.h:41
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:866
#define MUTT_SAVE_HOOK
save-hook: set a default folder when saving an email
Definition: hook.h:49
#define SLIST_FIRST(head)
Definition: queue.h:228
void mutt_account_hook(const char *url)
Perform an account hook.
Definition: hook.c:755
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:44
char * mutt_find_hook(HookFlags type, const char *pat)
Find a matching hook.
Definition: hook.c:552
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:394
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:60
void mutt_select_fcc(struct Buffer *path, struct Email *e)
Select the FCC path for an email.
Definition: hook.c:692
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:73
#define MUTT_PC_NO_FLAGS
No flags are set.
Definition: lib.h:59
Match patterns to emails.
char * data
Pointer to data.
Definition: buffer.h:35
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:96
int mutt_comp_valid_command(const char *cmd)
Is this command string allowed?
Definition: compress.c:405
Definitions of NeoMutt commands.
API for encryption/signing of emails.
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:802
Handling of email attachments.
#define MUTT_OPEN_HOOK
open-hook: to read a compressed mailbox
Definition: hook.h:58
bool C_SaveName
Config: Save outgoing message to mailbox of recipient&#39;s name if it exists.
Definition: hook.c:60
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:738
#define MUTT_TIMEOUT_HOOK
timeout-hook: run a command periodically
Definition: hook.h:63
#define TAILQ_ENTRY(type)
Definition: queue.h:633
WHERE char * C_Record
Config: Folder to save &#39;sent&#39; messages.
Definition: mutt_globals.h:98
Success: Command worked.
Definition: mutt_commands.h:38
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:323
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:56
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
Cached regular expression.
Definition: regex3.h:88
#define mutt_error(...)
Definition: logging.h:84
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:609
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:800
#define MUTT_REPLY_HOOK
reply-hook: when replying to an email
Definition: hook.h:55
#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:544
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
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:351
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition: mx.c:183
TAILQ_HEAD(HookList, Hook)
#define MUTT_HOOK_NO_FLAGS
No flags are set.
Definition: hook.h:44
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
Hundreds of global variables to back the user variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:573
char * C_DefaultHook
Config: Pattern to use for hooks that only have a simple regex.
Definition: hook.c:58
static void delete_hook(struct Hook *h)
Delete a Hook.
Definition: hook.c:288
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:1004
char * pattern
printable version
Definition: regex3.h:90
Cache commonly-used patterns.
Definition: lib.h:104
#define MUTT_HASH_STRDUP_KEYS
make a copy of the keys
Definition: hash.h:99
Log at debug level 5.
Definition: logging.h:44
#define MUTT_PC_FULL_MSG
Enable body and header matching.
Definition: lib.h:60
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:630
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:64
LookupType
Types of character set lookups.
Definition: charset.h:66
#define MUTT_FCC_HOOK
fcc-hook: to save outgoing email
Definition: hook.h:48
struct PatternList * pattern
Used for fcc,save,send-hook.
Definition: hook.c:70
uint8_t PatternCompFlags
Flags for mutt_pattern_comp(), e.g. MUTT_PC_FULL_MSG.
Definition: lib.h:58
#define MUTT_ACCOUNT_HOOK
account-hook: when changing between accounts
Definition: hook.h:54
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:485
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:70
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:45