NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
exec.h File Reference

Execute user-defined Hooks. More...

#include "core/lib.h"
#include "hook.h"
+ Include dependency graph for exec.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void exec_account_hook (const char *url)
 Perform an account hook.
 
void exec_folder_hook (const char *path, const char *desc)
 Perform a folder hook.
 
void exec_message_hook (struct Mailbox *m, struct Email *e, enum CommandId id)
 Perform a message hook.
 
void exec_startup_shutdown_hook (enum CommandId id)
 Execute any startup/shutdown hooks.
 
void exec_timeout_hook (void)
 Execute any timeout hooks.
 
void mutt_crypt_hook (struct ListHead *list, struct Address *addr)
 Find crypto hooks for an Address.
 
void mutt_default_save (struct Buffer *path, struct Email *e)
 Find the default save path for an email.
 
void mutt_delete_hooks (struct HookList *hooks, enum CommandId id)
 Delete matching hooks.
 
char * mutt_find_hook (enum CommandId id, const char *pat)
 Find a matching hook.
 
const struct Expandomutt_idxfmt_hook (const char *name, struct Mailbox *m, struct Email *e)
 Get index-format-hook format string.
 
void mutt_select_fcc (struct Buffer *path, struct Email *e)
 Select the FCC path for an email.
 

Detailed Description

Execute user-defined Hooks.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file exec.h.

Function Documentation

◆ exec_account_hook()

void exec_account_hook ( const char * url)

Perform an account hook.

Parameters
urlAccount URL to match

Definition at line 328 of file exec.c.

329{
330 /* parsing commands with URLs in an account hook can cause a recursive
331 * call. We just skip processing if this occurs. Typically such commands
332 * belong in a folder-hook -- perhaps we should warn the user. */
333 static bool inhook = false;
334 if (inhook)
335 return;
336
338 struct Hook *hook = NULL;
339 struct ParseContext *pc = parse_context_new();
340 struct ParseError *pe = parse_error_new();
341
343
344 TAILQ_FOREACH(hook, &mod_data->hooks, entries)
345 {
346 if (!(hook->command && (hook->id == CMD_ACCOUNT_HOOK)))
347 continue;
348
349 if (mutt_regex_match(&hook->regex, url))
350 {
351 inhook = true;
352 mutt_debug(LL_DEBUG1, "account-hook '%s' matches '%s'\n", hook->regex.pattern, url);
353 mutt_debug(LL_DEBUG5, " %s\n", hook->command);
354
355 if (parse_rc_line_cwd(hook->command, hook->source_file, pc, pe) == MUTT_CMD_ERROR)
356 {
357 mutt_error("%s", buf_string(pe->message));
358 inhook = false;
359 goto done;
360 }
361
362 inhook = false;
363 }
364 }
365
366done:
367 mod_data->current_hook_id = CMD_NONE;
369 parse_error_free(&pe);
370}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
@ CMD_NONE
No Command.
Definition command.h:62
@ CMD_ACCOUNT_HOOK
:account-hook
Definition command.h:63
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition command.h:38
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:49
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
@ MODULE_ID_HOOKS
ModuleHooks, Hook Commands
Definition module_api.h:70
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition regex.c:614
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:663
void parse_context_free(struct ParseContext **pptr)
Free a ParseContext.
Definition pcontext.c:48
struct ParseContext * parse_context_new(void)
Create a new ParseContext.
Definition pcontext.c:37
void parse_error_free(struct ParseError **pptr)
Free a ParseError.
Definition perror.c:50
struct ParseError * parse_error_new(void)
Create a new ParseError.
Definition perror.c:37
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
enum CommandResult parse_rc_line_cwd(const char *line, char *cwd, struct ParseContext *pc, struct ParseError *pe)
Parse and run a muttrc line in a relative directory.
Definition source.c:287
A list of user hooks.
Definition hook.h:33
struct Regex regex
Regular expression.
Definition hook.h:35
char * command
Filename, command or pattern to execute.
Definition hook.h:36
enum CommandId id
Hook CommandId, e.g. CMD_FOLDER_HOOK.
Definition hook.h:34
char * source_file
Used for relative-directory source.
Definition hook.h:37
Hooks private Module data.
Definition module_data.h:33
struct HookList hooks
All simple hooks, e.g. CMD_FOLDER_HOOK.
Definition module_data.h:35
int current_hook_id
The ID of the Hook currently being executed.
Definition module_data.h:37
Container for Accounts, Notifications.
Definition neomutt.h:41
Context for config parsing (history/backtrace)
Definition pcontext.h:34
Detailed error information from config parsing.
Definition perror.h:34
struct Buffer * message
Error message.
Definition perror.h:35
char * pattern
printable version
Definition regex3.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ exec_folder_hook()

