LIBMUTTOBJS= mutt/base64.o mutt/buffer.o mutt/charset.o mutt/date.o \
mutt/envlist.o mutt/exit.o mutt/file.o mutt/hash.o \
mutt/history.o mutt/list.o mutt/logging.o mutt/mapping.o \
- mutt/mbyte.o mutt/md5.o mutt/memory.o mutt/path.o mutt/pool.o \
+ mutt/mbyte.o mutt/md5.o mutt/memory.o mutt/notify.o \
+ mutt/path.o mutt/pool.o \
mutt/regex.o mutt/sha1.o mutt/signal.o mutt/string.o
CLEANFILES+= $(LIBMUTT) $(LIBMUTTOBJS)
MUTTLIBS+= $(LIBMUTT)
* | mutt/mbyte.c | @subpage mbyte |
* | mutt/md5.c | @subpage md5 |
* | mutt/memory.c | @subpage memory |
+ * | mutt/notify.c | @subpage notify |
+ * | mutt/observer.h | @subpage observer |
* | mutt/path.c | @subpage path |
* | mutt/pool.c | @subpage pool |
* | mutt/regex.c | @subpage regex |
#include "memory.h"
#include "message.h"
#include "queue.h"
+#include "notify.h"
+#include "notify_type.h"
+#include "observer.h"
#include "path.h"
#include "pool.h"
#include "regex3.h"
--- /dev/null
+/**
+ * @file
+ * Notification API
+ *
+ * @authors
+ * Copyright (C) 2019 Richard Russon <rich@flatcap.org>
+ *
+ * @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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @page notify Notification API
+ *
+ * Notification API
+ */
+
+#include "config.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include "notify.h"
+
+/**
+ * struct Notify - Notification API
+ */
+struct Notify
+{
+ void *obj;
+ enum NotifyType obj_type;
+ struct Notify *parent;
+ struct ObserverHead observers;
+};
+
+/**
+ * notify_new - Create a new notifications handler
+ * @param object Owner of the object
+ * @param type Object type, e.g. #NT_ACCOUNT
+ * @retval ptr New notification handler
+ */
+struct Notify *notify_new(void *object, enum NotifyType type)
+{
+ struct Notify *notify = mutt_mem_calloc(1, sizeof(*notify));
+
+ notify->obj = object;
+ notify->obj_type = type;
+ STAILQ_INIT(¬ify->observers);
+
+ return notify;
+}
+
+/**
+ * notify_free - Free a notification handler
+ * @param ptr Notification handler to free
+ */
+void notify_free(struct Notify **ptr)
+{
+ if (!ptr || !*ptr)
+ return;
+
+ // struct Notify *notify = *ptr;
+ // NOTIFY observers
+ // FREE observers
+
+ FREE(ptr);
+}
+
+/**
+ * notify_set_parent - Set the parent notification handler
+ * @param notify Notification handler to alter
+ * @param parent Parent notification handler
+ *
+ * Notifications are passed up the tree of handlers.
+ */
+void notify_set_parent(struct Notify *notify, struct Notify *parent)
+{
+ if (!notify || !parent)
+ return;
+
+ notify->parent = parent;
+}
+
+/**
+ * send - Send out a notification message
+ * @param source Source of the event, e.g. #Account
+ * @param current Current handler, e.g. #NeoMutt
+ * @param type Type of event, e.g. #NT_ACCOUNT
+ * @param subtype Subtype, e.g. NT_ACCOUNT_NEW
+ * @param data Private data associated with the event type
+ * @retval true If successfully sent
+ *
+ * Notifications are sent to all matching observers, then propagated up the
+ * handler tree. For example a "new email" notification would be sent to the
+ * Mailbox that owned it, the Account (owning the Mailbox) and finally the
+ * NeoMutt object.
+ */
+static bool send(struct Notify *source, struct Notify *current, int type,
+ int subtype, intptr_t data)
+{
+ if (!source || !current)
+ return false;
+
+ // mutt_debug(LL_NOTIFY, "send: %d, %ld\n", type, data);
+ struct ObserverNode *np = NULL;
+ STAILQ_FOREACH(np, ¤t->observers, entries)
+ {
+ struct Observer *o = np->observer;
+
+ struct NotifyCallback nc = { source->obj, source->obj_type, type, subtype,
+ data, o->flags, o->data };
+ o->callback(&nc);
+ }
+
+ if (current->parent)
+ return send(source, current->parent, type, subtype, data);
+ return true;
+}
+
+/**
+ * notify_send - Send out a notification message
+ * @param notify Notification handler
+ * @param type Type of event, e.g. #NT_ACCOUNT
+ * @param subtype Subtype, e.g. NT_ACCOUNT_NEW
+ * @param data Private data associated with the event type
+ * @retval true If successfully sent
+ *
+ * See send() for more details.
+ */
+bool notify_send(struct Notify *notify, int type, int subtype, intptr_t data)
+{
+ return send(notify, notify, type, subtype, data);
+}
+
+/**
+ * notify_observer_add - Add an observer to an object
+ * @param notify Notification handler
+ * @param type Type of event to listen for, e.g. #NT_ACCOUNT
+ * @param subtype Subtype, e.g. NT_ACCOUNT_NEW
+ * @param callback Function to call on a matching event, see ::observer_t
+ * @param data Private data associated with the event type
+ * @retval true If successful
+ */
+bool notify_observer_add(struct Notify *notify, enum NotifyType type,
+ int subtype, observer_t callback, intptr_t data)
+{
+ if (!notify || !callback)
+ return false;
+
+ struct ObserverNode *np = NULL;
+ STAILQ_FOREACH(np, ¬ify->observers, entries)
+ {
+ if (np->observer->callback == callback)
+ return true;
+ }
+
+ struct Observer *o = mutt_mem_calloc(1, sizeof(*o));
+ o->type = type;
+ o->flags = subtype;
+ o->callback = callback;
+ o->data = data;
+
+ np = mutt_mem_calloc(1, sizeof(*np));
+ np->observer = o;
+ STAILQ_INSERT_TAIL(¬ify->observers, np, entries);
+
+ return true;
+}
+
+/**
+ * notify_observer_remove - Remove an observer from an object
+ * @param notify Notification handler
+ * @param callback Function to call on a matching event, see ::observer_t
+ * @retval true If successful
+ */
+bool notify_observer_remove(struct Notify *notify, observer_t callback)
+{
+ if (!notify || !callback)
+ return false;
+
+ struct ObserverNode *np = NULL;
+ STAILQ_FOREACH(np, ¬ify->observers, entries)
+ {
+ if (np->observer->callback == callback)
+ {
+ STAILQ_REMOVE(¬ify->observers, np, ObserverNode, entries);
+ FREE(&np->observer);
+ FREE(&np);
+ return true;
+ }
+ }
+
+ return false;
+}
--- /dev/null
+/**
+ * @file
+ * Notification API
+ *
+ * @authors
+ * Copyright (C) 2019 Richard Russon <rich@flatcap.org>
+ *
+ * @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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MUTT_LIB_NOTIFY_H
+#define MUTT_LIB_NOTIFY_H
+
+#include <stdbool.h>
+#include "observer.h"
+#include "notify_type.h"
+
+struct Notify;
+
+struct Notify *notify_new(void *object, enum NotifyType type);
+void notify_free(struct Notify **ptr);
+void notify_set_parent(struct Notify *notify, struct Notify *parent);
+
+bool notify_send(struct Notify *notify, int type, int subtype, intptr_t data);
+
+bool notify_observer_add(struct Notify *notify, enum NotifyType type, int subtype, observer_t callback, intptr_t data);
+bool notify_observer_remove(struct Notify *notify, observer_t callback);
+
+#endif /* MUTT_LIB_NOTIFY_H */
--- /dev/null
+/**
+ * @file
+ * Notification Types
+ *
+ * @authors
+ * Copyright (C) 2019 Richard Russon <rich@flatcap.org>
+ *
+ * @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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MUTT_LIB_NOTIFY_TYPE_H
+#define MUTT_LIB_NOTIFY_TYPE_H
+
+/**
+ * enum NotifyType - Notification Types
+ */
+enum NotifyType
+{
+ NT_NEOMUTT, ///< Container for all notifications
+ NT_GLOBAL, ///< Not object-related
+ NT_CONFIG, ///< Config has changed
+ NT_ACCOUNT, ///< Account has changed
+ NT_MAILBOX, ///< Mailbox has changed
+ NT_EMAIL, ///< Email has changed
+ NT_WINDOW, ///< Window has changed
+
+ NT_MAX,
+};
+
+#endif /* MUTT_LIB_NOTIFY_TYPE_H */
--- /dev/null
+/**
+ * @file
+ * Observer of notifications
+ *
+ * @authors
+ * Copyright (C) 2019 Richard Russon <rich@flatcap.org>
+ *
+ * @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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @page observer Observer of notifications
+ *
+ * Observer of notifications
+ */
+
+#ifndef MUTT_LIB_OBSERVER_H
+#define MUTT_LIB_OBSERVER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "mutt/mutt.h"
+#include "notify_type.h"
+
+struct Notify;
+
+/**
+ * struct NotifyCallback - Data passed to a notification function
+ */
+struct NotifyCallback
+{
+ void *obj; ///< Notify: Event happened here
+ int obj_type; ///< Notify: type of object event happened on
+ int event_type; ///< Send: event type
+ int event_subtype; ///< Send: event subtype
+ intptr_t event; ///< Send: event data
+ int flags; ///< Observer: determine event data
+ intptr_t data; ///< Observer: private to observer
+};
+
+/**
+ * typedef observer_t - Prototype for a notification callback function
+ * @param[in] flags Flags, see #MuttFormatFlags
+ * @retval 0 Success
+ * @retval -1 Error
+ */
+typedef int (*observer_t)(struct NotifyCallback *nc);
+
+typedef uint8_t ObserverFlags; ///< Flags, e.g. #OBSERVE_RECURSIVE
+#define OBSERVE_NO_FLAGS 0 ///< No flags are set
+#define OBSERVE_RECURSIVE (1 << 0) ///< Listen for events of children
+
+/**
+ * struct Observer - An observer of notifications
+ */
+struct Observer
+{
+ enum NotifyType type; ///< Object to observe to, e.g. #NT_NEOMUTT
+ ObserverFlags flags; ///< Flags, e.g. #OBSERVE_RECURSIVE
+ observer_t callback; ///< Callback function for events
+ intptr_t data; ///< Private data to pass to callback
+};
+
+/**
+ * struct ObserverNode - List of Observers
+ */
+struct ObserverNode
+{
+ struct Observer *observer;
+ STAILQ_ENTRY(ObserverNode) entries;
+};
+STAILQ_HEAD(ObserverHead, ObserverNode);
+
+#endif /* MUTT_LIB_OBSERVER_H */
{
struct NeoMutt *n = mutt_mem_calloc(1, sizeof(*NeoMutt));
+ n->notify = notify_new(n, NT_NEOMUTT);
+
return n;
}
if (!ptr || !*ptr)
return;
- // struct NeoMutt *n = *ptr;
+ struct NeoMutt *n = *ptr;
+
+ notify_free(&n->notify);
FREE(ptr);
}