home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / INTERNET / UPC2S1.ZIP / MAILLIB.C < prev    next >
C/C++ Source or Header  |  1993-09-20  |  21KB  |  607 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    m a i l l i b . c                                               */
  3. /*                                                                    */
  4. /*    Mail user agent subroutine library for UUPC/extended            */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*       Changes Copyright (c) 1989-1993 by Kendra Electronic         */
  9. /*       Wonderworks.                                                 */
  10. /*                                                                    */
  11. /*       All rights reserved except those explicitly granted by       */
  12. /*       the UUPC/extended license agreement.                         */
  13. /*--------------------------------------------------------------------*/
  14.  
  15. /*--------------------------------------------------------------------*/
  16. /*                          RCS Information                           */
  17. /*--------------------------------------------------------------------*/
  18.  
  19. /*
  20.  *    $Id: maillib.c 1.6 1993/09/20 04:41:54 ahd Exp $
  21.  *
  22.  *    $Log: maillib.c $
  23.  * Revision 1.6  1993/09/20  04:41:54  ahd
  24.  * OS/2 2.x support
  25.  *
  26.  * Revision 1.5  1993/07/31  16:26:01  ahd
  27.  * Changes in support of Robert Denny's Windows support
  28.  *
  29.  * Revision 1.4  1993/06/13  14:06:00  ahd
  30.  * Add precedence to the standard ignore list
  31.  *
  32.  * Revision 1.3  1993/04/11  00:33:05  ahd
  33.  * Global edits for year, TEXT, etc.
  34.  *
  35.  * Revision 1.2  1992/11/27  14:36:10  ahd
  36.  * Use scrsize() for screen size
  37.  *
  38.  *       3 May 90 Create from mail.c
  39.  *       16 Jun 90:  Added support for mail (~) subcommands      pdm
  40.  *                   chgd calling seq of Collect_Mail to support
  41.  *                         above
  42.  *                   chges to CopyMsg to support ~i subcmd
  43.  *                   mods to SendMail to support autosign option
  44.  *                   broke out signature append code to seperate fn
  45.  *                   added support for alternate signature file
  46.  */
  47.  
  48. /*--------------------------------------------------------------------*/
  49. /*                        System include files                        */
  50. /*--------------------------------------------------------------------*/
  51.  
  52. #include <ctype.h>
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <string.h>
  56.  
  57. /*--------------------------------------------------------------------*/
  58. /*                    UUPC/extended include files                     */
  59. /*--------------------------------------------------------------------*/
  60.  
  61. #include "lib.h"
  62. #include "address.h"
  63. #include "hlib.h"
  64. #include "mlib.h"
  65. #include "alias.h"
  66. #include "mail.h"
  67. #include "maillib.h"
  68. #include "scrsize.h"
  69.  
  70. #define  INDENT "> "
  71.  
  72. /*--------------------------------------------------------------------*/
  73. /*       Local variables                                              */
  74. /*--------------------------------------------------------------------*/
  75.  
  76. static int PageCount = 0;
  77.  
  78. static char *ignorelist[] =  { "Message-ID:",
  79.                         "Received:",
  80.                         "Status: ",
  81.                         "X-Mailer: ",
  82.                         "From " ,
  83.                         "Precedence: " ,
  84.                         "Path: ",
  85.                         "Lines: ",
  86.                         "References: ",
  87.                         "" };
  88.  
  89. currentfile();                /* Define current file for panic()     */
  90.  
  91. /*--------------------------------------------------------------------*/
  92. /*    P a g e r                                                       */
  93. /*                                                                    */
  94. /*    Page through a message                                          */
  95. /*                                                                    */
  96. /*    There are hooks here to let the user use his/her own pager,     */
  97. /*    like LIST, MORE, or LESS.  We just write the message out to     */
  98. /*    a temporary file and invoke the appropriate external program    */
  99. /*    to do the browsing.                                             */
  100. /*--------------------------------------------------------------------*/
  101.  
  102. boolean Pager(const int msgnum,
  103.               boolean external,
  104.               copyopt received,
  105.               const boolean reset)
  106. {
  107.    long nextloc;
  108.    char *browse   = NULL;
  109.    char buf[BUFSIZ];
  110.    boolean exit  = FALSE;        /* Flag for PRE-MATURE exit   ahd   */
  111.    FILE *fmailbag;
  112.  
  113.    if (msgnum == -1)
  114.       return FALSE;
  115.  
  116.    if (bflag[F_PAGER])           /* User want pager option inverted? */
  117.       external = ! external;     /* Yes --> Do the inversion         */
  118.  
  119.    if (letters[msgnum].status < M_READ)
  120.       letters[msgnum].status = M_READ;
  121.  
  122.    if (external && (E_pager != nil(char)))
  123.    {
  124.       browse = mktempname( NULL,"TMP" );/* Get a temporary file name */
  125.  
  126.       if ((fmailbag = FOPEN(browse, "w",TEXT_MODE)) == nil(FILE))
  127.       {
  128.          printerr(browse);
  129.          printmsg(0,"Cannot open browse file %s",browse);
  130.          return FALSE;
  131.       } /* if */
  132.       CopyMsg(msgnum, fmailbag, received, FALSE);
  133.       fclose(fmailbag);
  134.  
  135.       Invoke(E_pager, browse);
  136.       remove(browse);
  137.       free(browse);
  138.  
  139.    } /* if */
  140.    else {
  141.       fseek(fmailbox, letters[msgnum].adr , SEEK_SET);
  142.       nextloc = letters[msgnum + 1].adr;
  143.  
  144.       if ( reset )
  145.          ClearScreen();
  146.       else
  147.          PageLine("\n");
  148.  
  149.       sprintf(buf,"Mailbox item %d:\n",msgnum + 1);
  150.       PageLine(buf);
  151.       while (ftell(fmailbox) < nextloc && (!exit) &&
  152.          fgets(buf, BUFSIZ, fmailbox) != nil(char))
  153.       {
  154.          boolean print = TRUE;
  155.  
  156.          switch(received)
  157.          {
  158.             case nocontinue:
  159.                if ((*buf != '\n') && !isgraph(*buf)) {
  160.                   print = FALSE;
  161.                   break;
  162.                }
  163.                else
  164.                   received = noreceived;
  165.             case noreceived:
  166.             {
  167.                char entry = 0;
  168.                while ( strlen(ignorelist[entry]) && print )
  169.                {
  170.                   if (equalni(ignorelist[entry],
  171.                         buf,strlen(ignorelist[entry])))
  172.                   {
  173.                      print = FALSE;
  174.                      received = nocontinue;
  175.                   }
  176.                   else
  177.                      entry++;
  178.                } /* while */
  179.             } /* case noreceived */
  180.          } /* switch */
  181.          if (received != seperators)
  182.             if (equal(buf,"\n"))
  183.                received = seperators;
  184.  
  185.          if (print)
  186.             if (PageLine(buf))         /* Exit if the user hits Q    */
  187.                exit = TRUE;
  188.       } /* while */
  189.  
  190.       if (equal(buf,"\n") && (!exit))                 /* ahd   */
  191.          putchar('\n');                               /* ahd   */
  192.    } /* else */
  193.  
  194.    return ! exit;
  195. } /*Pager*/
  196.  
  197.  
  198. /*--------------------------------------------------------------------*/
  199. /*    S u b _ P a g e r                                               */
  200. /*       pager for the ~p mail subcommand                             */
  201. /*       page through a mail message currently being entered          */
  202. /*                                                                    */
  203. /*    Clone of the Pager function                                     */
  204. /*--------------------------------------------------------------------*/
  205.  
  206. void Sub_Pager(const char *tinput,
  207.                      boolean external )
  208. {
  209.    boolean exit  = FALSE;        /* Flag for PRE-MATURE exit   ahd   */
  210.  
  211.    if (bflag[ F_PAGER ])
  212.       external = ! external;
  213.  
  214.    if ( external && (E_pager != nil(char)) )
  215.       Invoke(E_pager, tinput);
  216.    else {
  217.       FILE *finput;
  218.       char buf[BUFSIZ];
  219.       finput = FOPEN(tinput, "r",TEXT_MODE);
  220.       if (finput == NULL) {
  221.          printmsg(0,"Cannot open file %s for display",tinput);
  222.          printerr(tinput);
  223.          return;
  224.       }
  225.       PageReset();
  226.       ClearScreen();
  227.       while ( (!exit) && fgets(buf, BUFSIZ, finput) != nil(char))
  228.       {
  229.         if (PageLine(buf))         /* Exit if the user hits Q  */
  230.            exit = TRUE;
  231.       }
  232.       fclose(finput);
  233.    }
  234.  
  235. } /*Sub_Pager*/
  236.  
  237. /*--------------------------------------------------------------------*/
  238. /*    P a g e R e s e t                                               */
  239. /*                                                                    */
  240. /*    Reset page function to top of page                              */
  241. /*--------------------------------------------------------------------*/
  242.  
  243. void PageReset()
  244. {
  245.    PageCount = 0;
  246. } /*PageReset*/
  247.  
  248. /*--------------------------------------------------------------------*/
  249. /*    P a g e L i n e                                                 */
  250. /*                                                                    */
  251. /*    Print one line when paging through a file                       */
  252. /*--------------------------------------------------------------------*/
  253.  
  254. boolean PageLine(char *line)
  255. {
  256.  
  257. #ifdef _Windows
  258.    short pagesize = scrsize() - 3;
  259. #else
  260.    short pagesize = scrsize() - 3;
  261. #endif
  262.  
  263.    fputs(line, stdout);
  264.  
  265.    PageCount = PageCount + 1 + strlen(line) / 81; /* Handle long lines  */
  266.  
  267.    if (PageCount > (pagesize))
  268.    {
  269.       int c;
  270.       fputs("More?", stdout);
  271.       c = Get_One();
  272.  
  273.       switch (tolower(c))
  274.       {
  275.          case 'q':
  276.          case '\003':
  277.          case 'n':                        /* Because that's what I
  278.                                              keep Pressing           */
  279.          case 'x':
  280.             fputs("\rAborted.\n", stdout);
  281.             return TRUE;
  282.  
  283.          case 'd':
  284.             PageCount = pagesize / 2;     /* Half a Page More */
  285.             break;
  286.  
  287.          case '\r':
  288.             PageCount = pagesize;         /* Only print one line  */
  289.             break;
  290.  
  291.          default:
  292.             PageCount = 0;                /* Print full screen    */
  293.       }
  294.       fputs("\r      \r",stdout);
  295.    }
  296.  
  297.    return FALSE;
  298.  
  299. } /*PageLine*/
  300.  
  301. /*--------------------------------------------------------------------*/
  302. /*    C o p y M s g                                                   */
  303. /*                                                                    */
  304. /*    Copy a message                                                  */
  305. /*                                                                    */
  306. /*    Allows copying message with one or more of the options          */
  307. /*    specified in the copyopt data type.                             */
  308. /*--------------------------------------------------------------------*/
  309.  
  310. boolean CopyMsg(int msgnum, FILE *f, copyopt headers, boolean indent)
  311. {
  312.    long nextloc;
  313.    boolean print;
  314.    char buf[BUFSIZ];
  315.  
  316. /*--------------------------------------------------------------------*/
  317. /*                 Write a separator line, if needed                  */
  318. /*--------------------------------------------------------------------*/
  319.  
  320.    if (headers == seperators)
  321.    {
  322.       if (fputs(MESSAGESEP,f) == EOF)     /* Write out separator line   */
  323.       {
  324.          printerr("CopyMsg");
  325.          panic();
  326.       } /* if (fputs(MESSAGESEP,f) == EOF) */
  327.    } /* if (headers == seperators) */
  328.  
  329. /*--------------------------------------------------------------------*/
  330. /*             else add a one line from line, if desired              */
  331. /*--------------------------------------------------------------------*/
  332.  
  333.    else if (headers == fromheader )
  334.    {
  335.       register char *sp = buf;
  336.       headers = noheader;                 /* Do not print full header       */
  337.       if (RetrieveLine(letters[msgnum].date, buf, LSIZE))
  338.       {
  339.          register char  *sp = buf;
  340.          while (!isspace(*sp))
  341.             sp++;
  342.          while (isspace(*sp))
  343.             sp++;
  344.          fprintf(f,"On %s,", sp );
  345.       } /* if */
  346.  
  347.       if (RetrieveLine(letters[msgnum].from, buf, BUFSIZ))
  348.       {
  349.          while (!isspace(*sp) && (*sp != '\0'))
  350.             sp++;
  351.          BuildAddress( buf, sp );
  352.       } /* if */
  353.       else
  354.          strcpy(buf,"you");   /* Wimp out without admitting it       */
  355.  
  356.       fprintf(f, " %s wrote:\n", buf) ;
  357.    } /* if (headers == fromheader ) */
  358.  
  359. /*--------------------------------------------------------------------*/
  360. /*              Now position to the front of the letter               */
  361. /*--------------------------------------------------------------------*/
  362.  
  363.    fseek(fmailbox, letters[msgnum].adr , SEEK_SET);
  364.    nextloc = letters[msgnum + 1].adr;
  365.  
  366.    while (ftell(fmailbox) < nextloc &&
  367.       fgets(buf, BUFSIZ, fmailbox) != nil(char)) {
  368.  
  369. /*--------------------------------------------------------------------*/
  370. /*               Determine if we should write the line                */
  371. /*--------------------------------------------------------------------*/
  372.  
  373.       print = TRUE;
  374.  
  375.       switch (headers)
  376.       {
  377.          case noheader:
  378.             print = FALSE;
  379.             break;
  380.  
  381.          case nocontinue:
  382.             if ((*buf != '\n') && !isgraph(*buf)) {
  383.                print = FALSE;
  384.                break;
  385.             }
  386.             else
  387.                headers = noreceived;
  388.                /* Fall through ... */
  389.          case noreceived:
  390.          {
  391.             char entry = 0;
  392.             while ( strlen(ignorelist[entry]) && print )
  393.             {
  394.                if (equalni(ignorelist[entry],buf,strlen(ignorelist[entry])))
  395.                {
  396.                   print = FALSE;
  397.                   headers = nocontinue;
  398.                }
  399.                else
  400.                   entry++;
  401.             }
  402.          } /* case noreceived */
  403.                /* Fall through */
  404.          case noseperator:
  405.          case seperators:
  406.             break;
  407.  
  408.          default:
  409.             printmsg(0,"CopyMsg: Bad header copy state of %d",headers);
  410.             panic();
  411.       } /* switch */
  412.  
  413. /*--------------------------------------------------------------------*/
  414. /*                 If we should print the line, do so                 */
  415. /*--------------------------------------------------------------------*/
  416.  
  417.       if (print)
  418.       {
  419.          if (indent)
  420.          {
  421.             if ( fputs(INDENT , f ) == EOF )
  422.             {
  423.                printerr( "CopyMsg" );
  424.                panic();
  425.             } /* if ( fputs(INDENT , f ) == EOF ) */
  426.          } /* if (indent) */
  427.  
  428.          if ( fputs(buf , f ) == EOF )
  429.          {
  430.             printerr( "CopyMsg" );
  431.             panic();
  432.          } /* if ( fputs(buf , f ) == EOF ) */
  433.  
  434.       } /* if (print) */
  435.  
  436. /*--------------------------------------------------------------------*/
  437. /*  If end of the header, print all data until the end of the input   */
  438. /*--------------------------------------------------------------------*/
  439.  
  440.       if ( (headers != seperators) && equal(buf, "\n") )
  441.          headers = seperators;
  442.  
  443.    } /*while*/
  444.  
  445.    return TRUE;
  446. } /*CopyMsg*/
  447.  
  448. /*--------------------------------------------------------------------*/
  449. /*    N u m e r i c                                                   */
  450. /*                                                                    */
  451. /*    Determine if a string is numeric.  Returns TRUE if string is    */
  452. /*    numeric, else FALSE.                                            */
  453. /*--------------------------------------------------------------------*/
  454.  
  455.  boolean Numeric( const char *number)
  456.  {
  457.    char *column = (char *) number;
  458.  
  459.    if (*column == '\0')
  460.       return FALSE;
  461.  
  462.    while( isdigit(*column) )  /* Scan to string end or 1st non-digit */
  463.       column++;
  464.  
  465.    return *column == '\0';    /* Success if whole string was made of
  466.                                  digits                              */
  467.  } /* Numeric */
  468.  
  469. /*--------------------------------------------------------------------*/
  470. /*    R e t r i e v e L i n e                                         */
  471. /*                                                                    */
  472. /*    Read a line from a mail header, if available                    */
  473. /*--------------------------------------------------------------------*/
  474.  
  475. boolean RetrieveLine(long adr, char *line, const size_t len)
  476. {
  477.    char *cp = line;
  478.    size_t count;
  479.  
  480.    *line = '\0';              /* Insure nothing to find              */
  481.    if (adr == MISSING)        /* No information to read?             */
  482.       return FALSE;           /* Report this to caller               */
  483.  
  484.    if (fseek(fmailbox, adr, SEEK_SET)) /* Position to data           */
  485.    {                          /* Have a problem?                     */
  486.       printerr("mailbox");    /* Yes --> Report and return           */
  487.       return FALSE;
  488.    }
  489.  
  490. /*--------------------------------------------------------------------*/
  491. /*                     Actually read the data in                      */
  492. /*--------------------------------------------------------------------*/
  493.  
  494.    count = fread(line, sizeof *line, len-1, fmailbox);
  495.  
  496.    if ((count < (len-1)) && ferror( fmailbox ))
  497.    {
  498.       printerr( "RetrieveLine");
  499.       return FALSE;
  500.    }
  501.  
  502.    line[count] = '\0';        /* Terminate the string read           */
  503.  
  504. /*--------------------------------------------------------------------*/
  505. /*    A field continues until a new field begins in column of the     */
  506. /*    next line or the header ends (an empty line); find the end      */
  507. /*    of the field, trimming extra white space from the beginning     */
  508. /*    of each line as we go                                           */
  509. /*--------------------------------------------------------------------*/
  510.  
  511.    while( (cp = strchr(cp , '\n')) != NULL )
  512.    {
  513.       if ((cp[1] == '\n') || !isspace(cp[1]))   /* End of field?     */
  514.          *cp = '\0';          /* Yes --> Terminate string            */
  515.       else {
  516.          char *next;
  517.  
  518.          *cp++ = ' ';         /* Convert line break to whitespace    */
  519.          next = ++cp;         /* Get first position of new line      */
  520.          while( isspace( *next ) )  /* Ignore leading white space    */
  521.             next++;
  522.  
  523.          memmove( cp , next , strlen(next) + 1 );
  524.                               /* Trim leading white space            */
  525.       } /* else */
  526.    } /* while */
  527.  
  528.    return TRUE;
  529.  
  530. } /*RetrieveLine*/
  531.  
  532. /*--------------------------------------------------------------------*/
  533. /*    R e t u r n A d d r e s s                                       */
  534. /*                                                                    */
  535. /*    Returns the user name (if available and requested) or           */
  536. /*    E-mail address of the user                                      */
  537. /*                                                                    */
  538. /*    Written by ahd 15 July 1989                                     */
  539. /*--------------------------------------------------------------------*/
  540.  
  541. void ReturnAddress(char *line, struct ldesc *ld)
  542. {
  543.    char buffer[BUFSIZ];
  544.  
  545.    if (!RetrieveLine(ld->from, buffer, BUFSIZ))
  546.                                           /* From: line available?   */
  547.       strcpy(line,"-- Unknown --");       /* No --> Return error     */
  548.    else {
  549.       char *begin = buffer;
  550.       while (!isspace(*begin) && (*begin != '\0'))
  551.          begin++;
  552.       if (strlen(begin))
  553.          ExtractName(line,begin);         /* Yes --> Return name     */
  554.       else
  555.          strcpy(line,"-- Invalid From: line --");
  556.    }
  557.  
  558.    return;
  559.  
  560. } /*ReturnAddress*/
  561.  
  562. /*--------------------------------------------------------------------*/
  563. /*    s a y o p t i o n s                                             */
  564. /*                                                                    */
  565. /*    Announce user options in effect                                 */
  566. /*--------------------------------------------------------------------*/
  567.  
  568. void sayoptions( FLAGTABLE *flags)
  569. {
  570.  
  571.    size_t subscript;
  572.    size_t used = 0;
  573.  
  574.    printf("\nThe following options are set:\n");
  575.  
  576.    for (subscript = 0; flags[subscript].sym != NULL; subscript++)
  577.    {
  578.          size_t width;
  579.  
  580.          if (flags[subscript].bits & B_GLOBAL)
  581.             continue;               /* Don't print system options */
  582.  
  583.          width = 1 + strlen( flags[subscript].sym ) +
  584.                  ( bflag[ flags[subscript].position ] ? 0 : 2 );
  585.  
  586.          used += width;
  587.          if ( subscript > 0 )
  588.          {
  589.             if ( used > 79 )
  590.             {
  591.                putchar('\n');
  592.                used = width;
  593.             } /* if ( used > 79 ) */
  594.             else
  595.                putchar(' ');
  596.          } /* if ( subscript > 0 ) */
  597.  
  598.          printf("%s%s",
  599.                bflag[ flags[subscript].position ] ? "" : "no" ,
  600.                flags[subscript].sym );
  601.  
  602.    } /* for */
  603.  
  604.    putchar('\n');
  605.  
  606. } /* sayoptions */
  607.