vacation: read message body from the file
* doc/texinfo/sieve.texi: Document recent changes to vacation. * libmu_sieve/extensions/vacation.c (vacation_reply): Handle the "rfc2822" tag: if set together with :file, treat the file as the RFC2822 message. Otherwise, read message body from it. * sieve/tests/vacation.at: Add test for :rfc2822
Showing
4 changed files
with
175 additions
and
20 deletions
... | @@ -1453,20 +1453,35 @@ pipe "/usr/sbin/maidag --url smtp://gray@@mail.gnu.org" | ... | @@ -1453,20 +1453,35 @@ pipe "/usr/sbin/maidag --url smtp://gray@@mail.gnu.org" |
1453 | @deftypefn Action {} vacation [:days @var{ndays}(number)] @ | 1453 | @deftypefn Action {} vacation [:days @var{ndays}(number)] @ |
1454 | [:subject @var{subject}(string)] @ | 1454 | [:subject @var{subject}(string)] @ |
1455 | [:aliases @var{addrlist}(string-list)] @ | 1455 | [:aliases @var{addrlist}(string-list)] @ |
1456 | [:addresses @var{noreply-address}(string-list)] @ | 1456 | [:noreply @var{noreply-address}(string-list)] @ |
1457 | [:reply_regex @var{expr}(string)] @ | 1457 | [:reply_regex @var{expr}(string)] @ |
1458 | [:reply_prefix @var{prefix}(string)] @ | 1458 | [:reply_prefix @var{prefix}(string)] @ |
1459 | @var{reply-text}(string) | 1459 | [:sender @var{email}(string)] @ |
1460 | [:database @var{path}(string)] @ | ||
1461 | [:return_address @var{email}(string)] @ | ||
1462 | [:header @var{headers}(string-list)] @ | ||
1463 | [:mime] @ | ||
1464 | [:always_reply] @ | ||
1465 | [:rfc2822] @ | ||
1466 | [:file] @ | ||
1467 | @var{text}(string) | ||
1460 | @*Syntax: | 1468 | @*Syntax: |
1461 | @smallexample | 1469 | @smallexample |
1462 | require "vacation"; | 1470 | require "vacation"; |
1463 | vacation @var{args}; | 1471 | vacation @var{args}; |
1464 | @end smallexample | 1472 | @end smallexample |
1465 | @*Description: | 1473 | @*Description: |
1466 | The @code{vacation} action returns a message with @var{reply-text} to | 1474 | The @code{vacation} action returns a message with @var{text} to |
1467 | the sender. It is intended to inform the sender that the recipient is | 1475 | the sender. It is intended to inform the sender that the recipient is |
1468 | not currently reading his mail. | 1476 | not currently reading his mail. |
1469 | 1477 | ||
1478 | If the @code{:file} tag is present, @var{text} is treated as the name | ||
1479 | of the file to read the body of the reply message from. When used together | ||
1480 | with tag @code{:rfc2822}, the file should be formatted as a valid RFC | ||
1481 | 2822 message, i.e. headers followed by empty line and body. Headers | ||
1482 | must not contain @samp{To}, @samp{From}, and @samp{Subject}, as these | ||
1483 | will be generated automatically. | ||
1484 | |||
1470 | If the @code{:subject} tag is given, its argument sets the subject of | 1485 | If the @code{:subject} tag is given, its argument sets the subject of |
1471 | the message. Otherwise, the subject is formed by prefixing original | 1486 | the message. Otherwise, the subject is formed by prefixing original |
1472 | subject with @samp{Re:}, or @var{prefix}, given with the | 1487 | subject with @samp{Re:}, or @var{prefix}, given with the |
... | @@ -1475,6 +1490,11 @@ matching extended regular expression @var{expr} (@code{:reply_regex} | ... | @@ -1475,6 +1490,11 @@ matching extended regular expression @var{expr} (@code{:reply_regex} |
1475 | tag) are stripped from the subject line. If @code{:reply_regex} is not | 1490 | tag) are stripped from the subject line. If @code{:reply_regex} is not |
1476 | specified, the default regexp is @samp{^re: *}. | 1491 | specified, the default regexp is @samp{^re: *}. |
1477 | 1492 | ||
1493 | Another headers can be added using the @code{:header} tag. Its | ||
1494 | argument is a list of header strings, each one having the form | ||
1495 | @samp{"@var{name}:@var{value}"}. Additional whitespace is allowed on | ||
1496 | both sides of the colon. | ||
1497 | |||
1478 | The @code{:aliases} tag instructs @code{vacation} to handle messages | 1498 | The @code{:aliases} tag instructs @code{vacation} to handle messages |
1479 | for any address in @var{addrlist} in the same manner as those received | 1499 | for any address in @var{addrlist} in the same manner as those received |
1480 | for the user's principal email. | 1500 | for the user's principal email. |
... | @@ -1496,13 +1516,17 @@ exclusion list is: | ... | @@ -1496,13 +1516,17 @@ exclusion list is: |
1496 | ^MAILER-DAEMON@@.* | 1516 | ^MAILER-DAEMON@@.* |
1497 | @end smallexample | 1517 | @end smallexample |
1498 | 1518 | ||
1499 | New entries can be added to this list using @code{:addresses} tag. | 1519 | New entries can be added to this list using @code{:noreply} tag. |
1500 | 1520 | ||
1501 | The @code{:days} tag sets the @dfn{reply interval}. A reply is sent to | 1521 | The @code{:days} tag sets the @dfn{reply interval}. A reply is sent to |
1502 | each sender once in @var{ndays} days. GNU Sieve keeps track of | 1522 | each sender once in @var{ndays} days. GNU Sieve keeps track of |
1503 | sender addresses and dates in a DBM file @file{.vacation} stored in | 1523 | sender addresses and dates in file @file{.vacation} stored in |
1504 | the user's home directory. This tag is available only if Mailutils is | 1524 | the user's home directory. The file name can be changed using the |
1505 | compiled with DBM support. | 1525 | @code{:database} tag. |
1526 | |||
1527 | The tag @code{:always_reply} instructs vacation to respond to the | ||
1528 | message regardless of whether the user email is listed as a recipient | ||
1529 | for the message. | ||
1506 | @end deftypefn | 1530 | @end deftypefn |
1507 | 1531 | ||
1508 | @node GNU Extensions | 1532 | @node GNU Extensions | ... | ... |
... | @@ -93,7 +93,7 @@ enum mu_buffer_type | ... | @@ -93,7 +93,7 @@ enum mu_buffer_type |
93 | If pat==NULL, any reads from that stream will return EOF. */ | 93 | If pat==NULL, any reads from that stream will return EOF. */ |
94 | #define MU_IOCTL_NULLSTREAM_SET_PATTERN 0 | 94 | #define MU_IOCTL_NULLSTREAM_SET_PATTERN 0 |
95 | /* Set pattern class for reads: Argument int *pclass (a class mask | 95 | /* Set pattern class for reads: Argument int *pclass (a class mask |
96 | from mailutils/cctype.h */ | 96 | from mailutils/cctype.h) */ |
97 | #define MU_IOCTL_NULLSTREAM_SET_PATCLASS 1 | 97 | #define MU_IOCTL_NULLSTREAM_SET_PATCLASS 1 |
98 | /* Limit stream size. Argument: mu_off_t *psize; */ | 98 | /* Limit stream size. Argument: mu_off_t *psize; */ |
99 | #define MU_IOCTL_NULLSTREAM_SETSIZE 2 | 99 | #define MU_IOCTL_NULLSTREAM_SETSIZE 2 | ... | ... |
... | @@ -24,6 +24,7 @@ | ... | @@ -24,6 +24,7 @@ |
24 | [:reply_prefix <prefix: string>] | 24 | [:reply_prefix <prefix: string>] |
25 | [:sender <email: string>] | 25 | [:sender <email: string>] |
26 | [:database <path: string>] | 26 | [:database <path: string>] |
27 | [:rfc2822] | ||
27 | [:file] | 28 | [:file] |
28 | [:mime] | 29 | [:mime] |
29 | [:always_reply] | 30 | [:always_reply] |
... | @@ -637,17 +638,72 @@ vacation_reply (mu_sieve_machine_t mach, mu_list_t tags, mu_message_t msg, | ... | @@ -637,17 +638,72 @@ vacation_reply (mu_sieve_machine_t mach, mu_list_t tags, mu_message_t msg, |
637 | mu_strerror (rc)); | 638 | mu_strerror (rc)); |
638 | return -1; | 639 | return -1; |
639 | } | 640 | } |
640 | rc = mu_stream_to_message (instr, &newmsg); | 641 | |
641 | mu_stream_unref (instr); | 642 | if (mu_sieve_tag_lookup (tags, "rfc2822", NULL)) |
642 | if (rc) | ||
643 | { | 643 | { |
644 | mu_sieve_error (mach, | 644 | rc = mu_stream_to_message (instr, &newmsg); |
645 | _("%lu: cannot read message from file %s: %s"), | 645 | mu_stream_unref (instr); |
646 | (unsigned long) mu_sieve_get_message_num (mach), | 646 | if (rc) |
647 | text, | 647 | { |
648 | mu_strerror (rc)); | 648 | mu_sieve_error (mach, |
649 | return -1; | 649 | _("%lu: cannot read message from file %s: %s"), |
650 | } | 650 | (unsigned long) mu_sieve_get_message_num (mach), |
651 | text, | ||
652 | mu_strerror (rc)); | ||
653 | return -1; | ||
654 | } | ||
655 | } | ||
656 | else | ||
657 | { | ||
658 | mu_stream_t text_stream; | ||
659 | mu_transport_t trans[2]; | ||
660 | |||
661 | rc = mu_memory_stream_create (&text_stream, MU_STREAM_RDWR); | ||
662 | if (rc) | ||
663 | { | ||
664 | mu_stream_unref (instr); | ||
665 | mu_sieve_error (mach, | ||
666 | _("%lu: cannot create memory stream: %s"), | ||
667 | (unsigned long) mu_sieve_get_message_num (mach), | ||
668 | mu_strerror (rc)); | ||
669 | return -1; | ||
670 | } | ||
671 | |||
672 | rc = mu_stream_copy (text_stream, instr, 0, NULL); | ||
673 | mu_stream_unref (instr); | ||
674 | if (rc == 0) | ||
675 | rc = mu_stream_write (text_stream, "", 1, NULL); | ||
676 | if (rc) | ||
677 | { | ||
678 | mu_sieve_error (mach, | ||
679 | _("%lu: failed reading from %s: %s"), | ||
680 | (unsigned long) mu_sieve_get_message_num (mach), | ||
681 | text, | ||
682 | mu_strerror (rc)); | ||
683 | return -1; | ||
684 | } | ||
685 | |||
686 | rc = mu_stream_ioctl (text_stream, MU_IOCTL_TRANSPORT, | ||
687 | MU_IOCTL_OP_GET, trans); | ||
688 | if (rc) | ||
689 | { | ||
690 | mu_stream_unref (text_stream); | ||
691 | mu_sieve_error (mach, | ||
692 | "%lu: mu_stream_ioctl: %s", | ||
693 | (unsigned long) mu_sieve_get_message_num (mach), | ||
694 | mu_strerror (rc)); | ||
695 | return -1; | ||
696 | } | ||
697 | |||
698 | if (build_mime (mach, tags, &mime, msg, (char const *) trans[0])) | ||
699 | { | ||
700 | mu_stream_unref (text_stream); | ||
701 | return -1; | ||
702 | } | ||
703 | mu_mime_get_message (mime, &newmsg); | ||
704 | mu_message_unref (newmsg); | ||
705 | mu_stream_unref (text_stream); | ||
706 | } | ||
651 | } | 707 | } |
652 | else | 708 | else |
653 | { | 709 | { |
... | @@ -814,6 +870,7 @@ static mu_sieve_tag_def_t vacation_tags[] = { | ... | @@ -814,6 +870,7 @@ static mu_sieve_tag_def_t vacation_tags[] = { |
814 | {"always_reply", SVT_VOID}, | 870 | {"always_reply", SVT_VOID}, |
815 | {"return_address", SVT_STRING}, | 871 | {"return_address", SVT_STRING}, |
816 | {"header", SVT_STRING_LIST}, | 872 | {"header", SVT_STRING_LIST}, |
873 | {"rfc2822", SVT_VOID}, | ||
817 | {NULL} | 874 | {NULL} |
818 | }; | 875 | }; |
819 | 876 | ... | ... |
... | @@ -253,10 +253,10 @@ VACATION on msg uid 2 | ... | @@ -253,10 +253,10 @@ VACATION on msg uid 2 |
253 | VACATION on msg uid 3 | 253 | VACATION on msg uid 3 |
254 | ]) | 254 | ]) |
255 | 255 | ||
256 | MUT_SIEVE_EXT_TEST([reply from file],[vac05], | 256 | MUT_SIEVE_EXT_TEST([reply from RFC2822 file],[vac05], |
257 | [require "vacation"; | 257 | [require "vacation"; |
258 | 258 | ||
259 | vacation :database "vacation.db" :always_reply :file "reply"; | 259 | vacation :database "vacation.db" :always_reply :rfc2822 :file "reply"; |
260 | ], | 260 | ], |
261 | [AT_DATA([reply],[X-Mail-Processor: sieve | 261 | [AT_DATA([reply],[X-Mail-Processor: sieve |
262 | 262 | ||
... | @@ -320,5 +320,79 @@ VACATION on msg uid 2 | ... | @@ -320,5 +320,79 @@ VACATION on msg uid 2 |
320 | VACATION on msg uid 3 | 320 | VACATION on msg uid 3 |
321 | ]) | 321 | ]) |
322 | 322 | ||
323 | MUT_SIEVE_EXT_TEST([reply body from file],[vac06], | ||
324 | [require "vacation"; | ||
325 | |||
326 | vacation :database "vacation.db" :always_reply :file "reply"; | ||
327 | ], | ||
328 | [AT_DATA([reply],[I'm on vacation right now. | ||
329 | I will attend to your message as soon as I'm back. | ||
330 | |||
331 | Best regards, | ||
332 | Ty Coon | ||
333 | ]) | ||
334 | MUT_MBCOPY($abs_top_srcdir/testsuite/spool/sieve.mbox,mailbox) | ||
335 | MTA_DIAG=`pwd`/mta.diag | ||
336 | MTA_APPEND=1 | ||
337 | export MTA_DIAG MTA_APPEND | ||
338 | sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -f ./mailbox prog || exit 1 | ||
339 | cat ./mta.diag | ||
340 | ], | ||
341 | [ENVELOPE FROM: foobar@nonexistent.net | ||
342 | ENVELOPE TO: <coyote@desert.example.org> | ||
343 | 0: In-Reply-To: Your message of Sun May 6 22:16:47 2001 | ||
344 | 1: Subject: =?UTF-8?Q?Re:_I_have_a_present_for_you?= | ||
345 | 2: To: coyote@desert.example.org | ||
346 | 3: Content-Transfer-Encoding: 8bit | ||
347 | 4: Content-Type: text/plain;charset=UTF-8 | ||
348 | 5: MIME-Version: 1.0 | ||
349 | 6: | ||
350 | 7: I'm on vacation right now. | ||
351 | 8: I will attend to your message as soon as I'm back. | ||
352 | 9: | ||
353 | 10: Best regards, | ||
354 | 11: Ty Coon | ||
355 | 12: | ||
356 | END OF MESSAGE | ||
357 | ENVELOPE FROM: foobar@nonexistent.net | ||
358 | ENVELOPE TO: <b1ff@de.res.example.com> | ||
359 | 0: In-Reply-To: Your message of TBD | ||
360 | 1: Subject: =?UTF-8?Q?Re:_$$$_YOU,_TOO,_CAN_BE_A_MILLIONAIRE!_$$$?= | ||
361 | 2: To: b1ff@de.res.example.com | ||
362 | 3: Content-Transfer-Encoding: 8bit | ||
363 | 4: Content-Type: text/plain;charset=UTF-8 | ||
364 | 5: MIME-Version: 1.0 | ||
365 | 6: | ||
366 | 7: I'm on vacation right now. | ||
367 | 8: I will attend to your message as soon as I'm back. | ||
368 | 9: | ||
369 | 10: Best regards, | ||
370 | 11: Ty Coon | ||
371 | 12: | ||
372 | END OF MESSAGE | ||
373 | ENVELOPE FROM: foobar@nonexistent.net | ||
374 | ENVELOPE TO: <bar@dontmailme.org> | ||
375 | 0: References: <200112232808.fERKR9N16790@dontmailme.org> | ||
376 | 1: In-Reply-To: Your message of Fri, 28 Dec 2001 23:28:08 +0200 | ||
377 | 2: <200112232808.fERKR9N16790@dontmailme.org> | ||
378 | 3: Subject: =?UTF-8?Q?Re:_Coffee?= | ||
379 | 4: To: bar@dontmailme.org | ||
380 | 5: Content-Transfer-Encoding: 8bit | ||
381 | 6: Content-Type: text/plain;charset=UTF-8 | ||
382 | 7: MIME-Version: 1.0 | ||
383 | 8: | ||
384 | 9: I'm on vacation right now. | ||
385 | 10: I will attend to your message as soon as I'm back. | ||
386 | 11: | ||
387 | 12: Best regards, | ||
388 | 13: Ty Coon | ||
389 | 14: | ||
390 | END OF MESSAGE | ||
391 | ], | ||
392 | [VACATION on msg uid 1 | ||
393 | VACATION on msg uid 2 | ||
394 | VACATION on msg uid 3 | ||
395 | ]) | ||
396 | |||
323 | m4_popdef([MUT_SIEVE_EXT_NAME]) | 397 | m4_popdef([MUT_SIEVE_EXT_NAME]) |
324 | 398 | ... | ... |
-
Please register or sign in to post a comment