summaryrefslogtreecommitdiffstats
path: root/src/plugins/push-notification/push-notification-drivers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/push-notification/push-notification-drivers.c')
-rw-r--r--src/plugins/push-notification/push-notification-drivers.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/plugins/push-notification/push-notification-drivers.c b/src/plugins/push-notification/push-notification-drivers.c
new file mode 100644
index 0000000..67295d1
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-drivers.c
@@ -0,0 +1,181 @@
+/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "hash.h"
+#include "mail-user.h"
+
+#include "push-notification-drivers.h"
+#include "push-notification-events.h"
+
+static ARRAY(const struct push_notification_driver *) push_notification_drivers;
+
+static bool
+push_notification_driver_find(const char *name, unsigned int *idx_r)
+{
+ unsigned int count, i;
+ const struct push_notification_driver *const *drivers;
+
+ drivers = array_get(&push_notification_drivers, &count);
+ for (i = 0; i < count; i++) {
+ if (strcasecmp(drivers[i]->name, name) == 0) {
+ *idx_r = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static const struct push_notification_driver *
+push_notification_driver_find_class(const char *driver)
+{
+ unsigned int idx;
+
+ if (!push_notification_driver_find(driver, &idx))
+ return NULL;
+
+ return array_idx_elem(&push_notification_drivers, idx);
+}
+
+static struct push_notification_driver_config *
+push_notification_driver_parse_config(const char *p)
+{
+ const char **args, *key, *p2, *value;
+ struct push_notification_driver_config *config;
+
+ config = t_new(struct push_notification_driver_config, 1);
+ config->raw_config = p;
+
+ hash_table_create(&config->config, unsafe_data_stack_pool, 0,
+ str_hash, strcmp);
+
+ if (p == NULL)
+ return config;
+
+ args = t_strsplit_spaces(p, " ");
+
+ for (; *args != NULL; args++) {
+ p2 = strchr(*args, '=');
+ if (p2 != NULL) {
+ key = t_strdup_until(*args, p2);
+ value = t_strdup(p2 + 1);
+ } else {
+ key = *args;
+ value = "";
+ }
+ hash_table_update(config->config, key, value);
+ }
+
+ return config;
+}
+
+int push_notification_driver_init(
+ struct mail_user *user, const char *config_in, pool_t pool,
+ struct push_notification_driver_user **duser_r)
+{
+ void *context = NULL;
+ const struct push_notification_driver *driver;
+ const char *driver_name, *error_r, *p;
+ struct push_notification_driver_user *duser;
+ int ret;
+
+ /* <driver>[:<driver config>] */
+ p = strchr(config_in, ':');
+ if (p == NULL)
+ driver_name = config_in;
+ else
+ driver_name = t_strdup_until(config_in, p);
+
+ driver = push_notification_driver_find_class(driver_name);
+ if (driver == NULL) {
+ i_error("Unknown push notification driver: %s", driver_name);
+ return -1;
+ }
+
+ if (driver->v.init != NULL) {
+ T_BEGIN {
+ struct push_notification_driver_config *config;
+
+ config = push_notification_driver_parse_config(
+ (p == NULL) ? p : p + 1);
+ ret = driver->v.init(config, user, pool,
+ &context, &error_r);
+ if (ret < 0)
+ i_error("%s: %s", driver_name, error_r);
+ hash_table_destroy(&config->config);
+ } T_END;
+
+ if (ret < 0)
+ return -1;
+ }
+
+ duser = p_new(pool, struct push_notification_driver_user, 1);
+ duser->context = context;
+ duser->driver = driver;
+
+ *duser_r = duser;
+
+ return 0;
+}
+
+void push_notification_driver_cleanup_all(void)
+{
+ const struct push_notification_driver *driver;
+
+ /* Loop through driver list and perform global cleanup tasks. We may not
+ have used all drivers in this plugin/worker, but the cleanup hooks
+ are designed to ignore these unused drivers. */
+ array_foreach_elem(&push_notification_drivers, driver) {
+ if (driver->v.cleanup != NULL)
+ driver->v.cleanup();
+ }
+}
+
+void ATTR_FORMAT(3, 4)
+push_notification_driver_debug(const char *label, struct mail_user *user,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ T_BEGIN {
+ va_start(args, fmt);
+ e_debug(user->event, "%s%s", label,
+ t_strdup_vprintf(fmt, args));
+ va_end(args);
+ } T_END;
+}
+
+void push_notification_driver_register(
+ const struct push_notification_driver *driver)
+{
+ unsigned int idx;
+
+ if (!array_is_created(&push_notification_drivers))
+ i_array_init(&push_notification_drivers, 4);
+
+ if (push_notification_driver_find(driver->name, &idx)) {
+ i_panic("push_notification_driver_register(%s): "
+ "duplicate driver", driver->name);
+ }
+
+ array_push_back(&push_notification_drivers, &driver);
+}
+
+void push_notification_driver_unregister(
+ const struct push_notification_driver *driver)
+{
+ unsigned int idx;
+
+ if (!push_notification_driver_find(driver->name, &idx)) {
+ i_panic("push_notification_driver_register(%s): "
+ "unknown driver", driver->name);
+ }
+
+ if (array_is_created(&push_notification_drivers)) {
+ array_delete(&push_notification_drivers, idx, 1);
+
+ if (array_is_empty(&push_notification_drivers))
+ array_free(&push_notification_drivers);
+ }
+}