void exec_folder_hook ( const char * path,
const char * desc )

Perform a folder hook.

Parameters
pathPath to potentially match
descDescription to potentially match

Definition at line 64 of file exec.c.

65{
66 if (!path && !desc)
67 return;
68
70 struct Hook *hook = NULL;
71 struct ParseContext *pc = parse_context_new();
72 struct ParseError *pe = parse_error_new();
73
75
76 TAILQ_FOREACH(hook, &mod_data->hooks, entries)
77 {
78 if (!hook->command)
79 continue;
80
81 if (!(hook->id == CMD_FOLDER_HOOK))
82 continue;
83
84 const char *match = NULL;
85 if (mutt_regex_match(&hook->regex, path))
86 match = path;
87 else if (mutt_regex_match(&hook->regex, desc))
88 match = desc;
89
90 if (match)
91 {
92 mutt_debug(LL_DEBUG1, "folder-hook '%s' matches '%s'\n", hook->regex.pattern, match);
93 mutt_debug(LL_DEBUG5, " %s\n", hook->command);
94 if (parse_rc_line_cwd(hook->command, hook->source_file, pc, pe) == MUTT_CMD_ERROR)
95 {
96 mutt_error("%s", buf_string(pe->message));
97 break;
98 }
99 }
100 }
101
102 mod_data->current_hook_id = CMD_NONE;
104 parse_error_free(&pe);
105}
@ CMD_FOLDER_HOOK
:folder-hook
Definition command.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ exec_message_hook()

void exec_message_hook ( struct Mailbox * m,
struct Email * e,
enum CommandId id )

Perform a message hook.

Parameters
mMailbox
eEmail
idHook CommandId, e.g CMD_FOLDER_HOOK

Definition at line 137 of file exec.c.

138{
140 struct Hook *hook = NULL;
141 struct PatternCache cache = { 0 };
142 struct ParseContext *pc = parse_context_new();
143 struct ParseError *pe = parse_error_new();
144
145 mod_data->current_hook_id = id;
146
147 TAILQ_FOREACH(hook, &mod_data->hooks, entries)
148 {
149 if (!hook->command)
150 continue;
151
152 if (hook->id == id)
153 {
154 if ((mutt_pattern_exec(SLIST_FIRST(hook->pattern), 0, m, e, &cache) > 0) ^
155 hook->regex.pat_not)
156 {
157 if (parse_rc_line_cwd(hook->command, hook->source_file, pc, pe) == MUTT_CMD_ERROR)
158 {
159 mutt_error("%s", buf_string(pe->message));
160 goto done;
161 }
162 /* Executing arbitrary commands could affect the pattern results,
163 * so the cache has to be wiped */
164 memset(&cache, 0, sizeof(cache));
165 }
166 }
167 }
168
169done:
170 mod_data->current_hook_id = CMD_NONE;
172 parse_error_free(&pe);
173}
bool mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition exec.c:1151
#define SLIST_FIRST(head)
Definition queue.h:227
struct PatternList * pattern
Used for fcc,save,send-hook.
Definition hook.h:38
Cache commonly-used patterns.
Definition lib.h:130
bool pat_not
do not match
Definition regex3.h:88
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ exec_startup_shutdown_hook()

void exec_startup_shutdown_hook ( enum CommandId id)

Execute any startup/shutdown hooks.

Parameters
idHook CommandId: CMD_STARTUP_HOOK or CMD_SHUTDOWN_HOOK

The user can configure hooks to be run on startup/shutdown. This function finds all the matching hooks and executes them.

Definition at line 418 of file exec.c.

419{
421 struct Hook *hook = NULL;
422 struct ParseContext *pc = parse_context_new();
423 struct ParseError *pe = parse_error_new();
424
425 mod_data->current_hook_id = id;
426
427 TAILQ_FOREACH(hook, &mod_data->hooks, entries)
428 {
429 if (!(hook->command && (hook->id == id)))
430 continue;
431
432 if (parse_rc_line_cwd(hook->command, hook->source_file, pc, pe) == MUTT_CMD_ERROR)
433 {
434 mutt_error("%s", buf_string(pe->message));
436 }
437 }
438
439 mod_data->current_hook_id = CMD_NONE;
441 parse_error_free(&pe);
442}
void parse_error_reset(struct ParseError *pe)
Clear the contents of a ParseError.
Definition perror.c:66
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ exec_timeout_hook()

void exec_timeout_hook ( void )

Execute any timeout hooks.

