home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / misc / tcpipsrc / bmutil.c < prev    next >
C/C++ Source or Header  |  1990-12-09  |  24KB  |  1,033 lines

  1. /*
  2.  *    Simple mail user interface for KA9Q IP/TCP package.
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *    Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
  8.  *    Permission granted for non-commercial copying and use, provided
  9.  *    this notice is retained.
  10.  *
  11.  *    Ported to NOS at 900120 by Anders Klemets SM0RGV.
  12.  */
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <time.h>
  17. #include "global.h"
  18. #include "ftpserv.h"
  19. #include "smtp.h"
  20. #include "proc.h"
  21. #include "usock.h"
  22. #include "socket.h"
  23. #include "telnet.h"
  24. #include "timer.h"
  25. #include "session.h"
  26. #include "files.h"
  27.  
  28. #define        SETVBUF
  29. #if    defined(UNIX) || defined(MICROSOFT)
  30. #include    <sys/types.h>
  31. #endif
  32. /*
  33. #if    defined(UNIX) || defined(MICROSOFT) || defined(__TURBOC__)
  34. #include    <sys/stat.h>
  35. #endif
  36. #ifdef AZTEC
  37. #include <stat.h>
  38. #endif
  39. */
  40. #include <fcntl.h>
  41. #include "bm.h"
  42. #include "mailbox.h"
  43.  
  44. #ifdef SETVBUF
  45. #define        MYBUF    512
  46. char    *stdinbuf = NULLCHAR;    /* the stdio buffer for the mail file */
  47. char    *stdoutbuf = NULLCHAR;    /* the stdio file io buffer for the temp file */
  48. #endif
  49.  
  50. extern long ftell();
  51. static char Badmsg[] = "Invalid Message number %d\n";
  52. static char Nomail[] = "No messages\n";
  53. static char Noaccess[] = "Unable to access %s\n";
  54. static int readnotes __ARGS((struct mbx *m,FILE *ifile,int update));
  55. static long isnewmail __ARGS((struct mbx *m));
  56. static int initnotes __ARGS((struct mbx *m));
  57. static int lockit __ARGS((struct mbx *m));
  58. static long fsize __ARGS((char *name));
  59. static void mfclose __ARGS((struct mbx *m));
  60. static int tkeywait __ARGS((char *prompt,int flush));
  61.  
  62. static int
  63. initnotes(m)
  64. struct mbx *m;
  65. {
  66.     FILE    *tmpfile();
  67.     FILE    *ifile;
  68.     register struct    let *cmsg;
  69.     char buf[256];
  70.     int     i, ret;
  71.  
  72.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  73.     if ((ifile = fopen(buf,READ_TEXT)) == NULLFILE)
  74.         return 0;
  75.     fseek(ifile,0L,2);     /* go to end of file */
  76.     m->mboxsize = ftell(ifile);
  77.     rewind(ifile);
  78.     if(!stricmp(m->area,m->name)) /* our private mail area */
  79.         m->mysize = m->mboxsize;
  80.     if ((m->mfile = tmpfile()) == NULLFILE) {
  81.         (void) fclose(ifile);
  82.         return -1;
  83.     }
  84. #ifdef    SETVBUF
  85.     if (stdinbuf == NULLCHAR)
  86.         stdinbuf = mallocw(MYBUF);
  87.     setvbuf(ifile, stdinbuf, _IOFBF, MYBUF);
  88.     if (stdoutbuf == NULLCHAR)
  89.         stdoutbuf = mallocw(MYBUF);
  90.     setvbuf(m->mfile, stdoutbuf, _IOFBF, MYBUF);
  91. #endif
  92.     m->nmsgs = 0;
  93.     m->current = 0;
  94.     m->change = 0;
  95.     m->newmsgs = 0;
  96.     m->anyread = 0;
  97.     /* Allocate space for reading messages */
  98.     free((char *)m->mbox);
  99.     m->mbox = (struct let *)callocw(Maxlet+1,sizeof(struct let));
  100.     ret = readnotes(m,ifile,0);
  101.     (void) fclose(ifile);
  102. #ifdef SETVBUF
  103.     free(stdinbuf);
  104.     stdinbuf = NULLCHAR;
  105. #endif
  106.     if (ret != 0)
  107.         return -1;
  108.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++)  
  109.         if ((cmsg->status & BM_READ) == 0) {
  110.             m->newmsgs++;
  111.             if (m->current == 0)
  112.                 m->current = i;
  113.         }
  114.     /* start at one if no new messages */
  115.     if (m->current == 0)
  116.         m->current++;
  117.  
  118.     return 0;
  119. }
  120.  
  121. /* readnotes assumes that ifile is pointing to the first
  122.  * message that needs to be read.  For initial reads of a
  123.  * notesfile, this will be the beginning of the file.  For
  124.  * rereads when new mail arrives, it will be the first new
  125.  * message.
  126.  */
  127. static int
  128. readnotes(m,ifile,update)
  129. struct mbx *m;
  130. FILE *ifile ;
  131. int update;    /* true if this is not the initial read of the notesfile */
  132. {
  133.     char     tstring[LINELEN];
  134.     long    cpos;
  135.     register struct    let *cmsg;
  136.     register char *line;
  137.  
  138.     cmsg = (struct let *)NULL;
  139.     line = tstring;
  140.     while(fgets(line,LINELEN,ifile) != NULLCHAR) {
  141.         /* scan for begining of a message */
  142.         if(strncmp(line,"From ",5) == 0) {
  143.             pwait(NULL);
  144.             cpos = ftell(m->mfile);
  145.             fputs(line,m->mfile);
  146.             if (m->nmsgs == Maxlet) {
  147.                 tprintf("Mail box full: > %d messages\n",Maxlet);
  148.                 mfclose(m);
  149.                 return -1;
  150.             }
  151.             m->nmsgs++;
  152.             cmsg = &m->mbox[m->nmsgs];
  153.             cmsg->start = cpos;
  154.             if(!update)
  155.                 cmsg->status = 0;
  156.             cmsg->size = strlen(line);
  157.             while (fgets(line,LINELEN,ifile) != NULLCHAR) {
  158.                 if (*line == '\n') { /* done header part */
  159.                     cmsg->size++;
  160.                     putc(*line, m->mfile);
  161.                     break;
  162.                 }
  163.                 if (htype(line) == STATUS) {
  164.                     if (line[8] == 'R') 
  165.                         cmsg->status |= BM_READ;
  166.                     continue;
  167.                 }
  168.                 cmsg->size += strlen(line);
  169.                 if (fputs(line,m->mfile) == EOF) {
  170.                     tprintf("tmp file: %s",sys_errlist[errno]);
  171.                     mfclose(m);
  172.                     return -1;
  173.                 }
  174.  
  175.             }
  176.         } else if (cmsg) {
  177.             cmsg->size += strlen(line);
  178.             fputs(line,m->mfile);
  179.         }
  180.     }
  181.     return 0;
  182. }
  183.  
  184. /* list headers of a notesfile a message */
  185. int
  186. dolistnotes(argc,argv,p)
  187. int argc;
  188. char *argv[];
  189. void *p;
  190. {
  191.     struct mbx *m;
  192.     register struct    let *cmsg;
  193.     register char    *cp, *s;
  194.     char    smtp_date[SLINELEN], smtp_from[SLINELEN];
  195.     char    smtp_subject[SLINELEN], tstring[LINELEN], type;
  196.     int    start, stop;
  197.     long    size;
  198.  
  199.     m = (struct mbx *) p;
  200.     if (m->mfile == NULLFILE) {
  201.         tprintf(Nomail);
  202.         return 0;
  203.     }
  204.  
  205.     tprintf("Mail area: %s  %d message%s -  %d new\n\n",m->area,m->nmsgs,
  206.         m->nmsgs == 1 ? " " : "s ", m->newmsgs);
  207.     stop = m->nmsgs;
  208.     if(m->stype == 'L') {        /* LL (List Latest) command */
  209.          if(argc > 1)
  210.           start = stop - atoi(argv[1]) + 1;
  211.          else
  212.           start = stop;
  213.     }
  214.     else {
  215.          if(argc > 1)
  216.           start = atoi(argv[1]);
  217.          else
  218.           start = 1;
  219.          if(argc > 2)
  220.           stop = atoi(argv[2]);
  221.     }
  222.     if(stop > m->nmsgs)
  223.         stop = m->nmsgs;
  224.     if(start < 1 || start > stop) {
  225.         tprintf("Invalid range.\n");
  226.         return 0;
  227.     }
  228.     for (cmsg = &m->mbox[start]; start <= stop; start++, cmsg++) {
  229.         *smtp_date = '\0';
  230.         *smtp_from = '\0';
  231.         *smtp_subject = '\0';
  232.         type = ' ';
  233.         fseek(m->mfile,cmsg->start,0);
  234.         size = cmsg->size;
  235.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  236.                != NULLCHAR) {
  237.             if (*tstring == '\n')    /* end of header */
  238.                 break;
  239.             size -= strlen(tstring);
  240.             rip(tstring);
  241.             /* handle continuation later */
  242.             if (*tstring == ' '|| *tstring == '\t')
  243.                 continue;
  244.             switch(htype(tstring)) {
  245.             case FROM:
  246.                 cp = getaddress(tstring,0);
  247.                 sprintf(smtp_from,"%.30s",
  248.                     cp != NULLCHAR ? cp : "");
  249.                 break;
  250.             case SUBJECT:
  251.                 sprintf(smtp_subject,"%.34s",&tstring[9]);
  252.                 break;
  253.             case DATE:
  254.                 if ((cp = strchr(tstring,',')) == NULLCHAR)
  255.                     cp = &tstring[6];
  256.                 else
  257.                     cp++;
  258.                 /* skip spaces */
  259.                 while (*cp == ' ') cp++;
  260.                 if(strlen(cp) < 17)
  261.                     break;     /* not a valid length */
  262.                 s = smtp_date;
  263.                 /* copy day */
  264.                 if (atoi(cp) < 10 && *cp != '0') {
  265.                     *s++ = ' ';
  266.                 } else
  267.                     *s++ = *cp++;
  268.                 *s++ = *cp++;
  269.  
  270.                 *s++ = ' ';
  271.                 *s = '\0';
  272.                 while (*cp == ' ')
  273.                     cp++;
  274.                 strncat(s,cp,3);    /* copy month */
  275.                 cp += 3;
  276.                 while (*cp == ' ')
  277.                     cp++;
  278.                 /* skip year */
  279.                 while (isdigit(*cp))
  280.                     cp++;
  281.                 /* copy time */
  282.                 strncat(s,cp,6); /* space hour : min */
  283.                 break;
  284.             case BBSTYPE:
  285.                 type = tstring[16];
  286.                 break;
  287.             case NOHEADER:
  288.                 break;
  289.             }
  290.         }
  291.         if((type == m->stype && m->stype != ' ') || m->stype == ' '
  292.            || m->stype == 'L')
  293.              tprintf("%c%c%c%3d %-27.27s %-12.12s %5ld %.25s\n",
  294.                  (start == m->current ? '>' : ' '),
  295.                  (cmsg->status & BM_DELETE ? 'D' : ' '),
  296.                  (cmsg->status & BM_READ ? 'Y' : 'N'),
  297.                  start, smtp_from, smtp_date,
  298.                  cmsg->size, smtp_subject);
  299.     }
  300.     return 0;
  301. }
  302.  
  303. /*  save msg on stream - if noheader set don't output the header */
  304. int
  305. msgtofile(m,msg,tfile,noheader)
  306. struct mbx *m;
  307. int msg;
  308. FILE *tfile;   /* already open for write */
  309. int noheader;
  310. {
  311.     char    tstring[LINELEN];
  312.     long     size;
  313.  
  314.     if (m->mfile == NULLFILE) {
  315.         tprintf(Nomail);
  316.         return -1;
  317.     }
  318.     fseek(m->mfile,m->mbox[msg].start,0);
  319.     size = m->mbox[msg].size;
  320.  
  321.     if (noheader) {
  322.         /* skip header */
  323.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  324.                != NULLCHAR) {
  325.             size -= strlen(tstring);
  326.             if (*tstring == '\n')
  327.                 break;
  328.         }
  329.     }
  330.     while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  331.            != NULLCHAR) {
  332.         size -= strlen(tstring);
  333.         fputs(tstring,tfile);
  334.         if (ferror(tfile)) {
  335.             tprintf("Error writing mail file\n");
  336.             return -1;
  337.         }
  338.     }
  339.     return 0;
  340. }
  341.  
  342. /*  dodelmsg - delete message in current notesfile */
  343. int
  344. dodelmsg(argc,argv,p)
  345. int argc;
  346. char *argv[];
  347. void *p;
  348. {
  349.     struct mbx *m;
  350.     int msg,i;
  351.     m = (struct mbx *) p;
  352.     if (m->mfile == NULLFILE) {
  353.         tprintf(Nomail);
  354.         return 0;
  355.     }
  356.     for(i = 1; i < argc; ++i) {
  357.         msg = atoi(argv[i]);
  358.         if(msg < 0 || msg > m->nmsgs) {
  359.             tprintf(Badmsg,msg);
  360.             continue;
  361.         }
  362.         /* Check if we have permission to delete others mail */
  363.         if(!(m->privs & FTP_WRITE) && stricmp(m->area,m->name)) {
  364.             tprintf(Noperm);
  365.             return 0;
  366.         }
  367.         m->mbox[msg].status |= BM_DELETE;
  368.         tprintf("Msg %d Killed.\n", msg);
  369.         m->change = 1;
  370.     }
  371.     return 0;
  372. }
  373. /* close the temp file while coping mail back to the mailbox */
  374. int
  375. closenotes(m)
  376. struct mbx *m;
  377. {
  378.     register struct    let *cmsg;
  379.     register char *line;
  380.     char tstring[LINELEN], buf[256];
  381.     long size;
  382.     int i, nostatus = 0, nodelete;
  383.     FILE    *nfile;
  384.  
  385.     if (m->mfile == NULLFILE)
  386.         return 0;
  387.  
  388.     if(!m->change) {        /* no changes were made */
  389.         mfclose(m);
  390.         m->mboxsize = 0;
  391.         return 0;
  392.     }
  393.     /* If this area is a public message area, then we will not add a
  394.      * Status line to indicate that the message has been read.
  395.      */
  396.     nostatus = isarea(m->area);
  397.  
  398.     /* Don't delete messages from public message areas unless you are
  399.      * a BBS.
  400.      */
  401.     if(nostatus)
  402.         nodelete = !(m->privs & SYSOP_CMD);
  403.     else
  404.         nodelete = 0;
  405.  
  406.     /* See if any messages have been forwarded, otherwise just close
  407.      * the file and return since there is nothing to write back.
  408.      */
  409.     if(nostatus && nodelete) {
  410.         for(i=1; i <= m->nmsgs; ++i)
  411.             if(m->mbox[i].status & BM_FORWARDED)
  412.                 break;
  413.         if(i > m->nmsgs) {
  414.             mfclose(m);
  415.             m->mboxsize = 0;
  416.             return 0;
  417.         }
  418.     }
  419.     line = tstring;
  420.     scanmail(m);
  421.     if(lockit(m))
  422.         return -1;
  423.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  424.     if ((nfile = fopen(buf,WRITE_TEXT)) == NULLFILE) {
  425.         tprintf(Noaccess,buf);
  426.         mfclose(m);
  427.         m->mboxsize = 0;
  428.         rmlock(Mailspool,m->area);
  429.         return -1;
  430.     }
  431.     /* copy tmp file back to notes file */
  432.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++) {
  433.         fseek(m->mfile,cmsg->start,0);
  434.         size = cmsg->size;
  435.         /* It is not possible to delete messages if nodelete is set */
  436.         if ((cmsg->status & BM_DELETE) && !nodelete)
  437.             continue;
  438.         /* copy the header */
  439.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  440.             size -= strlen(line);
  441.             if (*line == '\n') {
  442.                 if (cmsg->status & BM_FORWARDED)
  443.                     fprintf(nfile,"%s%s\n",Hdrs[XFORWARD],
  444.                         m->name);
  445.                 if ((cmsg->status & BM_READ) != 0 && !nostatus)
  446.                     fprintf(nfile,"%sR\n",Hdrs[STATUS]);
  447.                 fprintf(nfile,"\n");
  448.                 break;
  449.             }
  450.             fputs(line,nfile);
  451.             /* pwait(NULL);  can cause problems if exiting NOS */
  452.         }
  453.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  454.             fputs(line,nfile);
  455.             size -= strlen(line);
  456.             /* pwait(NULL);   dont want no damaged files */
  457.             if (ferror(nfile)) {
  458.                 tprintf("Error writing mail file\n");
  459.                 (void) fclose(nfile);
  460.                 mfclose(m);
  461.                 m->mboxsize = 0;
  462.                 rmlock(Mailspool,m->area);
  463.                 return -1;
  464.             }
  465.         }
  466.     }
  467.     m->nmsgs = 0;
  468.     if (!stricmp(m->name,m->area))
  469.         m->mysize = ftell(nfile); /* Update the size of our mailbox */
  470.     /* remove a zero length file */
  471.     if (ftell(nfile) == 0L)
  472.         (void) unlink(buf);
  473.     (void) fclose(nfile);
  474.     mfclose(m);
  475.     m->mboxsize = 0;
  476.     rmlock(Mailspool,m->area);
  477.     pwait(NULL);
  478.     return 0;
  479. }
  480.  
  481. /* Returns 1 if name is a public message Area, 0 otherwise */
  482. int
  483. isarea(name)
  484. char *name;
  485. {
  486.     char buf[LINELEN], *cp;
  487.     FILE *fp;
  488.     if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
  489.         return 0;
  490.     while(fgets(buf,sizeof(buf),fp) != NULLCHAR) {
  491.         /* The first word on each line is all that matters */
  492.         if((cp = strchr(buf,' ')) == NULLCHAR)
  493.             if((cp = strchr(buf,'\t')) == NULLCHAR)
  494.                 continue;
  495.         *cp = '\0';
  496.         if((cp = strchr(buf,'\t')) != NULLCHAR)
  497.             *cp = '\0';
  498.         if(stricmp(name,buf) == 0) {    /* found it */
  499.             fclose(fp);
  500.             return 1;
  501.         }
  502.     }
  503.     fclose(fp);
  504.     return 0;
  505. }
  506.  
  507. static int
  508. lockit(m)
  509. struct mbx *m;
  510. {
  511.     int c, cnt = 0;
  512.  
  513.     while(mlock(Mailspool,m->area)) {
  514.         pause(1000L);    /* Wait one second */
  515.         if(++cnt == 10) {
  516.             cnt = 0;
  517.             c = tkeywait("Mail file is busy, Abort or Retry ? ",1);
  518.             if (c == 'A' || c == 'a' || c == EOF) {
  519.                 mfclose(m);
  520.                 return 1;
  521.             }
  522.         }
  523.     }
  524.     return 0;
  525. }
  526.  
  527. /* read the next message or the current one if new */
  528. int
  529. doreadnext(argc,argv,p)
  530. int argc;
  531. char *argv[];
  532. void *p;
  533. {
  534.     struct mbx *m;
  535.     char buf[10], *newargv[2];
  536.     m = (struct mbx *) p;
  537.     if (m->mfile == NULLFILE)
  538.         return 0;
  539.     if ((m->mbox[m->current].status & BM_READ) != 0) {
  540.         if (m->current == 1 && m->anyread == 0)
  541.             ;
  542.         else if (m->current < m->nmsgs) {
  543.             m->current++;
  544.         } else {
  545.             tprintf("Last message\n");
  546.             return 0;
  547.         }
  548.     }
  549.     sprintf(buf,"%d",m->current);
  550.     newargv[0] = "read";
  551.     newargv[1] = buf;
  552.     m->anyread = 1;
  553.     return doreadmsg(2,newargv,p);
  554. }
  555.  
  556. /*  display message on the crt given msg number */
  557. int
  558. doreadmsg(argc,argv,p)
  559. int argc;
  560. char *argv[];
  561. void *p;
  562. {
  563.     struct mbx *m;
  564.     register int c, col, lin;
  565.     char    buf[MAXCOL+2], *cp, *cp2;
  566.     int    msg, cnt, i, usemore, verbose, mbxheader, pathcol;
  567.     int    header, lastheader;
  568.     long     size;
  569.  
  570.     m = (struct mbx *) p;
  571.     if (m->mfile == NULLFILE) {
  572.         tprintf(Nomail);
  573.         return 0;
  574.     }
  575.     if(m->type == TELNET || m->type == TIP)
  576.         usemore = 1;    /* Display More prompt */
  577.     else
  578.         usemore = 0;
  579.     lin = MAXLIN-1;
  580.     for(i = 1; i < argc; ++i) {
  581.         msg = atoi(argv[i]);
  582.         if( msg < 1 || msg > m->nmsgs) {
  583.             tprintf(Badmsg,msg);
  584.             return 0;
  585.         }
  586.         fseek(m->mfile,m->mbox[msg].start,0);
  587.         size = m->mbox[msg].size;
  588.         m->current = msg;
  589.         header = NOHEADER;
  590.         mbxheader = 0;
  591.         if(*argv[0] == 'v')
  592.             verbose = 1;    /* display all header lines */
  593.         else
  594.             verbose = 0;
  595.  
  596.         tprintf("Message #%d %s\n", msg,
  597.             m->mbox[msg].status & BM_DELETE ? "[Deleted]" : "");
  598.         if ((m->mbox[msg].status & BM_READ) == 0) {
  599.             m->mbox[msg].status |= BM_READ;
  600.             m->change = 1;
  601.             m->newmsgs--;
  602.         }
  603.         --lin;
  604.         col = 0;
  605.         while (!feof(m->mfile) && size > 0) {
  606.             for (col = 0;  col < MAXCOL;) {
  607.                 c = getc(m->mfile);
  608.                 size--;
  609.                 if (feof(m->mfile) || size == 0) /* end this line */
  610.                     break;
  611.                 if (c == '\t') {
  612.                     cnt = col + 8 - (col & 7);
  613.                     if (cnt >= MAXCOL) /* end this line */
  614.                         break;
  615.                     while (col < cnt)
  616.                         buf[col++] = ' ';
  617.                 } else {
  618.                     if (c == '\n')
  619.                         break;
  620.                     buf[col++] = c;
  621.                 }
  622.             }
  623.             if(col < MAXCOL)
  624.                 buf[col++] = '\n';
  625.             buf[col] = '\0';
  626.             if(mbxheader > 0) {
  627.                  /* Digest R: lines and display as a Path: line */
  628.                  if(strncmp(buf,"R:",2) != 0 ||
  629.                 (cp = strchr(buf,'@')) == NULLCHAR) {
  630.                   tputc('\n');
  631.                   mbxheader = -1; /* don't get here again */
  632.                   verbose = 1;
  633.                  }
  634.                  else {
  635.                   if(*(++cp) == ':')
  636.                        ++cp;
  637.                   for(cp2 = cp; isalnum(*cp2); ++cp2)  ;
  638.                   *cp2 = '\0';
  639.                   if(mbxheader++ == 1) {
  640.                        tputs("Path: ");
  641.                        pathcol = 5;
  642.                        --lin;
  643.                   }
  644.                   else {
  645.                        tputc('!');
  646.                        if(++pathcol + strlen(cp) > MAXCOL-2){
  647.                         tputs("\n      ");
  648.                         pathcol = 5;
  649.                         --lin;
  650.                        }
  651.                   }
  652.                   tputs(cp);
  653.                   pathcol += strlen(cp);
  654.                  }
  655.             }
  656.             if(col == 1 && !verbose && !mbxheader)
  657.                  /* last header line reached */
  658.                  mbxheader = 1;
  659.             if(verbose)
  660.                 tputs(buf);
  661.             if(!verbose && !mbxheader){
  662.                  lastheader = header;
  663.                  if(!isspace(*buf))
  664.                   header = htype(buf);
  665.                  else
  666.                   header = lastheader;
  667.                 switch(header) {
  668.                 case TO:
  669.                 case CC:
  670.                 case FROM:
  671.                 case DATE:
  672.                 case SUBJECT:
  673.                 case APPARTO:
  674.                 case ORGANIZATION:
  675.                     tputs(buf);
  676.                     break;
  677.                 default:
  678.                     ++lin;
  679.                 }
  680.             }
  681.             col = 0;
  682.             if(usemore && --lin == 0){
  683.                 c = tkeywait("--More--",0);
  684.                 lin = MAXLIN-1;
  685.                 if(c == -1 || c == 'q' || c == 'Q')
  686.                     break;
  687.                 if(c == '\n' || c == '\r')
  688.                     lin = 1;
  689.             }
  690.         }
  691.     }
  692.     return 0;
  693. }
  694.  
  695. /* Set up m->to when replying to a message. The subject is returned in
  696.  * m->line.
  697.  */
  698. int
  699. mbx_reply(argc,argv,m,cclist,rhdr)
  700. int argc;
  701. char *argv[];
  702. struct mbx *m;
  703. struct list **cclist;    /* Pointer to buffer for pointers to cc recipients */
  704. char **rhdr;        /* Pointer to buffer for extra reply headers */
  705. {
  706.     char subject[MBXLINE], *msgid = NULLCHAR, *date = NULLCHAR;
  707.     char *cp;
  708.     int msg, lastheader, header = NOHEADER;
  709.     long size;
  710.  
  711.     /* Free anything that might be allocated
  712.      * since the last call to mbx_to() or mbx_reply()
  713.      */
  714.     free(m->to);
  715.     m->to = NULLCHAR;
  716.     free(m->tofrom);
  717.     m->tofrom = NULLCHAR;
  718.     free(m->tomsgid);
  719.     m->tomsgid = NULLCHAR;
  720.     free(m->origto);
  721.     m->origto = NULLCHAR;
  722.     subject[0] = '\0';
  723.  
  724.     if(argc == 1)
  725.          msg = m->current;
  726.     else
  727.          msg = atoi(argv[1]);
  728.     if (m->mfile == NULLFILE) {
  729.          if(m->sid & MBX_SID)
  730.           tputs("NO - ");
  731.         tputs(Nomail);
  732.         return 0;
  733.     }
  734.     if(msg < 1 || msg > m->nmsgs) {
  735.          if(m->sid & MBX_SID)
  736.           tputs("NO - ");
  737.          tputs(Badmsg);
  738.          return -1;
  739.     }
  740.     fseek(m->mfile,m->mbox[msg].start,0);
  741.     size = m->mbox[msg].size;
  742.     m->current = msg;
  743.     while(size > 0 && fgets(m->line,MBXLINE-1,m->mfile) != NULLCHAR) {
  744.          size -= strlen(m->line);
  745.          if(m->line[0] == '\n')    /* end of header */
  746.           break;
  747.          rip(m->line);
  748.          lastheader = header;
  749.          if(!isspace(m->line[0])) {
  750.           header = htype(m->line);
  751.           lastheader = NOHEADER;
  752.          }
  753.          switch(header) {
  754.          case SUBJECT:
  755.           if(strlen(m->line) > 11 && !strnicmp(&m->line[9],"Re:",3))
  756.                strcpy(subject,&m->line[9]);
  757.           else
  758.                sprintf(subject,"Re: %s",&m->line[9]);
  759.           break;
  760.          case FROM:
  761.           if(m->to == NULLCHAR && (cp = getaddress(m->line,0)) !=
  762.              NULLCHAR)
  763.                m->to = strdup(cp);
  764.           break;
  765.          case REPLYTO:
  766.           if((cp = getaddress(m->line,0)) != NULLCHAR) {
  767.                free(m->to);
  768.                m->to = strdup(cp);
  769.           }
  770.           break;
  771.          case MSGID:
  772.           free(msgid);
  773.           msgid = strdup(&m->line[12]);
  774.           break;
  775.          case DATE:
  776.           free(date);
  777.           date = strdup(&m->line[6]);
  778.           break;
  779.          case TO:
  780.          case CC:
  781.          case APPARTO:
  782.           /* Get addresses on To, Cc and Apparently-To lines */
  783.           cp = m->line;
  784.           m->line[strlen(cp)+1] = '\0';    /* add extra null at end */
  785.           for(;;) {
  786.                if((cp = getaddress(cp,lastheader == header ||
  787.                        cp != m->line)) == NULLCHAR)
  788.                 break;
  789.                addlist(cclist,cp,0);
  790.                /* skip to next address, if any */
  791.                cp += strlen(cp) + 1;
  792.           }
  793.           break;
  794.          }
  795.     }
  796.     if(msgid != NULLCHAR || date != NULLCHAR) {
  797.          *rhdr = mallocw(LINELEN);
  798.          sprintf(*rhdr,"In-Reply-To: your message ");
  799.          if(date != NULLCHAR) {
  800.           sprintf(m->line,"of %s.\n",date);
  801.           strcat(*rhdr,m->line);
  802.           if(msgid != NULLCHAR)
  803.                strcat(*rhdr,"             ");
  804.          }
  805.          if(msgid != NULLCHAR) {
  806.           sprintf(m->line,"%s\n",msgid);
  807.           strcat(*rhdr,m->line);
  808.          }
  809.          free(msgid);
  810.          free(date);
  811.     }
  812.     strcpy(m->line,subject);
  813.     return 0;
  814. }
  815.  
  816. void
  817. scanmail(m)         /* Get any new mail */
  818. struct mbx *m;
  819. {
  820.     FILE *nfile;
  821.     int ret, cnt;
  822.     char buf[256];
  823.     long diff;
  824.  
  825.     if ((diff = isnewmail(m)) == 0L)
  826.         return;
  827.     if(lockit(m))
  828.         return;
  829.     if(m->mfile == NULLFILE || diff < 0L) {
  830.         /* This is the first time scanmail is called, or the
  831.          * mail file size has decreased. In the latter case,
  832.          * any changes we did to this area will be lost, but this
  833.          * is not fatal.
  834.          */
  835.         initnotes(m);
  836.         rmlock(Mailspool,m->area);
  837.         return;
  838.     }
  839.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  840.     if ((nfile = fopen(buf,READ_TEXT)) == NULLFILE)
  841.         tprintf(Noaccess,buf);
  842.     else {
  843.         /* rewind tempfile */
  844.         fseek(m->mfile,0L,0);
  845.         cnt = m->nmsgs;
  846.         /* Reread all messages since size they may have changed
  847.          * in size after a X-Forwarded-To line was added.
  848.          */
  849.         m->nmsgs = 0;
  850.         ret = readnotes(m,nfile,1);   /* get the mail */
  851.         m->newmsgs += m->nmsgs - cnt;
  852.         m->mboxsize = ftell(nfile);
  853.         if(!stricmp(m->name,m->area))
  854.             m->mysize = m->mboxsize;
  855.         (void) fclose(nfile);
  856.         if (ret != 0)
  857.             tprintf("Error updating mail file\n");
  858.     }
  859.     rmlock(Mailspool,m->area);
  860. }
  861.  
  862. /* Check the current mailbox to see if new mail has arrived.
  863.  * Returns the difference in size.
  864.  */
  865. static long
  866. isnewmail(m)
  867. struct mbx *m;
  868. {
  869.     char buf[256];
  870.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  871.     return fsize(buf) - m->mboxsize;
  872. }
  873.  
  874. /* Check if the private mail area has changed */
  875. long
  876. isnewprivmail(m)
  877. struct mbx *m;
  878. {
  879.     long cnt;
  880.     char buf[256];
  881.     sprintf(buf,"%s/%s.txt",Mailspool,m->name);
  882.     cnt = m->mysize;
  883.     m->mysize = fsize(buf);
  884.     return m->mysize - cnt; /* != 0 not more than once */
  885. }
  886.  
  887. char *Hdrs[] = {
  888.     "Approved: ",
  889.     "From: ",
  890.     "To: ",
  891.     "Date: ",
  892.     "Message-Id: ",
  893.     "Subject: ",
  894.     "Received: ",
  895.     "Sender: ",
  896.     "Reply-To: ",
  897.     "Status: ",
  898.     "X-BBS-Msg-Type: ",
  899.     "X-Forwarded-To: ",
  900.     "Cc: ",
  901.     "Return-Receipt-To: ",
  902.     "Apparently-To: ",
  903.     "Errors-To: ",
  904.     "Organization: ",
  905.     NULLCHAR
  906. };
  907.  
  908. /* return the header type */
  909. int
  910. htype(s)
  911. char *s;
  912. {
  913.     register char *p;
  914.     register int i;
  915.  
  916.     p = s;
  917.     /* check to see if there is a ':' before and white space */
  918.     while (*p != '\0' && *p != ' ' && *p != ':')
  919.         p++;
  920.     if (*p != ':')
  921.         return NOHEADER;
  922.  
  923.     for (i = 0; Hdrs[i] != NULLCHAR; i++) {
  924.         if (strnicmp(Hdrs[i],s,strlen(Hdrs[i])) == 0)
  925.             return i;
  926.     }
  927.     return UNKNOWN;
  928. }
  929.  
  930. /* This function returns the length of a file. The proper thing would be
  931.  * to use stat(), but it fails when using DesqView together with Turbo-C
  932.  * code.
  933.  */
  934. static long
  935. fsize(name)
  936. char *name;
  937. {
  938.     long cnt;
  939.     FILE *fp;
  940.     if((fp = fopen(name,READ_TEXT)) == NULLFILE)
  941.         return -1L;
  942.     fseek(fp,0L,2);
  943.     cnt = ftell(fp);
  944.     fclose(fp);
  945.     return cnt;
  946. }
  947.  
  948. /* close the temporary mail file */
  949. static void
  950. mfclose(m)
  951. struct mbx *m;
  952. {
  953.     if(m->mfile != NULLFILE)
  954.         fclose(m->mfile);
  955.     m->mfile = NULLFILE;
  956. #ifdef SETVBUF
  957.     free(stdoutbuf);
  958.     stdoutbuf = NULLCHAR;
  959. #endif
  960. }
  961.  
  962. /* Parse a string in the "Text: <user@host>" or "Text: user@host (Text)"
  963.  * format for the address user@host.
  964.  */
  965. char *
  966. getaddress(string,cont)
  967. char *string;
  968. int cont;        /* true if string is a continued header line */
  969. {
  970.     char *cp, *ap = NULLCHAR;
  971.     int par = 0;
  972.     if((cp = getname(string)) != NULLCHAR) /* Look for <> style address */
  973.          return cp;
  974.     cp = string;
  975.     if(!cont)
  976.          if((cp = strchr(string,':')) == NULLCHAR)    /* Skip the token */
  977.           return NULLCHAR;
  978.          else
  979.           ++cp;
  980.     for(; *cp != '\0'; ++cp) {
  981.          if(par && *cp == ')') {
  982.           --par;
  983.           continue;
  984.          }
  985.          if(*cp == '(')        /* Ignore text within parenthesis */
  986.           ++par;
  987.          if(par)
  988.           continue;
  989.          if(*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == ',') {
  990.           if(ap != NULLCHAR)
  991.                break;
  992.           continue;
  993.          }
  994.          if(ap == NULLCHAR)
  995.           ap = cp;
  996.     }
  997.     *cp = '\0';
  998.     return ap;
  999. }
  1000.  
  1001. /* Print prompt and read one character, telnet version */
  1002. static int
  1003. tkeywait(prompt,flush)
  1004. char *prompt;    /* Optional prompt */
  1005. int flush;    /* Flush queued input? */
  1006. {
  1007.     int c, i;
  1008.  
  1009.     if(flush && socklen(Curproc->input,0) != 0)
  1010.         recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0); /* flush */
  1011.     if(prompt == NULLCHAR)
  1012.         prompt = "Hit enter to continue"; 
  1013.     tprintf("%s%c%c%c",prompt,IAC,WILL,TN_ECHO);
  1014.     usflush(Curproc->output);
  1015.  
  1016.     /* discard the response */
  1017.     while((c = rrecvchar(Curproc->input)) == IAC){
  1018.         c = rrecvchar(Curproc->input);
  1019.         if(c > 250 && c < 255)
  1020.             rrecvchar(Curproc->input);
  1021.     }
  1022.     /* Get rid of the prompt */
  1023.     for(i=strlen(prompt);i != 0;i--)
  1024.         tputc('\b');
  1025.     for(i=strlen(prompt);i != 0;i--)
  1026.         tputc(' ');
  1027.     for(i=strlen(prompt);i != 0;i--)
  1028.         tputc('\b');
  1029.     tprintf("%c%c%c",IAC,WONT,TN_ECHO);
  1030.     usflush(Curproc->output);
  1031.     return c;
  1032. }
  1033.