From a4c2217e6e1b58003aca5f57c4a5c62ddb9cd285 Mon Sep 17 00:00:00 2001 From: Thomas Adam Date: Wed, 26 Oct 2016 23:58:16 +0100 Subject: [PATCH] hooks: define hooks for startup and shutdown Having hooks which run when mutt first starts (startup-hook) but before the fist mbox is opened, and when mutt closes the mbox (shutdown-hook) before exiting, allows for those notmuch users to run commands to sync the state of their caches, etc. support GLOBALHOOK type There's now a few hooks (startup/shutdown/timeout) which don't operate on a mbox or pattern, but are instead global to mutt. Therefore, don't require the hooks themselves to needlessly define these parameters. Closes: #184 --- curs_main.c | 2 + doc/manual.xml.head | 190 +++++++++++++++++++++++++++----------------- doc/muttrc.man.head | 12 +++ hook.c | 60 +++++++++++--- init.h | 4 +- main.c | 1 + mutt.h | 3 + protos.h | 1 + 8 files changed, 191 insertions(+), 82 deletions(-) diff --git a/curs_main.c b/curs_main.c index 3b3ce625a..e028a6eb6 100644 --- a/curs_main.c +++ b/curs_main.c @@ -1508,6 +1508,8 @@ int mutt_index_menu (void) oldcount = Context ? Context->msgcount : 0; + mutt_startup_shutdown_hook (MUTT_SHUTDOWNHOOK); + if (!Context || (check = mx_close_mailbox (Context, &index_hint)) == 0) done = 1; else diff --git a/doc/manual.xml.head b/doc/manual.xml.head index 53582cb5d..59f0174be 100644 --- a/doc/manual.xml.head +++ b/doc/manual.xml.head @@ -10153,6 +10153,125 @@ set attach_keyword = "\\<attach(|ed|ments?)\\>" + + Global Hooks + Define actions to run globally within Mutt + + + Introduction + + + These hooks are called when global events take place in Mutt. + + + + Run a command... + timeout-hook - periodically + startup-hook - when mutt starts up, before opening the first mailbox + shutdown-hook - mutt shuts down, before closing the last mailbox + + + + Timeout Hook + Run a command periodically + Since: NeoMutt 2016-08-08 + + This feature implements a new hook that is called periodically when Mutt + checks for new mail. This hook is called every $timeout seconds. + + + + + Startup Hook + Run a command when mutt starts up, before opening the first mailbox + Since: NeoMutt 2016-11-25 + + This feature implements a new hook that is called when Mutt first + starts up, but before opening the first mailbox. This is most likely + to be useful to users of notmuch. + + + + + Shutdown Hook + Run a command when mutt shuts down, before closing the last mailbox + Since: NeoMutt 2016-11-25 + + This feature implements a hook that is called when Mutt shuts down, but + before closing the first mailbox. This is most likely to be useful to + users of notmuch. + + + + + + Commands + + + timeout-hook + + MUTT-COMMAND + + + + startup-hook + + MUTT-COMMAND + + + + shutdown-hook + + MUTT-COMMAND + + + + + + Muttrc + +# Example NeoMutt config file for the global hooks feature. + +# -------------------------------------------------------------------------- +# COMMANDS - shown with an example argument +# -------------------------------------------------------------------------- + +# After $timeout seconds of inactivity, run this mutt command +timeout-hook 'exec sync-mailbox' + +# When mutt first loads, run this mutt command +startup-hook 'exec sync-mailbox' + +# When mutt quits, run this mutt command +shutdown-hook 'exec sync-mailbox' + +# vim: syntax=muttrc + + + + + See Also + + + $timeout + + + + + Known Bugs + None + + + + Credits + + Armin Wolfermann armin@wolfermann.org + Richard Russon rich@flatcap.org + Thomas Adam thomas@xteddy.org + + + + Ifdef Feature Conditional config options @@ -13387,77 +13506,6 @@ color status brightwhite default 'Mutt: ([^ ]+)' 1 - - Timeout Feature - Run a command periodically - - - Support - - Since: NeoMutt 2016-08-08 - Dependencies: None - - - - Introduction - - - This feature implements a new hook that is called periodically when Mutt - checks for new mail. This hook is called every $timeout seconds. - - - - - Commands - - timeout-hook - - . - - - MUTT-COMMAND - - - - - - Muttrc - -# Example NeoMutt config file for the timeout feature. - -# -------------------------------------------------------------------------- -# COMMANDS - shown with an example arguments -# -------------------------------------------------------------------------- - -# After $timeout seconds of inactivity, run this mutt command -timeout-hook . 'exec sync-mailbox' - -# vim: syntax=muttrc - - - - - See Also - - - $timeout - - - - - Known Bugs - None - - - - Credits - - Armin Wolfermann armin@wolfermann.org - Richard Russon rich@flatcap.org - - - - TLS-SNI Feature Negotiate with a server for a TSL/SSL certificate diff --git a/doc/muttrc.man.head b/doc/muttrc.man.head index 6ab69a704..378f36c66 100644 --- a/doc/muttrc.man.head +++ b/doc/muttrc.man.head @@ -207,6 +207,18 @@ the given \fIcommand\fP is executed. When multiple \fBmessage-hook\fPs match, they are executed in the order in which they occur in the configuration file. .TP +\fBtimeout-hook\fP \fIcommand\fP +Run a command periodically when Mutt checks for new mail. +This hook is called every $timeout seconds. +.TP +\fBstartup-hook\fP \fIcommand\fP +Before mutt opens the first mailbox when first starting, mutt will run the +startup hook for the given \fIcommand\fP. +.TP +\fBshutdown-hook\fP \fIcommand\fP +Before mutt is about to exit, and before the mailbox is closed, mutt will run +the shutdown hook for the given \fIcommand\fP. +.TP \fBfolder-hook\fP [\fB!\fP]\fIregexp\fP \fIcommand\fP When mutt enters a folder which matches \fIregexp\fP (or, when \fIregexp\fP is preceded by an exclamation mark, does not match diff --git a/hook.c b/hook.c index dbf78d5c7..ed1bb2641 100644 --- a/hook.c +++ b/hook.c @@ -59,19 +59,26 @@ int mutt_parse_hook (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) mutt_buffer_init (&pattern); mutt_buffer_init (&command); - if (*s->dptr == '!') + if (~data & MUTT_GLOBALHOOK) { - s->dptr++; - SKIPWS (s->dptr); - not = 1; - } + if (*s->dptr == '!') + { + s->dptr++; + SKIPWS (s->dptr); + not = 1; + } - mutt_extract_token (&pattern, s, 0); + mutt_extract_token (&pattern, s, 0); - if (!MoreArgs (s)) + if (!MoreArgs (s)) + { + strfcpy (err->data, _("too few arguments"), err->dsize); + goto error; + } + } + else { - strfcpy (err->data, _("too few arguments"), err->dsize); - goto error; + mutt_extract_token (&pattern, s, 0); } mutt_extract_token (&command, s, (data & (MUTT_FOLDERHOOK | MUTT_SENDHOOK | MUTT_SEND2HOOK | MUTT_ACCOUNTHOOK | MUTT_REPLYHOOK)) ? MUTT_TOKEN_SPACE : 0); @@ -154,7 +161,7 @@ int mutt_parse_hook (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) ptr->rx.not == not && !mutt_strcmp (pattern.data, ptr->rx.pattern)) { - if (data & (MUTT_FOLDERHOOK | MUTT_SENDHOOK | MUTT_SEND2HOOK | MUTT_MESSAGEHOOK | MUTT_ACCOUNTHOOK | MUTT_REPLYHOOK | MUTT_CRYPTHOOK | MUTT_TIMEOUTHOOK)) + if (data & (MUTT_FOLDERHOOK | MUTT_SENDHOOK | MUTT_SEND2HOOK | MUTT_MESSAGEHOOK | MUTT_ACCOUNTHOOK | MUTT_REPLYHOOK | MUTT_CRYPTHOOK | MUTT_TIMEOUTHOOK | MUTT_STARTUPHOOK | MUTT_SHUTDOWNHOOK)) { /* these hooks allow multiple commands with the same * pattern, so if we've already seen this pattern/command pair, just @@ -583,3 +590,36 @@ void mutt_timeout_hook (void) } } +/** + * mutt_startup_shutdown_hook - Execute any startup/shutdown hooks + * @type: Hook type: MUTT_STARTUPHOOK or MUTT_SHUTDOWNHOOK + * + * The user can configure hooks to be run on startup/shutdown. + * This function finds all the matching hooks and executes them. + */ +void mutt_startup_shutdown_hook (int type) +{ + HOOK *hook; + BUFFER token; + BUFFER err; + char buf[STRING]; + + err.data = buf; + err.dsize = sizeof (buf); + memset (&token, 0, sizeof (token)); + + for (hook = Hooks; hook; hook = hook->next) + { + if (!(hook->command && (hook->type & type))) + continue; + + if (mutt_parse_rc_line (hook->command, &token, &err) == -1) + { + FREE (&token.data); + mutt_error ("%s", err.data); + mutt_sleep (1); + + } + } +} + diff --git a/init.h b/init.h index e7b4b7b36..6756004e6 100644 --- a/init.h +++ b/init.h @@ -4378,8 +4378,10 @@ const struct command_t Commands[] = { { "source", parse_source, 0 }, { "spam", parse_spam_list, MUTT_SPAM }, { "nospam", parse_spam_list, MUTT_NOSPAM }, + { "shutdown-hook", mutt_parse_hook, MUTT_SHUTDOWNHOOK | MUTT_GLOBALHOOK }, + { "startup-hook", mutt_parse_hook, MUTT_STARTUPHOOK | MUTT_GLOBALHOOK }, { "subscribe", parse_subscribe, 0 }, - { "timeout-hook", mutt_parse_hook, MUTT_TIMEOUTHOOK }, + { "timeout-hook", mutt_parse_hook, MUTT_TIMEOUTHOOK | MUTT_GLOBALHOOK }, { "toggle", parse_set, MUTT_SET_INV }, { "unalias", parse_unalias, 0 }, { "unalternative_order",parse_unlist, UL &AlternativeOrderList }, diff --git a/main.c b/main.c index ed2cc4e9a..12c29e7f8 100644 --- a/main.c +++ b/main.c @@ -870,6 +870,7 @@ int main (int argc, char **argv) } mutt_folder_hook (folder); + mutt_startup_shutdown_hook (MUTT_STARTUPHOOK); if((Context = mx_open_mailbox (folder, ((flags & MUTT_RO) || option (OPTREADONLY)) ? MUTT_READONLY : 0, NULL)) || !explicit_folder) diff --git a/mutt.h b/mutt.h index 0a75aa834..b440a6bcc 100644 --- a/mutt.h +++ b/mutt.h @@ -165,6 +165,9 @@ typedef enum #define MUTT_CLOSEHOOK (1<<14) #endif #define MUTT_TIMEOUTHOOK (1<<15) +#define MUTT_STARTUPHOOK (1<<16) +#define MUTT_SHUTDOWNHOOK (1<<17) +#define MUTT_GLOBALHOOK (1<<18) /* tree characters for linearize_tree and print_enriched_string */ #define MUTT_TREE_LLCORNER 1 diff --git a/protos.h b/protos.h index abe54588f..a0aaf6f64 100644 --- a/protos.h +++ b/protos.h @@ -160,6 +160,7 @@ char *mutt_get_parameter (const char *, PARAMETER *); LIST *mutt_crypt_hook (ADDRESS *); char *mutt_make_date (char *, size_t); void mutt_timeout_hook (void); +void mutt_startup_shutdown_hook (int); int mutt_set_xdg_path(const XDGType type, char *buf, size_t bufsize); const char *mutt_make_version (void); -- 2.40.0