NeoMutt  2019-12-07-60-g0cfa53
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  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_COMPRESSED
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_strcmp(hook->command, mutt_b2s(cmd)) == 0)
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_strcmp(mutt_b2s(pattern), hook->regex.pattern) == 0))
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_strcmp(hook->command, mutt_b2s(cmd)) == 0)
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  pat = mutt_pattern_comp(mutt_b2s(pattern),
245  err);
246  if (!pat)
247  goto cleanup;
248  }
249  else if (~data & MUTT_GLOBAL_HOOK) /* NOT a global hook */
250  {
251  /* Hooks not allowing full patterns: Check syntax of regex */
252  rx = mutt_mem_malloc(sizeof(regex_t));
253  int rc2 = REG_COMP(rx, NONULL(mutt_b2s(pattern)),
254  ((data & MUTT_CRYPT_HOOK) ? REG_ICASE : 0));
255  if (rc2 != 0)
256  {
257  regerror(rc2, rx, err->data, err->dsize);
258  FREE(&rx);
259  goto cleanup;
260  }
261  }
262 
263  hook = mutt_mem_calloc(1, sizeof(struct Hook));
264  hook->type = data;
265  hook->command = mutt_buffer_strdup(cmd);
266  hook->pattern = pat;
267  hook->regex.pattern = mutt_buffer_strdup(pattern);
268  hook->regex.regex = rx;
269  hook->regex.pat_not = pat_not;
270  TAILQ_INSERT_TAIL(&Hooks, hook, entries);
271  rc = MUTT_CMD_SUCCESS;
272 
273 cleanup:
275  mutt_buffer_pool_release(&pattern);
276  return rc;
277 }
278 
283 static void delete_hook(struct Hook *h)
284 {
285  FREE(&h->command);
286  FREE(&h->regex.pattern);
287  if (h->regex.regex)
288  {
289  regfree(h->regex.regex);
290  FREE(&h->regex.regex);
291  }
293  FREE(&h);
294 }
295 
303 {
304  struct Hook *h = NULL;
305  struct Hook *tmp = NULL;
306 
307  TAILQ_FOREACH_SAFE(h, &Hooks, entries, tmp)
308  {
309  if ((type == MUTT_HOOK_NO_FLAGS) || (type == h->type))
310  {
311  TAILQ_REMOVE(&Hooks, h, entries);
312  delete_hook(h);
313  }
314  }
315 }
316 
323 static void delete_idxfmt_hooklist(int type, void *obj, intptr_t data)
324 {
325  struct HookList *hl = obj;
326  struct Hook *h = NULL;
327  struct Hook *tmp = NULL;
328 
329  TAILQ_FOREACH_SAFE(h, hl, entries, tmp)
330  {
331  TAILQ_REMOVE(hl, h, entries);
332  delete_hook(h);
333  }
334 
335  FREE(&hl);
336 }
337 
341 static void delete_idxfmt_hooks(void)
342 {
343  mutt_hash_free(&IdxFmtHooks);
344 }
345 
349 enum CommandResult mutt_parse_idxfmt_hook(struct Buffer *buf, struct Buffer *s,
350  unsigned long data, struct Buffer *err)
351 {
352  enum CommandResult rc = MUTT_CMD_ERROR;
353  bool pat_not = false;
354 
355  struct Buffer *name = mutt_buffer_pool_get();
356  struct Buffer *pattern = mutt_buffer_pool_get();
357  struct Buffer *fmtstring = mutt_buffer_pool_get();
358 
359  if (!IdxFmtHooks)
360  {
361  IdxFmtHooks = mutt_hash_new(30, MUTT_HASH_STRDUP_KEYS);
363  }
364 
365  if (!MoreArgs(s))
366  {
367  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
368  goto out;
369  }
371  struct HookList *hl = mutt_hash_find(IdxFmtHooks, mutt_b2s(name));
372 
373  if (*s->dptr == '!')
374  {
375  s->dptr++;
376  SKIPWS(s->dptr);
377  pat_not = true;
378  }
380 
381  if (!MoreArgs(s))
382  {
383  mutt_buffer_printf(err, _("%s: too few arguments"), buf->data);
384  goto out;
385  }
387 
388  if (MoreArgs(s))
389  {
390  mutt_buffer_printf(err, _("%s: too many arguments"), buf->data);
391  goto out;
392  }
393 
394  if (C_DefaultHook)
396 
397  /* check to make sure that a matching hook doesn't already exist */
398  struct Hook *hook = NULL;
399  if (hl)
400  {
401  TAILQ_FOREACH(hook, hl, entries)
402  {
403  if ((hook->regex.pat_not == pat_not) &&
404  (mutt_str_strcmp(mutt_b2s(pattern), hook->regex.pattern) == 0))
405  {
406  mutt_str_replace(&hook->command, mutt_b2s(fmtstring));
407  rc = MUTT_CMD_SUCCESS;
408  goto out;
409  }
410  }
411  }
412 
413  /* MUTT_PC_PATTERN_DYNAMIC sets so that date ranges are regenerated during
414  * matching. This of course is slower, but index-format-hook is commonly
415  * used for date ranges, and they need to be evaluated relative to "now", not
416  * the hook compilation time. */
417  struct PatternList *pat = mutt_pattern_comp(
419  if (!pat)
420  goto out;
421 
422  hook = mutt_mem_calloc(1, sizeof(struct Hook));
423  hook->type = data;
424  hook->command = mutt_buffer_strdup(fmtstring);
425  hook->pattern = pat;
426  hook->regex.pattern = mutt_buffer_strdup(pattern);
427  hook->regex.regex = NULL;
428  hook->regex.pat_not = pat_not;
429 
430  if (!hl)
431  {
432  hl = mutt_mem_calloc(1, sizeof(*hl));
433  TAILQ_INIT(hl);
434  mutt_hash_insert(IdxFmtHooks, mutt_b2s(name), hl);
435  }
436 
437  TAILQ_INSERT_TAIL(hl, hook, entries);
438  rc = MUTT_CMD_SUCCESS;
439 
440 out:
442  mutt_buffer_pool_release(&pattern);
443  mutt_buffer_pool_release(&fmtstring);
444 
445  return rc;
446 }
447 
451 enum CommandResult mutt_parse_unhook(struct Buffer *buf, struct Buffer *s,
452  unsigned long data, struct Buffer *err)
453 {
454  while (MoreArgs(s))
455  {
457  if (mutt_str_strcmp("*", buf->data) == 0)
458  {
460  {
461  mutt_buffer_printf(err, "%s", _("unhook: Can't do unhook * from within a hook"));
462  return MUTT_CMD_WARNING;
463  }
467  }
468  else
469  {
471 
472  if (type == MUTT_HOOK_NO_FLAGS)
473  {
474  mutt_buffer_printf(err, _("unhook: unknown hook type: %s"), buf->data);
475  return MUTT_CMD_ERROR;
476  }
477  if (type & (MUTT_CHARSET_HOOK | MUTT_ICONV_HOOK))
478  {
480  return MUTT_CMD_SUCCESS;
481  }
482  if (current_hook_type == type)
483  {
484  mutt_buffer_printf(err, _("unhook: Can't delete a %s from within a %s"),
485  buf->data, buf->data);
486  return MUTT_CMD_WARNING;
487  }
488  if (type == MUTT_IDXFMTHOOK)
490  else
491  mutt_delete_hooks(type);
492  }
493  }
494  return MUTT_CMD_SUCCESS;
495 }
496 
502 void mutt_folder_hook(const char *path, const char *desc)
503 {
504  if (!path && !desc)
505  return;
506 
507  struct Hook *hook = NULL;
508  struct Buffer *err = mutt_buffer_pool_get();
509  struct Buffer *token = mutt_buffer_pool_get();
510 
512 
513  TAILQ_FOREACH(hook, &Hooks, entries)
514  {
515  if (!hook->command)
516  continue;
517 
518  if (!(hook->type & MUTT_FOLDER_HOOK))
519  continue;
520 
521  const char *match = NULL;
522  if (mutt_regex_match(&hook->regex, path))
523  match = path;
524  else if (mutt_regex_match(&hook->regex, desc))
525  match = desc;
526 
527  if (match)
528  {
529  mutt_debug(LL_DEBUG1, "folder-hook '%s' matches '%s'\n", hook->regex.pattern, match);
530  mutt_debug(LL_DEBUG5, " %s\n", hook->command);
531  if (mutt_parse_rc_line(hook->command, token, err) == MUTT_CMD_ERROR)
532  {
533  mutt_error("%s", mutt_b2s(err));
534  break;
535  }
536  }
537  }
538  mutt_buffer_pool_release(&token);
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  struct Buffer *token = mutt_buffer_pool_get();
579 
581 
582  TAILQ_FOREACH(hook, &Hooks, entries)
583  {
584  if (!hook->command)
585  continue;
586 
587  if (hook->type & type)
588  {
589  if ((mutt_pattern_exec(SLIST_FIRST(hook->pattern), 0, m, e, &cache) > 0) ^
590  hook->regex.pat_not)
591  {
592  if (mutt_parse_rc_line(hook->command, token, err) == MUTT_CMD_ERROR)
593  {
594  mutt_buffer_pool_release(&token);
595  mutt_error("%s", mutt_b2s(err));
598 
599  return;
600  }
601  /* Executing arbitrary commands could affect the pattern results,
602  * so the cache has to be wiped */
603  memset(&cache, 0, sizeof(cache));
604  }
605  }
606  }
607  mutt_buffer_pool_release(&token);
609 
611 }
612 
623 static int addr_hook(char *path, size_t pathlen, HookFlags type,
624  struct Context *ctx, struct Email *e)
625 {
626  struct Hook *hook = NULL;
627  struct PatternCache cache = { 0 };
628 
629  /* determine if a matching hook exists */
630  TAILQ_FOREACH(hook, &Hooks, entries)
631  {
632  if (!hook->command)
633  continue;
634 
635  if (hook->type & type)
636  {
637  struct Mailbox *m = ctx ? ctx->mailbox : NULL;
638  if ((mutt_pattern_exec(SLIST_FIRST(hook->pattern), 0, m, e, &cache) > 0) ^
639  hook->regex.pat_not)
640  {
641  mutt_make_string_flags(path, pathlen, 0, hook->command, ctx, m, e, MUTT_FORMAT_PLAIN);
642  return 0;
643  }
644  }
645  }
646 
647  return -1;
648 }
649 
656 void mutt_default_save(char *path, size_t pathlen, struct Email *e)
657 {
658  *path = '\0';
659  if (addr_hook(path, pathlen, MUTT_SAVE_HOOK, Context, e) == 0)
660  return;
661 
662  struct Envelope *env = e->env;
663  const struct Address *from = TAILQ_FIRST(&env->from);
664  const struct Address *reply_to = TAILQ_FIRST(&env->reply_to);
665  const struct Address *to = TAILQ_FIRST(&env->to);
666  const struct Address *cc = TAILQ_FIRST(&env->cc);
667  const struct Address *addr = NULL;
668  bool from_me = mutt_addr_is_user(from);
669 
670  if (!from_me && reply_to && reply_to->mailbox)
671  addr = reply_to;
672  else if (!from_me && from && from->mailbox)
673  addr = from;
674  else if (to && to->mailbox)
675  addr = to;
676  else if (cc && cc->mailbox)
677  addr = cc;
678  else
679  addr = NULL;
680  if (addr)
681  {
682  struct Buffer *tmp = mutt_buffer_pool_get();
683  mutt_safe_path(tmp, addr);
684  snprintf(path, pathlen, "=%s", mutt_b2s(tmp));
686  }
687 }
688 
694 void mutt_select_fcc(struct Buffer *path, struct Email *e)
695 {
697 
698  if (addr_hook(path->data, path->dsize, MUTT_FCC_HOOK, NULL, e) != 0)
699  {
700  const struct Address *to = TAILQ_FIRST(&e->env->to);
701  const struct Address *cc = TAILQ_FIRST(&e->env->cc);
702  const struct Address *bcc = TAILQ_FIRST(&e->env->bcc);
703  if ((C_SaveName || C_ForceName) && (to || cc || bcc))
704  {
705  const struct Address *addr = to ? to : (cc ? cc : bcc);
706  struct Buffer *buf = mutt_buffer_pool_get();
707  mutt_safe_path(buf, addr);
710  if (!C_ForceName && (mx_access(mutt_b2s(path), W_OK) != 0))
712  }
713  else
715  }
716  else
717  mutt_buffer_fix_dptr(path);
718 
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  if (inhook)
765  return;
766 
767  struct Hook *hook = NULL;
768  struct Buffer *err = mutt_buffer_pool_get();
769  struct Buffer *token = mutt_buffer_pool_get();
770 
771  TAILQ_FOREACH(hook, &Hooks, entries)
772  {
773  if (!(hook->command && (hook->type & MUTT_ACCOUNT_HOOK)))
774  continue;
775 
776  if (mutt_regex_match(&hook->regex, url))
777  {
778  inhook = true;
779  mutt_debug(LL_DEBUG1, "account-hook '%s' matches '%s'\n", hook->regex.pattern, url);
780  mutt_debug(LL_DEBUG5, " %s\n", hook->command);
781 
782  if (mutt_parse_rc_line(hook->command, token, err) == MUTT_CMD_ERROR)
783  {
784  mutt_buffer_pool_release(&token);
785  mutt_error("%s", mutt_b2s(err));
787 
788  inhook = false;
789  goto done;
790  }
791 
792  inhook = false;
793  }
794  }
795 done:
796  mutt_buffer_pool_release(&token);
798 }
799 #endif
800 
808 {
809  struct Hook *hook = NULL;
810  struct Buffer token;
811  struct Buffer err;
812  char buf[256];
813 
814  mutt_buffer_init(&err);
815  err.data = buf;
816  err.dsize = sizeof(buf);
817  mutt_buffer_init(&token);
818 
819  TAILQ_FOREACH(hook, &Hooks, entries)
820  {
821  if (!(hook->command && (hook->type & MUTT_TIMEOUT_HOOK)))
822  continue;
823 
824  if (mutt_parse_rc_line(hook->command, &token, &err) == MUTT_CMD_ERROR)
825  {
826  mutt_error("%s", err.data);
827  mutt_buffer_reset(&err);
828 
829  /* The hooks should be independent of each other, so even though this on
830  * failed, we'll carry on with the others. */
831  }
832  }
833  FREE(&token.data);
834 
835  /* Delete temporary attachment files */
837 }
838 
847 {
848  struct Hook *hook = NULL;
849  struct Buffer token = mutt_buffer_make(0);
850  struct Buffer err = mutt_buffer_make(0);
851  char buf[256];
852 
853  err.data = buf;
854  err.dsize = sizeof(buf);
855  mutt_buffer_init(&token);
856 
857  TAILQ_FOREACH(hook, &Hooks, entries)
858  {
859  if (!(hook->command && (hook->type & type)))
860  continue;
861 
862  if (mutt_parse_rc_line(hook->command, &token, &err) == MUTT_CMD_ERROR)
863  {
864  mutt_error("%s", err.data);
865  mutt_buffer_reset(&err);
866  }
867  }
868  FREE(&token.data);
869 }
870 
879 const char *mutt_idxfmt_hook(const char *name, struct Mailbox *m, struct Email *e)
880 {
881  if (!IdxFmtHooks)
882  return NULL;
883 
884  struct HookList *hl = mutt_hash_find(IdxFmtHooks, name);
885  if (!hl)
886  return NULL;
887 
889 
890  struct PatternCache cache = { 0 };
891  const char *fmtstring = NULL;
892  struct Hook *hook = NULL;
893 
894  TAILQ_FOREACH(hook, hl, entries)
895  {
896  struct Pattern *pat = SLIST_FIRST(hook->pattern);
897  if ((mutt_pattern_exec(pat, 0, m, e, &cache) > 0) ^ hook->regex.pat_not)
898  {
899  fmtstring = hook->command;
900  break;
901  }
902  }
903 
905 
906  return fmtstring;
907 }
#define MUTT_SEND_HOOK
send-hook: when composing a new email
Definition: hook.h:47
The "current" mailbox.
Definition: context.h:36
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:37
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:33
#define MUTT_SHUTDOWN_HOOK
shutdown-hook: run when leaving NeoMutt
Definition: hook.h:65
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
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.
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
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:2301
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:623
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: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:378
static void delete_idxfmt_hooks(void)
Delete all the index-format-hooks.
Definition: hook.c:341
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
char * mutt_buffer_strdup(struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
HookFlags mutt_get_hook_type(const char *name)
Find a hook by name.
Definition: init.c:2976
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:728
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:302
#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:131
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:1196
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:656
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:703
#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.
A simple (non-regex) pattern.
Definition: pattern.h:49
Hundreds of global variables to back the user variables.
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:145
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:388
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:502
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:846
struct Mailbox * mailbox
Definition: context.h:50
Parse and execute user-defined hooks.
API for mailboxes.
void mutt_make_string_flags(char *buf, size_t buflen, int cols, const char *s, struct Context *ctx, struct Mailbox *m, struct Email *e, MuttFormatFlags flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1505
#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:46
struct Envelope * env
Envelope information.
Definition: email.h:89
LookupType
Types of character set lookups.
Definition: charset.h:75
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:52
#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
#define TAILQ_INIT(head)
Definition: queue.h:758
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
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.
Definition: hook.c:323
#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:858
#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: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:2008
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1399
const char * mutt_idxfmt_hook(const char *name, struct Mailbox *m, struct Email *e)
Get index-format-hook format string.
Definition: hook.c:879
#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
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:119
void mutt_account_hook(const char *url)
Perform an account hook.
Definition: hook.c:758
A mailbox.
Definition: mailbox.h:80
#define PATH_MAX
Definition: mutt.h:50
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:2674
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:694
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:79
char * data
Pointer to data.
Definition: buffer.h:35
struct Hash * mutt_hash_new(size_t nelem, HashFlags flags)
Create a new Hash table (with string keys)
Definition: hash.c:275
Mapping from user command name to function.
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1347
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:802
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:451
Handling of email attachments.
API for encryption/signing of emails.
#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:349
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
#define MUTT_TIMEOUT_HOOK
timeout-hook: run a command periodically
Definition: hook.h:63
#define TAILQ_ENTRY(type)
Definition: queue.h:633
Success: Command worked.
Definition: mutt_commands.h:37
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:342
#define MUTT_PC_NO_FLAGS
No flags are set.
Definition: pattern.h:42
Log at debug level 1.
Definition: logging.h:40
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:807
#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:682
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
#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:169
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
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
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:317
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:283
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
Log at debug level 5.
Definition: logging.h:44
void mutt_hash_free(struct Hash **ptr)
Free a hash table.
Definition: hash.c:471
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:351
Match patterns to emails.
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
#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:3252
#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:76
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