summaryrefslogtreecommitdiffstats
path: root/maildrop
diff options
context:
space:
mode:
authorSam Varshavchik2014-06-18 18:13:27 -0400
committerSam Varshavchik2014-06-18 18:13:27 -0400
commit8f3ed494650eac351a8eadb1af08f309b89dfb2d (patch)
treec7255ab2a519dcebf68cfcbd0865dda41bd76005 /maildrop
parenta7c7a64052adc5723d4c549f163a70e0375e2adf (diff)
downloadcourier-libs-8f3ed494650eac351a8eadb1af08f309b89dfb2d.tar.bz2
maildrop: add -T replydraft option
Diffstat (limited to 'maildrop')
-rw-r--r--maildrop/Makefile.am4
-rw-r--r--maildrop/mailbot.c173
-rw-r--r--maildrop/mailbot.sgml153
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>