Commit 41f0a38f 41f0a38f900e0ee215503fa4202ede79263b940b by Sergey Poznyakoff

Implemented reject and redirect.

1 parent ef72d1bf
...@@ -76,8 +76,158 @@ sieve_action_fileinto (sieve_machine_t mach, list_t args, list_t tags) ...@@ -76,8 +76,158 @@ sieve_action_fileinto (sieve_machine_t mach, list_t args, list_t tags)
76 } 76 }
77 77
78 int 78 int
79 stream_printf (stream_t stream, size_t *off, const char *fmt, ...)
80 {
81 va_list ap;
82 char *buf = NULL;
83 size_t size, bytes;
84 int rc;
85
86 va_start (ap, fmt);
87 vasprintf (&buf, fmt, ap);
88 va_end (ap);
89 size = strlen (buf);
90 rc = stream_write (stream, buf, size, *off, &bytes);
91 if (rc)
92 return rc;
93 *off += bytes;
94 if (bytes != size)
95 return EIO;
96 return 0;
97 }
98
99 int
100 sieve_get_message_sender (message_t msg, char **ptext)
101 {
102 int rc;
103 envelope_t envelope;
104 char *text;
105 size_t size;
106
107 rc = message_get_envelope (msg, &envelope);
108 if (rc)
109 return rc;
110
111 rc = envelope_sender (envelope, NULL, 0, &size);
112 if (rc)
113 return rc;
114
115 if (!(text = malloc (size + 1)))
116 return ENOMEM;
117 envelope_sender (envelope, text, size + 1, NULL);
118 *ptext = text;
119 return 0;
120 }
121
122 static int
123 build_mime (mime_t *pmime, message_t msg, const char *text)
124 {
125 mime_t mime = NULL;
126 char datestr[80];
127
128 mime_create (&mime, NULL, 0);
129 {
130 message_t newmsg;
131 stream_t stream;
132 time_t t;
133 struct tm *tm;
134 char *sender;
135 size_t off = 0;
136 header_t hdr;
137 body_t body;
138
139 message_create (&newmsg, NULL);
140 message_get_body (newmsg, &body);
141 body_get_stream (body, &stream);
142
143 time (&t);
144 tm = localtime (&t);
145 strftime (datestr, sizeof datestr, "%a, %b %d %H:%M:%S %Y %Z", tm);
146
147 sieve_get_message_sender (msg, &sender);
148
149 stream_printf (stream, &off,
150 "\nThe original message was received at %s from %s.\n",
151 datestr, sender);
152 free (sender);
153 stream_printf (stream, &off,
154 "Message was refused by recipient's mail filtering program.\n");
155 stream_printf (stream, &off, "Reason given was as follows:\n");
156 stream_printf (stream, &off, "%s", text);
157 stream_close (stream);
158 mime_add_part (mime, newmsg);
159 }
160
161 /* message/delivery-status */
162 {
163 message_t newmsg;
164 stream_t stream;
165 header_t hdr;
166 size_t off = 0;
167 body_t body;
168
169 message_create (&newmsg, NULL);
170 message_get_header (newmsg, &hdr);
171 header_set_value (hdr, "Content-Type", "message/delivery-status", 1);
172 message_get_body (newmsg, &body);
173 body_get_stream (body, &stream);
174 stream_printf (stream, &off, "Reporting-UA: sieve; %s\n", PACKAGE_STRING);
175 stream_printf (stream, &off, "Arrival-Date: %s\n", datestr);
176 stream_printf (stream, &off, "Final-Recipient: RFC822; %s\n",
177 mu_get_user_email (NULL));
178 stream_printf (stream, &off, "Action: deleted\n");
179 stream_printf (stream, &off,
180 "Disposition: automatic-action/MDN-sent-automatically;deleted\n");
181 stream_printf (stream, &off, "Last-Attempt-Date: %s\n", datestr);
182 stream_close (stream);
183 mime_add_part(mime, newmsg);
184 }
185
186 /* Quote original message */
187 {
188 message_t newmsg;
189 stream_t istream, ostream;
190 header_t hdr;
191 size_t ioff = 0, ooff = 0, n;
192 char buffer[512];
193 body_t body;
194
195 message_create (&newmsg, NULL);
196 message_get_header (newmsg, &hdr);
197 header_set_value (hdr, "Content-Type", "message/rfc822", 1);
198 message_get_body (newmsg, &body);
199 body_get_stream (body, &ostream);
200 message_get_stream (msg, &istream);
201
202 while (stream_read (istream, buffer, sizeof buffer - 1, ioff, &n) == 0
203 && n != 0)
204 {
205 size_t sz;
206 stream_write (ostream, buffer, n, ooff, &sz);
207 if (sz != n)
208 return EIO;
209 ooff += n;
210 ioff += n;
211 }
212 stream_close (ostream);
213 mime_add_part (mime, newmsg);
214 }
215
216 *pmime = mime;
217
218 return 0;
219 }
220
221 int
79 sieve_action_reject (sieve_machine_t mach, list_t args, list_t tags) 222 sieve_action_reject (sieve_machine_t mach, list_t args, list_t tags)
80 { 223 {
224 mime_t mime = NULL;
225 mailer_t mailer = sieve_get_mailer (mach);
226 int rc;
227 message_t newmsg;
228 char *addrtext;
229 address_t from, to;
230
81 sieve_value_t *val = sieve_value_get (args, 0); 231 sieve_value_t *val = sieve_value_get (args, 0);
82 if (!val) 232 if (!val)
83 { 233 {
...@@ -87,22 +237,200 @@ sieve_action_reject (sieve_machine_t mach, list_t args, list_t tags) ...@@ -87,22 +237,200 @@ sieve_action_reject (sieve_machine_t mach, list_t args, list_t tags)
87 sieve_log_action (mach, "REJECT", NULL); 237 sieve_log_action (mach, "REJECT", NULL);
88 if (sieve_is_dry_run (mach)) 238 if (sieve_is_dry_run (mach))
89 return 0; 239 return 0;
90 return 0; 240
241 rc = build_mime (&mime, mach->msg, val->v.string);
242
243 mime_get_message (mime, &newmsg);
244
245 sieve_get_message_sender (mach->msg, &addrtext);
246 rc = address_create (&to, addrtext);
247 if (rc)
248 {
249 sieve_error (mach,
250 "%d: reject - can't create to address <%s>: %s\n",
251 sieve_get_message_num (mach),
252 addrtext, mu_errstring (rc));
253 free (addrtext);
254 goto end;
255 }
256 free (addrtext);
257
258 rc = address_create (&from, sieve_get_daemon_email (mach));
259 if (rc)
260 {
261 sieve_error (mach,
262 "%d: reject - can't create from address <%s>: %s\n",
263 sieve_get_message_num (mach),
264 sieve_get_daemon_email (mach),
265 mu_errstring (rc));
266 goto end;
267 }
268
269 rc = mailer_open (mailer, 0);
270 if (rc)
271 {
272 url_t url = NULL;
273 mailer_get_url (mailer, &url);
274
275 sieve_error (mach,
276 "%d: redirect - can't open mailer %s: %s\n",
277 sieve_get_message_num (mach),
278 url_to_string (url),
279 mu_errstring (rc));
280 goto end;
281 }
282
283 rc = mailer_send_message (mailer, newmsg, from, to);
284 mailer_close (mailer);
285
286 end:
287 sieve_mark_deleted (mach->msg, rc == 0);
288 mime_destroy (&mime);
289 address_destroy (&from);
290 address_destroy (&to);
291
292 return rc;
293 }
294
295 /* rfc3028 says:
296 "Implementations SHOULD take measures to implement loop control,"
297 We do this by appending an "X-Sender" header to each message
298 being redirected. If one of the "X-Sender" headers of the message
299 contains our email address, we assume it is a loop and bail out. */
300
301 static int
302 check_redirect_loop (message_t msg)
303 {
304 header_t hdr = NULL;
305 size_t i, num = 0;
306 char buf[512];
307 int loop = 0;
308 char *email = mu_get_user_email (NULL);
309
310 message_get_header (msg, &hdr);
311 header_get_field_count (hdr, &num);
312 for (i = 1; !loop && i <= num; i++)
313 {
314 header_get_field_name (hdr, i, buf, sizeof buf, NULL);
315 if (strcasecmp (buf, "X-Sender") == 0)
316 {
317 size_t j, cnt = 0;
318 address_t addr;
319
320 header_get_field_value (hdr, i, buf, sizeof buf, NULL);
321 if (address_create (&addr, buf))
322 continue;
323
324 address_get_count (addr, &cnt);
325 for (j = 1; !loop && j <= cnt; j++)
326 {
327 address_get_email (addr, j, buf, sizeof buf, NULL);
328 if (strcasecmp (buf, email) == 0)
329 loop = 1;
330 }
331 address_destroy (&addr);
332 }
333 }
334 return loop;
91 } 335 }
92 336
93 int 337 int
94 sieve_action_redirect (sieve_machine_t mach, list_t args, list_t tags) 338 sieve_action_redirect (sieve_machine_t mach, list_t args, list_t tags)
95 { 339 {
340 message_t msg, newmsg = NULL;
341 address_t addr = NULL, from = NULL;
342 header_t hdr = NULL;
343 int rc;
344 size_t size;
345 char *fromaddr;
346 mailer_t mailer = sieve_get_mailer (mach);
347
96 sieve_value_t *val = sieve_value_get (args, 0); 348 sieve_value_t *val = sieve_value_get (args, 0);
97 if (!val) 349 if (!val)
98 { 350 {
99 sieve_error (mach, "redirect: can't get address!"); 351 sieve_error (mach, "redirect: can't get address!");
100 sieve_abort (mach); 352 sieve_abort (mach);
101 } 353 }
354
355 rc = address_create (&addr, val->v.string);
356 if (rc)
357 {
358 sieve_error (mach,
359 "%d: redirect - parsing to `%s' failed: %s\n",
360 sieve_get_message_num (mach),
361 val->v.string, mu_errstring (rc));
362 return 1;
363 }
364
102 sieve_log_action (mach, "REDIRECT", "to %s", val->v.string); 365 sieve_log_action (mach, "REDIRECT", "to %s", val->v.string);
103 if (sieve_is_dry_run (mach)) 366 if (sieve_is_dry_run (mach))
104 return 0; 367 return 0;
105 return 0; 368
369 msg = sieve_get_message (mach);
370 if (check_redirect_loop (msg))
371 {
372 sieve_error (mach, "%d: Redirection loop detected",
373 sieve_get_message_num (mach));
374 goto end;
375 }
376
377 rc = sieve_get_message_sender (msg, &fromaddr);
378 if (rc)
379 {
380 sieve_error (mach,
381 "%d: redirect - can't get envelope sender: %s\n",
382 sieve_get_message_num (mach), mu_errstring (rc));
383 goto end;
384 }
385
386 rc = address_create (&from, fromaddr);
387 if (rc)
388 {
389 sieve_error (mach,
390 "%d: redirect - can't create from address <%s>: %s\n",
391 sieve_get_message_num (mach),
392 fromaddr, mu_errstring (rc));
393 free (fromaddr);
394 goto end;
395 }
396
397 free (fromaddr);
398
399 rc = message_create_copy (&newmsg, msg);
400 if (rc)
401 {
402 sieve_error (mach, "%d: can't copy message: %s",
403 sieve_get_message_num (mach),
404 mu_errstring (rc));
405 goto end;
406 }
407 message_get_header (newmsg, &hdr);
408 header_set_value (hdr, "X-Sender", mu_get_user_email (NULL), 0);
409
410 rc = mailer_open (mailer, 0);
411 if (rc)
412 {
413 url_t url = NULL;
414 mailer_get_url (mailer, &url);
415
416 sieve_error (mach,
417 "%d: redirect - can't open mailer %s: %s\n",
418 sieve_get_message_num (mach),
419 url_to_string (url),
420 mu_errstring (rc));
421 goto end;
422 }
423
424 rc = mailer_send_message (mailer, newmsg, from, addr);
425 mailer_close (mailer);
426
427 end:
428 sieve_mark_deleted (mach->msg, rc == 0);
429 message_destroy (&newmsg, NULL);
430 address_destroy (&from);
431 address_destroy (&addr);
432
433 return rc;
106 } 434 }
107 435
108 sieve_data_type fileinto_args[] = { 436 sieve_data_type fileinto_args[] = {
......