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