home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / uupc2mr2.zip / unmbox.c < prev    next >
C/C++ Source or Header  |  1997-01-08  |  14KB  |  464 lines

  1. /* unmbox.c
  2.  * Program to take a uupc inbox and translate it into separate mail messages
  3.  * ready for processing by MR/2 ICE.
  4.  *
  5.  * Michael Taylor miket@pcug.org.au
  6.  *
  7.  * History:
  8.  * 1.0.00    Initial version.        12/10/1996
  9.  * 1.0.01    Fixes.                  19/10/1996
  10.  *              Fix parsing of UUPC variables
  11.  *              Add fromsep logic - NO fromsep should be defined!
  12.  *              Inprove get_next_fname so it does not
  13.  *              return a filename that already exists.
  14.  *              Rename UUPC mbox so it cannot be written
  15.  *              to by uuxqt/rmail.
  16.  * 1.0.02    Fixes.                  26/12/1996
  17.  *              Use tmpnam rather than tempnam and remove
  18.  *              dependence on envvar TMP being unset.
  19.  *              Do not delete renamed mailbox if no mail.
  20.  * 1.0.03    Fixes.                  01/01/1997
  21.  *              Fix UNMB_MAIL - was broken :-(
  22.  *              Fix bug with writing out to getmail.err - added
  23.  *              new command line parameter for MR/2 username.
  24.  * 1.0.04    Cleanup.                04/01/1997
  25.  *              Remove all global variables.
  26.  *              Fix bug in parsing UUPC definition files - noone found this :-)
  27.  *              Works with nofromsep or fromsep format mailboxes.
  28.  * 1.0.05    Fixes.                  07/01/1997
  29.  *              Make new_mail routine more intelligent.
  30.  *
  31.  *
  32.  * This program is freely redistributable.
  33.  *
  34.  * Please maintain the current coding style if you want me to
  35.  * incorporate any changes.
  36. */
  37.  
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41.  
  42. static char version[] =
  43. "unmbox by Michael Taylor (miket@pcug.org.au) - Version 1.0.05";
  44.  
  45. static char * get_next_fname (char *basename, char *username);
  46. static int get_uupc_vars (char *username, char * mailbox_name, char * old_mailbox);
  47. static void err (char * str, char * username);
  48. static int parse_nofromsep (FILE *infile, char *xbuf, char *basename,
  49.                  char *username);
  50. static int parse_fromsep (FILE *infile, char *xbuf, char *basename,
  51.                char *username);
  52. static int new_mail (char * xbuf, int setup);
  53.  
  54. static char *
  55. get_next_fname (char *basename, char *username) {
  56.         char *  name1;
  57.     char    tname[L_tmpnam];
  58.         static char nxtfname[256];
  59.     FILE *    tmp;
  60.     int     x = 0, y = 1;
  61.  
  62. #define MAXTRIES        25000
  63.  
  64.     while (y && x < MAXTRIES) {
  65.                 if ((name1 = tmpnam (tname)) == NULL) {
  66.                         err ("Cannot create unique filename\n", username);
  67.                         return NULL;
  68.                 }
  69.                 strcpy (nxtfname, basename);
  70.             strcat (nxtfname, "\\");
  71.             strcat (nxtfname, tname+2);
  72. /*printf ("try: %s\n", nxtfname);*/
  73.             if ((tmp = fopen (nxtfname, "r")) != NULL) {
  74.             fclose (tmp);
  75.             ++x;
  76.             continue;
  77.         }
  78.         y = 0;
  79.         
  80.         }
  81.         if (!y) {
  82. /*printf ("use: %s\n", nxtfname);*/
  83.             return (char *)nxtfname;
  84.     } else
  85.         return NULL;
  86.  
  87. }
  88.  
  89. /*
  90.  get_uupc_vars
  91.  
  92.  Checks for the UUPC control files to locate the mail box.
  93.  The environment var UNMB_MAIL can be used to specify the mailbox.
  94. */
  95. static int
  96. get_uupc_vars (char * username, char * mailbox_name, char * old_mailbox) {
  97.     char buf[256];
  98.     int  i, cf;
  99.     char *p, *q, *fn;
  100.         char mailext[256];
  101.         static char mailbox[256];
  102.  
  103.     FILE *tmp;
  104.  
  105.     p = getenv ("UNMB_MAIL");
  106.     if (p != NULL) {
  107.             strcpy (old_mailbox, p);
  108.                 strcpy (mailbox_name, p);
  109.         for (q = (p = mailbox_name) + strlen (mailbox_name); p < q; ++p) {
  110.             if (*p == '.')
  111.                 break;
  112.                 }
  113.                 if (*p == '.')
  114.             p[1] = '\0';
  115.         else {
  116.             p[0] = '.';
  117.             p[1] = '\0';
  118.         }
  119.  
  120.             strcat (mailbox_name, "tmp");
  121.         return (1);
  122.     }
  123.  
  124.     /*--------------------- load UUPC rc files ---------------------------*/
  125.     /* read the system file first */
  126.     for (cf = 0, i = 0; i < 2; i++) {
  127.         /* choose the file to open */
  128.         if (i == 0) {
  129.         fn = getenv ("UUPCSYSRC");
  130.         if (fn == NULL) {
  131.             err ("Enviroment variable UUPCSYSRC not defined\n", username);
  132.                 exit (EXIT_FAILURE);
  133.         }
  134.         } else {
  135.         fn = getenv ("UUPCUSRRC");
  136.         if (fn == NULL) {
  137.             err ("Enviroment variable UUPCUSRRC not defined\n", username);
  138.                 exit (EXIT_FAILURE);
  139.         }
  140.         }
  141.         if ((tmp = fopen (fn, "r")) != NULL) {
  142.             while (fgets (buf, 255, tmp)) {
  143.             p = buf + strlen (buf) - 1;
  144.             if (*p == '\n')
  145.                 *p = '\0';
  146.             if (p > buf)
  147.                 if (*(p-1) == '\n')
  148.                     *(p-1) = '\0';
  149.  
  150.             if (!cf && strnicmp (buf, "confdir=", 8) == 0) {
  151.             /* default root dir if mailbox var not found */
  152.                 cf = 1;
  153.                 strcpy (mailbox_name, buf+8);
  154.                                 strcat (mailbox_name, "\\mail"); /* 1.0.01 */
  155.             } else
  156.             if (strnicmp (buf, "mailbox=", 8) == 0) {
  157.             /* mailbox base name */
  158.                 strcpy (mailbox, buf+8);
  159.             } else
  160.             if (strnicmp (buf, "maildir=", 8) == 0) {
  161.             /* file name for mailbox */
  162.                 cf = 1;
  163.                 strcpy (mailbox_name, buf+8);
  164.             } else
  165.             if (strnicmp (buf, "mailext=", 8) == 0) {
  166.             /* extension of file name for mailbox */
  167.                 strcpy (mailext, buf+8);
  168.             }
  169.             }
  170.             fclose (tmp);
  171.  
  172.         } else {
  173.         fprintf (stderr, "Cannot open %s\n", fn);
  174.         }
  175.     }
  176.  
  177.     if (!cf) {
  178.         return (0);
  179.     }
  180.  
  181.     strcat (mailbox_name, "\\");
  182.     strcat (mailbox_name, mailbox);
  183.     strcat (mailbox_name, ".");
  184.         strcpy (old_mailbox, mailbox_name);
  185.     strcat (old_mailbox, mailext);
  186.     strcat (mailbox_name, "tmp");
  187.     
  188.     return (1);
  189. }
  190.  
  191. static void
  192. err (char * str, char * username) {
  193.     FILE  * errfile;
  194.     char    errfname[256];
  195.  
  196.     strcpy (errfname, username);
  197.     strcat (errfname, "\\getmail.err");
  198.  
  199.         if ((errfile = fopen (errfname, "w")) == NULL) {
  200.             fprintf (stderr, "unmbox: error - cannot open file for error message\n");
  201.         exit (EXIT_FAILURE);
  202.            }
  203.         fprintf (errfile, "%s", str);
  204.         fclose (errfile);
  205. }
  206.  
  207. #define XBUFSIZE        20480
  208. static char x01x20[20] =
  209.     "\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01";
  210.  
  211. /*
  212.  parse_nofromsep
  213.  
  214.  parse the mailbox using the 20 x01s as the delimeter between mail items
  215. */
  216. static int
  217. parse_nofromsep (FILE *infile, char *xbuf, char *basename, char *username) {
  218.     FILE *    mfile=0;
  219.     int     nlines, reterr = 0;
  220.  
  221.     fgets (xbuf, XBUFSIZE, infile);
  222.     while (!feof (infile)) {
  223. /*        if (0 == memcmp (xbuf, x01x20, 20))
  224.             goto nextline;*/
  225.         if ((mfile = fopen (get_next_fname (basename, username), "w")) == NULL) {
  226. /* this error most likely occurs if the SMTP directory doesn't exist     */
  227.                     reterr = 1;
  228.             break;
  229.         }
  230.                 fputs (xbuf, mfile); nlines = 1;
  231.         while (fgets (xbuf, XBUFSIZE, infile)) {
  232.             if (0 == memcmp (xbuf, x01x20, 20))
  233.                 break;
  234.                        fputs (xbuf, mfile); nlines++;
  235.         }
  236.  
  237.             if (mfile) { fclose (mfile); mfile = 0;}
  238. /*nextline:*/
  239.         fgets (xbuf, XBUFSIZE, infile);
  240.     }
  241.  
  242.     if (mfile) { fclose (mfile); mfile = 0;}
  243.     return reterr;
  244. }
  245.  
  246. /* new_mail
  247.  *
  248.  * The logic here is that the From line will have the same format.
  249.  * From userid ...
  250.  * To make sure it is a valid From line we identify the format of the
  251.  * first From line and make sure all preceding From lines are the same
  252.  * format - it would be unlikely for a line starting with From to have
  253.  * Numerics and Non-numerics in the same places!
  254.  */
  255. static int
  256. new_mail (char * xbuf, int setup) {
  257.     char *  p;
  258.     static int nparts = 0;
  259.     static char stype[20];
  260.     static char *ppos[20];
  261.     char ptype[20];
  262.     int     n;
  263. /*
  264.  Example From lines
  265.  Current UUPC From format
  266.  From teamos2.org!owner-teamos2-l Sat Jan  4 18:33:31 1997 remote from miket
  267.  
  268.  This is from UUPC rmail:
  269.  From fkk Sat, 14 Mar 1992 14:53:27 MET remote from stasys
  270.                                                                                 
  271.  while this is another:
  272.  From fkk Sat Mar 14 14:53:27 1992 [MET]
  273. */
  274. /*printf ("xbuf=%s\n", xbuf);*/
  275.            if (memcmp (xbuf, "From ", 5))
  276.             return 0;
  277.  
  278.     for (n = 0; n < 20; ++n) {
  279.         ptype[n] = 0;
  280.         ppos[n] = NULL;
  281.     }
  282.     for (p = xbuf+5, n = 2; *p != '\0' && n < 20; ++p) {
  283.         if (*p == ' ' && p[-1] != ' ') {
  284.             ++n;
  285.             continue;
  286.         }
  287.         /* set the type of the part */
  288.         if (!ptype[n])
  289.             ppos[n] = p;
  290.         if (!ptype[n] && *p > '0' && *p < '9')
  291.             ptype[n] = 1; /* Numeric */
  292.         else
  293.             ptype[n] = 2; /* Non-Numeric */
  294.                 
  295.     }
  296. /* the first two parts are always a From and a userid
  297.  * are numeric userids possible?
  298.  */
  299. /*printf ("n=%d\n", n);
  300. printf ("ppos[-3] = %-10.10s\n", ppos[n-3]);
  301. printf ("ppos[-2] = %-10.10s\n", ppos[n-2]);
  302. printf ("ppos[-1] = %-10.10s\n", ppos[n-1]);*/
  303.     ppos[0] = xbuf;
  304.     ptype[0] = 3;   /* From identifier      */
  305.     ptype[1] = 4;   /* userid               */
  306. /* Check if last three parts are in form "remote from xxxxxx". If so then
  307.  * remove them from n/ptype */
  308.     if (n > 3 && 0 == memcmp (ppos[n-2], "remote ", 7)
  309.                   && 0 == memcmp (ppos[n-1], "from ", 5)) {
  310.         ptype[n] = ptype[n-1] = ptype[n-2] = 0;
  311.         n = n - 3;
  312.         
  313.         }
  314.  
  315.     if (setup) {
  316.         nparts = n;
  317.         memcpy (stype, ptype, 20);
  318.         return 1;
  319.     }
  320.  
  321.     /* if the format matches the remembered format then we have a match */
  322.     if (nparts == n && 0 == memcmp (stype, ptype, 20))
  323.         return 1;
  324.  
  325.         return 0;
  326. }
  327.  
  328. /*
  329.  parse_fromsep
  330.  
  331.  parse the mailbox using the FROM+header as the delimeter between mail items
  332. */
  333. static int
  334. parse_fromsep (FILE *infile, char *xbuf, char *basename, char *username) {
  335.     FILE *    mfile=0;
  336.     int     nlines, reterr=0;
  337.  
  338.     /* initialise new_mail test with From line format */
  339.     if (!new_mail (xbuf, 1)) {
  340.             reterr = 2;
  341.         return reterr;
  342.     }
  343.             
  344.     while (!feof (infile)) {
  345.         if ((mfile = fopen (get_next_fname (basename, username), "w")) == NULL) {
  346. /* this error most likely occurs if the SMTP directory doesn't exist     */
  347.                     reterr = 1;
  348.             break;
  349.         }
  350.                 fputs (xbuf, mfile); nlines = 1;
  351.         while (fgets (xbuf, XBUFSIZE, infile)) {
  352.             if (new_mail (xbuf, 0))
  353.                 break;
  354.                        fputs (xbuf, mfile); nlines++;
  355.         }
  356.  
  357.             if (mfile) { fclose (mfile); mfile = 0;}
  358.     }
  359.  
  360.     if (mfile) { fclose (mfile); mfile = 0;}
  361.     return reterr;
  362. }
  363.  
  364. int
  365. main (int argc, char * argv[]) {
  366.     FILE *    infile=0;
  367.     int    isfromsep=1, errs=0;
  368.         char username[256], basename[256], omailbox[256], maildir[256];
  369.         char * mailbox_name = maildir, * old_mailbox = omailbox;
  370.         char * xbuf = NULL;
  371.  
  372.     strcpy (username, "mail"); /* default value for username */
  373.         if (argc < 2) {
  374.         printf ("%s\n", version);
  375.         printf ("usage: unmbox <SMTP directory> [username]\n");
  376.         err ("usage: unmbox <SMTP directory> [username]\n", username);
  377.         exit (EXIT_FAILURE);
  378.     }
  379.  
  380.         strcpy (basename, argv[1]);
  381.         
  382.         if (argc > 2)
  383.                 strcpy (username, argv[2]);
  384.     
  385.         if (!get_uupc_vars (username, mailbox_name, old_mailbox)) {
  386.         err ("error - cannot find UUPC mail box\n", username);
  387.         exit (EXIT_FAILURE);
  388.     }
  389.  
  390.     /* test if any mail - so <mailbox>.tmp is not deleted! */
  391.     if ((infile = fopen (old_mailbox, "r")) == NULL) {
  392. /*        err ("error - cannot open UUPC mailbox\n", username);*/
  393.         exit (EXIT_FAILURE);
  394.     }
  395.     fclose (infile);
  396.  
  397.         remove (mailbox_name);
  398.     if (rename (old_mailbox, mailbox_name)) {
  399. /*        err ("error - cannot access UUPC mailbox - try again later\n", username);*/
  400.         exit (EXIT_FAILURE);
  401.     }
  402.     if ((infile = fopen (mailbox_name, "r")) == NULL) {
  403. /*        err ("error - cannot open UUPC mailbox\n", username);*/
  404.         exit (EXIT_FAILURE);
  405.     }
  406.  
  407.         xbuf = (char *)malloc (XBUFSIZE+1);
  408.         if (xbuf == NULL) {
  409.                 err("error - Cannot allocate temporary buffer\n", username);
  410.             exit (EXIT_FAILURE);
  411.     }
  412.  
  413. /* first check if file is nofromsep or fromsep format */
  414.     fgets (xbuf, XBUFSIZE, infile);
  415.     if (feof (infile)) {
  416.             fclose (infile);
  417. /* just to be nice - rename mailbox so that the user can try again later */
  418.                 rename (mailbox_name, old_mailbox);
  419.                   if (xbuf) {free (xbuf); xbuf = NULL;}
  420.         exit (EXIT_FAILURE);
  421.         }
  422. /* if the first line is 20 0x01s then this is a UUPC-style (nofromsep)
  423.  * delimeted mailbox.
  424. */
  425.     while (1) {
  426.             if (0 == memcmp (xbuf, x01x20, 20)) {
  427.                 isfromsep = 0;
  428.             break;
  429.         }
  430.                    if (0 == memcmp (xbuf, "From ", 5))
  431.             break;
  432.             fgets (xbuf, XBUFSIZE, infile);
  433.             if (feof (infile)) {
  434.                     fclose (infile);
  435. /* just to be nice - rename mailbox so that the user can try again later */
  436.                         rename (mailbox_name, old_mailbox);
  437.                           if (xbuf) {free (xbuf); xbuf = NULL;}
  438.                 err ("error - no From or nofromsep line in mailbox\n", username);
  439.                 exit (EXIT_FAILURE);
  440.                 }
  441.         }
  442.         
  443.     
  444.     if (isfromsep)
  445.         errs = parse_fromsep (infile, xbuf, basename, username);
  446.     else
  447.         errs = parse_nofromsep (infile, xbuf, basename, username);
  448.     if (errs) {
  449.         if (1 == errs)
  450.                 err ("error - cannot open new file for mail\n", username);
  451.         else if (2 == errs)
  452.                 err ("error - no From line at start of mailbox\n", username);
  453.         else
  454.                 err ("error - parse error reading mailbox\n", username);
  455. /* just to be nice - rename mailbox so that the user can try again later */
  456.                 rename (mailbox_name, old_mailbox);
  457.         }
  458.  
  459.     fclose (infile);
  460.     if (xbuf) {free (xbuf); xbuf = NULL;}
  461.     
  462.     exit (EXIT_SUCCESS);
  463.     return (EXIT_SUCCESS); /* gets rid of dumb compiler warning */
  464. }