/* 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; /* [:] */ 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); } }