Commit cdb95d01 cdb95d01e4ead871b5d10543a32dd28ea5740a0d by Sergey Poznyakoff

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
1 parent 42ca2c2e
...@@ -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
......