Back to index

courier  0.68.2
Classes | Defines | Functions | Variables
mailbot.c File Reference
#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>
#include <langinfo.h>
#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>

Go to the source code of this file.

Classes

struct  header
struct  mimeautoreply_s
struct  fb

Defines

#define EX_TEMPFAIL   75

Functions

void rfc2045_error (const char *str)
static void usage ()
static void read_headers (FILE *tmpfp)
const char * hdr (const char *hdrname)
static void check_sender ()
static void check_dsn ()
static void check_recips ()
static void opensendmail (int argn, int argc, char **argv)
static struct rfc2045savemessage (FILE *tmpfp)
static void mimeautoreply_write_func (const char *str, size_t cnt, void *ptr)
static void mimeautoreply_writesig_func (void *ptr)
static int mimeautoreply_myaddr_func (const char *addr, void *ptr)
static void copy_headers (void *ptr)
static void copy_body (void *ptr)
int main (int argc, char **argv)

Variables

static const char * recips = 0
static const char * dbfile = 0
static const char * charset
static unsigned interval = 1
static char * sender
static struct headerheader_list
static struct headerextra_headers = 0

Class Documentation

struct header

Definition at line 16 of file mimegpgheader.h.

Collaboration diagram for header:
Class Members
char * buf
char * header
struct header * next
struct mimeautoreply_s

Definition at line 463 of file mailbot.c.

Class Members
FILE * contentf
FILE * outf
struct fb

Definition at line 527 of file mailbot.c.

Collaboration diagram for fb:
Class Members
const char * n
struct fb * next
const char * v

Define Documentation

#define EX_TEMPFAIL   75

Definition at line 37 of file mailbot.c.


Function Documentation

static void check_dsn ( ) [static]

Definition at line 227 of file mailbot.c.

{
       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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void check_recips ( ) [static]

Definition at line 258 of file mailbot.c.

{
       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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void check_sender ( ) [static]

Definition at line 193 of file mailbot.c.

{
       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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void copy_body ( void *  ptr) [static]

Definition at line 516 of file mailbot.c.

{
       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);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void copy_headers ( void *  ptr) [static]

Definition at line 489 of file mailbot.c.

{
       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);
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* hdr ( const char *  hdrname)

Definition at line 168 of file mailbot.c.

{
       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 ("");
}

Here is the caller graph for this function:

int main ( int  argc,
char **  argv 
)

Definition at line 533 of file mailbot.c.

{
       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);
}

Here is the call graph for this function:

static int mimeautoreply_myaddr_func ( const char *  addr,
void *  ptr 
) [static]

Definition at line 484 of file mailbot.c.

{
       return 0;
}

Here is the caller graph for this function:

static void mimeautoreply_write_func ( const char *  str,
size_t  cnt,
void *  ptr 
) [static]

Definition at line 470 of file mailbot.c.

{
       if (cnt &&
           fwrite(str, cnt, 1, ((struct mimeautoreply_s *)ptr)->outf) != 1)
       {
              perror("tmpfile");
              exit(1);
       }
}

Here is the caller graph for this function:

static void mimeautoreply_writesig_func ( void *  ptr) [static]

Definition at line 480 of file mailbot.c.

{
}

Here is the caller graph for this function:

static void opensendmail ( int  argn,
int  argc,
char **  argv 
) [static]

Definition at line 400 of file mailbot.c.

{
       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);
}

Here is the caller graph for this function:

static void read_headers ( FILE *  tmpfp) [static]

Definition at line 114 of file mailbot.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rfc2045_error ( const char *  str)

Definition at line 56 of file mailbot.c.

{
       fprintf(stderr, "%s\n", str);
       exit(1);
}
static struct rfc2045* savemessage ( FILE *  tmpfp) [static, read]

Definition at line 431 of file mailbot.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void usage ( ) [static]

Definition at line 62 of file mailbot.c.

{
       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);
}

Variable Documentation

const char* charset [static]

Definition at line 42 of file mailbot.c.

const char* dbfile = 0 [static]

Definition at line 41 of file mailbot.c.

struct header* extra_headers = 0 [static]

Definition at line 53 of file mailbot.c.

struct header* header_list [static]

Definition at line 51 of file mailbot.c.

unsigned interval = 1 [static]

Definition at line 43 of file mailbot.c.

const char* recips = 0 [static]

Definition at line 40 of file mailbot.c.

char* sender [static]

Definition at line 44 of file mailbot.c.