fts-user.c revision 4c61d6b6ad6173f06563c2cee9bd813c59277dd2
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "lib.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "module-context.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "mail-user.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "fts-language.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "fts-filter.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "fts-user.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#define FTS_USER_CONTEXT(obj) \
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen MODULE_CONTEXT(obj, fts_user_module)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstruct fts_user {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen union mail_user_module_context module_ctx;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_language_list *lang_list;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen ARRAY_TYPE(fts_user_language) languages;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen};
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(fts_user_module,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen &mail_user_module_register);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstatic int
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenfts_user_init_languages(struct mail_user *user, struct fts_user *fuser)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const char *languages, *unknown;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const char *lang_config[3] = {NULL, NULL, NULL};
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen languages = mail_user_plugin_getenv(user, "fts_languages");
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (languages == NULL) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen i_error("fts-dovecot: fts_languages setting is missing - disabling");
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen lang_config[1] = mail_user_plugin_getenv(user, "fts_language_config");
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fuser->lang_list = fts_language_list_init(lang_config);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (lang_config[1] != NULL)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen lang_config[0] = "fts_language_config";
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (!fts_language_list_add_names(fuser->lang_list, languages, &unknown)) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen i_error("fts_languages: Unknown language '%s'", unknown);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (array_count(fts_language_list_get_all(fuser->lang_list)) == 0) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen i_error("fts-dovecot: fts_languages setting is empty - disabling");
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstatic int
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenfts_user_create_filters(struct mail_user *user, const struct fts_language *lang,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_filter **filter_r, const char **error_r)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const struct fts_filter *filter_class;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_filter *filter = NULL, *parent = NULL;
4c61d6b6ad6173f06563c2cee9bd813c59277dd2Timo Sirainen const char *filters_key, *const *filters, *filter_set_name;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const char *str, *error, *set_key, *const *settings;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen unsigned int i;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen int ret = 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen filters_key = "fts_filters";
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen str = mail_user_plugin_getenv(user, filters_key);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (str == NULL) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen filters_key = t_strconcat("fts_filters_", lang->name, NULL);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen str = mail_user_plugin_getenv(user, filters_key);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (str == NULL) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen *filter_r = NULL;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen filters = t_strsplit_spaces(str, " ");
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen for (i = 0; filters[i] != NULL; i++) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen filter_class = fts_filter_find(filters[i]);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (filter_class == NULL) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen *error_r = t_strdup_printf("%s: Unknown filter '%s'",
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen filters_key, filters[i]);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen ret = -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen break;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen /* try the language-specific setting first */
4c61d6b6ad6173f06563c2cee9bd813c59277dd2Timo Sirainen filter_set_name = t_str_replace(filters[i], '-', '_');
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen set_key = t_strdup_printf("fts_filters_%s_%s",
4c61d6b6ad6173f06563c2cee9bd813c59277dd2Timo Sirainen lang->name, filter_set_name);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen str = mail_user_plugin_getenv(user, set_key);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (str == NULL) {
4c61d6b6ad6173f06563c2cee9bd813c59277dd2Timo Sirainen set_key = t_strdup_printf("fts_filters_%s", filter_set_name);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen str = mail_user_plugin_getenv(user, set_key);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen settings = str == NULL ? NULL : t_strsplit_spaces(str, " ");
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (fts_filter_create(filter_class, parent, lang, settings,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen &filter, &error) < 0) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen *error_r = t_strdup_printf(
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen "Filter '%s' init via settings '%s' failed: %s",
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen filters[i], set_key, error);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen ret = -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen break;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (parent != NULL)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fts_filter_unref(&parent);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen parent = filter;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (ret < 0) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (parent != NULL)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fts_filter_unref(&parent);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen *filter_r = filter;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstatic struct fts_user_language *
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenfts_user_language_find(struct fts_user *fuser,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const struct fts_language *lang)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user_language *const *user_langp;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_foreach(&fuser->languages, user_langp) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (strcmp((*user_langp)->lang->name, lang->name) == 0)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return *user_langp;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return NULL;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenint fts_user_language_get(struct mail_user *user,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const struct fts_language *lang,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user_language **user_lang_r,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const char **error_r)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user *fuser = FTS_USER_CONTEXT(user);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user_language *user_lang;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_filter *filter;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen *user_lang_r = fts_user_language_find(fuser, lang);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (*user_lang_r != NULL)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (fts_user_create_filters(user, lang, &filter, error_r) < 0)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen user_lang = p_new(user->pool, struct fts_user_language, 1);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen user_lang->lang = lang;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen user_lang->filter = filter;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_append(&fuser->languages, &user_lang, 1);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen *user_lang_r = user_lang;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenint fts_user_languages_fill_all(struct mail_user *user, const char **error_r)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user *fuser = FTS_USER_CONTEXT(user);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const struct fts_language *const *langp;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user_language *user_lang;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_foreach(fts_language_list_get_all(fuser->lang_list), langp) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (fts_user_language_get(user, *langp, &user_lang, error_r) < 0)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstruct fts_language_list *fts_user_get_language_list(struct mail_user *user)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user *fuser = FTS_USER_CONTEXT(user);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return fuser->lang_list;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenconst ARRAY_TYPE(fts_user_language) *
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenfts_user_get_all_languages(struct mail_user *user)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user *fuser = FTS_USER_CONTEXT(user);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return &fuser->languages;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstatic void fts_user_free(struct fts_user *fuser)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user_language *const *user_langp;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (fuser->lang_list != NULL)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fts_language_list_deinit(&fuser->lang_list);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_foreach(&fuser->languages, user_langp) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if ((*user_langp)->filter != NULL)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fts_filter_unref(&(*user_langp)->filter);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstatic void fts_mail_user_deinit(struct mail_user *user)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user *fuser = FTS_USER_CONTEXT(user);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fts_user_free(fuser);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fuser->module_ctx.super.deinit(user);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenvoid fts_mail_user_created(struct mail_user *user)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct mail_user_vfuncs *v = user->vlast;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user *fuser;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fuser = p_new(user->pool, struct fts_user, 1);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen p_array_init(&fuser->languages, user->pool, 4);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (fts_user_init_languages(user, fuser) < 0) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fts_user_free(fuser);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fuser->module_ctx.super = *v;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen user->vlast = &fuser->module_ctx.super;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen v->deinit = fts_mail_user_deinit;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen MODULE_CONTEXT_SET(user, fts_user_module, fuser);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}