diff --git a/Makefile.autosetup b/Makefile.autosetup index de1116d2278..8fd1839a766 100644 --- a/Makefile.autosetup +++ b/Makefile.autosetup @@ -623,6 +623,21 @@ $(LIBNCRYPT): $(PWD)/ncrypt $(LIBNCRYPTOBJS) $(PWD)/ncrypt: $(MKDIR_P) $(PWD)/ncrypt +############################################################################### +# libnewmail +@if USE_DEVEL_NEW_MAIL +LIBNEWMAIL= libnewmail.a +LIBNEWMAILOBJS= newmail/new_mail.o +CLEANFILES+= $(LIBNEWMAIL) $(LIBNEWMAILOBJS) +ALLOBJS+= $(LIBNEWMAILOBJS) + +$(LIBNEWMAIL): $(PWD)/newmail $(LIBNEWMAILOBJS) + $(AR) cr $@ $(LIBNEWMAILOBJS) + $(RANLIB) $@ +$(PWD)/newmail: + $(MKDIR_P) $(PWD)/newmail +@endif + ############################################################################### # libnntp LIBNNTP= libnntp.a @@ -853,7 +868,7 @@ MUTTLIBS+= $(LIBINDEX) $(LIBPAGER) $(LIBAUTOCRYPT) $(LIBPOP) \ $(LIBNCRYPT) $(LIBIMAP) $(LIBCONN) $(LIBHCACHE) \ $(LIBCOMPRESS) $(LIBSIDEBAR) $(LIBBCACHE) $(LIBHISTORY) \ $(LIBCORE) $(LIBPARSE) $(LIBCONFIG) $(LIBEMAIL) $(LIBADDRESS) \ - $(LIBDEBUG) $(LIBMUTT) + $(LIBDEBUG) $(LIBNEWMAIL) $(LIBMUTT) # neomutt $(NEOMUTT): $(GENERATED) $(NEOMUTTOBJS) $(MUTTLIBS) diff --git a/auto.def b/auto.def index 0ff44676d5b..4df5c6361b0 100644 --- a/auto.def +++ b/auto.def @@ -125,6 +125,7 @@ set valid_options { debug-notify=0 => "DEBUG: Enable Notifications dump" debug-queue=0 => "DEBUG: Enable TAILQ debugging" debug-window=0 => "DEBUG: Enable windows dump" + devel-new-mail=0 => "Enable new work-in-progress system notifications" } set deprecated_options { @@ -168,7 +169,7 @@ if {1} { # Keep sorted, please. foreach opt { asan autocrypt bdb compile-commands coverage debug-backtrace debug-color debug-email - debug-graphviz debug-notify debug-queue debug-window doc + debug-graphviz devel-new-mail debug-notify debug-queue debug-window doc everything fmemopen full-doc fuzzing gdbm gnutls gpgme gsasl gss homespool idn2 include-path-in-cflags inotify kyotocabinet lmdb locales-fix lua lz4 mixmaster nls notmuch pcre2 pgp qdbm rocksdb sasl smime sqlite ssl @@ -1058,6 +1059,11 @@ if {[get-define want-debug-window]} { define USE_DEBUG_WINDOW 1 } +# WIP notifications implementation +if {[get-define want-devel-new-mail]} { + define USE_DEVEL_NEW_MAIL 1 +} + ############################################################################### # Address Sanitizer if {[get-define want-asan]} { diff --git a/core/mailbox.c b/core/mailbox.c index a55038cd7c0..a69091b31ef 100644 --- a/core/mailbox.c +++ b/core/mailbox.c @@ -76,6 +76,10 @@ struct Mailbox *mailbox_new(void) m->emails = mutt_mem_calloc(m->email_max, sizeof(struct Email *)); m->v2r = mutt_mem_calloc(m->email_max, sizeof(int)); m->gen = mailbox_gen(); +#ifdef USE_DEVEL_NEW_MAIL + m->last_notified.tv_sec = 0; + m->last_notified.tv_nsec = 0; +#endif return m; } diff --git a/core/mailbox.h b/core/mailbox.h index 613e75c5409..d407c48bd32 100644 --- a/core/mailbox.h +++ b/core/mailbox.h @@ -92,6 +92,9 @@ struct Mailbox int msg_new; ///< Number of new messages int msg_deleted; ///< Number of deleted messages int msg_tagged; ///< How many messages are tagged? +#ifdef USE_DEVEL_NEW_MAIL + int msg_unnotified; ///< Number of messages we have not notified about +#endif struct Email **emails; ///< Array of Emails int email_max; ///< Number of pointers in emails @@ -103,6 +106,9 @@ struct Mailbox bool newly_created; ///< Mbox or mmdf just popped into existence struct timespec mtime; ///< Time Mailbox was last changed struct timespec last_visited; ///< Time of last exit from this mailbox +#ifdef USE_DEVEL_NEW_MAIL + struct timespec last_notified; ///< Time when the user was last notified about new messages. +#endif const struct MxOps *mx_ops; ///< MXAPI callback functions @@ -176,6 +182,8 @@ enum NotifyMailbox NT_MAILBOX_RESORT, ///< Email list needs resorting NT_MAILBOX_UPDATE, ///< Update internal tables NT_MAILBOX_UNTAG, ///< Clear the 'last-tagged' pointer + + NT_MAILBOX_NEW_MAIL, ///< New messages have been added }; /** @@ -183,7 +191,7 @@ enum NotifyMailbox */ struct EventMailbox { - struct Mailbox *mailbox; ///< The Mailbox this Event relates to + struct Mailbox *mailbox; ///< The Mailbox this Event relates to }; void mailbox_changed (struct Mailbox *m, enum NotifyMailbox action); diff --git a/docs/config.c b/docs/config.c index 0ad4a6a2091..0a9aa2c1e92 100644 --- a/docs/config.c +++ b/docs/config.c @@ -1010,6 +1010,19 @@ ** or when you save it to another folder. */ +#ifdef USE_DEVEL_NEW_MAIL +{ "devel_new_mail_command", DT_COMMAND, 0 }, +/* +** .pp +** If \fIset\fP, NeoMutt will call this command after a new message is received. +** The following \fCprintf(3)\fP-like sequences are supported: +** .dl +** .dt %n .dd Mailbox name +** .dt %f .dd Mailbox folder path +** .de +*/ +#endif + { "digest_collapse", DT_BOOL, true }, /* ** .pp diff --git a/maildir/maildir.c b/maildir/maildir.c index 0260cd80852..99d263da2c2 100644 --- a/maildir/maildir.c +++ b/maildir/maildir.c @@ -46,10 +46,12 @@ #include #include "private.h" #include "mutt/lib.h" +#include "mutt/notify.h" #include "config/lib.h" #include "email/lib.h" #include "core/lib.h" #include "lib.h" +#include "newmail/lib.h" #include "progress/lib.h" #include "copy.h" #include "edata.h" @@ -95,6 +97,10 @@ static void maildir_check_dir(struct Mailbox *m, const char *dir_name, struct Buffer *msgpath = buf_pool_get(); buf_printf(path, "%s/%s", mailbox_path(m), dir_name); +#ifdef USE_DEVEL_NEW_MAIL + bool check_unnotified = check_new; +#endif + /* when $mail_check_recent is set, if the new/ directory hasn't been modified since * the user last exited the m, then we know there is no recent mail. */ const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent"); @@ -136,6 +142,22 @@ static void maildir_check_dir(struct Mailbox *m, const char *dir_name, { if (check_stats) m->msg_unread++; + +#ifdef USE_DEVEL_NEW_MAIL + if (check_unnotified) + { + struct timespec created; + buf_printf(msgpath, "%s/%s", buf_string(path), de->d_name); + stat(buf_string(msgpath), &st); + mutt_file_get_stat_timespec(&created, &st, MUTT_STAT_CTIME); + if (mutt_file_timespec_compare(&m->last_notified, &created) < 0) + { + mutt_debug(LL_DEBUG1, "Unnotified %s/%s\n", buf_string(path), de->d_name); + m->msg_unnotified++; + } + } +#endif + if (check_new) { if (c_mail_check_recent) @@ -1361,6 +1383,9 @@ static enum MxStatus maildir_mbox_check_stats(struct Mailbox *m, uint8_t flags) m->msg_count = 0; m->msg_unread = 0; m->msg_flagged = 0; +#ifdef USE_DEVEL_NEW_MAIL + m->msg_unnotified = 0; +#endif } maildir_check_dir(m, "new", check_new, check_stats); @@ -1370,6 +1395,17 @@ static enum MxStatus maildir_mbox_check_stats(struct Mailbox *m, uint8_t flags) if (check_new || check_stats) maildir_check_dir(m, "cur", check_new, check_stats); +#ifdef USE_DEVEL_NEW_MAIL + if (check_stats && m->msg_unnotified > 0) + { + mutt_debug(LL_DEBUG1, "Unnotified = %d\n", m->msg_unnotified); + struct EventMailbox ev_m = { m }; + notify_send(m->notify, NT_MAILBOX, NT_MAILBOX_NEW_MAIL, &ev_m); + clock_gettime(CLOCK_REALTIME, &m->last_notified); + mutt_debug(LL_DEBUG2, "resetting time\n"); + } +#endif + return m->msg_new ? MX_STATUS_NEW_MAIL : MX_STATUS_OK; } diff --git a/main.c b/main.c index 6edcc3620e4..ea455c5c855 100644 --- a/main.c +++ b/main.c @@ -159,6 +159,7 @@ #include "index/lib.h" #include "menu/lib.h" #include "ncrypt/lib.h" +#include "newmail/lib.h" #include "postpone/lib.h" #include "question/lib.h" #include "send/lib.h" @@ -921,6 +922,10 @@ main notify_observer_add(NeoMutt->notify, NT_CONFIG, main_log_observer, NULL); notify_observer_add(NeoMutt->notify, NT_CONFIG, main_config_observer, NULL); +#ifdef USE_DEVEL_NEW_MAIL + notify_observer_add(NeoMutt->notify, NT_MAILBOX, new_mail_observer, NULL); +#endif + if (sendflags & SEND_POSTPONED) { if (!OptNoCurses) diff --git a/mutt_config.c b/mutt_config.c index 023df14e927..3e9ff81866e 100644 --- a/mutt_config.c +++ b/mutt_config.c @@ -371,6 +371,11 @@ static struct ConfigDef MainVars[] = { { "new_mail_command", DT_STRING|DT_COMMAND, 0, 0, NULL, "External command to run when new mail arrives" }, +#ifdef USE_DEVEL_NEW_MAIL + { "devel_new_mail_command", DT_STRING|DT_COMMAND, 0, 0, NULL, + "External command to run when new mail arrives (in development, clashes with new_mail_command)" + }, +#endif { "pipe_decode", DT_BOOL, false, 0, NULL, "Decode the message when piping it" }, diff --git a/mx.c b/mx.c index 3a29564115f..1b251c26ae7 100644 --- a/mx.c +++ b/mx.c @@ -1798,7 +1798,7 @@ int mx_ac_remove(struct Mailbox *m, bool keep_account) /** * mx_mbox_check_stats - Check the statistics for a mailbox - Wrapper for MxOps::mbox_check_stats() * - * @note Emits: #NT_MAILBOX_CHANGE + * @note Emits: #NT_MAILBOX_CHANGE and #NT_MAILBOX_NEW_MAIL */ enum MxStatus mx_mbox_check_stats(struct Mailbox *m, uint8_t flags) { diff --git a/newmail/lib.h b/newmail/lib.h new file mode 100644 index 00000000000..2a7b03232b3 --- /dev/null +++ b/newmail/lib.h @@ -0,0 +1,42 @@ +/** + * @file + * New mail notification observer. + * + * @authors + * Copyright (C) 2022 Michal Siedlaczek + * + * @copyright + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * 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 . + */ + +#ifndef MUTT_NEW_MAIL_H +#define MUTT_NEW_MAIL_H + +#include +#include +#include "mutt/lib.h" +#include "format_flags.h" + +struct NotifyCallback; + +typedef int(Execute)(const char *cmd); + +const char *new_mail_format_str(char *buf, size_t buflen, size_t col, int cols, + char op, const char *src, const char *prec, + const char *if_str, const char *else_str, + intptr_t data, MuttFormatFlags flags); +int handle_new_mail_event(const char *cmd, struct NotifyCallback *nc, Execute *execute); +int new_mail_observer(struct NotifyCallback *nc); + +#endif diff --git a/newmail/new_mail.c b/newmail/new_mail.c new file mode 100644 index 00000000000..e572d828444 --- /dev/null +++ b/newmail/new_mail.c @@ -0,0 +1,117 @@ +/** + * @file + * New mail notification observer implementation. + * + * @authors + * Copyright (C) 2022 Michal Siedlaczek + * + * @copyright + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * 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 . + */ + +/** + * @page new_mail Notify about new incoming mail + * + * Use an external command to send a system notification when new mail arrives. + */ + +#include "mutt/lib.h" +#include "config/lib.h" +#include "email/lib.h" +#include "newmail/lib.h" +#include "mutt_mailbox.h" +#include "muttlib.h" +#include "protos.h" + +/** + * new_mail_format_str - Format a string for the new mail notification. + * @param[out] buf Buffer in which to save string + * @param[in] buflen Buffer length + * @param[in] col Starting column + * @param[in] cols Number of screen columns + * @param[in] op printf-like operator, e.g. 't' + * @param[in] src printf-like format string + * @param[in] prec Field precision, e.g. "-3.4" + * @param[in] if_str If condition is met, display this string + * @param[in] else_str Otherwise, display this string + * @param[in] data Private data + * @param[in] flags Flags, see #MuttFormatFlags + * @retval ptr src (unchanged) + * + * | Expando | Description + * | :------ | :------------------------------------------------------- + * | \%c | New messages + * | \%n | Folder name + * | \%f | Folder path + * | \%u | Unread messages + */ +const char *new_mail_format_str(char *buf, size_t buflen, size_t col, int cols, + char op, const char *src, const char *prec, + const char *if_str, const char *else_str, + intptr_t data, MuttFormatFlags flags) +{ + struct EventMailbox *ev_m = (struct EventMailbox *) data; + struct Mailbox *mailbox = ev_m->mailbox; + + switch (op) + { + case 'n': + snprintf(buf, buflen, "%d", mailbox->msg_unnotified); + break; + case 'N': + snprintf(buf, buflen, "%d", mailbox->msg_new); + break; + case 'f': + snprintf(buf, buflen, "%s", NONULL(mailbox_path(mailbox))); + break; + case 'F': + snprintf(buf, buflen, "%s", NONULL(mailbox->name)); + break; + case 'u': + snprintf(buf, buflen, "%d", mailbox->msg_unread); + break; + } + return src; +} + +int handle_new_mail_event(const char *cmd, struct NotifyCallback *nc, Execute *execute) +{ + if (nc->event_subtype != NT_MAILBOX_NEW_MAIL) + return 0; + + struct EventMailbox *ev_m = nc->event_data; + if (!ev_m || !ev_m->mailbox) + return 0; + + char expanded_cmd[1024]; + mutt_expando_format(expanded_cmd, 1024, 0, 1024, cmd, new_mail_format_str, + (intptr_t) ev_m, MUTT_FORMAT_NO_FLAGS); + execute(expanded_cmd); + return 0; +} + +int execute_cmd(const char *cmd) +{ + if (mutt_system(cmd) != 0) + mutt_error(_("Error running \"%s\""), cmd); + return 0; +} + +int new_mail_observer(struct NotifyCallback *nc) +{ + const char *c_devel_new_mail_command = cs_subset_string(NeoMutt->sub, "devel_new_mail_command"); + if (!c_devel_new_mail_command) + return 0; + return handle_new_mail_event(c_devel_new_mail_command, nc, execute_cmd); +} diff --git a/pager/pager.c b/pager/pager.c index 6d73892ecf0..bcbfe2c311f 100644 --- a/pager/pager.c +++ b/pager/pager.c @@ -331,10 +331,8 @@ static int pager_global_observer(struct NotifyCallback *nc) */ static int pager_index_observer(struct NotifyCallback *nc) { - if (nc->event_type != NT_INDEX) + if ((nc->event_type != NT_INDEX) || !nc->global_data) return 0; - if (!nc->global_data) - return -1; struct MuttWindow *win_pager = nc->global_data; diff --git a/test/Makefile.autosetup b/test/Makefile.autosetup index de5584b3731..774d537d519 100644 --- a/test/Makefile.autosetup +++ b/test/Makefile.autosetup @@ -377,6 +377,11 @@ NEOMUTT_OBJS = test/neo/neomutt_account_add.o \ test/neo/neomutt_mailboxlist_get_all.o \ test/neo/neomutt_new.o +@if USE_DEVEL_NEW_MAIL +NEW_MAIL_OBJS = test/newmail/new_mail_observer.o \ + test/newmail/new_mail_format_str.o +@endif + NOTIFY_OBJS = test/notify/notify_free.o \ test/notify/notify_new.o \ test/notify/notify_observer_add.o \ @@ -596,7 +601,7 @@ BUILD_DIRS = $(PWD)/test/account $(PWD)/test/address $(PWD)/test/array \ $(PWD)/test/history $(PWD)/test/idna $(PWD)/test/list \ $(PWD)/test/logging $(PWD)/test/mailbox $(PWD)/test/mapping \ $(PWD)/test/mbyte $(PWD)/test/md5 $(PWD)/test/memory \ - $(PWD)/test/neo $(PWD)/test/notify $(PWD)/test/notmuch \ + $(PWD)/test/neo $(PWD)/test/newmail $(PWD)/test/notify $(PWD)/test/notmuch \ $(PWD)/test/parameter $(PWD)/test/parse $(PWD)/test/path \ $(PWD)/test/pattern $(PWD)/test/pool $(PWD)/test/prex \ $(PWD)/test/regex $(PWD)/test/rfc2047 $(PWD)/test/rfc2231 \ @@ -659,6 +664,10 @@ TEST_OBJS = test/main.o test/common.o \ $(THREAD_OBJS) \ $(URL_OBJS) +@if USE_DEVEL_NEW_MAIL +TEST_OBJS += $(NEW_MAIL_OBJS) +@endif + CFLAGS += -I$(SRCDIR)/test TEST_BINARY = test/neomutt-test$(EXEEXT) diff --git a/test/main.c b/test/main.c index 74b9281fa4d..5acf90bd7d4 100644 --- a/test/main.c +++ b/test/main.c @@ -634,6 +634,10 @@ NEOMUTT_TEST_LIST #ifdef USE_ZSTD NEOMUTT_TEST_ITEM(test_compress_zstd) #endif +#ifdef USE_DEVEL_NEW_MAIL + NEOMUTT_TEST_ITEM(test_new_mail_observer) + NEOMUTT_TEST_ITEM(test_new_mail_format_str) +#endif #if defined(HAVE_BDB) || defined(HAVE_GDBM) || defined(HAVE_KC) || defined(HAVE_LMDB) || defined(HAVE_QDBM) || defined(HAVE_ROCKSDB) || defined(HAVE_TC) || defined(HAVE_TDB) NEOMUTT_TEST_ITEM(test_store_store) #endif @@ -686,6 +690,10 @@ NEOMUTT_TEST_ITEM(test_compress_common) #ifdef USE_ZSTD NEOMUTT_TEST_ITEM(test_compress_zstd) #endif +#ifdef USE_DEVEL_NEW_MAIL + NEOMUTT_TEST_ITEM(test_new_mail_observer) + NEOMUTT_TEST_ITEM(test_new_mail_format_str) +#endif #if defined(HAVE_BDB) || defined(HAVE_GDBM) || defined(HAVE_KC) || defined(HAVE_LMDB) || defined(HAVE_QDBM) || defined(HAVE_ROCKSDB) || defined(HAVE_TC) || defined(HAVE_TDB) NEOMUTT_TEST_ITEM(test_store_store) #endif diff --git a/test/newmail/new_mail_format_str.c b/test/newmail/new_mail_format_str.c new file mode 100644 index 00000000000..b1b7d0a57c2 --- /dev/null +++ b/test/newmail/new_mail_format_str.c @@ -0,0 +1,74 @@ +/** + * @file + * Test code for new_mail_format_str() + * + * @authors + * Copyright (C) 2022 Michal Siedlaczek + * + * @copyright + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * 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 . + */ + +#include "mutt/string2.h" +#define TEST_NO_MAIN +#include "config.h" +#include "acutest.h" +#include "email/lib.h" +#include "core/lib.h" +#include "newmail/lib.h" + +void test_new_mail_format_str(void) +{ + // const char *new_mail_format_str(char *buf, size_t buflen, size_t col, int cols, + // char op, const char *src, const char *prec, + // const char *if_str, const char *else_str, + // intptr_t data, MuttFormatFlags flags); + + char buf[64]; + size_t col = 0; + int cols = 64; + struct Mailbox *mailbox = mailbox_new(); + mailbox->name = mutt_str_dup("MailBox"); + mailbox->pathbuf = buf_make(16); + mailbox->msg_unread = 7; + mailbox->msg_unnotified = 2; + mailbox->msg_new = 3; + buf_strcpy(&mailbox->pathbuf, "/path"); + + struct EventMailbox ev_m = { mailbox }; + + intptr_t data = (intptr_t) &ev_m; + + new_mail_format_str((char *) buf, 64, col, cols, 'F', NULL, NULL, NULL, NULL, data, 0); + TEST_CHECK(mutt_str_equal(buf, "MailBox")); + TEST_MSG("Check failed: %s != MailBox", buf); + + new_mail_format_str((char *) buf, 64, col, cols, 'f', NULL, NULL, NULL, NULL, data, 0); + TEST_CHECK(mutt_str_equal(buf, "/path")); + TEST_MSG("Check failed: %s != /path", buf); + + new_mail_format_str((char *) buf, 64, col, cols, 'u', NULL, NULL, NULL, NULL, data, 0); + TEST_CHECK(mutt_str_equal(buf, "7")); + TEST_MSG("Check failed: %s != 7", buf); + + new_mail_format_str((char *) buf, 64, col, cols, 'n', NULL, NULL, NULL, NULL, data, 0); + TEST_CHECK(mutt_str_equal(buf, "2")); + TEST_MSG("Check failed: %s != 2", buf); + + new_mail_format_str((char *) buf, 64, col, cols, 'N', NULL, NULL, NULL, NULL, data, 0); + TEST_CHECK(mutt_str_equal(buf, "3")); + TEST_MSG("Check failed: %s != 3", buf); + + mailbox_free(&mailbox); +} diff --git a/test/newmail/new_mail_observer.c b/test/newmail/new_mail_observer.c new file mode 100644 index 00000000000..5a35a20bb0d --- /dev/null +++ b/test/newmail/new_mail_observer.c @@ -0,0 +1,64 @@ +/** + * @file + * Test code for new_mail_observer() + * + * @authors + * Copyright (C) 2022 Michal Siedlaczek + * + * @copyright + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * 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 . + */ + +#include "mutt/notify.h" +#include "mutt/observer.h" +#include "mutt/string2.h" +#define TEST_NO_MAIN +#include "config.h" +#include "acutest.h" +#include "core/lib.h" +#include "newmail/lib.h" + +static char *message = NULL; + +int dummy_execute_cmd(const char *cmd) +{ + message = mutt_str_dup(cmd); + return 0; +} + +int dummy_new_mail_observer(struct NotifyCallback *nc) +{ + return handle_new_mail_event("New messages", nc, dummy_execute_cmd); +} + +void test_new_mail_observer(void) +{ + struct Notify *notify = notify_new(); + notify_observer_add(notify, NT_MAILBOX, dummy_new_mail_observer, NULL); + struct Mailbox *mailbox = mailbox_new(); + mailbox->name = mutt_str_dup("Mailbox"); + struct EventMailbox event = { mailbox }; + + notify_send(notify, NT_MAILBOX, NT_MAILBOX_NEW_MAIL, NULL); + TEST_CHECK(message == NULL); + + notify_send(notify, NT_MAILBOX, NT_MAILBOX_NEW_MAIL, &event); + TEST_CHECK(message != NULL); + TEST_CHECK(mutt_str_equal(message, "New messages")); + TEST_MSG("Check failed: \"%s\" != \"New messages\"", message); + + notify_free(¬ify); + mailbox_free(&mailbox); + FREE(&message); +} diff --git a/test/pattern/dummy.c b/test/pattern/dummy.c index e51fa3c9810..4536aa228c1 100644 --- a/test/pattern/dummy.c +++ b/test/pattern/dummy.c @@ -26,9 +26,11 @@ #include #include #include "mutt/lib.h" +#include "mutt/string2.h" #include "core/lib.h" #include "history/lib.h" #include "menu/lib.h" +#include "newmail/lib.h" #include "mview.h" struct Address; @@ -93,16 +95,10 @@ bool OptNoCurses; bool OptSearchInvalid; bool OptSearchReverse; -typedef uint8_t MuttFormatFlags; typedef uint16_t CompletionFlags; typedef uint16_t PagerFlags; typedef uint8_t SelectFileFlags; -typedef const char *(format_t) (char *buf, size_t buflen, size_t col, int cols, - char op, const char *src, const char *prec, - const char *if_str, const char *else_str, - intptr_t data, MuttFormatFlags flags); - struct Address *alias_reverse_lookup(const struct Address *addr) { return NULL; @@ -213,6 +209,7 @@ int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t *callback, intptr_t data, MuttFormatFlags flags) { + mutt_str_copy(buf, src, buflen); } void menu_pop_current(struct Menu *menu) diff --git a/version.c b/version.c index 39ba81527f8..a04f5846996 100644 --- a/version.c +++ b/version.c @@ -308,6 +308,9 @@ static struct CompileOptions DebugOpts[] = { #ifdef USE_DEBUG_GRAPHVIZ { "graphviz", 2 }, #endif +#ifdef USE_DEVEL_NEW_MAIL + { "new_mail", 2 }, +#endif #ifdef USE_DEBUG_NOTIFY { "notify", 2 }, #endif