fts-user.c revision f5e35763912e29c420a6977a211ae215ece3a8ab
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 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"
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila#include "fts-tokenizer.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;
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen int refcount;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_language_list *lang_list;
60ba197d17023594231d9805d889817782e41859Timo Sirainen struct fts_user_language *data_lang;
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen ARRAY_TYPE(fts_user_language) languages, data_languages;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen};
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(fts_user_module,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen &mail_user_module_register);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainenstatic const char *const *str_keyvalues_to_array(const char *str)
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen{
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen const char *key, *value, *const *keyvalues;
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen ARRAY_TYPE(const_string) arr;
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen unsigned int i;
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen if (str == NULL)
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen return NULL;
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen t_array_init(&arr, 8);
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen keyvalues = t_strsplit_spaces(str, " ");
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen for (i = 0; keyvalues[i] != NULL; i++) {
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen value = strchr(keyvalues[i], '=');
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen if (value != NULL)
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen key = t_strdup_until(keyvalues[i], value++);
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen else {
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen key = keyvalues[i];
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen value = "";
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen }
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen array_append(&arr, &key, 1);
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen array_append(&arr, &value, 1);
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen }
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen array_append_zero(&arr);
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen return array_idx(&arr, 0);
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen}
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstatic int
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainenfts_user_init_languages(struct mail_user *user, struct fts_user *fuser,
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen const char **error_r)
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) {
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen *error_r = "fts_languages setting is missing";
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen lang_config[1] = mail_user_plugin_getenv(user, "fts_language_config");
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (lang_config[1] != NULL)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen lang_config[0] = "fts_language_config";
a9b3887f4d9ed75a76fed964c1930432bf84f4f5Timo Sirainen if (fts_language_list_init(lang_config, &fuser->lang_list, error_r) < 0)
a9b3887f4d9ed75a76fed964c1930432bf84f4f5Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (!fts_language_list_add_names(fuser->lang_list, languages, &unknown)) {
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen *error_r = t_strdup_printf(
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen "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) {
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen *error_r = "fts_languages setting is empty";
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;
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen const char *str, *error, *set_key;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen unsigned int i;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen int ret = 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
57dc9669d34de7d08a44be9d7d3c9f6a0c34cc87Timo Sirainen /* try to get the language-specific filters first */
57dc9669d34de7d08a44be9d7d3c9f6a0c34cc87Timo 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) {
57dc9669d34de7d08a44be9d7d3c9f6a0c34cc87Timo Sirainen /* fallback to global filters */
57dc9669d34de7d08a44be9d7d3c9f6a0c34cc87Timo Sirainen filters_key = "fts_filters";
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen str = mail_user_plugin_getenv(user, filters_key);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (str == NULL) {
5455a917515f774fcaad35558f149536b796b531Teemu Huovila /* No filters */
5455a917515f774fcaad35558f149536b796b531Teemu Huovila *filter_r = NULL;
5455a917515f774fcaad35558f149536b796b531Teemu Huovila 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], '-', '_');
fe0dff63d6b53d22ae16ac53ab183e9355a64a32Timo Sirainen set_key = t_strdup_printf("fts_filter_%s_%s",
4c61d6b6ad6173f06563c2cee9bd813c59277dd2Timo Sirainen lang->name, filter_set_name);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen str = mail_user_plugin_getenv(user, set_key);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (str == NULL) {
fe0dff63d6b53d22ae16ac53ab183e9355a64a32Timo Sirainen set_key = t_strdup_printf("fts_filter_%s", filter_set_name);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen str = mail_user_plugin_getenv(user, set_key);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen if (fts_filter_create(filter_class, parent, lang,
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen str_keyvalues_to_array(str),
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen &filter, &error) < 0) {
fac865bad1ba10e85d80b63dedfd3493a65510d4Timo Sirainen *error_r = t_strdup_printf("%s: %s", 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
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovilastatic int
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovilafts_user_create_tokenizer(struct mail_user *user,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen const struct fts_language *lang,
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila struct fts_tokenizer **tokenizer_r, bool search,
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila const char **error_r)
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila{
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila const struct fts_tokenizer *tokenizer_class;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila struct fts_tokenizer *tokenizer = NULL, *parent = NULL;
957b0b4c9aeff7153bb9ebf91d8aea550bd07865Teemu Huovila const char *tokenizers_key, *const *tokenizers, *tokenizer_set_name;
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen const char *str, *error, *set_key;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila unsigned int i;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila int ret = 0;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen tokenizers_key = t_strconcat("fts_tokenizers_", lang->name, NULL);
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila str = mail_user_plugin_getenv(user, tokenizers_key);
5455a917515f774fcaad35558f149536b796b531Teemu Huovila if (str == NULL) {
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen str = mail_user_plugin_getenv(user, "fts_tokenizers");
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (str == NULL) {
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen *error_r = t_strdup_printf("%s or fts_tokenizers setting must exist", tokenizers_key);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen return -1;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen }
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen tokenizers_key = "fts_tokenizers";
5455a917515f774fcaad35558f149536b796b531Teemu Huovila }
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila tokenizers = t_strsplit_spaces(str, " ");
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila for (i = 0; tokenizers[i] != NULL; i++) {
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila tokenizer_class = fts_tokenizer_find(tokenizers[i]);
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila if (tokenizer_class == NULL) {
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila *error_r = t_strdup_printf("%s: Unknown tokenizer '%s'",
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila tokenizers_key, tokenizers[i]);
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila ret = -1;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila break;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila }
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
957b0b4c9aeff7153bb9ebf91d8aea550bd07865Teemu Huovila tokenizer_set_name = t_str_replace(tokenizers[i], '-', '_');
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen set_key = t_strdup_printf("fts_tokenizer_%s_%s", tokenizer_set_name, lang->name);
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila str = mail_user_plugin_getenv(user, set_key);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (str == NULL) {
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen set_key = t_strdup_printf("fts_tokenizer_%s", tokenizer_set_name);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen str = mail_user_plugin_getenv(user, set_key);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen }
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
0c827d2094e80ede4c089fc00260d7ffcc764636Timo Sirainen /* tell the tokenizers that we're tokenizing a search string
0c827d2094e80ede4c089fc00260d7ffcc764636Timo Sirainen (instead of tokenizing indexed data) */
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen if (search)
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen str = t_strconcat("search=yes ", str, NULL);
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen if (fts_tokenizer_create(tokenizer_class, parent,
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen str_keyvalues_to_array(str),
0ebeb1831a56e020b0958ed1ced50e86ee9347ecTimo Sirainen &tokenizer, &error) < 0) {
fac865bad1ba10e85d80b63dedfd3493a65510d4Timo Sirainen *error_r = t_strdup_printf("%s: %s", set_key, error);
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila ret = -1;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila break;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila }
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila if (parent != NULL)
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila fts_tokenizer_unref(&parent);
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila parent = tokenizer;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila }
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila if (ret < 0) {
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila if (parent != NULL)
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila fts_tokenizer_unref(&parent);
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila return -1;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila }
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila *tokenizer_r = tokenizer;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila return 0;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila}
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainenstatic int
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainenfts_user_language_init_tokenizers(struct mail_user *user,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen struct fts_user_language *user_lang,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen const char **error_r)
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila{
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (fts_user_create_tokenizer(user, user_lang->lang,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen &user_lang->index_tokenizer, FALSE,
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila error_r) < 0)
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila return -1;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (fts_user_create_tokenizer(user, user_lang->lang,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen &user_lang->search_tokenizer, TRUE,
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila error_r) < 0)
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila return -1;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila return 0;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila}
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovilastruct fts_user_language *
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovilafts_user_language_find(struct mail_user *user,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const struct fts_language *lang)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct fts_user_language *const *user_langp;
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila struct fts_user *fuser = FTS_USER_CONTEXT(user);
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila
084431105a179063aeb08f45eb5f506c61ea8602Aki Tuomi i_assert(fuser != NULL);
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
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovilastatic int fts_user_language_create(struct mail_user *user,
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila struct fts_user *fuser,
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila const struct fts_language *lang,
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila const char **error_r)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila struct fts_user_language *user_lang;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen user_lang = p_new(user->pool, struct fts_user_language, 1);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen user_lang->lang = lang;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_append(&fuser->languages, &user_lang, 1);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (fts_user_language_init_tokenizers(user, user_lang, error_r) < 0)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen return -1;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (fts_user_create_filters(user, lang, &user_lang->filter, error_r) < 0)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovilastatic int fts_user_languages_fill_all(struct mail_user *user,
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila struct fts_user *fuser,
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila const char **error_r)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const struct fts_language *const *langp;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_foreach(fts_language_list_get_all(fuser->lang_list), langp) {
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila if (fts_user_language_create(user, fuser, *langp, error_r) < 0)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainenstatic int
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainenfts_user_init_data_language(struct mail_user *user, struct fts_user *fuser,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen const char **error_r)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen{
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen struct fts_user_language *user_lang;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen const char *error;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen user_lang = p_new(user->pool, struct fts_user_language, 1);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen user_lang->lang = &fts_language_data;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (fts_user_language_init_tokenizers(user, user_lang, error_r) < 0)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen return -1;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (fts_filter_create(fts_filter_lowercase, NULL, user_lang->lang, NULL,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen &user_lang->filter, &error) < 0)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen i_unreached();
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen i_assert(user_lang->filter != NULL);
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen p_array_init(&fuser->data_languages, user->pool, 1);
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen array_append(&fuser->data_languages, &user_lang, 1);
f5e35763912e29c420a6977a211ae215ece3a8abTimo Sirainen array_append(&fuser->languages, &user_lang, 1);
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen fuser->data_lang = user_lang;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen return 0;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen}
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo 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
084431105a179063aeb08f45eb5f506c61ea8602Aki Tuomi i_assert(fuser != NULL);
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
084431105a179063aeb08f45eb5f506c61ea8602Aki Tuomi i_assert(fuser != NULL);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return &fuser->languages;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainenconst ARRAY_TYPE(fts_user_language) *
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainenfts_user_get_data_languages(struct mail_user *user)
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen{
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen struct fts_user *fuser = FTS_USER_CONTEXT(user);
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen
084431105a179063aeb08f45eb5f506c61ea8602Aki Tuomi i_assert(fuser != NULL);
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen return &fuser->data_languages;
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen}
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen
60ba197d17023594231d9805d889817782e41859Timo Sirainenstruct fts_user_language *fts_user_get_data_lang(struct mail_user *user)
60ba197d17023594231d9805d889817782e41859Timo Sirainen{
60ba197d17023594231d9805d889817782e41859Timo Sirainen struct fts_user *fuser = FTS_USER_CONTEXT(user);
60ba197d17023594231d9805d889817782e41859Timo Sirainen
084431105a179063aeb08f45eb5f506c61ea8602Aki Tuomi i_assert(fuser != NULL);
60ba197d17023594231d9805d889817782e41859Timo Sirainen return fuser->data_lang;
60ba197d17023594231d9805d889817782e41859Timo Sirainen}
60ba197d17023594231d9805d889817782e41859Timo Sirainen
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainenstatic void fts_user_language_free(struct fts_user_language *user_lang)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen{
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (user_lang->filter != NULL)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen fts_filter_unref(&user_lang->filter);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (user_lang->index_tokenizer != NULL)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen fts_tokenizer_unref(&user_lang->index_tokenizer);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (user_lang->search_tokenizer != NULL)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen fts_tokenizer_unref(&user_lang->search_tokenizer);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen}
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo 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
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen array_foreach(&fuser->languages, user_langp)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen fts_user_language_free(*user_langp);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainenint fts_mail_user_init(struct mail_user *user, const char **error_r)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen struct fts_user *fuser = FTS_USER_CONTEXT(user);
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen if (fuser != NULL) {
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen /* multiple fts plugins are loaded */
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen fuser->refcount++;
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen return 0;
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fuser = p_new(user->pool, struct fts_user, 1);
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen fuser->refcount = 1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen p_array_init(&fuser->languages, user->pool, 4);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (fts_user_init_languages(user, fuser, error_r) < 0 ||
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen fts_user_init_data_language(user, fuser, error_r) < 0) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen fts_user_free(fuser);
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (fts_user_languages_fill_all(user, fuser, error_r) < 0) {
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila fts_user_free(fuser);
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila return -1;
09aed882b99e865ff6d7140ae2f77a42c9e7d1a7Teemu Huovila }
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen MODULE_CONTEXT_SET(user, fts_user_module, fuser);
4ba3717a04823875c2a1d60ff9dc8177ae033d12Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainenvoid fts_mail_user_deinit(struct mail_user *user)
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen{
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen struct fts_user *fuser = FTS_USER_CONTEXT(user);
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen if (fuser != NULL) {
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen i_assert(fuser->refcount > 0);
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen if (--fuser->refcount == 0)
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen fts_user_free(fuser);
6634e45500e81cfa36932203ee69c81745efd3e6Timo Sirainen }
eeb03434472130f9631f164440566fd8d09e6380Timo Sirainen}