diff options
| author | Sam Varshavchik | 2014-06-18 18:13:27 -0400 |
|---|---|---|
| committer | Sam Varshavchik | 2014-06-18 18:13:27 -0400 |
| commit | 8f3ed494650eac351a8eadb1af08f309b89dfb2d (patch) | |
| tree | c7255ab2a519dcebf68cfcbd0865dda41bd76005 /maildrop | |
| parent | a7c7a64052adc5723d4c549f163a70e0375e2adf (diff) | |
| download | courier-libs-8f3ed494650eac351a8eadb1af08f309b89dfb2d.tar.bz2 | |
maildrop: add -T replydraft option
Diffstat (limited to 'maildrop')
| -rw-r--r-- | maildrop/Makefile.am | 4 | ||||
| -rw-r--r-- | maildrop/mailbot.c | 173 | ||||
| -rw-r--r-- | maildrop/mailbot.sgml | 153 |
3 files changed, 278 insertions, 52 deletions
diff --git a/maildrop/Makefile.am b/maildrop/Makefile.am index d37d054..0367891 100644 --- a/maildrop/Makefile.am +++ b/maildrop/Makefile.am @@ -57,10 +57,10 @@ reformail_DEPENDENCIES = $(reformail_LDADD) noinst_PROGRAMS=maildrop reformail mailbot mailbot_SOURCES=mailbot.c -mailbot_DEPENDENCIES=../rfc2045/librfc2045.la \ +mailbot_DEPENDENCIES=../rfc2045/librfc2045.la ../maildir/libmaildir.la \ ../rfc822/librfc822.la ../liblock/liblock.la \ ../numlib/libnumlib.la $(DBLIB) -mailbot_LDADD=../rfc2045/librfc2045.la \ +mailbot_LDADD=../rfc2045/librfc2045.la ../maildir/libmaildir.la \ ../rfc822/librfc822.la ../liblock/liblock.la \ ../numlib/libnumlib.la $(DBLIB) -lunicode mailbot_LDFLAGS = -static diff --git a/maildrop/mailbot.c b/maildrop/mailbot.c index 5fbb860..2ae29d3 100644 --- a/maildrop/mailbot.c +++ b/maildrop/mailbot.c @@ -1,5 +1,5 @@ /* -** Copyright 2001-2010 Double Precision, Inc. +** Copyright 2001-2014 Double Precision, Inc. ** See COPYING for distribution information. */ @@ -7,6 +7,7 @@ #include "dbobj.h" #include "liblock/config.h" #include "liblock/liblock.h" +#include "maildir/maildirmisc.h" #include <unicode.h> #include "numlib/numlib.h" #include <string.h> @@ -27,6 +28,9 @@ #include "rfc2045/rfc2045.h" #include "rfc2045/rfc2045charset.h" #include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <dirent.h> #include "mywait.h" #include <signal.h> #if HAVE_SYSEXITS_H @@ -74,7 +78,7 @@ static void usage() " -e - Prefer replies to Errors-To: or Return-Path: instead\n" " of From:\n" " -T type - \"type\": reply, replyall, replydsn, replyfeedback,\n" - " forward, forwardatt\n" + " replydraft, forward, forwardatt\n" " -N - Omit contents of the original message from replies\n" " -F \"separator\" - Set the forwarding separator\n" " -S \"salutation\" - Set salutation for replies\n" @@ -92,6 +96,8 @@ static void usage() " -n - only show the resulting message, do not send it\n" " -a - Attach entire message for replydsn, feedback, and\n" " replyfeedback, instead of only the headers.\n" + " -l - maildir to read a draft message with the reply\n" + " (required by -T replydraft).\n" ); fprintf(stderr, @@ -524,6 +530,137 @@ static void copy_body(void *ptr) } } +static void copy_draft(void *ptr) +{ + struct mimeautoreply_s *p=(struct mimeautoreply_s *)ptr; + char buf[BUFSIZ]; + int copying_this_header=0; + int continuing=0; + + while (1) + { + if (!fgets(buf, sizeof(buf), p->contentf)) + return; + + if (!continuing) + { + if (*buf == '\n') + break; + + if (!isspace(*buf)) + { + /* Copy MIME headers only */ + copying_this_header= + strncasecmp(buf, "content-", 8) == 0; + } + } + + continuing=strchr(buf, '\n') == NULL; + + if (copying_this_header) + mimeautoreply_write_func(buf, strlen(buf), ptr); + } + + do + { + mimeautoreply_write_func(buf, strlen(buf), ptr); + } while (fgets(buf, sizeof(buf), p->contentf)); +} + +FILE *find_draft(const char *maildirfolder) +{ + char *draftfile=0; + struct stat draft_stat; + + FILE *fp=NULL; + static const char * const newcur[2]={"new", "cur"}; + int i; + + for (i=0; i<2; ++i) + { + char *dirbuf=malloc(strlen(maildirfolder)+10); + DIR *dirp; + struct dirent *de; + + if (!dirbuf) + { + perror("malloc"); + exit(1); + } + + strcat(strcat(strcpy(dirbuf, maildirfolder), "/"), + newcur[i]); + + dirp=opendir(dirbuf); + if (!dirp) + { + free(dirbuf); + continue; + } + + while ((de=readdir(dirp)) != NULL) + { + const char *filename=de->d_name; + char *filenamebuf; + FILE *new_file; + struct stat new_stat; + + if (*filename == '.') + continue; + if (MAILDIR_DELETED(filename)) + continue; + + /* + ** 1st maildir filename component should be creation + ** time_t, take advantage of that. + */ + + if (draftfile && atol(draftfile) > atol(filename)) + continue; + + filenamebuf=malloc(strlen(dirbuf)+strlen(filename)+2); + if (!filenamebuf) + { + perror("malloc"); + exit(1); + } + strcat(strcat(strcpy(filenamebuf, dirbuf), "/"), + filename); + new_file=fopen(filenamebuf, "r"); + free(filenamebuf); + if (!new_file) + continue; + + if (fstat(fileno(new_file), &new_stat) < 0) + continue; + + if (draftfile) + { + if (new_stat.st_mtime < draft_stat.st_mtime) + continue; + + if (new_stat.st_mtime == draft_stat.st_mtime + && strcmp(filename, draftfile) > 0) + continue; + + free(draftfile); + fclose(fp); + } + + if ((draftfile=strdup(filename)) == NULL) + { + perror("strdup"); + exit(1); + } + fp=new_file; + draft_stat=new_stat; + } + free(dirbuf); + closedir(dirp); + } + return fp; +} + struct fb { struct fb *next; const char *n; @@ -538,6 +675,7 @@ int main(int argc, char **argv) struct mimeautoreply_s replyinfo; const char *subj=0; const char *txtfile=0, *mimefile=0; + FILE *draftfile=0; const char *mimedsn=0; int nosend=0; const char *replymode="reply"; @@ -546,6 +684,7 @@ int main(int argc, char **argv) int fullmsg=0; const char *forwardsep="--- Forwarded message ---"; const char *replysalut="%F writes:"; + const char *maildirfolder=0; struct rfc2045src *src; const char *feedback_type=0; @@ -739,6 +878,11 @@ int main(int argc, char **argv) exit(1); } continue; + case 'l': + if (!optarg && argn+1 < argc) + optarg=argv[++argn]; + maildirfolder=optarg; + continue; case 'n': nosend=1; continue; @@ -747,12 +891,22 @@ int main(int argc, char **argv) } } - if (!txtfile && !mimefile) - usage(); - - if (txtfile && mimefile) - usage(); + if (strcmp(replymode, "replydraft") == 0) + { + if (!maildirfolder) + usage(); + draftfile=find_draft(maildirfolder); + if (!draftfile) + exit(0); + } + else + { + if (!txtfile && !mimefile) + usage(); + if (txtfile && mimefile) + usage(); + } tmpfp=tmpfile(); if (!tmpfp) @@ -915,6 +1069,11 @@ int main(int argc, char **argv) } replyinfo.info.content_specify=copy_body; } + else if (draftfile) + { + replyinfo.contentf=draftfile; + replyinfo.info.content_specify=copy_draft; + } if (replyinfo.contentf) fcntl(fileno(replyinfo.contentf), F_SETFD, FD_CLOEXEC); diff --git a/maildrop/mailbot.sgml b/maildrop/mailbot.sgml index c9700b2..fdbfe3c 100644 --- a/maildrop/mailbot.sgml +++ b/maildrop/mailbot.sgml @@ -17,14 +17,14 @@ <refsynopsisdiv> <cmdsynopsis sepchar=" "> - <command moreinfo="none">mailbot</command> + <command>mailbot</command> <arg choice="opt" rep="norepeat">options</arg> <arg choice="req" rep="norepeat"><replaceable>program</replaceable></arg> <arg rep="repeat" choice="opt">arg</arg> </cmdsynopsis> <informalexample> - <para>In <filename moreinfo="none">.mailfilter:</filename></para> + <para>In <filename>.mailfilter:</filename></para> <programlisting format="linespecific"> if (/^Subject: *info/) { @@ -39,21 +39,21 @@ if (/^Subject: *info/) <title>DESCRIPTION</title> - <para><command moreinfo="none">mailbot</command> reads an E-mail message on standard input + <para><command>mailbot</command> reads an E-mail message on standard input and creates an E-mail message replying to the original message's sender. A -<command moreinfo="none">program</command> is specified as an argument to -<command moreinfo="none">mailbot</command> after all of <command moreinfo="none">mailbot</command> options. -<command moreinfo="none">program</command> is expected to read the +<command>program</command> is specified as an argument to +<command>mailbot</command> after all of <command>mailbot</command> options. +<command>program</command> is expected to read the created autoreply on its standard input, and mail it. -If <command moreinfo="none">program</command> is not specified, -<command moreinfo="none">mailbot</command> runs '<literal moreinfo="none">sendmail -f ""</literal>'.</para> +If <command>program</command> is not specified, +<command>mailbot</command> runs '<literal>sendmail -f ""</literal>'.</para> <para> -<command moreinfo="none">mailbot</command> has several options for suppressing duplicate +<command>mailbot</command> has several options for suppressing duplicate autoresponse messages. -If <command moreinfo="none">mailbot</command> chooses not to send an autoresponse, it quietly -terminates without running <command moreinfo="none">program</command>. +If <command>mailbot</command> chooses not to send an autoresponse, it quietly +terminates without running <command>program</command>. The autoresponse is optionally formatted as a MIME delivery status notification.</para> @@ -61,13 +61,16 @@ formatted as a MIME delivery status notification.</para> The text of the autoresponse is specified by the <option>-t</option> or the <option>-m</option> argument. Either one is required. Everything else is optional. +The only exception is the <option>-T replydraft</option> option, which requires +the <option>-l</option> option instead of either <option>-t</option> or +<option>-m</option>. The default behavior is to send an autoresponse unless the original message -has the "<literal moreinfo="none">Precedence: junk</literal>" or the -"<literal moreinfo="none">Precedence: bulk</literal>" header, or the -"<literal moreinfo="none">Precedence: list</literal>" header, or the -"<literal moreinfo="none">List-ID:</literal>" header, +has the "<literal>Precedence: junk</literal>" or the +"<literal>Precedence: bulk</literal>" header, or the +"<literal>Precedence: list</literal>" header, or the +"<literal>List-ID:</literal>" header, or if -its MIME content type is "<literal moreinfo="none">multipart/report</literal>" +its MIME content type is "<literal>multipart/report</literal>" (this is the MIME content type for delivery status notifications). The <option>-M</option> option formats the the autoresponse itself as a MIME delivery status notification.</para> @@ -97,9 +100,9 @@ Address the autoresponse to <replaceable>address</replaceable>, which must be an <ulink url="http://tools.ietf.org/html/rfc2822">RFC 2822</ulink> address. -By default <command moreinfo="none">mailbot</command> takes the autoresponse +By default <command>mailbot</command> takes the autoresponse address from the -<literal moreinfo="none">From:</literal> (or the <literal moreinfo="none">Reply-To:</literal>) header +<literal>From:</literal> (or the <literal>Reply-To:</literal>) header in the original message. <option>-f</option>, if present, overrides and explicitly sets the autoresponse address. @@ -152,7 +155,7 @@ using their original width.</para> <para> Set the autoresponse's MIME character set to <replaceable>charset</replaceable>. -Run <command moreinfo="none">mailbot</command> without any arguments to see the +Run <command>mailbot</command> without any arguments to see the default character set.</para> </listitem> </varlistentry> @@ -160,7 +163,7 @@ default character set.</para> <term>-m <replaceable>filename</replaceable></term> <listitem> <para> - Read a MIME autoresponse from <filename moreinfo="none">filename</filename>. + Read a MIME autoresponse from <filename>filename</filename>. This is similar to the <option>-t</option> option, except that <replaceable>filename</replaceable> contains MIME headers, followed by a blank line, and the corresponding @@ -178,7 +181,7 @@ default character set.</para> If the specified file has a <quote>Content-Transfer-Encoding</quote> header it must be either <quote>7bit</quote> or <quote>8bit</quote>, it may not be <quote>quoted-printable</quote>. - <command moreinfo="none">mailbot</command> always drops any + <command>mailbot</command> always drops any existing <quote>Content-Transfer-Encoding</quote> header and always adds the <quote>Content-Transfer-Encoding: 8bit</quote> header, even with @@ -202,7 +205,7 @@ The lamb was sure to go.</programlisting> <note> <para> When the <option>-m</option> option is specified -<command moreinfo="none">mailbot</command> ignores the locale's character +<command>mailbot</command> ignores the locale's character set and formats the autoreply according to the character set read from the <quote>Content-Type</quote> header.</para> </note> @@ -220,10 +223,10 @@ set and formats the autoreply according to the character set read from the E-mail address that generates the DSN. Note that the <option>-A</option> option should still be used in addition to <option>-M</option> in order to set the - <literal moreinfo="none">From:</literal> header on the autoresponse. + <literal>From:</literal> header on the autoresponse. <option>-M</option> sets the DSN address only. The <option>-M</option> option automatically sets - <option>-T <literal moreinfo="none">replydsn</literal></option> + <option>-T <literal>replydsn</literal></option> </para> </listitem> </varlistentry> @@ -274,6 +277,14 @@ set and formats the autoreply according to the character set read from the </listitem> <listitem> <para> + <quote>replydraft</quote> - like <quote>reply</quote>, with + the text of the autoresponse coming from a maildir specified + by the <option>-l</option> option. See <quote>Autoreplies + from a maildir folder</quote>, below. + </para> + </listitem> + <listitem> + <para> <quote>forward</quote> - attach the original message as forwarded text. </para> @@ -381,62 +392,62 @@ set and formats the autoreply according to the character set read from the <itemizedlist> <listitem> <para> - <literal moreinfo="none">%%</literal> - an explicit <literal moreinfo="none">%</literal> + <literal>%%</literal> - an explicit <literal>%</literal> character. </para> </listitem> <listitem> <para> - <literal moreinfo="none">%n</literal> - a newline character. + <literal>%n</literal> - a newline character. </para> </listitem> <listitem> <para> - <literal moreinfo="none">%C</literal> - the + <literal>%C</literal> - the <quote>X-Newsgroup:</quote> header from the original message. </para> </listitem> <listitem> <para> - <literal moreinfo="none">%N</literal> - the <quote>Newsgroups:</quote> + <literal>%N</literal> - the <quote>Newsgroups:</quote> header from the original message. </para> </listitem> <listitem> <para> - <literal moreinfo="none">%i</literal> - the <quote>Message-ID:</quote> + <literal>%i</literal> - the <quote>Message-ID:</quote> header from the original message. </para> </listitem> <listitem> <para> - <literal moreinfo="none">%f</literal> - the original message's sender's address. + <literal>%f</literal> - the original message's sender's address. </para> </listitem> <listitem> <para> - <literal moreinfo="none">%F</literal> - the original message's sender's name. + <literal>%F</literal> - the original message's sender's name. </para> </listitem> <listitem> <para> - <literal moreinfo="none">%S</literal> - the + <literal>%S</literal> - the <quote>Subject:</quote> header from the original message </para> </listitem> <listitem> <para> - <literal moreinfo="none">%d</literal> - the original message's date, in the + <literal>%d</literal> - the original message's date, in the local timezone. </para> </listitem> <listitem> <para> - <literal moreinfo="none">%{<replaceable>...</replaceable>}d</literal> - - use <function moreinfo="none">strftime</function>() to format the original + <literal>%{<replaceable>...</replaceable>}d</literal> + - use <function>strftime</function>() to format the original message's date. - A plain <literal moreinfo="none">%d</literal> is equivalent to - <literal moreinfo="none">%{%a, %d %b %Y %H:%M:%S %z}d</literal>. + A plain <literal>%d</literal> is equivalent to + <literal>%{%a, %d %b %Y %H:%M:%S %z}d</literal>. </para> </listitem> </itemizedlist> @@ -452,7 +463,7 @@ set and formats the autoreply according to the character set read from the <listitem> <para> - When generating a <literal moreinfo="none">forward</literal>, use the + When generating a <literal>forward</literal>, use the <replaceable>marker</replaceable> to separate the forwarded message from the autoreply text, instead of the default <quote>--- Forwarded message ---</quote> @@ -467,9 +478,9 @@ set and formats the autoreply according to the character set read from the <replaceable>addrlist</replaceable> is a comma-separated list of <ulink url="http://tools.ietf.org/html/rfc2822">RFC 2822</ulink> E-mail addresses. -<command moreinfo="none">mailbot</command> sends an autoresponse only if +<command>mailbot</command> sends an autoresponse only if the original message has at least one of the specified addresses in any -<literal moreinfo="none">To:</literal> or <literal moreinfo="none">Cc:</literal> header.</para> +<literal>To:</literal> or <literal>Cc:</literal> header.</para> </listitem> </varlistentry> <varlistentry> @@ -482,7 +493,7 @@ and prevent duplicate autoresponses going to the same address (suppress autoresponses going back to the same senders, for subsequent received messages). The <option>-d</option> option is only available if -<command moreinfo="none">maildrop</command> has GDBM/DB extensions enabled.</para> +<command>maildrop</command> has GDBM/DB extensions enabled.</para> </listitem> </varlistentry> <varlistentry> @@ -502,7 +513,7 @@ the <option>-D</option> option has elapsed.</para> <term>-s "<replaceable>subject</replaceable>"</term> <listitem> <para> -Set the <literal moreinfo="none">Subject:</literal> header on the autoresponse to +Set the <literal>Subject:</literal> header on the autoresponse to <replaceable>subject</replaceable>.</para> </listitem> </varlistentry> @@ -544,9 +555,65 @@ Set the <literal moreinfo="none">Subject:</literal> header on the autoresponse t </para> </listitem> </varlistentry> + <varlistentry> + <term>-l <replaceable>maildir</replaceable></term> + + <listitem> + <para> + Specifies the maildir for the <quote>-T replydraft</quote> + option. See <quote>Autoreplies + from a maildir folder</quote>, below. + </para> + </listitem> + </varlistentry> </variablelist> - </refsect1> + <refsect2> + <title>Autoreplies from a maildir folder</title> + + <para>In <filename>.mailfilter:</filename></para> + + <blockquote> + <informalexample> + <programlisting> +cc "| mailbot -T replydraft -l './Maildir/.Vacation' \ + -d autoresponsedb \ + -A 'From: info@domain.com' /usr/bin/sendmail -f ''" +to "./Maildir"</programlisting> + </informalexample> + </blockquote> + + <para> + The <option>-T replydraft</option> reply format takes the content of + the autoresponse from the most recent message in a maildir. + The <option>-l</option> option specifies the maildir. The above + example takes the message from <literal>$HOME/Maildir/.Drafts</literal> + which should be a maildir (with the usual <filename>cur</filename>, + <filename>new</filename>, and <filename>tmp</filename> subdirectories). + It would typically get created by Courier-IMAP as a folder named + <quote>Vacation</quote>. + </para> + + <para> + This makes it possible to install autoreplies via an IMAP client by + creating a folder named <quote>Vacation</quote>, and copying a message + into it. The contents of the message become the autoresponse. + </para> + + <para> + If the named maildir does not exist, or is empty, + <command>mailbot</command> does nothing. If the named maildir has + more than one message, the most recent message gets used. + </para> + + <para> + The above example uses additional <command>mailbot</command> options + to suppress duplicate autoresponses, and to set the <quote>From:</quote> + header on the autoresponse. + </para> + </refsect2> + + </refsect1> <refsect1> <title>SEE ALSO</title> |
