1 /* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "array.h"
5 #include "str.h"
6 #include "fts-language.h"
7 #include "fts-filter-private.h"
8
9 #ifdef HAVE_LIBICU
10 # include "fts-icu.h"
11 #endif
12
13 static ARRAY(const struct fts_filter *) fts_filter_classes;
14
fts_filters_init(void)15 void fts_filters_init(void)
16 {
17 i_array_init(&fts_filter_classes, FTS_FILTER_CLASSES_NR);
18
19 fts_filter_register(fts_filter_stopwords);
20 fts_filter_register(fts_filter_stemmer_snowball);
21 fts_filter_register(fts_filter_normalizer_icu);
22 fts_filter_register(fts_filter_lowercase);
23 fts_filter_register(fts_filter_english_possessive);
24 fts_filter_register(fts_filter_contractions);
25 }
26
fts_filters_deinit(void)27 void fts_filters_deinit(void)
28 {
29 #ifdef HAVE_LIBICU
30 fts_icu_deinit();
31 #endif
32 array_free(&fts_filter_classes);
33 }
34
fts_filter_register(const struct fts_filter * filter_class)35 void fts_filter_register(const struct fts_filter *filter_class)
36 {
37 i_assert(fts_filter_find(filter_class->class_name) == NULL);
38
39 array_push_back(&fts_filter_classes, &filter_class);
40 }
41
fts_filter_find(const char * name)42 const struct fts_filter *fts_filter_find(const char *name)
43 {
44 const struct fts_filter *filter;
45
46 array_foreach_elem(&fts_filter_classes, filter) {
47 if (strcmp(filter->class_name, name) == 0)
48 return filter;
49 }
50 return NULL;
51 }
52
fts_filter_create(const struct fts_filter * filter_class,struct fts_filter * parent,const struct fts_language * lang,const char * const * settings,struct fts_filter ** filter_r,const char ** error_r)53 int fts_filter_create(const struct fts_filter *filter_class,
54 struct fts_filter *parent,
55 const struct fts_language *lang,
56 const char *const *settings,
57 struct fts_filter **filter_r,
58 const char **error_r)
59 {
60 struct fts_filter *fp;
61 const char *empty_settings = NULL;
62
63 i_assert(settings == NULL || str_array_length(settings) % 2 == 0);
64
65 if (settings == NULL)
66 settings = &empty_settings;
67
68 if (filter_class->v.create != NULL) {
69 if (filter_class->v.create(lang, settings, &fp, error_r) < 0) {
70 *filter_r = NULL;
71 return -1;
72 }
73 } else {
74 /* default implementation */
75 if (settings[0] != NULL) {
76 *error_r = t_strdup_printf("Unknown setting: %s", settings[0]);
77 return -1;
78 }
79 fp = i_new(struct fts_filter, 1);
80 *fp = *filter_class;
81 }
82 fp->refcount = 1;
83 fp->parent = parent;
84 if (parent != NULL) {
85 fts_filter_ref(parent);
86 }
87 *filter_r = fp;
88 return 0;
89 }
fts_filter_ref(struct fts_filter * fp)90 void fts_filter_ref(struct fts_filter *fp)
91 {
92 i_assert(fp->refcount > 0);
93
94 fp->refcount++;
95 }
96
fts_filter_unref(struct fts_filter ** _fpp)97 void fts_filter_unref(struct fts_filter **_fpp)
98 {
99 struct fts_filter *fp = *_fpp;
100
101 i_assert(fp->refcount > 0);
102 *_fpp = NULL;
103
104 if (--fp->refcount > 0)
105 return;
106
107 if (fp->parent != NULL)
108 fts_filter_unref(&fp->parent);
109 if (fp->v.destroy != NULL)
110 fp->v.destroy(fp);
111 else {
112 /* default destroy implementation */
113 str_free(&fp->token);
114 i_free(fp);
115 }
116 }
117
fts_filter_filter(struct fts_filter * filter,const char ** token,const char ** error_r)118 int fts_filter_filter(struct fts_filter *filter, const char **token,
119 const char **error_r)
120 {
121 int ret = 0;
122
123 i_assert((*token)[0] != '\0');
124
125 /* Recurse to parent. */
126 if (filter->parent != NULL)
127 ret = fts_filter_filter(filter->parent, token, error_r);
128
129 /* Parent returned token or no parent. */
130 if (ret > 0 || filter->parent == NULL)
131 ret = filter->v.filter(filter, token, error_r);
132
133 if (ret <= 0)
134 *token = NULL;
135 else {
136 i_assert(*token != NULL);
137 i_assert((*token)[0] != '\0');
138 }
139 return ret;
140 }
141