home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / auucp+-1.02 / fuucp_plus_src.lzh / sendmail / sendmail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-11  |  38.5 KB  |  1,589 lines

  1. /**********************************************************************/
  2. /*                             sendmail.c                             */
  3. /*                             ----------                             */
  4. /*                                                                    */
  5. /*   Copyright (C) 1990, 1991 Ingo Feulner, Magic Soft Developments   */
  6. /*                     -- all rights reserved --                      */
  7. /*                                                                    */
  8. /*         This program may be copied for non-comercial use.          */
  9. /*                                                                    */
  10. /**********************************************************************/
  11.  
  12. /*
  13.    Note: This Programm has been written for the SAS/C compiler.
  14.          So I have used sometimes C++ - style comments (//).
  15.  
  16.    Revision history:
  17.  
  18.    29-Jul-90    first version created.
  19.    19-Aug-90    new parser. seems to work
  20.    20-Aug-90    first mail read-in routine written. works well.
  21.                 version is now 0.10
  22.    21-Aug-90    Mail is now copied into a mail structure.
  23.    22-Aug-90    First save routine written. It works!
  24.    28-Aug-90    Last known bugs corrected. Looks well.
  25.    30-Aug-90    First send_mailerdaemon() routine written.
  26.     1-Sep-90    Now sendmail can be used without the need of a maps database
  27.    14-Sep-90    UULIB:Domain file has now the same format than the output
  28.                 of 'pathalias'. There can be now domain and system path
  29.                 entries. version is now 0.90
  30.    18-Sep-90    Some bug-fixes. version is now 0.91
  31.     2-Oct-90    Fixed a bug in the rfctime() routine. version is 0.92
  32.                 The "From " line is now RFC976 compatible.
  33.     1-Nov-90    Corrected clean_address(). Now a address in the form
  34.                 "Realname <user@node.domain>" is passed correctly.
  35.                 Version is now 0.93
  36.     2-Mar-91    Changed parse() in parse.c so, that now site.domain will be used
  37.                 for database searching. This is the correct way.
  38.                 Version is now 0.94
  39.     7-Mar-91    parse() returned wrong path if the address had the dummy ".UUCP"
  40.                 domain. This is now corrected.
  41.                 Version is again 0.94
  42.    17-Apr-91    Changed rfctime() and messageid() to be to RFC1123-conform.
  43.                 Corrected some bugs in strltok() and readin_mail() which
  44.                 caused Enforcer hits.
  45.                 Added support for multiline header entries.
  46.    20-Apr-91    Rewritten the address parser. Now there should be no more problems.
  47.                 Version is now 0.95.
  48.    24-Apr-91    Now the "Reply-To:" entry will not be deleted, if given.
  49.                 Version is now 0.96.
  50.    29-Apr-91    The address in the form "@gateway.dom.ain:user@system.dom.ain"
  51.                 will now be parsed correctly.
  52.                 Version is now 0.97
  53.     3-May-91    'Bcc:' thing works now.
  54.                 Version is now 0.98
  55.     8-May-91    Now every address is parsed very carefully for comments and
  56.                 things like this.
  57.                 Version is now 1.00 - released to the public.
  58.    19-May-91    clean_address_line() completely rewritten. Has now no more problems
  59.                 with commas in comments. Corrected some other bugs and an enforcer
  60.                 hit in compare_address().
  61.                 Version is now 1.01
  62.    11-Jun-91    Now there will ever be a "remote" entry in the frompath...
  63.                 Version is now 1.02
  64. */
  65.  
  66. #include <string.h>
  67. #include <stdlib.h>
  68. #include <stdio.h>
  69. #include <time.h>
  70. #include "config.h"
  71. #include "log.h"
  72. #include "support.h"
  73.  
  74. #define MAINVERSION "//\\\\migaUUCP Plus 1.02b"
  75. #define VERDATE     " 1.02 (11 Jun 91) "
  76.  
  77. #define PALIAS   "palias" /* Name of the database relative to UULIB */
  78. #define MYBUFLEN 4096     /* Must be enough in any case */
  79.  
  80. #define ADDRSEPCHAR '\x08' /* Defines End of a single address */
  81. #define ADDRSEP     "\x08"
  82.  
  83.  
  84.  
  85. /********************/
  86. /* data structures: */
  87. /********************/
  88.  
  89. /* linked address list */
  90. struct Address
  91. {
  92.   struct Address *a_next; /* Pointer to next address. NULL if only one addr. */
  93.   char *a_original;       /* Original address (smart, bang, etc) */
  94.   char *a_address;        /* Address without the node we will sent the mail to */
  95.   char *a_system;         /* node we will sent the mail to. NULL if local */
  96.   short a_type;           /* Type of Address (Bcc or normal) */
  97. };
  98.  
  99. #define NRM_ADDR  0
  100. #define BCC_ADDR  10
  101.  
  102. /* our mail structure */
  103. struct Mail
  104. {
  105.   /* struct mail *m_next; Pointer to next mail. Yet unused */
  106.   struct Address m_address; /* linked address list */
  107.   short m_rmail;       /* if m_rmail != 0, than act as rmail */
  108.   char *m_rmailaddr;   /* rmail address, if m_rmail != 0 */
  109.   char *m_frompath;    /* 'From ' line. The way the mail came */
  110.   char *m_fromsystem;  /* The system name we got the mail from */
  111.   char *m_messageid;   /* The messageid of the mail, if given */
  112.   char *m_date;        /* Date when the mail was written */
  113.   char *m_from;        /* User sent the mail */
  114.   char *m_replyto;     /* If given, it must be used instead of From: */
  115.   char *m_to;          /* Address where the mail should go */
  116.   char *m_subject;     /* mail subject */
  117.   char *m_cc;          /* Copies to the following addresses */
  118.   char *m_bcc;         /* Blind carbon copy */
  119.   char *m_receivedbuf; /* contains all old 'received: ' lines */
  120.   long  m_rbuflen;     /* lenght of receivedbuf in bytes */
  121.   char *m_headerbuf;   /* contains the uninteresting rest of the header */
  122.   long  m_hbuflen;     /* length of headerbuf in bytes */
  123.   char *m_mailbuf;     /* contains the pure mail */
  124.   long  m_mbuflen;     /* length of mailbuf in bytes */
  125. };
  126.  
  127.  
  128. /***************/
  129. /* Prototypes: */
  130. /***************/
  131.  
  132. /* Imports: */
  133.  
  134. /* Local: */
  135. void            version(void);
  136. void            init(void);
  137. struct Mail    *init_mailstruct(void);
  138. int             readin_mail(struct Mail *, FILE *);
  139. void            set_mailparams(struct Mail *);
  140. int             sendmail(struct Mail *);
  141. int             local_sendmail(struct Mail *, struct Address *);
  142. int             forward_sendmail(struct Mail *, struct Address *);
  143. int             check_addressline(struct Address *, struct Mail *, char *, short);
  144. char           *get_header_entry(char *, long, FILE *);
  145. void            test_parsing(void);
  146.  
  147. /* Support routines: */
  148. char *__regargs strltok(char *, char *, char **);
  149. char *__regargs clean_address_line(char *);
  150. char *__regargs clean_address(char *, char *);
  151. int   __regargs compare_nodes(char *, char *);
  152. char           *get_sender(char *);
  153. char           *messageid(int);
  154. int             check_local_address(char *, char **);
  155.  
  156.  
  157. /************/
  158. /* Globals: */
  159. /************/
  160.  
  161. static char *version20 = "$VER: sendmail" VERDATE "\n\r";
  162. static char *NULL_String = "\x00";
  163.  
  164. char *_TZ;
  165. char *Progname;
  166. char *UserName;
  167. char *RealName;
  168. char *NodeName;
  169. char *DomainName;
  170. char *DefaultNode;
  171. int  Seq; /* Global Sequence number. Used for messagid, if new mail,
  172.              and for first Received - line entry */
  173.  
  174. int sendmailcalls = 1; /* How often have we send a mail?
  175.                           This is used for the right sequence number; */
  176.  
  177. short DataBase = 1;    /* Used by parse() */
  178.  
  179. void version(void)
  180. {
  181.   fprintf(stderr, "AmigaUUCP Plus: %s%s\n", Progname, VERDATE);
  182.   fprintf(stderr, "Copyright (C) 1990, 1991 Ingo Feulner\n\n");
  183.   fprintf(stderr, "Usage: %s [-f from] [-t to] [-s subject]\n", Progname);
  184.   fprintf(stderr, "\t\t[-c cc] [-b bcc] [-r] [-?] [-V]\n");
  185. }
  186.  
  187. int mybreak(void)
  188. {
  189.   return 0;
  190. }
  191.  
  192. int main(int argc, char *argv[])
  193. {
  194.   extern char *optarg;
  195.   extern int  optind;
  196.  
  197.   struct Mail *mail;
  198.   struct Address *addr;
  199.   char *buf;
  200.   signed char c;
  201.   int returncode = 0;
  202.  
  203.  
  204.   LogProgram = "sendmail";
  205.  
  206.   onbreak(mybreak);
  207.  
  208.   /* Get pure program name */
  209.   {
  210.     char *ptr = argv[0] + strlen(argv[0]);
  211.  
  212.     while(ptr >= argv[0] && *ptr != '/' && *ptr != ':')
  213.       ptr--;
  214.     ++ptr;
  215.  
  216.     Progname = ptr;
  217.   }
  218.   
  219.   init();
  220.   mail = init_mailstruct(); /* allocate and init mail structure */
  221.  
  222.   while((c = getopt(argc, argv, "f:t:s:c:b:r:T?V")) > 0)
  223.   {
  224.     switch(c)
  225.     {
  226.       case 'f':
  227.         buf = xmalloc(256);
  228.         if(strchr(optarg, ATSIGN) == NULL) /* Only Username, without node */
  229.         {
  230.           if((strcmp(optarg, UserName)) == 0)
  231.             sprintf(buf, "%s@%s%s (%s)", optarg, NodeName, DomainName, RealName);
  232.           else
  233.             sprintf(buf, "%s@%s%s", optarg, NodeName, DomainName);
  234.  
  235.           mail->m_from = strsave(buf);
  236.         }
  237.         else /* Address contains node */
  238.         {
  239.           mail->m_from = strsave(optarg);
  240.         }
  241.         free(buf);
  242.         break;
  243.       case 't':
  244.         mail->m_to = strsave(optarg);
  245.         break;
  246.       case 's':
  247.         mail->m_subject = strsave(optarg);
  248.         break;
  249.       case 'c':
  250.         mail->m_cc = strsave(optarg);
  251.         break;
  252.       case 'b':
  253.         mail->m_bcc = strsave(optarg);
  254.         break;
  255.       case 'r':
  256.         mail->m_rmail = 1;
  257.         mail->m_rmailaddr = strsave(optarg);
  258.         break;
  259.       case '?':
  260.         version();
  261.         exit(20);
  262.         break;
  263.       case 'V':
  264.         version();
  265.         break;
  266.  
  267.       case 'T':
  268.         test_parsing();
  269.         exit(0);
  270.         break;
  271.     }
  272.   }
  273.  
  274.   LockFile("sendmail");
  275.  
  276.   if(readin_mail(mail, stdin) != SUCCEED)
  277.   {
  278.     fprintf(stderr, "This is no mail\n");
  279.     exit(20);
  280.   }
  281.  
  282.   set_mailparams(mail);
  283.  
  284. #ifdef MYDEBUG
  285.   printf("From System: %s\n", mail->m_fromsystem);
  286.   printf("Frompath: %s\n\n", mail->m_frompath);
  287.   printf("Receivedbuf: (Size %ld bytes)\n%s\n\n", mail->m_rbuflen,
  288.                                                   mail->m_receivedbuf);
  289.   printf("Message-Id: %s\n", mail->m_messageid);
  290.   printf("Date: %s\n", mail->m_date);
  291.   printf("From: %s\n", mail->m_from);
  292.   printf("To: %s\n", mail->m_to);
  293.   printf("Cc: %s\n", mail->m_cc);
  294.   printf("Bcc: %s\n", mail->m_bcc);
  295.   printf("Subject: %s\n\n", mail->m_subject);
  296.   printf("Rest of header: (Size %ld bytes)\n%s\n\n", mail->m_hbuflen,
  297.                                                      mail->m_headerbuf);
  298.   printf("Mail: (Size %ld bytes)\n%s\n\n", mail->m_mbuflen, mail->m_mailbuf);
  299.  
  300.   printf("This mail will be sent to:\n");
  301.   for(addr = mail->m_address.a_next; addr != NULL; addr = addr->a_next)
  302.   {
  303.     printf("Spoolsystem: %s\n", addr->a_system);
  304.     printf("Address    : %s\n\n", addr->a_address);
  305.   }
  306.  
  307.   exit(0);
  308. #endif /* MYDEBUG */
  309.  
  310.  
  311.   if(sendmail(mail) != SUCCEED)
  312.   {
  313.     ulog(-1, "All addresses were unknown");
  314.   }
  315.  
  316.   UnLockFile("sendmail");
  317.   return returncode;
  318. }
  319.  
  320. static char *funnytext = "This is a binary and not a textfile, you idiot!";
  321.  
  322. int sendmail(struct Mail *mail)
  323. {
  324.   struct Address *addr;
  325.   char *buf = xmalloc(256);
  326.  
  327.   int returncode;
  328.   int successful = 0;
  329.  
  330.   for(addr = mail->m_address.a_next; addr != NULL; addr = addr->a_next)
  331.   {
  332.     if(*addr->a_system != '\0') /* Forward Mail */
  333.     {
  334.       returncode = forward_sendmail(mail, addr);
  335.     }
  336.     else /* Local mail */
  337.     {
  338.       returncode = local_sendmail(mail, addr);
  339.     }
  340.  
  341.     sendmailcalls++;
  342.  
  343.     if(returncode != SUCCEED)
  344.     {
  345.       sprintf(buf, "sending mail to '%s' failed", addr->a_original);
  346.     }
  347.     else
  348.     {
  349.       sprintf(buf, "sending mail to '%s' succeeded", addr->a_original);
  350.       successful++;
  351.     }
  352.     ulog(-1, buf);
  353.   }
  354.   free(buf);
  355.  
  356.   if(successful > 0)
  357.     return SUCCEED;
  358.   else
  359.     return FAIL;
  360. }
  361.  
  362. int forward_sendmail(struct Mail *mail, struct Address *addr)
  363. {
  364.   FILE *cfp;
  365.   FILE *dfp;
  366.   FILE *xfp;
  367.  
  368.   static char comfile[50];
  369.   static char datfile[50];
  370.   static char exefile[50];
  371.   static char xfile[50];
  372.  
  373.   char *user;
  374.   int seq;
  375.  
  376.   seq = (sendmailcalls == 1) ? Seq : GetSequence(1);
  377.  
  378.   if(mail->m_rmail == 0)
  379.     user = get_sender(mail->m_from);
  380.   else
  381.     user = "uucp";
  382.  
  383.   sprintf(comfile, "C.%.6sA%04lx", addr->a_system, seq);
  384.   sprintf(datfile, "D.%.6sB%04lx", addr->a_system, seq);
  385.   sprintf(exefile, "D.%.6sX%04lx", addr->a_system, seq);
  386.   sprintf(xfile,   "X.%.6sX%04lx", addr->a_system, seq);
  387.  
  388.   cfp = fopen(MakeConfigPath(UUSPOOL, comfile), "w");
  389.   dfp = fopen(MakeConfigPath(UUSPOOL, datfile), "w");
  390.   xfp = fopen(MakeConfigPath(UUSPOOL, exefile), "w");
  391.  
  392.   if(cfp == NULL || dfp == NULL || xfp == NULL)
  393.     return FAIL;
  394.  
  395.   /* First, write the mail */
  396.  
  397.   fprintf(dfp, "From %s\n", mail->m_frompath);
  398.  
  399.   if(mail->m_rmail != 0)
  400.   {
  401.     fprintf(dfp,
  402.       "Received: from %s by %s%s (" MAINVERSION ")\n"
  403.       "\tid AA%05ld; %s\n",
  404.       mail->m_fromsystem, NodeName, DomainName, seq, rfctime());
  405.   }
  406.   else
  407.   {
  408.     fprintf(dfp,
  409.       "Received: by %s%s (" MAINVERSION ")\n"
  410.       "\tid AA%05ld; %s\n", NodeName, DomainName, seq, rfctime());
  411.   }
  412.  
  413.   if(mail->m_rbuflen > 0)
  414.     (void)fwrite(mail->m_receivedbuf, mail->m_rbuflen, 1, dfp);
  415.  
  416.   if(mail->m_hbuflen > 0)
  417.     (void)fwrite(mail->m_headerbuf, mail->m_hbuflen, 1, dfp);
  418.  
  419.   fprintf(dfp, "Message-Id: %s\n", mail->m_messageid);
  420.   fprintf(dfp, "Date: %s\n", mail->m_date);
  421.   fprintf(dfp, "From: %s\n", mail->m_from);
  422.  
  423.   if(mail->m_replyto != NULL && *mail->m_replyto != '\0')
  424.     fprintf(dfp, "Reply-To: %s\n", mail->m_replyto);
  425.  
  426.   fprintf(dfp, "To: %s\n", mail->m_to);
  427.  
  428.   if(mail->m_cc != NULL && *mail->m_cc != '\0')
  429.     fprintf(dfp, "Cc: %s\n", mail->m_cc);
  430.  
  431.   if(mail->m_bcc != NULL && *mail->m_bcc != '\0' && addr->a_type == BCC_ADDR)
  432.     fprintf(dfp, "Bcc: %s\n", mail->m_bcc);
  433.  
  434.   fprintf(dfp, "Subject: %s\n\n", mail->m_subject);
  435.   /* double newline indicates end of header */
  436.  
  437.   /* So lets write the pure mail */
  438.   if(mail->m_mbuflen > 0)
  439.     (void)fwrite(mail->m_mailbuf, mail->m_mbuflen, 1, dfp);
  440.  
  441.   if(ferror(dfp))
  442.     return FAIL;
  443.  
  444.   fclose(dfp);
  445.  
  446.   /* Second, write the exefile */
  447.  
  448.   fprintf(xfp, "U %s %s\n", user, NodeName);
  449.   fprintf(xfp, "F %s\n", datfile);
  450.   fprintf(xfp, "I %s\n", datfile);
  451.   fprintf(xfp, "C rmail %s\n", addr->a_address);
  452.  
  453.   if(ferror(xfp))
  454.     return FAIL;
  455.  
  456.   fclose(xfp);
  457.  
  458.   /* Last, write the commandfile */
  459.  
  460.   fprintf(cfp, "S %s %s %s - %s 0666\n", datfile, datfile, user, datfile);
  461.   fprintf(cfp, "S %s %s %s - %s 0666\n", exefile, xfile, user, exefile);
  462.  
  463.   if(ferror(cfp))
  464.     return FAIL;
  465.  
  466.   fclose(cfp);
  467.  
  468.   return SUCCEED;
  469. }
  470.  
  471. int local_sendmail(struct Mail *mail, struct Address *addr)
  472. {
  473.   FILE *output;
  474.  
  475.   int seq = (sendmailcalls == 1) ? Seq : GetSequence(1);
  476.  
  477.   if((output = fopen(MakeConfigPath(UUMAIL, addr->a_address), "a")) == NULL)
  478.     return FAIL;
  479.  
  480.  
  481.   fprintf(output, "From %s\n", mail->m_frompath);
  482.  
  483.   if(mail->m_rmail != 0)
  484.   {
  485.     fprintf(output,
  486.       "Received: from %s by %s%s (" MAINVERSION ")\n"
  487.       "\tid AA%05ld; %s\n",
  488.       mail->m_fromsystem, NodeName, DomainName, seq, rfctime());
  489.   }
  490.   else
  491.   {
  492.     fprintf(output,
  493.       "Received: by %s%s (" MAINVERSION ")\n"
  494.       "\tid AA%05ld; %s\n", NodeName, DomainName, seq, rfctime());
  495.   }
  496.  
  497.   if(mail->m_rbuflen > 0)
  498.     (void)fwrite(mail->m_receivedbuf, mail->m_rbuflen, 1, output);
  499.  
  500.   if(mail->m_hbuflen > 0)
  501.     (void)fwrite(mail->m_headerbuf, mail->m_hbuflen, 1, output);
  502.  
  503.   fprintf(output, "Message-Id: %s\n", mail->m_messageid);
  504.   fprintf(output, "Date: %s\n", mail->m_date);
  505.   fprintf(output, "From: %s\n", mail->m_from);
  506.  
  507.   if(mail->m_replyto != NULL && *mail->m_replyto != '\0')
  508.     fprintf(output, "Reply-To: %s\n", mail->m_replyto);
  509.  
  510.   fprintf(output, "To: %s\n", mail->m_to);
  511.  
  512.   if(mail->m_cc != NULL && *mail->m_cc != '\0')
  513.     fprintf(output, "Cc: %s\n", mail->m_cc);
  514.  
  515.   if(mail->m_bcc != NULL && *mail->m_bcc != '\0' && addr->a_type == BCC_ADDR)
  516.     fprintf(output, "Bcc: %s\n", mail->m_bcc);
  517.  
  518.   fprintf(output, "Subject: %s\n\n", mail->m_subject);
  519.   /* double newline indicates end of header */
  520.  
  521.   /* So lets write now the pure mail */
  522.   if(mail->m_mbuflen > 0)
  523.     (void)fwrite(mail->m_mailbuf, mail->m_mbuflen, 1, output);
  524.  
  525.   if(ferror(output))
  526.     return FAIL;
  527.  
  528.   fclose(output);
  529.  
  530.   return SUCCEED;
  531. }
  532.  
  533. static char *addr_error_banner = "\
  534. |------------------------- Failed address follows -----------------------|\n";
  535. static char *text_banner ="\
  536. |------------------------- Message text follows -------------------------|\n";
  537. static char *textend_banner ="\
  538. |------------------------- End of message -------------------------------|\n";
  539.  
  540. void send_mailerdaemon(struct Mail *mail, char *address)
  541. {
  542. #define ENDOFBUF(ptr) ((ptr += strlen(ptr)))
  543.  
  544.   struct Mail *dmail;
  545.   struct Address *faddress;
  546.  
  547.   char *sender;
  548.   char *buf = xmalloc(512); /* Used as a temporary buffer */
  549.  
  550.   dmail = xcalloc(sizeof(struct Mail));
  551.   faddress = xcalloc(sizeof(struct Address));
  552.  
  553.   sender = clean_address_line(mail->m_from); /* Cut off Realname */
  554.  
  555.   if((check_addressline(faddress, NULL, sender, NRM_ADDR)) == 1)
  556.   {
  557.     char *tmpbuf;
  558.     char *ptr;
  559.  
  560.     ulog(-1, "mailerguru: sending mail back to sender '%s'", sender);
  561.  
  562.  
  563.     tmpbuf = xmalloc(mail->m_rbuflen + mail->m_hbuflen
  564.                      + mail->m_mbuflen + 8192);
  565.     ptr = tmpbuf;
  566.  
  567.     /* Initialize new daemon mail structure */
  568.     sprintf(buf, "mailerguru@%s%s (Guru Mailer)", NodeName, DomainName);
  569.  
  570.     /* Mail header */
  571.     dmail->m_from = strsave(buf);
  572.     dmail->m_to   = strsave(mail->m_from);
  573.     dmail->m_subject = strsave("Failed mail");
  574.  
  575.     /* Mail */
  576.     sprintf(ptr, "%s\n%s\n\n%s\n", addr_error_banner, address, text_banner);
  577.     ENDOFBUF(ptr); /* Jump to end of buf */
  578.  
  579.     sprintf(ptr, ">From %s\n", mail->m_frompath);
  580.     ENDOFBUF(ptr);
  581.  
  582. /*
  583.     if(mail->m_rmail != 0)
  584.     {
  585.       sprintf(ptr,
  586.         "Received: from %s by %s%s (" MAINVERSION ")\n"
  587.         "\tid AA%05ld; %s\n",
  588.         mail->m_fromsystem, NodeName, DomainName, seq, rfctime());
  589.     }
  590.     else
  591.     {
  592.       sprintf(ptr,
  593.         "Received: by %s%s (" MAINVERSION ")\n"
  594.         "\tid AA%05ld; %s\n", NodeName, DomainName, seq, rfctime());
  595.     }
  596.     ENDOFBUF(ptr);
  597. */
  598.  
  599.     if(mail->m_rbuflen > 0)
  600.     {
  601.       (void)stccpy(ptr, mail->m_receivedbuf, mail->m_rbuflen);
  602.       ENDOFBUF(ptr);
  603.     }
  604.  
  605.     if(mail->m_hbuflen > 0)
  606.     {
  607.       (void)stccpy(ptr, mail->m_headerbuf, mail->m_hbuflen);
  608.       ENDOFBUF(ptr);
  609.     }
  610.  
  611.     sprintf(ptr, "Message-Id: %s\n", mail->m_messageid);
  612.     ENDOFBUF(ptr);
  613.     sprintf(ptr, "Date: %s\n", mail->m_date);
  614.     ENDOFBUF(ptr);
  615.     sprintf(ptr, "From: %s\n", mail->m_from);
  616.     ENDOFBUF(ptr);
  617.     sprintf(ptr, "To: %s\n", mail->m_to);
  618.     ENDOFBUF(ptr);
  619.  
  620.     if(mail->m_cc != NULL && *mail->m_cc != '\0')
  621.     {
  622.       sprintf(ptr, "Cc: %s\n", mail->m_cc);
  623.       ENDOFBUF(ptr);
  624.     }
  625.  
  626.     if(mail->m_bcc != NULL && *mail->m_bcc != '\0')
  627.     {
  628.       sprintf(ptr, "Bcc: %s\n", mail->m_bcc);
  629.       ENDOFBUF(ptr);
  630.     }
  631.  
  632.     sprintf(ptr, "Subject: %s\n\n", mail->m_subject);
  633.     /* double newline indicates end of header */
  634.     ENDOFBUF(ptr);
  635.  
  636.     /* So lets write now the pure mail */
  637.     if(mail->m_mbuflen > 0)
  638.     {
  639.       (void)stccpy(ptr, mail->m_mailbuf, mail->m_mbuflen);
  640.       ENDOFBUF(ptr);
  641.     }
  642.  
  643.     sprintf(ptr, "\n\n%s", textend_banner);
  644.  
  645.     dmail->m_mailbuf = tmpbuf;
  646.     dmail->m_mbuflen = strlen(tmpbuf); /* Hope that works always */
  647.  
  648.     /* Set the other mail parameters */
  649.     set_mailparams(dmail);
  650.  
  651.     /* Lets send it! */
  652.     if((sendmail(dmail)) != SUCCEED)
  653.     {
  654.       ulog(-1, "mailerguru: failed.");
  655.       fprintf(stderr, "%s: Fatal Error! Sending mailerdaemon message failed\n", Progname);
  656.       fprintf(stderr, "ABORTING!\n");
  657.       exit(20);
  658.     }
  659.   }
  660.   else
  661.   {
  662.     fprintf(stderr, "Sender unknown\n");
  663.   }
  664. }
  665.  
  666. int readin_mail(struct Mail *mail, FILE *input)
  667. {
  668.   char *buf = xmalloc(MYBUFLEN);
  669.   char *tmphdr = NULL;
  670.  
  671.   /*
  672.      if mail->m_rmail != 0, act as rmail. So the first line must be
  673.      the "From ..." line
  674.   */
  675.   if(mail->m_rmail != 0)
  676.   {
  677.     if((fgets(buf, MYBUFLEN - 1, input)) != NULL)
  678.     {
  679.       if((strncmp(buf, "From ", 5)) == 0) /* Found it */
  680.       {
  681.         char *tmpbuf = strsave(strclean(&buf[5]));
  682.         *(strchr(tmpbuf, ' ')) = '\0'; /* Cut away old time & date */
  683.  
  684.         mail->m_frompath = strsave(tmpbuf);
  685.         free(tmpbuf);
  686.       }
  687.       else /* Ugh, no mail! */
  688.       {
  689.         fprintf(stderr, "%s: no mail.\n", Progname);
  690.         return FAIL;
  691.       }
  692.     }
  693.     else
  694.     {
  695.       fprintf(stderr, "%s: null file\n", Progname);
  696.       return FAIL;
  697.     }
  698.   }
  699.  
  700.  
  701.   while((get_header_entry(buf, MYBUFLEN - 1, input)) != NULL)
  702.   {
  703.     if(mail->m_rmail != 0) /* Check only for 'Received' if acting as rmail */
  704.     {
  705.       if((strncmp(buf, "Received: ", 10)) == 0)
  706.       {
  707.         char *tmpbuf;
  708.         char *destbuf;
  709.         char *rptr;
  710.         char *dest;
  711.     
  712.         destbuf = xmalloc(strlen(buf) + 1);
  713.         dest = destbuf;
  714.  
  715.         rptr = &buf[10];
  716.         if((strncmp(rptr, "by ", 3)) == 0)
  717.         {
  718.           char *ptr = &rptr[3];
  719.  
  720.           while(*ptr != ' ' && *ptr != '.' && *ptr != '\0')
  721.             *dest++ = *ptr++;
  722.           *dest = '\0';
  723.         }
  724.         else if((strncmp(rptr, "from ", 5)) == 0)
  725.         {
  726.           char *ptr = &rptr[5];
  727.  
  728.           while(*ptr != '\0' && *ptr != ' ')
  729.             ptr++;
  730.  
  731.           if(*ptr != '\0')
  732.             ptr++;
  733.  
  734.           if((strncmp(ptr, "by ", 3)) == 0)
  735.           {
  736.             ptr += 3;
  737.  
  738.             while(*ptr != ' ' && *ptr != '.' && *ptr != '\0')
  739.               *dest++ = *ptr++;
  740.             *dest = '\0';
  741.           }
  742.         }
  743.  
  744.         if(*destbuf != '\0')
  745.         {
  746.           mail->m_fromsystem = xmalloc(strlen(destbuf) + 1);
  747.           strcpy(mail->m_fromsystem, destbuf);
  748.         }
  749.         else
  750.         {
  751.           fprintf(stderr, "%s: warning: unknown received line format:\n%s\n",
  752.                                                              Progname, buf);
  753.         }
  754.         free(destbuf);
  755.  
  756.         tmpbuf = strsave(buf);
  757.  
  758.         while((fgets(buf, MYBUFLEN - 1, input)) != NULL)
  759.         {
  760.           if(((strncmp(buf, "Received: ", 10)) == 0)
  761.             || (*buf == '\t') || (*buf == ' '))
  762.           {
  763.             tmpbuf = xrealloc(tmpbuf, strlen(tmpbuf) + strlen(buf) + 1);
  764.             strcat(tmpbuf, buf);
  765.           }
  766.           else
  767.             break;
  768.         }
  769.         mail->m_receivedbuf = tmpbuf;
  770.         mail->m_rbuflen     = strlen(tmpbuf);
  771.       }
  772.     } /* end of rmail part */
  773.  
  774.     if((strncmp(buf, "From:", 5)) == 0)
  775.     {
  776.       if(mail->m_from == NULL)
  777.         mail->m_from = strsave(strclean(&buf[5]));
  778.     }
  779.     else if((strncmp(buf, "Reply-To:", 9)) == 0)
  780.     {
  781.       mail->m_replyto = strsave(strclean(&buf[9]));
  782.     }
  783.     else if((strncmp(buf, "To:", 3)) == 0)
  784.     {
  785.       if(mail->m_to == NULL)
  786.         mail->m_to = strsave(strclean(&buf[3]));
  787.     }
  788.     else if((strncmp(buf, "Subject:", 8)) == 0)
  789.     {
  790.       if(mail->m_subject == NULL)
  791.         mail->m_subject = strsave(strclean(&buf[8]));
  792.     }
  793.     else if((strncmp(buf, "Date:", 5)) == 0)
  794.     {
  795.       mail->m_date = strsave(strclean(&buf[5]));
  796.     }
  797.     else if((strncmp(buf, "Message-Id:", 11)) == 0)
  798.     {
  799.       mail->m_messageid = strsave(strclean(&buf[11]));
  800.     }
  801.     else if((strncmp(buf, "Cc:", 3)) == 0)
  802.     {
  803.       if(mail->m_cc == NULL)
  804.         mail->m_cc = strsave(strclean(&buf[3]));
  805.     }
  806.     else if((strncmp(buf, "Bcc:", 4)) == 0)
  807.     {
  808.       if(mail->m_bcc == NULL)
  809.         mail->m_bcc = strsave(strclean(&buf[4]));
  810.     }
  811.     else if(*buf == '\n') /* Newline indicates end of header */
  812.     {
  813.       break;
  814.     }
  815.     else /* Other header entries, not specially scanned */
  816.     {
  817.       if(tmphdr == NULL)
  818.         tmphdr = strsave(buf);
  819.       else
  820.       {
  821.         tmphdr = xrealloc(tmphdr, strlen(tmphdr) + strlen(buf) + 1);
  822.         strcat(tmphdr, buf);
  823.       }
  824.     }
  825.   }
  826.  
  827.   if(tmphdr != NULL)
  828.   {
  829.     mail->m_headerbuf = tmphdr;
  830.     mail->m_hbuflen   = strlen(tmphdr);
  831.   }
  832.   else
  833.   {
  834.     mail->m_headerbuf = NULL;
  835.     mail->m_hbuflen   = 0;
  836.   }
  837.  
  838.  
  839.   if(!feof(input)) /* Now lets read in the 'real' mail */
  840.   {
  841.     char *tmpmail;
  842.     long i = 0;
  843.  
  844.     tmpmail = xmalloc(MYBUFLEN);
  845.  
  846.     (void)memset(buf, 0, MYBUFLEN);
  847.  
  848.     while((fread(buf, MYBUFLEN, 1, input)) == 1)
  849.     {
  850.       (void)memcpy(tmpmail + (i * MYBUFLEN), buf, MYBUFLEN);
  851.       tmpmail = xrealloc(tmpmail, (i + 2) * MYBUFLEN); /* allocate next block */
  852.  
  853.       (void)memset(buf, 0, MYBUFLEN);
  854.       i++;
  855.     }
  856.     /* And finally, copy the rest until 0 is reached */
  857.     (void)strcpy(tmpmail + (i * MYBUFLEN), buf);
  858.  
  859.     mail->m_mailbuf = tmpmail;
  860.     mail->m_mbuflen = (i * MYBUFLEN) + strlen(buf);
  861.   }
  862.   else
  863.   {
  864.     return FAIL;
  865.   }
  866.  
  867.   free(buf);
  868.  
  869.   return SUCCEED;
  870. }
  871.  
  872. /*
  873.    get_header_entry()
  874.  
  875.    Returns a header entry. Checks for multiple-line entries.
  876. */
  877. char *get_header_entry(char *buffer, long length, FILE *fp)
  878. {
  879.   char buf[512];
  880.   char *destbuf;
  881.   char *p;
  882.  
  883.   int c;
  884.  
  885.   p = destbuf = xmalloc(length + 1);
  886.  
  887.  
  888.   if((fgets(buf, sizeof(buf), fp)) != NULL)
  889.   {
  890.     if( ((strncmp(buf, "Received: ", 10)) == 0) || (*buf == '\n') )
  891.     {
  892.       strcpy(buffer, buf);
  893.       free(destbuf);
  894.  
  895.       return buffer;
  896.     }
  897.  
  898. //    strcpy(p, strclean(buf));
  899.     strcpy(p, buf);
  900.     p += strlen(buf);
  901.  
  902.     for(;;)
  903.     {
  904.       if((c = getc(fp)) != EOF && (c == ' ' || c == '\t'))
  905.       {      
  906.         fgets(buf, sizeof(buf), fp);
  907.         *p++ = ' ';
  908.  
  909. //        strcpy(p, strclean(buf));
  910.         strcpy(p, buf);
  911.         p += strlen(buf);
  912.       }
  913.       else
  914.       {
  915.         ungetc(c, fp);
  916.         break;
  917.       }
  918.     }
  919.  
  920.     strcpy(buffer, destbuf);
  921.     free(destbuf);
  922.     return buffer;
  923.   }
  924.   return NULL;
  925. }
  926.  
  927.  
  928. void set_mailparams(struct Mail *mail)
  929. {
  930.   if(mail->m_rmail != 0) /* act as rmail */
  931.   {
  932.     char *fromsystem;
  933.  
  934.     fromsystem = strsave(mail->m_fromsystem);
  935.  
  936.     /* First, make the new 'From' Line. */
  937.     {
  938.       char *tmpbuf;
  939.  
  940.       if(*fromsystem != '\0')
  941.       {
  942.         char *currtime = rfctime();
  943.       
  944.         tmpbuf = xmalloc(strlen(fromsystem) + strlen(mail->m_frompath) +
  945.                          strlen(currtime) + 100);
  946.  
  947.         /* First let's see if the node is already in the from - line */
  948.         if((compare_nodes(fromsystem, mail->m_frompath)) != SUCCEED)
  949.         { /* no */
  950.           strcpy(tmpbuf, fromsystem);
  951.           strcat(tmpbuf, "!");
  952.         }
  953.         strcat(tmpbuf, mail->m_frompath);
  954.         strcat(tmpbuf, " ");
  955.         strcat(tmpbuf, currtime);
  956.         strcat(tmpbuf, " remote from ");
  957.         strcat(tmpbuf, NodeName);
  958.       }
  959.       else /* we can't get a system name out of the last 'received' line, */
  960.       {    /* so change only time & date */
  961.         char *currtime = rfctime();
  962.  
  963.         tmpbuf = xmalloc(strlen(mail->m_frompath) + strlen(currtime) + 100);
  964.  
  965.         strcpy(tmpbuf, mail->m_frompath);
  966.         strcat(tmpbuf, " ");
  967.         strcat(tmpbuf, currtime);
  968.         strcat(tmpbuf, " remote from ");
  969.         strcat(tmpbuf, NodeName);
  970.       }
  971.  
  972.       free(mail->m_frompath);
  973.       mail->m_frompath = strsave(tmpbuf);
  974.       free(tmpbuf);
  975.     }
  976.  
  977.     /* So, now lets look what we have to do with the mail */
  978.     (void)check_addressline(&mail->m_address, mail, mail->m_rmailaddr, NRM_ADDR);
  979.   }
  980.   else /* act as sendmail - new mail */
  981.   {
  982.     char *fromname;
  983.     char *buf = xmalloc(512);
  984.  
  985.     if(mail->m_from == NULL || *mail->m_from == '\0')
  986.     {
  987.       fromname = UserName;
  988.  
  989.       sprintf(buf, "%s@%s%s (%s)", UserName, NodeName, DomainName, RealName);
  990.       mail->m_from = strsave(buf);
  991.     }
  992.     else
  993.     {
  994.       fromname = get_sender(mail->m_from);
  995.     }
  996.  
  997.     /* Let's make the from - path */
  998. /* RFC976
  999.     sprintf(buf, "%s%s!%s %s remote from %s", NodeName, DomainName,
  1000.                   fromname, rfctime(), NodeName);
  1001. */
  1002.  
  1003. /* Normal */
  1004.     sprintf(buf, "%s %s remote from %s", fromname, rfctime(), NodeName);
  1005.  
  1006.     mail->m_frompath = strsave(buf);
  1007.  
  1008.     /* And check the other entries */
  1009.     if(mail->m_date == NULL || *mail->m_date == '\0')
  1010.     {
  1011.       mail->m_date = strsave(rfctime());
  1012.     }
  1013.  
  1014.     if(mail->m_messageid == NULL || *mail->m_messageid == '\0')
  1015.     {
  1016.       mail->m_messageid = messageid(0);
  1017.     }
  1018.  
  1019.     /* No subject? */
  1020.     if(mail->m_subject == NULL || *mail->m_subject == '\0')
  1021.       mail->m_subject = strsave("(none)");
  1022.  
  1023.     free(buf); /* Finally, free the buf */
  1024.  
  1025.     /* now let's check the dest. address */
  1026.     {
  1027.       /* First, the 'To: ' line */
  1028.       (void)check_addressline(&mail->m_address, mail,
  1029.                                clean_address_line(mail->m_to), NRM_ADDR);
  1030.  
  1031.       /* And then, the 'Cc:' line */
  1032.       if(mail->m_cc != NULL && *mail->m_cc != '\0')
  1033.         (void)check_addressline(&mail->m_address, mail,
  1034.                                 clean_address_line(mail->m_cc), NRM_ADDR);
  1035.  
  1036.       /* And finally the 'Bcc' line */
  1037.       if(mail->m_bcc != NULL && *mail->m_bcc != '\0')
  1038.         (void)check_addressline(&mail->m_address, mail,
  1039.                                 clean_address_line(mail->m_bcc), BCC_ADDR);
  1040.     }   
  1041.   }
  1042. }
  1043.  
  1044. int __regargs compare_nodes(char *node, char *fromline)
  1045. {
  1046.   char *a, *b;
  1047.  
  1048.   for(a = node, b = fromline; *b != '.' && *b != '!' && *b != '\0'; a++, b++)
  1049.     if(*a != *b)
  1050.       break;
  1051.  
  1052.   if((*b == '!' || *b == '.' || *b == '\0') && *a == '\0') /* equal */
  1053.     return SUCCEED;
  1054.   else
  1055.     return FAIL;
  1056. }
  1057.     
  1058. int check_addressline(struct Address *address,
  1059.                       struct Mail *mail, char *addressline, short addr_type)
  1060. {
  1061.   struct Address *q, *p;
  1062.   char *addrline = strsave(addressline);
  1063.   char *lastpos;  /* last position in token string. for strltok() */
  1064.   char *token;
  1065.   char *path;
  1066.   int  type;
  1067.  
  1068.   int noad = 0;  /* Number of addresses found */
  1069.  
  1070.   for(q = address; ; q = q->a_next)
  1071.     if(q == NULL || q->a_next == NULL) /* end of address structure */
  1072.       break;
  1073.  
  1074.   token = strltok(addrline, ADDRSEP, &lastpos);
  1075.   while(token != NULL)
  1076.   {
  1077.     type = parse(token, &path); /* Parse the address */
  1078.  
  1079.     if(type == LOCALMAIL)
  1080.     {
  1081.       char *forwardbuf;
  1082.  
  1083.       type = check_local_address(path, &forwardbuf);
  1084.       if(type == LOCALMAIL)
  1085.       {
  1086.         if((compare_address(address->a_next, path)) != SUCCEED)
  1087.         {
  1088.           p = xmalloc(sizeof(struct Address));
  1089.  
  1090.           p->a_original = strsave(token); /* Save the original address */
  1091.           p->a_address  = strsave(path);
  1092.           p->a_system   = NULL_String;
  1093.           p->a_type     = addr_type;
  1094.  
  1095.           q->a_next = p;
  1096.           p->a_next = NULL;
  1097.           q = p;
  1098.           noad++;
  1099.         }
  1100.       }
  1101.       else /* type == FORWARDMAIL */
  1102.       {
  1103.         int no;
  1104.  
  1105.         no = check_addressline(address, mail, forwardbuf, addr_type);
  1106.         if(no < 1)
  1107.         {
  1108.           ulog(-1, "All addresses in %s are illegal",
  1109.                        MakeConfigPath(UUMAIL, path));
  1110.         }
  1111.         else
  1112.         {
  1113.           noad += no;
  1114.           for(q = address; ; q = q->a_next) /* search for new end */
  1115.             if(q == NULL || q->a_next == NULL)
  1116.               break;
  1117.         }
  1118.       }
  1119.     }
  1120.     else if(type == FORWARDMAIL)
  1121.     {
  1122.       if((compare_address(address->a_next, path)) != SUCCEED)
  1123.       {
  1124.         char *ptr = strchr(path, '!');
  1125.  
  1126.         p = xmalloc(sizeof(struct Address));
  1127.  
  1128.         p->a_original = strsave(token); /* Save the original address */
  1129.         p->a_address  = correct_address(ptr + 1);
  1130.         *ptr = '\0';
  1131.         p->a_system   = strsave(path);
  1132.         p->a_type     = addr_type;
  1133.  
  1134.         q->a_next = p;
  1135.         p->a_next = NULL;
  1136.         q = p;
  1137.         noad++;
  1138.       }
  1139.     }
  1140.     else /* type == UNKNOWNMAIL */
  1141.     {
  1142.       ulog(-1, "Unknown address '%s' - calling mailerguru", token);
  1143.       if(mail != NULL)
  1144.         send_mailerdaemon(mail, token);
  1145.     }
  1146.  
  1147.     free(path);
  1148.     token = strltok(NULL, ADDRSEP, &lastpos);
  1149.   }
  1150.   return noad;
  1151. }
  1152.  
  1153. int compare_address(struct Address *address, char *path)
  1154. {
  1155.   struct Address *q;
  1156.   char *pathline;
  1157.   char *ptr;
  1158.  
  1159.   pathline = strsave(path);
  1160.  
  1161.   if((ptr = strchr(pathline, '!')) != NULL) /* Forward mail */
  1162.   {
  1163.     char *addr;
  1164.     char *sys;
  1165.  
  1166.     addr = strsave(ptr + 1);
  1167.     *ptr = '\0';
  1168.     sys  = strsave(pathline);
  1169.  
  1170.     for(q = address; q != NULL; q = q->a_next)
  1171.     {
  1172.       if((strcmp(q->a_system, sys)) == 0)
  1173.       {
  1174.         if((strcmp(q->a_address, addr)) == 0)
  1175.         {
  1176.           free(pathline);
  1177.           free(sys);
  1178.           free(addr);
  1179.           return SUCCEED;
  1180.         }
  1181.       }
  1182.     }
  1183.     free(sys);
  1184.     free(addr);
  1185.   }
  1186.   else /* Local mail, a_system is NULL */
  1187.   {
  1188.     for(q = address; q != NULL; q = q->a_next)
  1189.     {
  1190.       if(*q->a_system == '\0')
  1191.       {
  1192.         if((strcmp(q->a_address, pathline)) == 0)
  1193.         {
  1194.           free(pathline);
  1195.           return SUCCEED;
  1196.         }
  1197.       }
  1198.     }
  1199.   }
  1200.   free(pathline);
  1201.   return FAIL;
  1202. }
  1203.  
  1204. int check_local_address(char *address, char **forwardbuf)
  1205. {
  1206.   FILE *fp;
  1207.  
  1208.   char *mailpath = MakeConfigPath(UUMAIL, address);
  1209.   char *buf = xmalloc(512);
  1210.  
  1211.   if((fp = fopen(mailpath, "r")) != NULL)
  1212.   {
  1213.     if((fgets(buf, 511, fp)) != NULL)
  1214.     {
  1215.       if((strncmp(buf, "forward to ", 11)) == 0)
  1216.       {
  1217.         *forwardbuf = xmalloc(strlen(buf) - 10);
  1218.         strcpy(*forwardbuf, strclean(&buf[11]));
  1219.         free(buf);
  1220.         return FORWARDMAIL;
  1221.       }
  1222.     }
  1223.     fclose(fp);
  1224.   }
  1225.   free(buf);
  1226.  
  1227.   *forwardbuf = NULL;
  1228.   return LOCALMAIL;
  1229. }
  1230.  
  1231. void init(void)
  1232. {
  1233.   char *paliasdat;
  1234.  
  1235.   /* Read out config file */
  1236.  
  1237.   /* Set local time */
  1238.   _TZ         = FindConfig("TimeZone");
  1239.   tzset();
  1240.  
  1241.   UserName    = FindConfig("UserName");
  1242.   RealName    = FindConfig("RealName");
  1243.   NodeName    = FindConfig("NodeName");
  1244.   DomainName  = FindConfig("DomainName");
  1245.  
  1246.   DefaultNode = FindConfig("DefaultNode");
  1247.   *(strchr(DefaultNode, DOT)) = '\0'; /* Pure Node, without domain */
  1248.  
  1249.   if(!is_in_L_sys_file(DefaultNode))
  1250.   {
  1251.     ulog(-1, "fatal error - DefaultNode '%s' not in L.sys file!", DefaultNode);
  1252.     exit(20);
  1253.   }
  1254.  
  1255.   paliasdat = MakeConfigPath(UULIB, PALIAS);
  1256.  
  1257.   if(dbminit(paliasdat) != 0)
  1258.   {
  1259.     ulog(-1, "warning: maps database not available.");
  1260.     DataBase = 0;
  1261.   }
  1262.  
  1263.   Seq = GetSequence(1);
  1264. }
  1265.  
  1266.  
  1267. /*********************/
  1268. /* Support functions */
  1269. /*********************/
  1270.  
  1271. struct Mail *init_mailstruct(void)
  1272. {
  1273.   struct Mail *mail;
  1274.  
  1275.   mail = xcalloc(sizeof(struct Mail));
  1276.  
  1277.   return mail;
  1278. }
  1279.  
  1280. char *__regargs strsave(char *string)
  1281. {
  1282.   char *buf;
  1283.  
  1284.   buf = xmalloc(strlen(string) + 1);
  1285.   strcpy(buf, string);
  1286.   return buf;
  1287. }
  1288.  
  1289. char *__regargs strclean(char *string)
  1290. {
  1291.   char *ptr;
  1292.  
  1293.   ptr = string + strlen(string) - 1; /* end of string. */
  1294.  
  1295.   while(ptr >= string &&
  1296.        (*ptr == ' ' || *ptr == '\n' || *ptr == '\r' || *ptr == '\t'))
  1297.     --ptr;
  1298.   *++ptr = '\0';
  1299.  
  1300.   ptr = string;
  1301.  
  1302.   while(*ptr != '\0' &&
  1303.        (*ptr == ' ' || *ptr == '\n' || *ptr == '\r' || *ptr == '\t'))
  1304.     ++ptr;
  1305.  
  1306.   return ptr;
  1307. }  
  1308.  
  1309. /* Delete Realnames (in brackets) out of a given address and return it */
  1310. /* 1/11/90: New: Does now understand 'Realname <user@node.domain>'     */
  1311.  
  1312. char *__regargs clean_address_line(char *addr)
  1313. {
  1314.   char *new_addr = xcalloc(strlen(addr) + 1);
  1315.   char *ptr;
  1316.   char *dest;
  1317.   short blev = 0;
  1318.   long addr_pos = 0; // Begin of an address
  1319.   long cur_pos = 0;  // Position in this address
  1320.  
  1321.  
  1322.   ptr  = addr;
  1323.   dest = new_addr;
  1324.  
  1325.   for(; *ptr != '\0'; ptr++)
  1326.   {
  1327.     switch(*ptr)
  1328.     {
  1329.       case '(':
  1330.         blev++;
  1331.  
  1332.         while(blev > 0 && *ptr != '\0')
  1333.         {
  1334.           ptr++;
  1335.  
  1336.           if(*ptr == ')')
  1337.             blev--;
  1338.           else if(*ptr == '(')
  1339.             blev++;
  1340.         }
  1341.         break;
  1342.  
  1343.       case '"':
  1344.         *dest++ = *ptr++;
  1345.         cur_pos++;
  1346.  
  1347.         while(*ptr != '\0' && *ptr != '"')
  1348.         {
  1349.           *dest++ = *ptr++;
  1350.           cur_pos++;
  1351.         }
  1352.  
  1353.         if(*ptr != '\0')
  1354.         {
  1355.           *dest++ = *ptr;
  1356.           cur_pos++;
  1357.         }
  1358.  
  1359.         break;
  1360.  
  1361.       case '<':
  1362.         dest = new_addr + addr_pos;
  1363.         cur_pos = 0;
  1364.         ptr++;
  1365.  
  1366.         while(*ptr != '\0' && *ptr != '>')
  1367.         {
  1368.           *dest++ = *ptr++;
  1369.           cur_pos++;
  1370.         }
  1371.         break;
  1372.  
  1373.       case ',':
  1374.         *dest++ = ADDRSEPCHAR; /* Defines next address */
  1375.         addr_pos += cur_pos + 1;
  1376.         cur_pos   = 0;
  1377.         break;
  1378.  
  1379.       case ' ':
  1380.       case '\t':
  1381.       case '\f':
  1382.       case '\n':
  1383.         break;
  1384.  
  1385.       default:
  1386.         *dest++ = *ptr;
  1387.         cur_pos++;
  1388.         break;
  1389.     }
  1390.   }
  1391.   *dest = '\0';
  1392.  
  1393.   return new_addr;
  1394. }
  1395.  
  1396. /* strtok without the need of a static variable */
  1397. char *__regargs strltok(char *buf, char *separators, char **lastpos)
  1398. {
  1399. #define STRING_END      '\0'
  1400.  
  1401.   char *token, *end;     /* Start and end of token. */
  1402.  
  1403.   if(token = (buf != NULL) ? buf : *lastpos)
  1404.   {
  1405.     token += strspn(token, separators);     /* Find token! */
  1406.     if(*token == STRING_END)
  1407.       return(NULL);
  1408.  
  1409.     *lastpos = ((end = strpbrk(token, separators)) ? &end[1] : NULL);
  1410.     if(end != NULL)
  1411.       *end = STRING_END;                      /* Cut it short! */
  1412.   }
  1413.   return(token);
  1414. }
  1415.  
  1416. /* malloc with error checking */
  1417. void *xmalloc(unsigned int size)
  1418. {
  1419.   void *buf;
  1420.  
  1421.   if((buf = malloc(size)) != NULL)
  1422.   {
  1423.     return buf;
  1424.   }
  1425.   else
  1426.   {
  1427.     fprintf(stderr, "%s: Insufficient free store!\n", Progname);
  1428.     exit(20);
  1429.   }
  1430. }
  1431.  
  1432. void *xcalloc(unsigned int size)
  1433. {
  1434.   void *buf;
  1435.  
  1436.   if((buf = malloc(size)) != NULL)
  1437.   {
  1438.     (void)memset(buf, 0, size);
  1439.     return buf;
  1440.   }
  1441.   else
  1442.   {
  1443.     fprintf(stderr, "%s: Insufficient free store!\n", Progname);
  1444.     exit(20);
  1445.   }
  1446. }
  1447.  
  1448. void *xrealloc(void *oldbuf, unsigned int size)
  1449. {
  1450.   void *buf;
  1451.  
  1452.   if((buf = realloc(oldbuf, size)) != NULL)
  1453.   {
  1454.     return buf;
  1455.   }
  1456.   else
  1457.   {
  1458.     fprintf(stderr, "%s: Insufficient free store!\n", Progname);
  1459.     exit(20);
  1460.   }
  1461. }
  1462.  
  1463. /*
  1464.     rfctime() - return time & date in the official RFC format
  1465.  
  1466.     17-Apr-91: Uses now a 4-digit year. (RFC 1123)
  1467.  */
  1468.  
  1469. static char *wdays[] =
  1470. {
  1471.   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  1472. };
  1473.  
  1474. static char *mdays[] =
  1475. {
  1476.   "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
  1477.   "Aug", "Sep", "Oct", "Nov", "Dec"
  1478. };
  1479.  
  1480. char *rfctime(void)
  1481. {
  1482.   static char timestr[40];
  1483.   struct tm *tm;
  1484.   long t;
  1485.  
  1486.  
  1487.   (void)time(&t);
  1488.   tm = gmtime(&t);
  1489.  
  1490.   sprintf(timestr, "%s, %ld %s %ld %02ld:%02ld:%02ld GMT",
  1491.                     wdays[tm->tm_wday],
  1492.                     tm->tm_mday,
  1493.                     mdays[tm->tm_mon],
  1494.                     tm->tm_year + 1900,
  1495.                     tm->tm_hour,
  1496.                     tm->tm_min,
  1497.                     tm->tm_sec);
  1498.  
  1499.   return timestr;
  1500. }
  1501.  
  1502. /*
  1503.    messageid()
  1504.  
  1505.    Returns an unique messageid.
  1506.  
  1507.    17 Apr 91: Made it RFC1123-conform. (4-digit year)
  1508. */
  1509.  
  1510. char *messageid(int seq)
  1511. {
  1512.   static char messageid[100];
  1513.  
  1514.   struct tm *tm;
  1515.   long t;
  1516.  
  1517.   (void)time(&t);
  1518.   tm = gmtime(&t);
  1519.  
  1520.   sprintf(messageid, "<%ld%s%ld%02ld%02ld.AA%05ld@%s%s>",
  1521.           tm->tm_mday, mdays[tm->tm_mon], tm->tm_year + 1900,
  1522.           tm->tm_hour, tm->tm_min, (seq == 0) ? Seq : seq,
  1523.           NodeName, DomainName);
  1524.  
  1525.   return messageid;
  1526. }
  1527.  
  1528. char *get_sender(char *fromline)
  1529. {
  1530.   char *ptr;
  1531.   char *fromname;
  1532.   char *tmpbuf = strsave(fromline);
  1533.  
  1534.   /* From: Line MUST contain an ATSIGN */
  1535.   if((ptr = strchr(tmpbuf, ATSIGN)) != NULL)
  1536.   {
  1537.     char *ptre = ptr;
  1538.  
  1539.     while(ptr >= tmpbuf && *ptr != '<')
  1540.       --ptr;
  1541.     ++ptr;
  1542.  
  1543.     ptre = fromname = xmalloc((ptre - ptr) + 1);
  1544.  
  1545.     while(*ptr != ATSIGN)
  1546.       *ptre++ = *ptr++;
  1547.     *ptre = '\0';
  1548.   }
  1549.   else
  1550.     fromname = NULL;
  1551.  
  1552.   return fromname;
  1553. }
  1554.  
  1555. static void test_parsing(void)
  1556. {
  1557.   struct Address *faddress, *fa;
  1558.   char buf[256];
  1559.  
  1560.  
  1561.   fprintf(stdout, "Entering interactive mode... please type in your test address\n\n");
  1562.  
  1563.   while((fgets(buf, sizeof(buf), stdin)) != NULL)
  1564.   {
  1565.     if(buf[0] == '\n')
  1566.       break;
  1567.  
  1568.     *(strchr(buf, '\n')) = '\0';
  1569.  
  1570.     faddress = xcalloc(sizeof(struct Address));
  1571.  
  1572.     if((check_addressline(faddress, NULL, clean_address_line(buf), NRM_ADDR)) >= 1)
  1573.     {
  1574.       for(fa = faddress->a_next; fa != NULL; fa = fa->a_next)
  1575.       {
  1576.         fprintf(stdout, "Spool mail to system: %s\n",
  1577.           (*fa->a_system != '\0') ? fa->a_system : "<local>");
  1578.         fprintf(stdout, "With this path      : %s\n\n",
  1579.           fa->a_address);
  1580.       }
  1581.     }
  1582.     else
  1583.     {
  1584.       fprintf(stdout, "'%s' is not a valid address!\n\n", buf);
  1585.     }
  1586.     free(faddress);
  1587.   }
  1588. }
  1589.