From: Karl Fleischmann Date: Thu, 7 Sep 2023 11:35:58 +0000 (+0200) Subject: plugins/push-notification: Rewrite push notification driver config initialization X-Git-Tag: 2.4.1~1353 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2d5f85e0ab367efbbd985410288bc8389e5c44c3;p=thirdparty%2Fdovecot%2Fcore.git plugins/push-notification: Rewrite push notification driver config initialization Replace the old config lookup mechanism - a per-driver parsing of a settings-string and a subsequent creation of a config hash-map - with a new settings-based mechanism. This way each driver can now access its native settings directly. For this to work the driver identification and initialization needs to be adapted, as well. --- diff --git a/src/plugins/push-notification/push-notification-driver-dlog.c b/src/plugins/push-notification/push-notification-driver-dlog.c index 256340c70f..4063177551 100644 --- a/src/plugins/push-notification/push-notification-driver-dlog.c +++ b/src/plugins/push-notification/push-notification-driver-dlog.c @@ -2,11 +2,13 @@ #include "lib.h" #include "array.h" +#include "settings.h" #include "mail-storage-private.h" #include "push-notification-plugin.h" #include "push-notification-drivers.h" #include "push-notification-events.h" +#include "push-notification-settings.h" #include "push-notification-txn-mbox.h" #include "push-notification-txn-msg.h" @@ -31,23 +33,16 @@ static struct event *create_dlog_event(struct event *parent) static int push_notification_driver_dlog_init( - struct push_notification_driver_config *config, - struct mail_user *user, pool_t pool, - void **context, const char **error_r ATTR_UNUSED) + struct mail_user *user, pool_t pool, ATTR_UNUSED const char *name, + void **context_r, ATTR_UNUSED const char **error_r) { struct event *log_event = create_dlog_event(user->event); struct dlog_push_notification_txn_context *ctx = p_new( pool, struct dlog_push_notification_txn_context, 1); ctx->event = log_event; - *context = ctx; + *context_r = ctx; e_debug(log_event, "Called init push_notification plugin hook."); - if (config->raw_config != NULL) { - e_debug(log_event, - "Config string for dlog push_notification driver: %s", - config->raw_config); - } - return 0; } diff --git a/src/plugins/push-notification/push-notification-driver-lua.c b/src/plugins/push-notification/push-notification-driver-lua.c index 8cc4cf46dc..8d536da3a3 100644 --- a/src/plugins/push-notification/push-notification-driver-lua.c +++ b/src/plugins/push-notification/push-notification-driver-lua.c @@ -7,6 +7,7 @@ #include "hash.h" #include "dlua-script.h" #include "dlua-script-private.h" +#include "settings.h" #include "mail-storage.h" #include "mail-user.h" @@ -17,6 +18,7 @@ #include "push-notification-drivers.h" #include "push-notification-events.h" #include "push-notification-event-message-common.h" +#include "push-notification-settings.h" #include "push-notification-txn-mbox.h" #include "push-notification-txn-msg.h" @@ -71,18 +73,26 @@ static const char *push_notification_driver_lua_to_fn(const char *evname); static int push_notification_driver_lua_init( - struct push_notification_driver_config *config, struct mail_user *user, - pool_t pool, void **context, const char **error_r) + struct mail_user *user, pool_t pool, const char *name, + void **context, const char **error_r) { struct dlua_push_notification_context *ctx; const char *path; + struct push_notification_lua_settings *lua_settings; + if (settings_get_filter(user->event, PUSH_NOTIFICATION_SETTINGS_FILTER_NAME, + name, &push_notification_lua_setting_parser_info, + 0, &lua_settings, error_r) < 0) + return -1; + struct event *event = event_create(user->event); event_add_category(event, push_notification_get_event_category()); event_set_append_log_prefix(event, "lua: "); if ((path = mail_user_plugin_getenv(user, DLUA_LOG_USERENV_KEY)) == NULL) - path = hash_table_lookup(config->config, (const char *)"path"); + path = t_strdup(lua_settings->path); + + settings_free(lua_settings); if (path == NULL) { struct dlua_script *script; diff --git a/src/plugins/push-notification/push-notification-driver-ox.c b/src/plugins/push-notification/push-notification-driver-ox.c index 8e88ad6037..82c75c359d 100644 --- a/src/plugins/push-notification/push-notification-driver-ox.c +++ b/src/plugins/push-notification/push-notification-driver-ox.c @@ -10,11 +10,14 @@ #include "json-ostream.h" #include "mailbox-attribute.h" #include "mail-storage-private.h" +#include "settings.h" #include "str.h" #include "strescape.h" +#include "strnum.h" #include "str-parse.h" #include "iostream-ssl.h" +#include "push-notification-settings.h" #include "push-notification-plugin.h" #include "push-notification-drivers.h" #include "push-notification-event-messagenew.h" @@ -28,7 +31,6 @@ /* Default values. */ static const char *const default_events[] = { "MessageNew", NULL }; static const char *const default_mboxes[] = { "INBOX", NULL }; -#define DEFAULT_CACHE_LIFETIME_SECS 60 /* This is data that is shared by all plugin users. */ struct push_notification_driver_ox_global { @@ -70,53 +72,46 @@ push_notification_driver_ox_init_global(struct mail_user *user) { } static int -push_notification_driver_ox_init(struct push_notification_driver_config *config, - struct mail_user *user, pool_t pool, - void **context, const char **error_r) +push_notification_driver_ox_init(struct mail_user *user, pool_t pool, + const char *name, void **context, + const char **error_r) { struct push_notification_driver_ox_config *dconfig; - const char *error, *tmp; - /* Valid config keys: cache_lifetime, url */ - tmp = hash_table_lookup(config->config, (const char *)"url"); - if (tmp == NULL) { - *error_r = "Driver requires the url parameter"; + struct push_notification_ox_settings *ox_settings; + if (settings_get_filter(user->event, PUSH_NOTIFICATION_SETTINGS_FILTER_NAME, + name, &push_notification_ox_setting_parser_info, + 0, &ox_settings, error_r) < 0) return -1; - } dconfig = p_new(pool, struct push_notification_driver_ox_config, 1); dconfig->event = event_create(user->event); event_add_category(dconfig->event, &event_category_push_notification); event_set_append_log_prefix(dconfig->event, "push-notification-ox: "); - if (http_url_parse(tmp, NULL, HTTP_URL_ALLOW_USERINFO_PART, pool, - &dconfig->http_url, &error) < 0) { - event_unref(&dconfig->event); - *error_r = t_strdup_printf("Failed to parse OX REST URL %s: %s", - tmp, error); - return -1; - } - dconfig->use_unsafe_username = - hash_table_lookup(config->config, - (const char *)"user_from_metadata") != NULL; - - e_debug(dconfig->event, "Using URL %s", tmp); - - tmp = hash_table_lookup(config->config, (const char *)"cache_lifetime"); - if (tmp == NULL) { - dconfig->cached_ox_metadata_lifetime_secs = - DEFAULT_CACHE_LIFETIME_SECS; - } else if (str_parse_get_interval( - tmp, &dconfig->cached_ox_metadata_lifetime_secs, &error) < 0) { - event_unref(&dconfig->event); - *error_r = t_strdup_printf( - "Failed to parse OX cache_lifetime %s: %s", tmp, error); - return -1; + /* The settings check is deliberately only validating a url if it is + given in the settings. Otherwise any file that does not contain + push-notification specific settings would fail the validation. + Thus we need to check here, whether the parsed url exists. */ + if (ox_settings->parsed_url == NULL) { + *error_r = "push_notification_ox_url is missing or empty"; + event_unref(&dconfig->event); + settings_free(ox_settings); + return -1; } + + dconfig->http_url = http_url_clone_with_userinfo(pool, ox_settings->parsed_url); + e_debug(dconfig->event, "Using URL %s", + http_url_create(dconfig->http_url)); + dconfig->cached_ox_metadata_lifetime_secs = ox_settings->cache_ttl; e_debug(dconfig->event, "Using cache lifetime: %u", dconfig->cached_ox_metadata_lifetime_secs); + dconfig->use_unsafe_username = ox_settings->user_from_metadata; + e_debug(dconfig->event, "Using user %s", + dconfig->use_unsafe_username ? "stored in METADATA" : "sent by OX endpoint"); + if (ox_global == NULL) { ox_global = i_new(struct push_notification_driver_ox_global, 1); ox_global->refcount = 0; @@ -125,6 +120,7 @@ push_notification_driver_ox_init(struct push_notification_driver_config *config, ++ox_global->refcount; *context = dconfig; + settings_free(ox_settings); return 0; } diff --git a/src/plugins/push-notification/push-notification-drivers.c b/src/plugins/push-notification/push-notification-drivers.c index 175ac74f09..d3ec7028fb 100644 --- a/src/plugins/push-notification/push-notification-drivers.c +++ b/src/plugins/push-notification/push-notification-drivers.c @@ -4,9 +4,11 @@ #include "array.h" #include "hash.h" #include "mail-user.h" +#include "settings.h" #include "push-notification-drivers.h" #include "push-notification-events.h" +#include "push-notification-settings.h" static ARRAY(const struct push_notification_driver *) push_notification_drivers; @@ -27,47 +29,29 @@ push_notification_driver_find(const char *name, unsigned int *idx_r) return FALSE; } -static const struct push_notification_driver * -push_notification_driver_find_class(const char *driver) +static bool +push_notification_driver_identify(struct mail_user *user, const char *name, + const struct push_notification_driver **driver_r, + const char **error_r) { + struct push_notification_settings *set; 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); + if (settings_get_filter(user->event, PUSH_NOTIFICATION_SETTINGS_FILTER_NAME, + name, &push_notification_setting_parser_info, + 0, &set, error_r) < 0) + return FALSE; + + bool ret = FALSE; + if (push_notification_driver_find(set->driver, &idx)) { + *driver_r = array_idx_elem(&push_notification_drivers, idx); + ret = TRUE; } + settings_free(set); - return config; + if (!ret) + *error_r = "Name does not match any registered drivers"; + + return ret; } int push_notification_driver_init( @@ -76,40 +60,30 @@ int push_notification_driver_init( { void *context = NULL; const struct push_notification_driver *driver; - const char *driver_name, *error_r, *p; + const char *error; 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) { + bool found_driver = push_notification_driver_identify(user, config_in, + &driver, &error); + if (!found_driver) { e_error(user->event, - "Unknown push notification driver: %s", driver_name); + "Unable to identify push notification driver '%s': %s", + config_in, error); 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) - e_error(user->event, "%s: %s", - driver_name, error_r); - hash_table_destroy(&config->config); - } T_END; - - if (ret < 0) + ret = driver->v.init(user, pool, config_in, &context, + &error); + } T_END_PASS_STR_IF(ret < 0, &error); + + if (ret < 0) { + e_error(user->event, "%s: %s", driver->name, + error); return -1; + } } duser = p_new(pool, struct push_notification_driver_user, 1); diff --git a/src/plugins/push-notification/push-notification-drivers.h b/src/plugins/push-notification/push-notification-drivers.h index 07b570fac5..67d17c0fb5 100644 --- a/src/plugins/push-notification/push-notification-drivers.h +++ b/src/plugins/push-notification/push-notification-drivers.h @@ -7,7 +7,6 @@ #include "push-notification-triggers.h" struct mail_user; -struct push_notification_driver_config; struct push_notification_driver_txn; struct push_notification_driver_user; struct push_notification_txn_mbox; @@ -18,12 +17,11 @@ HASH_TABLE_DEFINE_TYPE(push_notification_msgs, void *, struct push_notification_txn_msg *); struct push_notification_driver_vfuncs { - /* Init driver. Config (from plugin configuration) is parsed once (no - user variable substitutions). Return 0 on success, or -1 if this - driver should be disabled (or on error). */ - int (*init)(struct push_notification_driver_config *config, - struct mail_user *user, pool_t pool, void **context, - const char **error_r); + /* Init driver. Config should be read from settings via the name + parameter. Return 0 on success, or -1 if this driver should be + disabled (or on error). */ + int (*init)(struct mail_user *user, pool_t pool, const char *name, + void **context, const char **error_r); /* Called at the beginning of a notification transaction. Return TRUE on success, or FALSE if this driver should be ignored for this transaction. */ @@ -48,11 +46,6 @@ struct push_notification_driver { struct push_notification_driver_vfuncs v; }; -struct push_notification_driver_config { - HASH_TABLE_TYPE(push_notification_config) config; - const char *raw_config; -}; - struct push_notification_driver_user { const struct push_notification_driver *driver; void *context; diff --git a/src/plugins/push-notification/push-notification-plugin.c b/src/plugins/push-notification/push-notification-plugin.c index 75fcfc7f77..6b12e29989 100644 --- a/src/plugins/push-notification/push-notification-plugin.c +++ b/src/plugins/push-notification/push-notification-plugin.c @@ -7,17 +7,18 @@ #include "mail-storage.h" #include "mail-storage-private.h" #include "notify-plugin.h" +#include "settings.h" #include "str.h" #include "push-notification-drivers.h" #include "push-notification-events.h" #include "push-notification-events-rfc5423.h" +#include "push-notification-settings.h" #include "push-notification-plugin.h" #include "push-notification-triggers.h" #include "push-notification-txn-mbox.h" #include "push-notification-txn-msg.h" -#define PUSH_NOTIFICATION_CONFIG "push_notification_driver" #define PUSH_NOTIFICATION_EVENT_FINISHED "push_notification_finished" #define PUSH_NOTIFICATION_USER_CONTEXT(obj) \ @@ -248,32 +249,33 @@ static void push_notification_transaction_rollback(void *txn) } static void -push_notification_config_init(const char *config_name, struct mail_user *user, +push_notification_config_init(struct mail_user *user, struct push_notification_driver_list *dlist) { + const struct push_notification_settings *set; struct push_notification_driver_user *duser; - const char *env; - unsigned int i; - string_t *root_name; + const char *error, *name; - root_name = t_str_new(32); - str_append(root_name, config_name); - - for (i = 2;; i++) { - env = mail_user_plugin_getenv(user, str_c(root_name)); - if ((env == NULL) || (*env == '\0')) - break; + if (settings_get(user->event, &push_notification_setting_parser_info, + 0, &set, &error) < 0) { + e_error(user->event, "Failed to get push_notification settings: %s", + error); + return; + } - if (push_notification_driver_init( - user, env, user->pool, &duser) < 0) - break; + if (array_is_created(&set->push_notifications)) { + array_foreach_elem(&set->push_notifications, name) { + if (push_notification_driver_init( + user, name, user->pool, + &duser) < 0) + break; - /* Add driver. */ - array_push_back(&dlist->drivers, &duser); + /* Add driver. */ + array_push_back(&dlist->drivers, &duser); + } - str_truncate(root_name, strlen(config_name)); - str_printfa(root_name, "%d", i); } + settings_free(set); } static struct push_notification_driver_list * @@ -284,7 +286,7 @@ push_notification_driver_list_init(struct mail_user *user) dlist = p_new(user->pool, struct push_notification_driver_list, 1); p_array_init(&dlist->drivers, user->pool, 4); - push_notification_config_init(PUSH_NOTIFICATION_CONFIG, user, dlist); + push_notification_config_init(user, dlist); return dlist; }