The user can configure hooks to be run on timeout. This function finds all the matching hooks and executes them.

Definition at line 378 of file exec.c.

379{
381 struct Hook *hook = NULL;
382 struct ParseContext *pc = parse_context_new();
383 struct ParseError *pe = parse_error_new();
384
386
387 TAILQ_FOREACH(hook, &mod_data->hooks, entries)
388 {
389 if (!(hook->command && (hook->id == CMD_TIMEOUT_HOOK)))
390 continue;
391
392 if (parse_rc_line_cwd(hook->command, hook->source_file, pc, pe) == MUTT_CMD_ERROR)
393 {
394 mutt_error("%s", buf_string(pe->message));
396
397 /* The hooks should be independent of each other, so even though this one
398 * failed, we'll carry on with the others. */
399 }
400 }
401
402 /* Delete temporary attachment files */
405
406 mod_data->current_hook_id = CMD_NONE;
408 parse_error_free(&pe);
409}
@ CMD_TIMEOUT_HOOK
:timeout-hook
Definition command.h:124
@ MODULE_ID_ATTACH
ModuleAttach, Attachments
Definition module_api.h:49
void mutt_temp_attachments_cleanup(struct ListHead *list)
Delete all temporary attachments.
Attach private Module data.
Definition module_data.h:32
struct ListHead temp_attachments
List of temporary files for displaying attachments.
Definition module_data.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_crypt_hook()

void mutt_crypt_hook ( struct ListHead * list,
struct Address * addr )

Find crypto hooks for an Address.

Parameters
[out]listList of keys
[in]addrAddress to match

The crypt-hook associates keys with addresses.

Definition at line 319 of file exec.c.

320{
322}
@ CMD_CRYPT_HOOK
:crypt-hook
Definition command.h:75
static void list_hook(struct ListHead *matches, const char *match, enum CommandId id)
Find hook strings matching.
Definition exec.c:298
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_default_save()

void mutt_default_save ( struct Buffer * path,
struct Email * e )

Find the default save path for an email.

Parameters
pathBuffer for the path
eEmail

Definition at line 218 of file exec.c.

219{
220 struct Mailbox *m_cur = get_current_mailbox();
221 if (addr_hook(path, CMD_SAVE_HOOK, m_cur, e) == 0)
222 return;
223
224 struct Envelope *env = e->env;
225 const struct Address *from = TAILQ_FIRST(&env->from);
226 const struct Address *reply_to = TAILQ_FIRST(&env->reply_to);
227 const struct Address *to = TAILQ_FIRST(&env->to);
228 const struct Address *cc = TAILQ_FIRST(&env->cc);
229 const struct Address *addr = NULL;
230 bool from_me = mutt_addr_is_user(from);
231
232 if (!from_me && reply_to && reply_to->mailbox)
233 addr = reply_to;
234 else if (!from_me && from && from->mailbox)
235 addr = from;
236 else if (to && to->mailbox)
237 addr = to;
238 else if (cc && cc->mailbox)
239 addr = cc;
240 else
241 addr = NULL;
242 if (addr)
243 {
244 struct Buffer *tmp = buf_pool_get();
245 generate_save_path(tmp, addr);
246 buf_add_printf(path, "=%s", buf_string(tmp));
247 buf_pool_release(&tmp);
248 }
249}
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition alias.c:600
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:204
@ CMD_SAVE_HOOK
:save-hook
Definition command.h:107
static int addr_hook(struct Buffer *path, enum CommandId id, struct Mailbox *m, struct Email *e)
Perform an address hook (get a path)
Definition exec.c:184
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition index.c:726
void generate_save_path(struct Buffer *dest, const struct Address *a)
Make a safe filename from an email address.
Definition muttlib.c:608
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define TAILQ_FIRST(head)
Definition queue.h:780
An email address.
Definition address.h:35
String manipulation buffer.
Definition buffer.h:36
struct Envelope * env
Envelope information.
Definition email.h:68
The header of an Email.
Definition envelope.h:57
struct AddressList to
Email's 'To' list.
Definition envelope.h:60
struct AddressList reply_to
Email's 'reply-to'.
Definition envelope.h:64
struct AddressList cc
Email's 'Cc' list.
Definition envelope.h:61
struct AddressList from
Email's 'From' list.
Definition envelope.h:59
A mailbox.
Definition mailbox.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_delete_hooks()

void mutt_delete_hooks ( struct HookList * hooks,
enum CommandId id )

Delete matching hooks.

Parameters
hooksHook list to modify
idHook CommandId to delete, e.g. CMD_SEND_HOOK

