pfix-srsd: add a -I option
[apps/pfixtools.git] / postlicyd / filter.h
1 /******************************************************************************/
2 /*          pfixtools: a collection of postfix related tools                  */
3 /*          ~~~~~~~~~                                                         */
4 /*  ________________________________________________________________________  */
5 /*                                                                            */
6 /*  Redistribution and use in source and binary forms, with or without        */
7 /*  modification, are permitted provided that the following conditions        */
8 /*  are met:                                                                  */
9 /*                                                                            */
10 /*  1. Redistributions of source code must retain the above copyright         */
11 /*     notice, this list of conditions and the following disclaimer.          */
12 /*  2. Redistributions in binary form must reproduce the above copyright      */
13 /*     notice, this list of conditions and the following disclaimer in the    */
14 /*     documentation and/or other materials provided with the distribution.   */
15 /*  3. The names of its contributors may not be used to endorse or promote    */
16 /*     products derived from this software without specific prior written     */
17 /*     permission.                                                            */
18 /*                                                                            */
19 /*  THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS   */
20 /*  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED         */
21 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE    */
22 /*  DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY         */
23 /*  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        */
24 /*  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS   */
25 /*  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)     */
26 /*  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,       */
27 /*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN  */
28 /*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
29 /*  POSSIBILITY OF SUCH DAMAGE.                                               */
30 /*                                                                            */
31 /*   Copyright (c) 2006-2008 the Authors                                      */
32 /*   see AUTHORS and source files for details                                 */
33 /******************************************************************************/
34
35 /*
36  * Copyright © 2008 Florent Bruneau
37  */
38
39 #ifndef PFIXTOOLS_FILTER_H
40 #define PFIXTOOLS_FILTER_H
41
42 #include "common.h"
43 #include "filter_tokens.h"
44 #include "hook_tokens.h"
45 #include "param_tokens.h"
46 #include "query.h"
47 #include "array.h"
48
49
50 typedef filter_token filter_type_t;
51 typedef hook_token   filter_result_t;
52 typedef param_token  filter_param_id_t;
53
54 typedef struct filter_hook_t {
55     filter_result_t type;
56     char *value;
57
58     int counter;
59     int cost;
60
61     unsigned postfix:1;
62     unsigned async:1;
63     int filter_id;
64
65 } filter_hook_t;
66 ARRAY(filter_hook_t)
67
68 typedef struct filter_param_t {
69     filter_param_id_t type;
70     char  *value;
71     int    value_len;
72 } filter_param_t;
73 ARRAY(filter_param_t)
74
75 /** Description of a filter.
76  */
77 typedef struct filter_t {
78     char *name;
79     filter_type_t type;
80
81     A(filter_hook_t)   hooks;
82     void *data;
83
84     A(filter_param_t) params;
85
86     /* Loop checking flags.
87      */
88     int last_seen;
89 } filter_t;
90 ARRAY(filter_t)
91
92 #define MAX_COUNTERS (64)
93
94 /** Context of the query. To be filled with data to use when
95  * performing asynchronous filtering.
96  */
97 typedef struct filter_context_t {
98     /* filter context
99      */
100     const filter_t *current_filter;
101     void *contexts[FTK_count];
102
103     /* message context
104      */
105     char instance[64];
106     uint32_t counters[MAX_COUNTERS];
107
108     /* connection context
109      */
110     void *data;
111 } filter_context_t;
112
113
114 #define FILTER_INIT { NULL, FTK_UNKNOWN, ARRAY_INIT, NULL, ARRAY_INIT, -1 }
115 #define CHECK_FILTER(Filter)                                                   \
116     assert(Filter != FTK_UNKNOWN && Filter != FTK_count                        \
117            && "Unknown filter type")
118 #define CHECK_HOOK(Hook)                                                       \
119     assert(Hook != HTK_UNKNOWN && Hook != HTK_count                            \
120            && "Unknown hook")
121 #define CHECK_PARAM(Param)                                                     \
122     assert(Param != ATK_UNKNOWN && Param != ATK_count                          \
123            && "Unknown param")
124
125
126 /* Callback to be implemented by a filter.
127  */
128
129 typedef filter_result_t (*filter_runner_t)(const filter_t *filter,
130                                            const query_t *query,
131                                            filter_context_t *context);
132 typedef bool (*filter_constructor_t)(filter_t *filter);
133 typedef void (*filter_destructor_t)(filter_t *filter);
134
135 typedef void *(*filter_context_constructor_t)(void);
136 typedef void (*filter_context_destructor_t)(void*);
137
138 typedef void (*filter_async_handler_t)(filter_context_t *context,
139                                        const filter_hook_t *result);
140
141 /** Number of filter currently running.
142  */
143 extern uint32_t filter_running;
144
145 /* Registration.
146  */
147
148 __attribute__((nonnull(1,4)))
149 filter_type_t filter_register(const char *type, filter_constructor_t constructor,
150                               filter_destructor_t destructor, filter_runner_t runner,
151                               filter_context_constructor_t context_constructor,
152                               filter_context_destructor_t context_destructor);
153
154 __attribute__((nonnull(2)))
155 filter_result_t filter_hook_register(filter_type_t filter, const char *name);
156
157 __attribute__((nonnull(2)))
158 filter_param_id_t filter_param_register(filter_type_t filter, const char *name);
159
160 __attribute__((nonnull))
161 void filter_async_handler_register(filter_async_handler_t handler);
162
163 /* Filter builder.
164  */
165
166 __attribute__((nonnull(1)))
167 static inline void filter_init(filter_t *filter)
168 {
169     const filter_t f = FILTER_INIT;
170     *filter = f;
171 }
172
173 __attribute__((nonnull(1,2)))
174 void filter_set_name(filter_t *filter, const char *name, int len);
175
176 __attribute__((nonnull(1,2)))
177 bool filter_set_type(filter_t *filter, const char *type, int len);
178
179 __attribute__((nonnull(1,2,4)))
180 bool filter_add_param(filter_t *filter, const char *name, int name_len,
181                       const char *value, int value_len);
182
183 __attribute__((nonnull(1,2,4)))
184 bool filter_add_hook(filter_t *filter, const char *name, int name_len,
185                      const char *value, int value_len);
186
187 __attribute__((nonnull(1)))
188 bool filter_build(filter_t *filter);
189
190 __attribute__((nonnull(1,2)))
191 static inline int filter_find_with_name(const A(filter_t) *array, const char *name)
192 {
193     int start = 0;
194     int end   = array->len;
195
196     while (start < end) {
197         int mid = (start + end) / 2;
198         int cmp = strcmp(name, array_elt(*array, mid).name);
199
200         if (cmp == 0) {
201             return mid;
202         } else if (cmp < 0) {
203             end = mid;
204         } else {
205             start = mid + 1;
206         }
207     }
208     return -1;
209 }
210
211 __attribute__((nonnull(1,2)))
212 bool filter_update_references(filter_t *filter, A(filter_t) *array);
213
214 __attribute__((nonnull(1)))
215 bool filter_check_safety(A(filter_t) *array);
216
217 __attribute__((nonnull(1)))
218 static inline void filter_hook_wipe(filter_hook_t *hook)
219 {
220     p_delete(&hook->value);
221 }
222
223 __attribute__((nonnull(1)))
224 static inline void filter_params_wipe(filter_param_t *param)
225 {
226     p_delete(&param->value);
227 }
228
229 __attribute__((nonnull(1)))
230 void filter_wipe(filter_t *filter);
231
232
233 /* Runner.
234  */
235
236 __attribute__((nonnull(1,2)))
237 const filter_hook_t *filter_run(const filter_t *filter, const query_t *query,
238                                 filter_context_t *context);
239
240 __attribute__((nonnull(1,2)))
241 bool filter_test(const filter_t *filter, const query_t *query,
242                  filter_context_t *context, filter_result_t expt);
243
244
245 /* Parsing Helpers
246  */
247
248 #define FILTER_PARAM_PARSE_STRING(Param, Dest, Copy)                           \
249     case ATK_ ## Param: {                                                      \
250         (Dest) = (Copy) ? m_strdup(param->value) : param->value;               \
251     } break
252
253 #define FILTER_PARAM_PARSE_INT(Param, Dest)                                    \
254     case ATK_ ## Param: {                                                      \
255         char *next;                                                            \
256         (Dest) = strtol(param->value, &next, 10);                              \
257         PARSE_CHECK(!*next, "invalid %s value %.*s", atokens[ATK_ ## Param],   \
258                     param->value_len, param->value);                           \
259      } break
260
261 #define FILTER_PARAM_PARSE_BOOLEAN(Param, Dest)                                \
262     case ATK_ ## Param: {                                                      \
263         if (param->value_len == 1 && param->value[0] == '1') {                 \
264             (Dest) = true;                                                     \
265         } else if (param->value_len == 1 && param->value[0] == '0') {          \
266             (Dest) = false;                                                    \
267         } else if (param->value_len == 4                                       \
268                    && ascii_tolower(param->value[0]) == 't'                    \
269                    && ascii_tolower(param->value[1]) == 'r'                    \
270                    && ascii_tolower(param->value[2]) == 'u'                    \
271                    && ascii_tolower(param->value[3]) == 'e') {                 \
272             (Dest) = true;                                                     \
273         } else if (param->value_len == 5                                       \
274                    && ascii_tolower(param->value[0]) == 'f'                    \
275                    && ascii_tolower(param->value[1]) == 'a'                    \
276                    && ascii_tolower(param->value[2]) == 'l'                    \
277                    && ascii_tolower(param->value[3]) == 's'                    \
278                    && ascii_tolower(param->value[4]) == 'e') {                 \
279             (Dest) = false;                                                    \
280         } else {                                                               \
281             PARSE_CHECK(false, "invalid %s value %.*s", atokens[ATK_ ## Param],\
282                         param->value_len, param->value);                       \
283         }                                                                      \
284     } break
285
286
287 /* Filter context
288  */
289
290 __attribute__((nonnull(1)))
291 void filter_context_prepare(filter_context_t *context, void* qctx);
292
293 __attribute__((nonnull))
294 void filter_context_wipe(filter_context_t *context);
295
296 __attribute__((nonnull))
297 void filter_context_clean(filter_context_t *context);
298
299 __attribute__((nonnull))
300 void filter_post_async_result(filter_context_t *context, filter_result_t result);
301
302 #endif