1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2021 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <assert.h>
24 #include <sieve-priv.h>
25
26 #define SIEVE_RT_ARG(m,n,t) ((m)->prog[(m)->pc+(n)].t)
27 #define SIEVE_RT_ADJUST(m,n) (m)->pc+=(n)
28
29 #define INSTR_DISASS(m) ((m)->state == mu_sieve_state_disass)
30 #define INSTR_DEBUG(m) \
31 (INSTR_DISASS(m) || mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE9))
32
33 void
_mu_i_sv_instr_locus(mu_sieve_machine_t mach)34 _mu_i_sv_instr_locus (mu_sieve_machine_t mach)
35 {
36 mu_locus_point_set_file (&mach->locus.beg,
37 mu_i_sv_id_str (mach, SIEVE_RT_ARG (mach, 0, pc)));
38 mach->locus.beg.mu_line = SIEVE_RT_ARG (mach, 1, unum);
39 mach->locus.beg.mu_col = SIEVE_RT_ARG (mach, 2, unum);
40
41 mu_locus_point_set_file (&mach->locus.end,
42 mu_i_sv_id_str (mach, SIEVE_RT_ARG (mach, 3, pc)));
43 mach->locus.end.mu_line = SIEVE_RT_ARG (mach, 4, unum);
44 mach->locus.end.mu_col = SIEVE_RT_ARG (mach, 5, unum);
45 mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
46 MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &mach->locus);
47 if (INSTR_DEBUG (mach))
48 mu_i_sv_debug (mach, mach->pc - 1, "LOCUS");
49 SIEVE_RT_ADJUST (mach, 6);
50 }
51
52 static int
instr_run(mu_sieve_machine_t mach,char const * what)53 instr_run (mu_sieve_machine_t mach, char const *what)
54 {
55 int rc = 0;
56 mu_sieve_handler_t han = SIEVE_RT_ARG (mach, 0, handler);
57 mach->argstart = SIEVE_RT_ARG (mach, 1, pc);
58 mach->argcount = SIEVE_RT_ARG (mach, 2, pc);
59 mach->tagcount = SIEVE_RT_ARG (mach, 3, pc);
60 mach->identifier = SIEVE_RT_ARG (mach, 4, string);
61 mach->comparator = SIEVE_RT_ARG (mach, 5, comp);
62
63 SIEVE_RT_ADJUST (mach, 6);
64
65 if (INSTR_DEBUG (mach))
66 mu_i_sv_debug_command (mach, mach->pc - 7, what);
67 else
68 mu_i_sv_trace (mach, what);
69
70 if (!INSTR_DISASS (mach))
71 rc = han (mach);
72 mach->argstart = 0;
73 mach->argcount = 0;
74 mach->tagcount = 0;
75 mach->identifier = NULL;
76 mach->comparator = NULL;
77 return rc;
78 }
79
80 void
_mu_i_sv_instr_action(mu_sieve_machine_t mach)81 _mu_i_sv_instr_action (mu_sieve_machine_t mach)
82 {
83 mach->action_count++;
84 instr_run (mach, "ACTION");
85 }
86
87 void
_mu_i_sv_instr_test(mu_sieve_machine_t mach)88 _mu_i_sv_instr_test (mu_sieve_machine_t mach)
89 {
90 mach->reg = instr_run (mach, "TEST");
91 }
92
93 void
_mu_i_sv_instr_not(mu_sieve_machine_t mach)94 _mu_i_sv_instr_not (mu_sieve_machine_t mach)
95 {
96 if (INSTR_DEBUG (mach))
97 mu_i_sv_debug (mach, mach->pc - 1, "NOT");
98 if (INSTR_DISASS (mach))
99 return;
100 mach->reg = !mach->reg;
101 }
102
103 void
_mu_i_sv_instr_branch(mu_sieve_machine_t mach)104 _mu_i_sv_instr_branch (mu_sieve_machine_t mach)
105 {
106 long num = SIEVE_RT_ARG (mach, 0, number);
107
108 SIEVE_RT_ADJUST (mach, 1);
109 if (INSTR_DEBUG (mach))
110 mu_i_sv_debug (mach, mach->pc - 2, "BRANCH %lu",
111 (unsigned long)(mach->pc + num));
112 if (INSTR_DISASS (mach))
113 return;
114
115 mach->pc += num;
116 }
117
118 void
_mu_i_sv_instr_brz(mu_sieve_machine_t mach)119 _mu_i_sv_instr_brz (mu_sieve_machine_t mach)
120 {
121 long num = SIEVE_RT_ARG (mach, 0, number);
122 SIEVE_RT_ADJUST (mach, 1);
123
124 if (INSTR_DEBUG (mach))
125 mu_i_sv_debug (mach, mach->pc - 2, "BRZ %lu",
126 (unsigned long)(mach->pc + num));
127 if (INSTR_DISASS (mach))
128 return;
129
130 if (!mach->reg)
131 mach->pc += num;
132 }
133
134 void
_mu_i_sv_instr_brnz(mu_sieve_machine_t mach)135 _mu_i_sv_instr_brnz (mu_sieve_machine_t mach)
136 {
137 long num = SIEVE_RT_ARG (mach, 0, number);
138 SIEVE_RT_ADJUST (mach, 1);
139
140 if (INSTR_DEBUG (mach))
141 mu_i_sv_debug (mach, mach->pc - 2, "BRNZ %lu",
142 (unsigned long)(mach->pc + num));
143 if (INSTR_DISASS (mach))
144 return;
145
146 if (mach->reg)
147 mach->pc += num;
148 }
149
150 void
mu_sieve_abort(mu_sieve_machine_t mach)151 mu_sieve_abort (mu_sieve_machine_t mach)
152 {
153 longjmp (mach->errbuf, MU_ERR_FAILURE);
154 }
155
156 void
mu_sieve_set_data(mu_sieve_machine_t mach,void * data)157 mu_sieve_set_data (mu_sieve_machine_t mach, void *data)
158 {
159 mach->data = data;
160 }
161
162 void *
mu_sieve_get_data(mu_sieve_machine_t mach)163 mu_sieve_get_data (mu_sieve_machine_t mach)
164 {
165 return mach->data;
166 }
167
168 int
mu_sieve_get_locus(mu_sieve_machine_t mach,struct mu_locus_range * loc)169 mu_sieve_get_locus (mu_sieve_machine_t mach, struct mu_locus_range *loc)
170 {
171 return mu_locus_range_copy (loc, &mach->locus);
172 }
173
174 mu_mailbox_t
mu_sieve_get_mailbox(mu_sieve_machine_t mach)175 mu_sieve_get_mailbox (mu_sieve_machine_t mach)
176 {
177 return mach->mailbox;
178 }
179
180 mu_message_t
mu_sieve_get_message(mu_sieve_machine_t mach)181 mu_sieve_get_message (mu_sieve_machine_t mach)
182 {
183 if (!mach->msg)
184 mu_mailbox_get_message (mach->mailbox, mach->msgno, &mach->msg);
185 return mach->msg;
186 }
187
188 size_t
mu_sieve_get_message_num(mu_sieve_machine_t mach)189 mu_sieve_get_message_num (mu_sieve_machine_t mach)
190 {
191 return mach->msgno;
192 }
193
194 const char *
mu_sieve_get_identifier(mu_sieve_machine_t mach)195 mu_sieve_get_identifier (mu_sieve_machine_t mach)
196 {
197 return mach->identifier;
198 }
199
200 void
mu_sieve_get_argc(mu_sieve_machine_t mach,size_t * args,size_t * tags)201 mu_sieve_get_argc (mu_sieve_machine_t mach, size_t *args, size_t *tags)
202 {
203 if (args)
204 *args = mach->argcount;
205 if (tags)
206 *tags = mach->tagcount;
207 }
208
209 int
mu_sieve_is_dry_run(mu_sieve_machine_t mach)210 mu_sieve_is_dry_run (mu_sieve_machine_t mach)
211 {
212 return mach->dry_run;
213 }
214
215 int
mu_sieve_set_dry_run(mu_sieve_machine_t mach,int val)216 mu_sieve_set_dry_run (mu_sieve_machine_t mach, int val)
217 {
218 if (mach->state != mu_sieve_state_compiled)
219 return EINVAL; /* FIXME: another error code */
220 return mach->dry_run = val;
221 }
222
223 int
sieve_run(mu_sieve_machine_t mach)224 sieve_run (mu_sieve_machine_t mach)
225 {
226 int rc;
227
228 mu_sieve_stream_save (mach);
229
230 rc = setjmp (mach->errbuf);
231 if (rc == 0)
232 {
233 mach->action_count = 0;
234
235 mu_i_sv_init_variables (mach);
236
237 for (mach->pc = 1; mach->prog[mach->pc].handler; )
238 (*mach->prog[mach->pc++].instr) (mach);
239
240 if (mach->action_count == 0)
241 mu_sieve_log_action (mach, "IMPLICIT KEEP", NULL);
242
243 if (INSTR_DEBUG (mach))
244 mu_i_sv_debug (mach, mach->pc, "STOP");
245 }
246
247 mu_sieve_stream_restore (mach);
248
249 return rc;
250 }
251
252 int
mu_sieve_disass(mu_sieve_machine_t mach)253 mu_sieve_disass (mu_sieve_machine_t mach)
254 {
255 int rc;
256
257 if (mach->state != mu_sieve_state_compiled)
258 return EINVAL; /* FIXME: Error code */
259 mach->state = mu_sieve_state_disass;
260 rc = sieve_run (mach);
261 mach->state = mu_sieve_state_compiled;
262 return rc;
263 }
264
265 static int
_sieve_action(mu_observer_t obs,size_t type,void * data,void * action_data)266 _sieve_action (mu_observer_t obs, size_t type, void *data, void *action_data)
267 {
268 mu_sieve_machine_t mach;
269
270 if (type != MU_EVT_MESSAGE_ADD)
271 return 0;
272
273 mach = mu_observer_get_owner (obs);
274 mach->msgno++;
275 mu_mailbox_get_message (mach->mailbox, mach->msgno, &mach->msg);
276 sieve_run (mach);
277 return 0;
278 }
279
280 int
mu_sieve_mailbox(mu_sieve_machine_t mach,mu_mailbox_t mbox)281 mu_sieve_mailbox (mu_sieve_machine_t mach, mu_mailbox_t mbox)
282 {
283 int rc;
284 size_t total;
285 mu_observer_t observer;
286 mu_observable_t observable;
287
288 if (!mach || !mbox)
289 return EINVAL;
290
291 if (mach->state != mu_sieve_state_compiled)
292 return EINVAL; /* FIXME: Error code */
293 mach->state = mu_sieve_state_running;
294
295 mu_observer_create (&observer, mach);
296 mu_observer_set_action (observer, _sieve_action, mach);
297 mu_mailbox_get_observable (mbox, &observable);
298 mu_observable_attach (observable, MU_EVT_MESSAGE_ADD, observer);
299
300 mach->mailbox = mbox;
301 mach->msgno = 0;
302 rc = mu_mailbox_scan (mbox, 1, &total);
303 if (rc)
304 mu_sieve_error (mach, _("mu_mailbox_scan: %s"), mu_strerror (errno));
305
306 mu_observable_detach (observable, observer);
307 mu_observer_destroy (&observer, mach);
308
309 mach->state = mu_sieve_state_compiled;
310 mach->mailbox = NULL;
311
312 return rc;
313 }
314
315 int
mu_sieve_message(mu_sieve_machine_t mach,mu_message_t msg)316 mu_sieve_message (mu_sieve_machine_t mach, mu_message_t msg)
317 {
318 int rc;
319
320 if (!mach || !msg)
321 return EINVAL;
322
323 if (mach->state != mu_sieve_state_compiled)
324 return EINVAL; /* FIXME: Error code */
325 mach->state = mu_sieve_state_running;
326
327 mach->msgno = 1;
328 mach->msg = msg;
329 mach->mailbox = NULL;
330 rc = sieve_run (mach);
331 mach->state = mu_sieve_state_compiled;
332 mach->msg = NULL;
333
334 return rc;
335 }
336