If CMD_NONE is passed, all the hooks will be deleted.

Definition at line 1020 of file parse.c.

1021{
1022 struct Hook *h = NULL;
1023 struct Hook *tmp = NULL;
1024
1025 TAILQ_FOREACH_SAFE(h, hooks, entries, tmp)
1026 {
1027 if ((id == CMD_NONE) || (id == h->id))
1028 {
1029 TAILQ_REMOVE(hooks, h, entries);
1030 hook_free(&h);
1031 }
1032 }
1033}
void hook_free(struct Hook **ptr)
Free a Hook.
Definition hook.c:47
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition queue.h:792
#define TAILQ_REMOVE(head, elm, field)
Definition queue.h:901
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_find_hook()

char * mutt_find_hook ( enum CommandId id,
const char * pat )

Find a matching hook.

Parameters
idHook CommandId, e.g CMD_FOLDER_HOOK
patPattern to match
Return values
ptrCommand string
Note
The returned string must not be freed.

Definition at line 115 of file exec.c.

116{
118 struct Hook *hook = NULL;
119
120 TAILQ_FOREACH(hook, &mod_data->hooks, entries)
121 {
122 if (hook->id == id)
123 {
124 if (mutt_regex_match(&hook->regex, pat))
125 return hook->command;
126 }
127 }
128 return NULL;
129}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_idxfmt_hook()

const struct Expando * mutt_idxfmt_hook ( const char * name,
struct Mailbox * m,
struct Email * e )

Get index-format-hook format string.

Parameters
nameHook name
mMailbox
eEmail
Return values
ptrExpando
NULLNo matching hook

Definition at line 452 of file exec.c.

453{
455 if (!mod_data->idx_fmt_hooks)
456 return NULL;
457
458 struct HookList *hl = mutt_hash_find(mod_data->idx_fmt_hooks, name);
459 if (!hl)
460 return NULL;
461
462 struct PatternCache cache = { 0 };
463 const struct Expando *exp = NULL;
464 struct Hook *hook = NULL;
465
466 TAILQ_FOREACH(hook, hl, entries)
467 {
468 struct Pattern *pat = SLIST_FIRST(hook->pattern);
469 if ((mutt_pattern_exec(pat, 0, m, e, &cache) > 0) ^ hook->regex.pat_not)
470 {
471 exp = hook->expando;
472 break;
473 }
474 }
475
476 return exp;
477}
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:364
Parsed Expando trees.
Definition expando.h:41
struct Expando * expando
Used for format hooks.
Definition hook.h:39
struct HashTable * idx_fmt_hooks
All Index Format hooks.
Definition module_data.h:36
A simple (non-regex) pattern.
Definition lib.h:84
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_select_fcc()

void mutt_select_fcc ( struct Buffer * path,
struct Email * e )

Select the FCC path for an email.

Parameters
pathBuffer for the path
eEmail

Definition at line 256 of file exec.c.

257{
258 buf_alloc(path, PATH_MAX);
259
260 if (addr_hook(path, CMD_FCC_HOOK, NULL, e) != 0)
261 {
262 const struct Address *to = TAILQ_FIRST(&e->env->to);
263 const struct Address *cc = TAILQ_FIRST(&e->env->cc);
264 const struct Address *bcc = TAILQ_FIRST(&e->env->bcc);
265 const bool c_save_name = cs_subset_bool(NeoMutt->sub, "save_name");
266 const bool c_force_name = cs_subset_bool(NeoMutt->sub, "force_name");
267 const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
268 if ((c_save_name || c_force_name) && (to || cc || bcc))
269 {
270 const struct Address *addr = to ? to : (cc ? cc : bcc);
271 struct Buffer *buf = buf_pool_get();
272 generate_save_path(buf, addr);
273 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
274 buf_concat_path(path, NONULL(c_folder), buf_string(buf));
275 buf_pool_release(&buf);
276 if (!c_force_name && (mx_access(buf_string(path), W_OK) != 0))
277 buf_strcpy(path, c_record);
278 }
279 else
280 {
281 buf_strcpy(path, c_record);
282 }
283 }
284 else
285 {
286 buf_fix_dptr(path);
287 }
288
289 pretty_mailbox(path);
290}
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition buffer.c:182
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition buffer.c:509
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:337
@ CMD_FCC_HOOK
:fcc-hook
Definition command.h:78
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
#define PATH_MAX
Definition mutt.h:49
void pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition muttlib.c:428
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition mx.c:167
#define NONULL(x)
Definition string2.h:44
struct AddressList bcc
Email's 'Bcc' list.
Definition envelope.h:62
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function: