summaryrefslogtreecommitdiffstats
path: root/maildrop/mailbot.c
diff options
context:
space:
mode:
Diffstat (limited to 'maildrop/mailbot.c')
-rw-r--r--maildrop/mailbot.c965
1 files changed, 965 insertions, 0 deletions
diff --git a/maildrop/mailbot.c b/maildrop/mailbot.c
new file mode 100644
index 0000000..dc8d43f
--- /dev/null
+++ b/maildrop/mailbot.c
@@ -0,0 +1,965 @@
+/*
+** Copyright 2001-2010 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#include "config.h"
+#include "dbobj.h"
+#include "liblock/config.h"
+#include "liblock/liblock.h"
+#include "unicode/unicode.h"
+#include "numlib/numlib.h"
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <time.h>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <langinfo.h>
+#if HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <ctype.h>
+#include "rfc822/rfc822.h"
+#include "rfc2045/rfc2045.h"
+#include "rfc2045/rfc2045charset.h"
+#include <sys/types.h>
+#include "mywait.h"
+#include <signal.h>
+#if HAVE_SYSEXITS_H
+#include <sysexits.h>
+#endif
+
+#ifndef EX_TEMPFAIL
+#define EX_TEMPFAIL 75
+#endif
+
+static const char *recips=0;
+static const char *dbfile=0;
+static const char *charset;
+static unsigned interval=1;
+static char *sender;
+
+struct header {
+ struct header *next;
+ char *buf;
+} ;
+
+static struct header *header_list;
+
+static struct header *extra_headers=0;
+
+
+void rfc2045_error(const char *str)
+{
+ fprintf(stderr, "%s\n", str);
+ exit(1);
+}
+
+static void usage()
+{
+ fprintf(stderr,
+ "Usage: mailbot [ options ] [ $MAILER arg arg... ]\n"
+ "\n"
+ " -t filename - text autoresponse\n"
+ " -c charset - text MIME character set (default %s)\n"
+ " -m filename - text autoresponse with a MIME header\n"
+ " -r addr1,addr2... - any 'addr' required in a To/Cc header\n",
+ charset);
+
+ fprintf(stderr,
+ " -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"
+ " -N - Omit contents of the original message from replies\n"
+ " -F \"separator\" - Set the forwarding separator\n"
+ " -S \"salutation\" - Set salutation for replies\n"
+ " -d $pathname - database to prevent duplicate autoresponses\n"
+ " -D x - at least 'x' days before dupes (default: 1)\n");
+
+ fprintf(stderr,
+ " -s subject - Subject: on autoresponses\n"
+ " -A \"Header: stuff\" - Additional header on the autoresponse\n"
+ " -M recipient - format \"replydsn\" as a DSN from 'recipient' (required)\n"
+ " -fuser@domain - Set responding address for replydsn\n"
+ " -f - Set responding address from $SENDER\n"
+ " -R type - Feedback type, for \"-T feedback\" or \"-T replyfeedback\":\n"
+ " \"abuse\", \"fraud\", \"other\", or \"virus\"\n"
+ " -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"
+);
+
+ fprintf(stderr,
+ " --feedback-original-envelope-id {\"<envelopeid>\"}\n"
+ " --feedback-original-mail-from {\"<mailfrom>\"}\n"
+ " --feedback-reporting-mta {\"dns; hostname\"}\n"
+ " --feedback-source-ip {aaa.bbb.ccc.ddd}\n"
+ " --feedback-incidents {n}\n"
+ " --feedback-authentication-results {\"results\"}\n"
+ " --feedback-original-rcpt-to {\"<rcptto>\"]\n"
+ " --feedback-reported-domain {example.com}\n"
+ " - optional parameters for -T \"feedback\" and \n"
+ " -T \"replyfeedback\"\n"
+ " $MAILER arg arg... - run $MAILER (sendmail) to mail the autoresponse\n"
+ );
+
+ exit(EX_TEMPFAIL);
+}
+
+static void read_headers(FILE *tmpfp)
+{
+ char buf[BUFSIZ];
+ struct header **lasthdr= &header_list, *prevhdr=0;
+
+ while (fgets(buf, sizeof(buf), tmpfp))
+ {
+ size_t l=strlen(buf);
+
+ if (l > 0 && buf[l-1] == '\n')
+ --l;
+ if (l > 0 && buf[l-1] == '\r')
+ --l;
+ buf[l]=0;
+
+ if (l == 0)
+ {
+ /* Eat rest of message from stdin */
+
+ while (getc(stdin) != EOF)
+ ;
+ break;
+ }
+
+ if (isspace((int)(unsigned char)buf[0]) && prevhdr)
+ {
+ if ( (prevhdr->buf=
+ realloc( prevhdr->buf,
+ strlen (prevhdr->buf)+2+strlen(buf)))
+ == NULL)
+ {
+ perror("malloc");
+ exit(EX_TEMPFAIL);
+ }
+ strcat(strcat( prevhdr->buf, "\n"), buf);
+ }
+ else
+ {
+ if ((*lasthdr=(struct header *)
+ malloc(sizeof(struct header))) == NULL ||
+ ((*lasthdr)->buf=strdup(buf)) == NULL)
+ {
+ perror("malloc");
+ exit(EX_TEMPFAIL);
+ }
+
+ prevhdr= *lasthdr;
+ lasthdr= &(*lasthdr)->next;
+ }
+ }
+
+ *lasthdr=NULL;
+}
+
+const char *hdr(const char *hdrname)
+{
+ struct header *h;
+ size_t l=strlen(hdrname);
+
+ for (h=header_list; h; h=h->next)
+ {
+ if (strncasecmp(h->buf, hdrname, l) == 0 &&
+ h->buf[l] == ':')
+ {
+ const char *p=h->buf+l+1;
+
+ while (*p && isspace((int)(unsigned char)*p))
+ ++p;
+ return (p);
+ }
+ }
+
+ return ("");
+}
+
+/*
+** Get the sender's address
+*/
+
+static void check_sender()
+{
+ const char *h=hdr("reply-to");
+ struct rfc822t *t;
+ struct rfc822a *a;
+
+ if (!h || !*h)
+ h=hdr("from");
+
+ if (!h || !*h)
+ exit(0);
+
+ t=rfc822t_alloc_new(h, NULL, NULL);
+
+ if (!t || !(a=rfc822a_alloc(t)))
+ {
+ perror("malloc");
+ exit(EX_TEMPFAIL);
+ }
+
+ if (a->naddrs <= 0)
+ exit (0);
+ sender=rfc822_getaddr(a, 0);
+ rfc822a_free(a);
+ rfc822t_free(t);
+
+ if (!sender || !*sender)
+ exit(0);
+}
+
+/*
+** Do not autorespond to DSNs
+*/
+
+static void check_dsn()
+{
+ static const char ct[]="multipart/report;";
+
+ const char *p=hdr("content-type");
+
+ if (strncasecmp(p, ct, sizeof(ct)-1) == 0)
+ exit(0);
+
+ p=hdr("precedence");
+
+ if (strncasecmp(p, "junk", 4) == 0 ||
+ strncasecmp(p, "bulk", 4) == 0 ||
+ strncasecmp(p, "list", 4) == 0)
+ exit(0); /* Just in case */
+
+ p=hdr("auto-submitted");
+
+ if (*p && strcmp(p, "no"))
+ exit(0);
+
+ p=hdr("list-id");
+
+ if (*p)
+ exit(0);
+}
+
+/*
+** Check for a required recipient
+*/
+
+static void check_recips()
+{
+ char *buf;
+ struct rfc822t *t;
+ struct rfc822a *a;
+ struct header *h;
+
+ if (!recips || !*recips)
+ return;
+
+ buf=strdup(recips);
+ if (!buf)
+ {
+ perror("strdup");
+ exit(EX_TEMPFAIL);
+ }
+
+ for (h=header_list; h; h=h->next)
+ {
+ int i;
+
+ if (strncasecmp(h->buf, "to:", 3) &&
+ strncasecmp(h->buf, "cc:", 3))
+ continue;
+
+ t=rfc822t_alloc_new(h->buf+3, NULL, NULL);
+ if (!t || !(a=rfc822a_alloc(t)))
+ {
+ perror("malloc");
+ exit(EX_TEMPFAIL);
+ }
+
+ for (i=0; i<a->naddrs; i++)
+ {
+ char *p=rfc822_getaddr(a, i);
+ char *q;
+
+ strcpy(buf, recips);
+
+ for (q=buf; (q=strtok(q, ", ")) != 0; q=0)
+ {
+ if (p && strcasecmp(p, q) == 0)
+ {
+ free(p);
+ free(buf);
+ rfc822a_free(a);
+ rfc822t_free(t);
+ return;
+ }
+ }
+
+ free(p);
+ }
+ rfc822a_free(a);
+ rfc822t_free(t);
+ }
+ free(buf);
+ exit(0);
+}
+
+/*
+** Check the dupe database.
+*/
+
+#ifdef DbObj
+static void check_db()
+{
+ char *dbname;
+ char *lockname;
+ int lockfd;
+ struct dbobj db;
+ time_t now;
+ char *sender_key, *p;
+
+ size_t val_len;
+ char *val;
+
+ if (!dbfile || !*dbfile)
+ return;
+
+ sender_key=strdup(sender);
+ dbname=malloc(strlen(dbfile)+ sizeof( "." DBNAME));
+ lockname=malloc(strlen(dbfile)+ sizeof(".lock"));
+
+ for (p=sender_key; *p; p++)
+ *p=tolower((int)(unsigned char)*p);
+
+ if (!dbname || !lockname || !sender)
+ {
+ perror("malloc");
+ exit(EX_TEMPFAIL);
+ }
+
+ strcat(strcpy(dbname, dbfile), "." DBNAME);
+ strcat(strcpy(lockname, dbfile), ".lock");
+
+ lockfd=open(lockname, O_RDWR|O_CREAT, 0666);
+
+ if (lockfd < 0 || ll_lock_ex(lockfd))
+ {
+ perror(lockname);
+ exit(EX_TEMPFAIL);
+ }
+
+ dbobj_init(&db);
+
+ if (dbobj_open(&db, dbname, "C") < 0)
+ {
+ perror(dbname);
+ exit(EX_TEMPFAIL);
+ }
+
+ time(&now);
+
+ val=dbobj_fetch(&db, sender_key, strlen(sender_key), &val_len, "");
+
+ if (val)
+ {
+ time_t t;
+
+ if (val_len >= sizeof(t))
+ {
+ memcpy(&t, val, sizeof(t));
+
+ if (t >= now - interval * 60 * 60 * 24)
+ {
+ free(val);
+ dbobj_close(&db);
+ close(lockfd);
+ exit(0);
+ }
+ }
+ free(val);
+ }
+
+ dbobj_store(&db, sender_key, strlen(sender_key),
+ (void *)&now, sizeof(now), "R");
+ dbobj_close(&db);
+ close(lockfd);
+}
+#endif
+
+static void opensendmail(int argn, int argc, char **argv)
+{
+ char **newargv;
+ int i;
+
+ if (argn >= argc)
+ {
+ static char *sendmail_argv[]={"sendmail", "-f", ""};
+
+ argn=0;
+ argc=3;
+ argv=sendmail_argv;
+ }
+
+ newargv=(char **)malloc( sizeof(char *)*(argc-argn+1));
+ if (!newargv)
+ {
+ perror("malloc");
+ exit(EX_TEMPFAIL);
+ }
+
+ for (i=0; argn+i < argc; i++)
+ newargv[i]=argv[argn+i];
+ newargv[i]=0;
+ signal(SIGCHLD, SIG_DFL);
+
+ execvp(newargv[0], newargv);
+ perror(newargv[0]);
+ exit(EX_TEMPFAIL);
+}
+
+static struct rfc2045 *savemessage(FILE *tmpfp)
+{
+ struct rfc2045 *rfcp=rfc2045_alloc();
+ char buf[BUFSIZ];
+ int n;
+
+ if (!rfcp)
+ {
+ perror("rfc2045_alloc");
+ exit(1);
+ }
+
+ while ((n=fread(buf, 1, sizeof(buf), stdin)) > 0)
+ {
+ if (fwrite(buf, n, 1, tmpfp) != 1)
+ {
+ perror("fwrite(tempfile)");
+ exit(1);
+ }
+
+ rfc2045_parse(rfcp, buf, n);
+ }
+
+ if (n < 0)
+ {
+ perror("tempfile");
+ exit(1);
+ }
+ return rfcp;
+}
+
+
+struct mimeautoreply_s {
+ struct rfc2045_mkreplyinfo info;
+ FILE *outf;
+
+ FILE *contentf;
+};
+
+static void mimeautoreply_write_func(const char *str, size_t cnt, void *ptr)
+{
+ if (cnt &&
+ fwrite(str, cnt, 1, ((struct mimeautoreply_s *)ptr)->outf) != 1)
+ {
+ perror("tmpfile");
+ exit(1);
+ }
+}
+
+static void mimeautoreply_writesig_func(void *ptr)
+{
+}
+
+static int mimeautoreply_myaddr_func(const char *addr, void *ptr)
+{
+ return 0;
+}
+
+static void copy_headers(void *ptr)
+{
+ struct mimeautoreply_s *p=(struct mimeautoreply_s *)ptr;
+ char buf[BUFSIZ];
+
+ static const char ct[]="Content-Transfer-Encoding:";
+
+ while (fgets(buf, sizeof(buf), p->contentf) != NULL)
+ {
+ if (buf[0] == '\n')
+ break;
+
+ if (strncasecmp(buf, ct, sizeof(ct)-1) == 0)
+ continue;
+
+ mimeautoreply_write_func(buf, strlen(buf), ptr);
+
+ while (strchr(buf, '\n') == NULL)
+ {
+ if (fgets(buf, sizeof(buf), p->contentf) == NULL)
+ break;
+
+ mimeautoreply_write_func(buf, strlen(buf), ptr);
+ }
+ }
+}
+
+static void copy_body(void *ptr)
+{
+ struct mimeautoreply_s *p=(struct mimeautoreply_s *)ptr;
+ char buf[BUFSIZ];
+
+ while (fgets(buf, sizeof(buf), p->contentf) != NULL)
+ {
+ mimeautoreply_write_func(buf, strlen(buf), ptr);
+ }
+}
+
+struct fb {
+ struct fb *next;
+ const char *n;
+ const char *v;
+};
+
+int main(int argc, char **argv)
+{
+ int argn;
+ FILE *tmpfp;
+ struct rfc2045 *rfcp;
+ struct mimeautoreply_s replyinfo;
+ const char *subj=0;
+ const char *txtfile=0, *mimefile=0;
+ const char *mimedsn=0;
+ int nosend=0;
+ const char *replymode="reply";
+ int replytoenvelope=0;
+ int donotquote=0;
+ int fullmsg=0;
+ const char *forwardsep="--- Forwarded message ---";
+ const char *replysalut="%F writes:";
+ struct rfc2045src *src;
+
+ const char *feedback_type=0;
+ struct fb *fb_list=0, **fb_tail=&fb_list;
+ size_t fb_cnt=0;
+
+ setlocale(LC_ALL, "");
+ charset=unicode_default_chset();
+
+ sender=NULL;
+ for (argn=1; argn < argc; argn++)
+ {
+ char optc;
+ char *optarg;
+
+ if (argv[argn][0] != '-')
+ break;
+
+ if (strcmp(argv[argn], "--") == 0)
+ {
+ ++argn;
+ break;
+ }
+
+ if (strncmp(argv[argn], "--feedback-", 11) == 0)
+ {
+ struct fb *f;
+
+ if (++argn >= argc)
+ break;
+
+ if ((f=malloc(sizeof(struct fb))) == NULL)
+ {
+ perror("malloc");
+ exit(1);
+ }
+
+ f->n=argv[argn-1]+11;
+ f->v=argv[argn];
+
+ f->next=NULL;
+ *fb_tail=f;
+ fb_tail=&f->next;
+ ++fb_cnt;
+ continue;
+ }
+
+ optc=argv[argn][1];
+ optarg=argv[argn]+2;
+
+ if (!*optarg)
+ optarg=NULL;
+
+ switch (optc) {
+ case 'c':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ if (optarg && *optarg)
+ {
+ char *p=libmail_u_convert_tobuf("",
+ optarg,
+ libmail_u_ucs4_native,
+ NULL);
+
+ if (!p)
+ {
+ fprintf(stderr, "Unknown charset: %s\n",
+ charset);
+ exit(1);
+ }
+ free(p);
+ charset=optarg;
+ }
+ continue;
+ case 't':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ txtfile=optarg;
+ continue;
+ case 'm':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ mimefile=optarg;
+ continue;
+ case 'r':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ recips=optarg;
+ continue;
+ case 'M':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ mimedsn=optarg;
+ continue;
+ case 'R':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ feedback_type=optarg;
+ continue;
+ case 'd':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ dbfile=optarg;
+ continue;
+ case 'e':
+ replytoenvelope=1;
+ continue;
+ case 'T':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ if (optarg && *optarg)
+ replymode=optarg;
+ continue;
+ case 'N':
+ donotquote=1;
+ continue;
+ case 'a':
+ fullmsg=1;
+ continue;
+ case 'F':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ if (optarg && *optarg)
+ forwardsep=optarg;
+ continue;
+ case 'S':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ if (optarg && *optarg)
+ replysalut=optarg;
+ continue;
+ case 'D':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ interval=optarg ? atoi(optarg):1;
+ continue;
+ case 'A':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ if (optarg)
+ {
+ struct header **h;
+
+ for (h= &extra_headers; *h;
+ h= &(*h)->next)
+ ;
+
+ if ((*h=malloc(sizeof(struct header))) == 0 ||
+ ((*h)->buf=strdup(optarg)) == 0)
+ {
+ perror("malloc");
+ exit(EX_TEMPFAIL);
+ }
+ (*h)->next=0;
+ }
+ continue;
+ case 's':
+ if (!optarg && argn+1 < argc)
+ optarg=argv[++argn];
+
+ subj=optarg;
+ continue;
+
+ case 'f':
+ if (optarg && *optarg)
+ {
+ sender=strdup(optarg);
+ }
+ else
+ {
+ sender=getenv("SENDER");
+ if (!sender)
+ continue;
+ sender=strdup(sender);
+ }
+ if (sender == NULL)
+ {
+ perror("malloc");
+ exit(1);
+ }
+ continue;
+ case 'n':
+ nosend=1;
+ continue;
+ default:
+ usage();
+ }
+ }
+
+ if (!txtfile && !mimefile)
+ usage();
+
+ if (txtfile && mimefile)
+ usage();
+
+ tmpfp=tmpfile();
+
+ if (!tmpfp)
+ {
+ perror("tmpfile");
+ exit(1);
+ }
+
+ rfcp=savemessage(tmpfp);
+
+ if (fseek(tmpfp, 0L, SEEK_SET) < 0)
+ {
+ perror("fseek(tempfile)");
+ exit(1);
+ }
+
+ read_headers(tmpfp);
+
+ if (sender == NULL || *sender == 0)
+ check_sender();
+
+ check_dsn();
+ check_recips();
+#ifdef DbObj
+ check_db();
+#endif
+
+ src=rfc2045src_init_fd(fileno(tmpfp));
+
+ memset(&replyinfo, 0, sizeof(replyinfo));
+
+ replyinfo.info.src=src;
+ replyinfo.info.rfc2045partp=rfcp;
+ replyinfo.info.voidarg=&replyinfo;
+
+ replyinfo.info.write_func=mimeautoreply_write_func;
+
+ replyinfo.info.writesig_func=mimeautoreply_writesig_func;
+
+ replyinfo.info.myaddr_func=mimeautoreply_myaddr_func;
+
+ replyinfo.info.replymode=replymode;
+ replyinfo.info.replytoenvelope=replytoenvelope;
+ replyinfo.info.donotquote=donotquote;
+
+ replyinfo.info.replysalut=replysalut;
+ replyinfo.info.forwarddescr="Forwarded message";
+ replyinfo.info.mailinglists="";
+ replyinfo.info.charset=charset;
+ replyinfo.info.subject=subj;
+ replyinfo.info.forwardsep=forwardsep;
+ replyinfo.info.fullmsg=fullmsg;
+
+ if (mimedsn && *mimedsn)
+ {
+ replyinfo.info.dsnfrom=mimedsn;
+ replyinfo.info.replymode="replydsn";
+ }
+ else if (feedback_type && *feedback_type)
+ {
+ replyinfo.info.feedbacktype=feedback_type;
+
+ if (strcmp(replyinfo.info.replymode, "feedback") &&
+ strcmp(replyinfo.info.replymode, "replyfeedback"))
+ {
+ fprintf(stderr, "\"-T feedback\" or \"-T replyfeedback\" required\n");
+ exit(1);
+ }
+
+ if (fb_cnt > 0)
+ {
+ size_t i;
+ struct fb *p;
+ const char **strp;
+
+ replyinfo.info.feedbackheaders=
+ strp=malloc(sizeof(char *) * 2 * fb_cnt+1);
+
+ for (i=0, p=fb_list; p; p=p->next)
+ {
+ strp[i++]=p->n;
+ strp[i++]=p->v;
+ }
+ strp[i]=NULL;
+ }
+ }
+
+ if (mimefile)
+ {
+ if ((replyinfo.contentf=fopen(mimefile, "r")) == NULL)
+ {
+ perror(mimefile);
+ exit(1);
+ }
+
+ {
+ struct rfc2045 *rfcp=rfc2045_alloc();
+ static const char mv[]="Mime-Version: 1.0\n";
+ char buf[BUFSIZ];
+ int l;
+ const char *content_type;
+ const char *content_transfer_encoding;
+ const char *charset;
+
+ rfc2045_parse(rfcp, mv, sizeof(mv)-1);
+
+ while ((l=fread(buf, 1, sizeof(buf), replyinfo.contentf)
+ ) > 0)
+ {
+ rfc2045_parse(rfcp, buf, l);
+ }
+
+ if (l < 0 ||
+ fseek(replyinfo.contentf, 0L, SEEK_SET) < 0)
+ {
+ perror(mimefile);
+ exit(1);
+ }
+
+ rfc2045_mimeinfo(rfcp, &content_type,
+ &content_transfer_encoding,
+ &charset);
+
+ if (strcasecmp(content_type, "text/plain"))
+ {
+ fprintf(stderr,
+ "%s must specify text/plain MIME type\n",
+ mimefile);
+ exit(1);
+ }
+ {
+ char *p=NULL;
+
+ if (charset)
+ p=libmail_u_convert_tobuf("",
+ charset,
+ libmail_u_ucs4_native,
+ NULL);
+
+ if (!p)
+ {
+ fprintf(stderr, "Unknown charset in %s\n",
+ mimefile);
+ exit(1);
+ }
+ free(p);
+ replyinfo.info.charset=strdup(charset);
+ }
+ rfc2045_free(rfcp);
+ }
+ replyinfo.info.content_set_charset=copy_headers;
+ replyinfo.info.content_specify=copy_body;
+ }
+ else if (txtfile)
+ {
+ if ((replyinfo.contentf=fopen(txtfile, "r")) == NULL)
+ {
+ perror(mimefile);
+ exit(1);
+ }
+ replyinfo.info.content_specify=copy_body;
+ }
+
+ if (replyinfo.contentf)
+ fcntl(fileno(replyinfo.contentf), F_SETFD, FD_CLOEXEC);
+
+ if (nosend)
+ replyinfo.outf=stdout;
+ else
+ {
+ replyinfo.outf=tmpfile();
+
+ if (replyinfo.outf == NULL)
+ {
+ perror("tmpfile");
+ exit(1);
+ }
+ }
+
+ {
+ struct header *h;
+
+ for (h=extra_headers; h; h=h->next)
+ fprintf(replyinfo.outf, "%s\n", h->buf);
+ }
+ fprintf(replyinfo.outf,
+ "Precedence: junk\n"
+ "Auto-Submitted: auto-replied\n");
+
+ if (rfc2045_makereply(&replyinfo.info) < 0 ||
+ fflush(replyinfo.outf) < 0 || ferror(replyinfo.outf) ||
+ (!nosend &&
+ (
+ fseek(replyinfo.outf, 0L, SEEK_SET) < 0 ||
+ (close(0), dup(fileno(replyinfo.outf))) < 0)
+ ))
+ {
+ perror("tempfile");
+ exit(1);
+ }
+ fclose(replyinfo.outf);
+ fcntl(0, F_SETFD, 0);
+
+ rfc2045_free(rfcp);
+ rfc2045src_deinit(src);
+
+ if (!nosend)
+ opensendmail(argn, argc, argv);
+ return (0);
+}