NeoMutt  2018-07-16 +2481-68dcde
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 <regex.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include "mutt/mutt.h"
38 #include "address/lib.h"
39 #include "email/lib.h"
40 #include "mutt.h"
41 #include "hook.h"
42 #include "alias.h"
43 #include "context.h"
44 #include "format_flags.h"
45 #include "globals.h"
46 #include "hdrline.h"
47 #include "mutt_attach.h"
48 #include "mutt_commands.h"
49 #include "muttlib.h"
50 #include "mx.h"
51 #include "ncrypt/ncrypt.h"
52 #include "pattern.h"
53 #ifdef USE_COMPRESSED
54 #include "compress.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 Hash *IdxFmtHooks = NULL;
79 
85 enum CommandResult mutt_parse_hook(struct Buffer *buf, struct Buffer *s,
86  unsigned long data, struct Buffer *err)
87 {
88  struct Hook *hook = NULL;
89  struct Buffer cmd, pattern;
90  int rc;
91  bool pat_not = false, warning = false;
92  regex_t *rx = NULL;
93  struct PatternList *pat = NULL;
94  char path[PATH_MAX];
95 
96  mutt_buffer_init(&pattern);
97  mutt_buffer_init(&cmd);
98 
99  if (~data & MUTT_GLOBAL_HOOK) /* NOT a global hook */
100  {
101  if (*s->dptr == '!')
102  {
103  s->dptr++;
104  SKIPWS(s->dptr);
105  pat_not = true;
106  }
107 
109 
110  if (!MoreArgs(s))
111  {
112  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
113  goto warn;
114  }
115  }
116 
117  mutt_extract_token(&cmd, s,
122 
123  if (!cmd.data)
124  {
125  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
126  goto warn;
127  }
128 
129  if (MoreArgs(s))
130  {
131  mutt_buffer_printf(err, _("%s: too many arguments"), buf->data);
132  goto warn;
133  }
134 
135  if (data & (MUTT_FOLDER_HOOK | MUTT_MBOX_HOOK))
136  {
137  /* Accidentally using the ^ mailbox shortcut in the .neomuttrc is a
138  * common mistake */
139  if ((*pattern.data == '^') && (!CurrentFolder))
140  {
141  mutt_buffer_strcpy(err, _("current mailbox shortcut '^' is unset"));
142  goto error;
143  }
144 
145  mutt_str_strfcpy(path, pattern.data, sizeof(path));
146  mutt_expand_path_regex(path, sizeof(path), true);
147 
148  /* Check for other mailbox shortcuts that expand to the empty string.
149  * This is likely a mistake too */
150  if (!*path && *pattern.data)
151  {
152  mutt_buffer_strcpy(err, _("mailbox shortcut expanded to empty regex"));
153  goto error;
154  }
155 
156  FREE(&pattern.data);
157  mutt_buffer_init(&pattern);
158  pattern.data = mutt_str_strdup(path);
159  }
160 #ifdef USE_COMPRESSED
161  else if (data & (MUTT_APPEND_HOOK | MUTT_OPEN_HOOK | MUTT_CLOSE_HOOK))
162  {
163  if (mutt_comp_valid_command(cmd.data) == 0)
164  {
165  mutt_buffer_strcpy(err, _("badly formatted command string"));
166  return MUTT_CMD_ERROR;
167  }
168  }
169 #endif
170  else if (C_DefaultHook && (~data & MUTT_GLOBAL_HOOK) &&
172  (!WithCrypto || !(data & MUTT_CRYPT_HOOK)))
173  {
174  struct Buffer *tmp = mutt_buffer_pool_get();
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. */
179  mutt_buffer_strcpy(tmp, pattern.data);
181  FREE(&pattern.data);
182  mutt_buffer_init(&pattern);
183  pattern.data = mutt_str_strdup(mutt_b2s(tmp));
185  }
186 
188  {
189  mutt_str_strfcpy(path, cmd.data, sizeof(path));
190  mutt_expand_path(path, sizeof(path));
191  FREE(&cmd.data);
192  mutt_buffer_init(&cmd);
193  cmd.data = mutt_str_strdup(path);
194  }
195 
196  /* check to make sure that a matching hook doesn't already exist */
197  TAILQ_FOREACH(hook, &Hooks, entries)
198  {
199  if (data & MUTT_GLOBAL_HOOK)
200  {
201  /* Ignore duplicate global hooks */
202  if (mutt_str_strcmp(hook->command, cmd.data) == 0)
203  {
204  FREE(&cmd.data);
205  return MUTT_CMD_SUCCESS;
206  }
207  }
208  else if ((hook->type == data) && (hook->regex.pat_not == pat_not) &&
209  (mutt_str_strcmp(pattern.data, hook->regex.pattern) == 0))
210  {
212  MUTT_ACCOUNT_HOOK | MUTT_REPLY_HOOK | MUTT_CRYPT_HOOK |
214  {
215  /* these hooks allow multiple commands with the same
216  * pattern, so if we've already seen this pattern/command pair, just
217  * ignore it instead of creating a duplicate */
218  if (mutt_str_strcmp(hook->command, cmd.data) == 0)
219  {
220  FREE(&cmd.data);
221  FREE(&pattern.data);
222  return MUTT_CMD_SUCCESS;
223  }
224  }
225  else
226  {
227  /* other hooks only allow one command per pattern, so update the
228  * entry with the new command. this currently does not change the
229  * order of execution of the hooks, which i think is desirable since
230  * a common action to perform is to change the default (.) entry
231  * based upon some other information. */
232  FREE(&hook->command);
233  hook->command = cmd.data;
234  FREE(&pattern.data);
235  return MUTT_CMD_SUCCESS;
236  }
237  }
238  }
239 
240  if (data & (MUTT_CHARSET_HOOK | MUTT_ICONV_HOOK))
241  {
242  /* These are managed separately by the charset code */
244  if (!mutt_ch_lookup_add(type, pattern.data, cmd.data, err))
245  goto error;
246  FREE(&pattern.data);
247  FREE(&cmd.data);
248  return MUTT_CMD_SUCCESS;
249  }
250  else if (data & (MUTT_SEND_HOOK | MUTT_SEND2_HOOK | MUTT_SAVE_HOOK |
252  {
253  pat = mutt_pattern_comp(pattern.data,
257  err);
258  if (!pat)
259  goto error;
260  }
261  else if (~data & MUTT_GLOBAL_HOOK) /* NOT a global hook */
262  {
263  /* Hooks not allowing full patterns: Check syntax of regex */
264  rx = mutt_mem_malloc(sizeof(regex_t));
265  rc = REG_COMP(rx, NONULL(pattern.data), ((data & MUTT_CRYPT_HOOK) ? REG_ICASE : 0));
266  if (rc != 0)
267  {
268  regerror(rc, rx, err->data, err->dsize);
269  FREE(&rx);
270  goto error;
271  }
272  }
273 
274  hook = mutt_mem_calloc(1, sizeof(struct Hook));
275  hook->type = data;
276  hook->command = cmd.data;
277  hook->pattern = pat;
278  hook->regex.pattern = pattern.data;
279  hook->regex.regex = rx;
280  hook->regex.pat_not = pat_not;
281  TAILQ_INSERT_TAIL(&Hooks, hook, entries);
282  return MUTT_CMD_SUCCESS;
283 
284 warn:
285  warning = true;
286 error:
287  if (~data & MUTT_GLOBAL_HOOK) /* NOT a global hook */
288  FREE(&pattern.data);
289  FREE(&cmd.data);
290  return (warning ? MUTT_CMD_WARNING : MUTT_CMD_ERROR);
291 }
292 
297 static void delete_hook(struct Hook *h)
298 {
299  FREE(&h->command);
300  FREE(&h->regex.pattern);
301  if (h->regex.regex)
302  {
303  regfree(h->regex.regex);
304  FREE(&h->regex.regex);
305  }
307  FREE(&h);
308 }
309 
317 {
318  struct Hook *h = NULL;
319  struct Hook *tmp = NULL;
320 
321  TAILQ_FOREACH_SAFE(h, &Hooks, entries, tmp)
322  {
323  if ((type == MUTT_HOOK_NO_FLAGS) || (type == h->type))
324  {
325  TAILQ_REMOVE(&Hooks, h, entries);
326  delete_hook(h);
327  }
328  }
329 }
330 
337 static void delete_idxfmt_hooklist(int type, void *obj, intptr_t data)
338 {
339  struct HookList *hl = obj;
340  struct Hook *h = NULL;
341  struct Hook *tmp = NULL;
342 
343  TAILQ_FOREACH_SAFE(h, hl, entries, tmp)
344  {
345  TAILQ_REMOVE(hl, h, entries);
346  delete_hook(h);
347  }
348 
349  FREE(&hl);
350 }
351 
355 static void delete_idxfmt_hooks(void)
356 {
357  mutt_hash_free(&IdxFmtHooks);
358 }
359 
363 enum CommandResult mutt_parse_idxfmt_hook(struct Buffer *buf, struct Buffer *s,
364  unsigned long data, struct Buffer *err)
365 {
366  enum CommandResult rc = MUTT_CMD_ERROR;
367  bool pat_not = false;
368 
369  struct Buffer *name = mutt_buffer_pool_get();
370  struct Buffer *pattern = mutt_buffer_pool_get();
371  struct Buffer *fmtstring = mutt_buffer_pool_get();
372 
373  if (!IdxFmtHooks)
374  {
375  IdxFmtHooks = mutt_hash_new(30, MUTT_HASH_STRDUP_KEYS);
377  }
378 
379  if (!MoreArgs(s))
380  {
381  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
382  goto out;
383  }
385  struct HookList *hl = mutt_hash_find(IdxFmtHooks, mutt_b2s(name));
386 
387  if (*s->dptr == '!')
388  {
389  s->dptr++;
390  SKIPWS(s->dptr);
391  pat_not = true;
392  }
394 
395  if (!MoreArgs(s))
396  {
397  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
398  goto out;
399  }
401 
402  if (MoreArgs(s))
403  {
404  mutt_buffer_printf(err, _("%s: too many arguments"), buf->data);
405  goto out;
406  }
407 
408  if (C_DefaultHook)
410 
411  /* check to make sure that a matching hook doesn't already exist */
412  struct Hook *hook = NULL;
413  if (hl)
414  {
415  TAILQ_FOREACH(hook, hl, entries)
416  {
417  if ((hook->regex.pat_not == pat_not) &&
418  (mutt_str_strcmp(mutt_b2s(pattern), hook->regex.pattern) == 0))
419  {
420  mutt_str_replace(&hook->command, mutt_b2s(fmtstring));
421  rc = MUTT_CMD_SUCCESS;
422  goto out;
423  }
424  }
425  }
426 
427  /* MUTT_PC_PATTERN_DYNAMIC sets so that date ranges are regenerated during
428  * matching. This of course is slower, but index-format-hook is commonly
429  * used for date ranges, and they need to be evaluated relative to "now", not
430  * the hook compilation time. */
431  struct PatternList *pat = mutt_pattern_comp(
433  if (!pat)
434  goto out;
435 
436  hook = mutt_mem_calloc(1, sizeof(struct Hook));
437  hook->type = data;
438  hook->command = mutt_str_strdup(mutt_b2s(fmtstring));
439  hook->pattern = pat;
440  hook->regex.pattern = mutt_str_strdup(mutt_b2s(pattern));
441  hook->regex.regex = NULL;
442  hook->regex.pat_not = pat_not;
443 
444  if (!hl)
445  {
446  hl = mutt_mem_calloc(1, sizeof(*hl));
447  TAILQ_INIT(hl);
448  mutt_hash_insert(IdxFmtHooks, mutt_b2s(name), hl);
449  }
450 
451  TAILQ_INSERT_TAIL(hl, hook, entries);
452  rc = MUTT_CMD_SUCCESS;
453 
454 out:
456  mutt_buffer_pool_release(&pattern);
457  mutt_buffer_pool_release(&fmtstring);
458 
459  return rc;
460 }
461 
465 enum CommandResult mutt_parse_unhook(struct Buffer *buf, struct Buffer *s,
466  unsigned long data, struct Buffer *err)
467 {
468  while (MoreArgs(s))
469  {
471  if (mutt_str_strcmp("*", buf->data) == 0)
472  {
474  {
475  mutt_buffer_printf(err, "%s", _("unhook: Can't do unhook * from within a hook"));
476  return MUTT_CMD_WARNING;
477  }
481  }
482  else
483  {
485 
486  if (type == MUTT_HOOK_NO_FLAGS)
487  {
488  mutt_buffer_printf(err, _("unhook: unknown hook type: %s"), buf->data);
489  return MUTT_CMD_ERROR;
490  }
491  if (type & (MUTT_CHARSET_HOOK | MUTT_ICONV_HOOK))
492  {
494  return MUTT_CMD_SUCCESS;
495  }
496  if (current_hook_type == type)
497  {
498  mutt_buffer_printf(err, _("unhook: Can't delete a %s from within a %s"),
499  buf->data, buf->data);
500  return MUTT_CMD_WARNING;
501  }
502  if (type == MUTT_IDXFMTHOOK)
504  else
505  mutt_delete_hooks(type);
506  }
507  }
508  return MUTT_CMD_SUCCESS;
509 }
510 
516 void mutt_folder_hook(const char *path, const char *desc)
517 {
518  if (!path && !desc)
519  return;
520 
521  struct Hook *tmp = NULL;
522  struct Buffer *err = mutt_buffer_pool_get();
523  struct Buffer *token = mutt_buffer_pool_get();
524 
526 
527  TAILQ_FOREACH(tmp, &Hooks, entries)
528  {
529  if (!tmp->command)
530  continue;
531 
532  if (!(tmp->type & MUTT_FOLDER_HOOK))
533  continue;
534 
535  if (mutt_regex_match(&tmp->regex, path) || mutt_regex_match(&tmp->regex, desc))
536  {
537  if (mutt_parse_rc_line(tmp->command, token, err) == MUTT_CMD_ERROR)
538  {
539  mutt_error("%s", mutt_b2s(err));
540  break;
541  }
542  }
543  }
544  mutt_buffer_pool_release(&token);
546 
548 }
549 
558 char *mutt_find_hook(HookFlags type, const char *pat)
559 {
560  struct Hook *tmp = NULL;
561 
562  TAILQ_FOREACH(tmp, &Hooks, entries)
563  {
564  if (tmp->type & type)
565  {
566  if (mutt_regex_match(&tmp->regex, pat))
567  return tmp->command;
568  }
569  }
570  return NULL;
571 }
572 
579 void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
580 {
581  struct Hook *hook = NULL;
582  struct PatternCache cache = { 0 };
583  struct Buffer *err = mutt_buffer_pool_get();
584  struct Buffer *token = mutt_buffer_pool_get();
585 
587 
588  TAILQ_FOREACH(hook, &Hooks, entries)
589  {
590  if (!hook->command)
591  continue;
592 
593  if (hook->type & type)
594  {
595  if ((mutt_pattern_exec(SLIST_FIRST(hook->pattern), 0, m, e, &cache) > 0) ^
596  hook->regex.pat_not)
597  {
598  if (mutt_parse_rc_line(hook->command, token, err) == MUTT_CMD_ERROR)
599  {
600  mutt_buffer_pool_release(&token);
601  mutt_error("%s", mutt_b2s(err));
604 
605  return;
606  }
607  /* Executing arbitrary commands could affect the pattern results,
608  * so the cache has to be wiped */
609  memset(&cache, 0, sizeof(cache));
610  }
611  }
612  }
613  mutt_buffer_pool_release(&token);
615 
617 }
618 
629 static int addr_hook(char *path, size_t pathlen, HookFlags type,
630  struct Context *ctx, struct Email *e)
631 {
632  struct Hook *hook = NULL;
633  struct PatternCache cache = { 0 };
634 
635  /* determine if a matching hook exists */
636  TAILQ_FOREACH(hook, &Hooks, entries)
637  {
638  if (!hook->command)
639  continue;
640 
641  if (hook->type & type)
642  {
643  struct Mailbox *m = ctx ? ctx->mailbox : NULL;
644  if ((mutt_pattern_exec(SLIST_FIRST(hook->pattern), 0, m, e, &cache) > 0) ^
645  hook->regex.pat_not)
646  {
647  mutt_make_string_flags(path, pathlen, hook->command, ctx, m, e, MUTT_FORMAT_PLAIN);
648  return 0;
649  }
650  }
651  }
652 
653  return -1;
654 }
655 
662 void mutt_default_save(char *path, size_t pathlen, struct Email *e)
663 {
664  *path = '\0';
665  if (addr_hook(path, pathlen, MUTT_SAVE_HOOK, Context, e) == 0)
666  return;
667 
668  struct Envelope *env = e->env;
669  const struct Address *from = TAILQ_FIRST(&env->from);
670  const struct Address *reply_to = TAILQ_FIRST(&env->reply_to);
671  const struct Address *to = TAILQ_FIRST(&env->to);
672  const struct Address *cc = TAILQ_FIRST(&env->cc);
673  const struct Address *addr = NULL;
674  bool from_me = mutt_addr_is_user(from);
675 
676  if (!from_me && reply_to && reply_to->mailbox)
677  addr = reply_to;
678  else if (!from_me && from && from->mailbox)
679  addr = from;
680  else if (to && to->mailbox)
681  addr = to;
682  else if (cc && cc->mailbox)
683  addr = cc;
684  else
685  addr = NULL;
686  if (addr)
687  {
688  char tmp[PATH_MAX];
689  mutt_safe_path(tmp, sizeof(tmp), addr);
690  snprintf(path, pathlen, "=%s", tmp);
691  }
692 }
693 
700 void mutt_select_fcc(char *path, size_t pathlen, struct Email *e)
701 {
702  if (addr_hook(path, pathlen, MUTT_FCC_HOOK, NULL, e) != 0)
703  {
704  const struct Address *to = TAILQ_FIRST(&e->env->to);
705  const struct Address *cc = TAILQ_FIRST(&e->env->cc);
706  const struct Address *bcc = TAILQ_FIRST(&e->env->bcc);
707  if ((C_SaveName || C_ForceName) && (to || cc || bcc))
708  {
709  const struct Address *addr = to ? to : (cc ? cc : bcc);
710  char buf[PATH_MAX];
711  mutt_safe_path(buf, sizeof(buf), addr);
712  mutt_path_concat(path, NONULL(C_Folder), buf, pathlen);
713  if (!C_ForceName && (mx_access(path, W_OK) != 0))
714  mutt_str_strfcpy(path, C_Record, pathlen);
715  }
716  else
717  mutt_str_strfcpy(path, C_Record, pathlen);
718  }
719  mutt_pretty_mailbox(path, pathlen);
720 }
721 
728 static void list_hook(struct ListHead *matches, const char *match, HookFlags hook)
729 {
730  struct Hook *tmp = NULL;
731 
732  TAILQ_FOREACH(tmp, &Hooks, entries)
733  {
734  if ((tmp->type & hook) && mutt_regex_match(&tmp->regex, match))
735  {
737  }
738  }
739 }
740 
748 void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
749 {
750  list_hook(list, addr->mailbox, MUTT_CRYPT_HOOK);
751 }
752 
753 #ifdef USE_SOCKET
754 
758 void mutt_account_hook(const char *url)
759 {
760  /* parsing commands with URLs in an account hook can cause a recursive
761  * call. We just skip processing if this occurs. Typically such commands
762  * belong in a folder-hook -- perhaps we should warn the user. */
763  static bool inhook = false;
764 
765  struct Hook *hook = NULL;
766  struct Buffer *err = mutt_buffer_pool_get();
767  struct Buffer *token = mutt_buffer_pool_get();
768 
769  if (inhook)
770  return;
771 
772  TAILQ_FOREACH(hook, &Hooks, entries)
773  {
774  if (!(hook->command && (hook->type & MUTT_ACCOUNT_HOOK)))
775  continue;
776 
777  if (mutt_regex_match(&hook->regex, url))
778  {
779  inhook = true;
780 
781  if (mutt_parse_rc_line(hook->command, token, err) == MUTT_CMD_ERROR)
782  {
783  mutt_buffer_pool_release(&token);
784  mutt_error("%s", mutt_b2s(err));
786 
787  inhook = false;
788  return;
789  }
790 
791  inhook = false;
792  }
793  }
794 
795  mutt_buffer_pool_release(&token);
797 }
798 #endif
799 
807 {
808  struct Hook *hook = NULL;
809  struct Buffer token;
810  struct Buffer err;
811  char buf[256];
812 
813  mutt_buffer_init(&err);
814  err.data = buf;
815  err.dsize = sizeof(buf);
816  mutt_buffer_init(&token);
817 
818  TAILQ_FOREACH(hook, &Hooks, entries)
819  {
820  if (!(hook->command && (hook->type & MUTT_TIMEOUT_HOOK)))
821  continue;
822 
823  if (mutt_parse_rc_line(hook->command, &token, &err) == MUTT_CMD_ERROR)
824  {
825  mutt_error("%s", err.data);
826  mutt_buffer_reset(&err);
827 
828  /* The hooks should be independent of each other, so even though this on
829  * failed, we'll carry on with the others. */
830  }
831  }
832  FREE(&token.data);
833 
834  /* Delete temporary attachment files */
836 }
837 
846 {
847  struct Hook *hook = NULL;
848  struct Buffer token = mutt_buffer_make(0);
849  struct Buffer err = mutt_buffer_make(0);
850  char buf[256];
851 
852  err.data = buf;
853  err.dsize = sizeof(buf);
854  mutt_buffer_init(&token);
855 
856  TAILQ_FOREACH(hook, &Hooks, entries)
857  {
858  if (!(hook->command && (hook->type & type)))
859  continue;
860 
861  if (mutt_parse_rc_line(hook->command, &token, &err) == MUTT_CMD_ERROR)
862  {
863  mutt_error("%s", err.data);
864  mutt_buffer_reset(&err);
865  }
866  }
867  FREE(&token.data);
868 }
869 
878 const char *mutt_idxfmt_hook(const char *name, struct Mailbox *m, struct Email *e)
879 {
880  if (!IdxFmtHooks)
881  return NULL;
882 
883  struct HookList *hl = mutt_hash_find(IdxFmtHooks, name);
884  if (!hl)
885  return NULL;
886 
888 
889  struct PatternCache cache = { 0 };
890  const char *fmtstring = NULL;
891  struct Hook *hook = NULL;
892 
893  TAILQ_FOREACH(hook, hl, entries)
894  {
895  struct Pattern *pat = SLIST_FIRST(hook->pattern);
896  if ((mutt_pattern_exec(pat, 0, m, e, &cache) > 0) ^ hook->regex.pat_not)
897  {
898  fmtstring = hook->command;
899  break;
900  }
901  }
902 
904 
905  return fmtstring;
906 }
#define MUTT_SEND_HOOK
send-hook: when composing a new email
Definition: hook.h:47
The "current" mailbox.
Definition: context.h:36
char * mutt_path_concat(char *d, const char *dir, const char *fname, size_t l)
Join a directory name and a filename.
Definition: path.c:330
Character set conversion.
Definition: charset.h:78
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
The envelope/body of an email.
Definition: email.h:39
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
#define TAILQ_FIRST(head)
Definition: queue.h:717
CommandResult
Error codes for command_t parse functions.
Definition: mutt_commands.h:33
#define MUTT_SHUTDOWN_HOOK
shutdown-hook: run when leaving NeoMutt
Definition: hook.h:65
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
Error: Can&#39;t help the user.
Definition: mutt_commands.h:35
Structs that make up an email.
String processing routines to generate the mail index.
The "currently-open" mailbox.
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
A Hash Table.
Definition: hash.h:61
HookFlags type
Hook type.
Definition: hook.c:67
void mutt_check_simple(struct Buffer *buf, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:2296
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:629
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
regex_t * regex
compiled expression
Definition: regex3.h:60
Compressed mbox local mailbox type.
void * mutt_hash_find(const struct Hash *table, const char *strkey)
Find the HashElem data in a Hash table element using a key.
Definition: hash.c:379
static void delete_idxfmt_hooks(void)
Delete all the index-format-hooks.
Definition: hook.c:355
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:2953
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:61
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:729
A list of user hooks.
Definition: hook.c:65
#define _(a)
Definition: message.h:28
void mutt_delete_hooks(HookFlags type)
Delete matching hooks.
Definition: hook.c:316
#define MUTT_CHARSET_HOOK
charset-hook: create a charset alias for malformed emails
Definition: hook.h:50
An email address.
Definition: address.h:34
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:728
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:52
WHERE char * C_Record
Config: Folder to save &#39;sent&#39; messages.
Definition: globals.h:136
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:479
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1189
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:662
Flags to control mutt_expando_format()
#define MUTT_CRYPT_HOOK
crypt-hook: automatically select a PGP/SMIME key
Definition: hook.h:53
Representation of a single alias to an email address.
void mutt_select_fcc(char *path, size_t pathlen, struct Email *e)
Select the FCC path for an email.
Definition: hook.c:700
A simple (non-regex) pattern.
Definition: pattern.h:49
Hundreds of global variables to back the user variables.
Email Address Handling.
char * command
Filename, command or pattern to execute.
Definition: hook.c:69
int mutt_comp_valid_command(const char *cmd)
Is this command string allowed?
Definition: compress.c:418
Some miscellaneous functions.
#define MUTT_PC_PATTERN_DYNAMIC
Enable runtime date range evaluation.
Definition: pattern.h:44
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:516
char * mutt_expand_path_regex(char *buf, size_t buflen, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:337
size_t dsize
Length of data.
Definition: buffer.h:37
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:128
#define MoreArgs(buf)
Definition: buffer.h:43
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:845
struct Mailbox * mailbox
Definition: context.h:50
Parse and execute user-defined hooks.
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
enum CommandResult mutt_parse_hook(struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err)
Parse the &#39;hook&#39; family of commands - Implements command_t.
Definition: hook.c:85
const char * name
Definition: pgpmicalg.c:45
struct Envelope * env
Envelope information.
Definition: email.h:91
LookupType
Types of character set lookups.
Definition: charset.h:75
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:52
void mutt_make_string_flags(char *buf, size_t buflen, const char *s, struct Context *ctx, struct Mailbox *m, struct Email *e, MuttFormatFlags flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1497
#define SKIPWS(ch)
Definition: string2.h:47
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:748
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
void mutt_safe_path(char *buf, size_t buflen, const struct Address *a)
Make a safe filename from an email address.
Definition: muttlib.c:825
#define TAILQ_INIT(head)
Definition: queue.h:759
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: globals.h:54
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
#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
static void delete_idxfmt_hooklist(int type, void *obj, intptr_t data)
Delete a index-format-hook from the Hash Table.
Definition: hook.c:337
#define MUTT_GLOBAL_HOOK
Hooks which don&#39;t take a regex.
Definition: hook.h:66
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:821
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
#define mutt_b2s(buf)
Definition: buffer.h:41
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: pattern.c:2002
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1386
const char * mutt_idxfmt_hook(const char *name, struct Mailbox *m, struct Email *e)
Get index-format-hook format string.
Definition: hook.c:878
#define MUTT_SAVE_HOOK
save-hook: set a default folder when saving an email
Definition: hook.h:49
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
#define SLIST_FIRST(head)
Definition: queue.h:229
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:124
void mutt_account_hook(const char *url)
Perform an account hook.
Definition: hook.c:758
A mailbox.
Definition: mailbox.h:92
#define PATH_MAX
Definition: mutt.h:52
char * mutt_find_hook(HookFlags type, const char *pat)
Find a matching hook.
Definition: hook.c:558
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:2649
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
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:81
char * data
Pointer to data.
Definition: buffer.h:35
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
struct Hash * mutt_hash_new(size_t nelem, HashFlags flags)
Create a new Hash table (with string keys)
Definition: hash.c:276
Mapping from user command name to function.
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1334
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:803
enum CommandResult mutt_parse_unhook(struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err)
Parse the &#39;unhook&#39; command - Implements command_t.
Definition: hook.c:465
Handling of email attachments.
API for encryption/signing of emails.
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:612
#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
void mutt_ch_lookup_remove(void)
Remove all the character set lookups.
Definition: charset.c:511
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
enum CommandResult mutt_parse_idxfmt_hook(struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err)
Parse the &#39;index-format-hook&#39; command - Implements command_t.
Definition: hook.c:363
#define MUTT_TIMEOUT_HOOK
timeout-hook: run a command periodically
Definition: hook.h:63
#define TAILQ_ENTRY(type)
Definition: queue.h:634
Success: Command worked.
Definition: mutt_commands.h:37
#define MUTT_PC_NO_FLAGS
No flags are set.
Definition: pattern.h:42
Warning: Help given to the user.
Definition: mutt_commands.h:36
#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_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
Cached regular expression.
Definition: regex3.h:57
#define mutt_error(...)
Definition: logging.h:84
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:610
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:806
#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:683
#define MUTT_PC_FULL_MSG
Enable body and header matching.
Definition: pattern.h:43
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition: mx.c:170
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
void mutt_hash_set_destructor(struct Hash *table, hashelem_free_t fn, intptr_t fn_data)
Set the destructor for a Hash Table.
Definition: hash.c:318
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:579
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:297
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
char * pattern
printable version
Definition: regex3.h:59
Cache commonly-used patterns.
Definition: pattern.h:85
#define MUTT_HASH_STRDUP_KEYS
make a copy of the keys
Definition: hash.h:76
void mutt_hash_free(struct Hash **ptr)
free_hdata a hash table
Definition: hash.c:472
struct HashElem * mutt_hash_insert(struct Hash *table, const char *strkey, void *data)
Add a new element to the Hash table (with string keys)
Definition: hash.c:352
Match patterns to emails.
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:631
#define WithCrypto
Definition: ncrypt.h:160
Convenience wrapper for the library headers.
#define MUTT_STARTUP_HOOK
startup-hook: run when starting NeoMutt
Definition: hook.h:64
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
Alias for another character set.
Definition: charset.h:77
#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
enum CommandResult mutt_parse_rc_line(char *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:3224
#define MUTT_ACCOUNT_HOOK
account-hook: when changing between accounts
Definition: hook.h:54
The header of an Email.
Definition: envelope.h:54
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:78
#define MUTT_FOLDER_HOOK
folder-hook: when entering a mailbox
Definition: hook.h:45