home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / BMUTIL.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  43KB  |  1,527 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.  *  Userlogging, 'RM' and 'KM' implementation,
  14.  *  more-prompts for all types
  15.  *  920307 and later, by Johan. K. Reinalda, WG7J/PA3DIS
  16.  *  Mail indexing by Johan. K. Reinalda, WG7J, June/July 1993
  17.  */
  18. #ifdef MSDOS
  19. #include <io.h>
  20. #endif
  21. #include <fcntl.h>
  22. #include <sys\stat.h>
  23. #include <ctype.h>
  24. #include <time.h>
  25. #include <conio.h>
  26. #ifdef MSDOS
  27. #include <dir.h>
  28. #include <dos.h>
  29. #endif
  30. #include "global.h"
  31. #include "ftpserv.h"
  32. #include "smtp.h"
  33. #include "proc.h"
  34. #include "usock.h"
  35. #include "socket.h"
  36. #include "telnet.h"
  37. #include "timer.h"
  38. #include "session.h"
  39. #include "files.h"
  40. #include "mailbox.h"
  41. #include "cmdparse.h"
  42. #include "bm.h"
  43. #include "mailutil.h"
  44. #include "dirutil.h"
  45. #include "index.h"
  46.   
  47. #define     SETVBUF
  48. #if defined(UNIX) || defined(MICROSOFT)
  49. #include    <sys/types.h>
  50. #endif
  51. /*
  52. #if defined(UNIX) || defined(MICROSOFT) || defined(__TURBOC__)
  53. #include    <sys/stat.h>
  54. #endif
  55. #ifdef AZTEC
  56. #include <stat.h>
  57. #endif
  58. */
  59. #include <fcntl.h>
  60. #include "bm.h"
  61. #include "mailbox.h"
  62.   
  63. #ifdef SETVBUF
  64. #define     MYBUF   1024
  65. #endif
  66.   
  67. #ifdef MAILCMDS
  68.   
  69. char Badmsg[] = "Invalid Message number %d\n";
  70. char Nomail[] = "No messages\n";
  71. static char Noaccess[] = "Unable to access %s\n";
  72. static char OpenError[] = "user %s: error %d opening %s\n";
  73.   
  74. static int readnotes __ARGS((struct mbx *m,int ifile));
  75. static long isnewmail __ARGS((struct mbx *m));
  76. static int initnotes __ARGS((struct mbx *m));
  77. static int lockit __ARGS((struct mbx *m));
  78. static int unlockit __ARGS((struct mbx *m));
  79.   
  80. static int
  81. initnotes(m)
  82. struct mbx *m;
  83. {
  84.     int idx;
  85.     char *area;
  86.     int ret;
  87.     char buf[FILE_PATH_SIZE];
  88.   
  89.     /* Reset all mailbox status variables */
  90.     m->change = m->anyread = m->nmsgs = m->current =  m->newmsgs = 0;
  91.     m->mboxsize = 0L;
  92.   
  93.     area = strdup(m->area);
  94.     dirformat(area);
  95.     sprintf(buf,"%s/%s.ind",Mailspool,area);
  96.     free(area);
  97.   
  98.     if ((idx = open(buf,READBINARY)) == -1)
  99.         /* No mail ! */
  100.         return 0;
  101.     ret = readnotes(m,idx);
  102.     close(idx);
  103.     if (ret != 0)
  104.         return -1;
  105.   
  106.     return 0;
  107. }
  108.   
  109. /* readnotes assumes that idx is pointing to the index file */
  110. static int
  111. readnotes(m,idx)
  112. struct mbx *m;
  113. int idx;
  114. {
  115.     char buf[LINELEN];
  116.     struct let *oldmbox;
  117.     int len,i;
  118.     long pos;
  119.     char status;
  120.     struct let *cmsg;
  121.     struct indexhdr hdr;
  122.     struct mailindex ind;
  123.   
  124.     /* Get the number of messages in the mailbox */
  125.     lseek(idx,0L,SEEK_SET);
  126.     if (read_header(idx,&hdr) == -1) return -1;
  127.   
  128.     if(m->mbox)
  129.         oldmbox = m->mbox;
  130.     else
  131.         oldmbox = NULL;
  132.   
  133.     /* Get the new number of messages */
  134.     m->mbox = (struct let *)callocw(hdr.msgs+1,sizeof(struct let));
  135.   
  136.     if(oldmbox) {    /* Copy the status of the messages back */
  137.         if (m->nmsgs <= hdr.msgs)      /* unless mbox shrank */
  138.             memcpy(m->mbox,oldmbox,(m->nmsgs+1)*sizeof(struct let));
  139.         else m->current=0;
  140.         free(oldmbox);
  141.     }
  142.     else m->current=0;
  143.   
  144.     cmsg = m->mbox;
  145.     pos = 0;
  146.     m->nmsgs = 0;
  147.     m->newmsgs = 0;
  148.     memset(&ind,0,sizeof(ind));
  149.     default_index(m->area,&ind);
  150.   
  151.     /* Check for unread(ie. new) messages */
  152.     for(i=1;i<=hdr.msgs;i++) {
  153.         pwait(NULL);
  154.         cmsg++;
  155.         m->nmsgs++;
  156.         if (read_index(idx,&ind) == -1) {    /* should never happen */
  157.             m->nmsgs--;
  158.             log(-1,"readnotes: index for %s is damaged (#%d)", m->area, i);
  159.             break;
  160.         }
  161. #ifdef USERLOG
  162.         cmsg->msgid = ind.msgid;
  163. #endif
  164.         cmsg->size = ind.size;
  165.         cmsg->start = pos;
  166.         pos += cmsg->size;
  167.         cmsg->status |= ind.status;
  168. #ifdef USERLOG
  169.         if(m->areatype == AREA)
  170.             if(cmsg->msgid <= m->lastread)
  171.                 cmsg->status |= BM_READ;
  172. #endif
  173.         if(!(cmsg->status & BM_READ)) {
  174.             m->newmsgs++;
  175.             if(m->current == 0)
  176.                 m->current = m->nmsgs; /* first new message */
  177.         }
  178.         default_index(m->area,&ind);
  179.     }
  180.      /* start at one if no new messages */
  181.     if(m->current == 0)
  182.         m->current++;
  183.     m->mboxsize = pos;
  184. #ifdef JPDEBUG
  185.     if (pos < 0L || pos > 4000000L)
  186.         log(-1,"readnotes: suspicious len %ld for %s", pos, m->area);
  187. #endif
  188.     if(m->areatype == PRIVATE)  /* our private mail area */
  189.         m->mycnt = m->nmsgs;
  190.  
  191.     if (m->nmsgs == hdr.msgs) return 0;
  192.     else return -1;
  193. }
  194.   
  195. static char ListHeader[] = "St.  #  TO            FROM     DATE   SIZE SUBJECT\n";
  196.   
  197. /* list headers of a notesfile a message */
  198. /* Rearranged display - WG7J */
  199. int
  200. dolistnotes(argc,argv,p)
  201. int argc;
  202. char *argv[];
  203. void *p;
  204. {
  205.     struct mbx *m;
  206.     struct let *cmsg;
  207.     char *cp, *s, *datestr;
  208.     int idx;
  209.     char *area;
  210.     char type;
  211.     char status;
  212.     int start, stop;
  213.     long pos;
  214.     int i,len,header,list,listed;
  215. #ifdef USERLOG
  216.     long msgid;
  217. #endif
  218.     long size;
  219.     int c,usemore=0,lin;
  220.     struct indexhdr hdr;
  221.     struct mailindex ind;
  222.     char buf[FILE_PATH_SIZE];
  223.   
  224.     m = (struct mbx *) p;
  225.   
  226.     /* If this user doesn't have read-permissions,
  227.      * we're not going to let him list anything - WG7J
  228.      */
  229.     if(m->privs & NO_READCMD) {
  230.         tputs(Noperm);
  231.         return 0;
  232.     }
  233.   
  234.     if(m->nmsgs == 0) {
  235.         tputs(Nomail);
  236.         return 0;
  237.     }
  238.   
  239.     if((m->stype == '>' || m->stype == '<' || m->stype ==  'S') && argc == 1) {
  240.         tputs("Search criterium needed!\n");
  241.         return 0;
  242.     }
  243.   
  244.     if((lin=m->morerows) != 0)
  245.         usemore = 1;    /* Display More prompt */
  246.   
  247.     area = strdup(m->area);
  248.     dirformat(area);
  249.     sprintf(buf,"%s/%s.ind",Mailspool,area);
  250.     free(area);
  251.     if((idx = open(buf,READBINARY)) == -1) {
  252.         closenotes(m);
  253.         tprintf("Can not read index file %s\n",buf);
  254.         return 0;
  255.     }
  256.   
  257.     tprintf("Mail area: %s\n"
  258.     "%d message%s -  %d new\n\n",
  259.     m->area,m->nmsgs,m->nmsgs == 1 ? " " : "s ", m->newmsgs);
  260.   
  261.     stop = m->nmsgs;
  262. #ifdef USERLOG
  263.     if(m->areatype != PRIVATE && m->stype != 'A')
  264.         start = stop - m->newmsgs + 1;
  265.     else
  266. #endif
  267.         if((argc == 1) & (m->stype == 'L'))
  268.             start = stop;
  269.         else
  270.             start = 1;
  271.     if(argc > 1) {
  272.         if(m->stype == 'L')                     /* LL (List Last) command */
  273.             start = stop - atoi(argv[1]) + 1;
  274.         else
  275.             start = atoi(argv[1]);
  276.         if(argc > 2)
  277.             stop = atoi(argv[2]);
  278.   
  279.         /* Check the boundaries */
  280.         if(stop > m->nmsgs)
  281.             stop = m->nmsgs;
  282.         if(start < 1)
  283.             start = 1;
  284.     }
  285.     if(start > stop) {
  286.         if((m->stype == ' ') || (m->stype == 'M'))
  287.             tputs("None to list.\n");
  288.         else
  289.             tputs("Invalid range.\n");
  290.         close(idx);
  291.         return 0;
  292.     }
  293.   
  294.     cmsg = m->mbox;
  295.     header = 0;
  296.     listed = 0;
  297.   
  298.     memset(&ind,0,sizeof(ind));
  299.     default_index(m->area,&ind);
  300.   
  301.     /* Read the index file header */
  302.     if (read_header(idx,&hdr) == 0)
  303.      for(i=1;i<=hdr.msgs;i++) {
  304.         pwait(NULL);
  305.         if (read_index(idx,&ind) == -1) goto irerr;
  306.         cmsg++;
  307.         if(start <= i && i <= stop) {
  308.             list = 1;
  309.             /* Now see if we should list this one */
  310.             if(m->stype == ' ') {
  311.                 if(argc > 1)
  312.                     list = 1;
  313.                 else if(cmsg->status & BM_READ)
  314.                     list = 0;
  315.             } else if(m->stype == '>') {
  316.                 if(strstr(ind.to,argv[1]) == NULL)
  317.                     list  = 0;
  318.             } else if( m->stype == '<' ||
  319.             (m->stype == 'M' && m->areatype != PRIVATE)) {
  320.                 if(strstr(ind.from,argv[1]) == NULL)
  321.                     list  = 0;
  322.             } else if(m->stype == 'S') {
  323.                 cp = strlwr(strdup(ind.subject));   /* case-independent scan */
  324.                 if(strstr(cp,argv[1]) == NULL)
  325.                     list  = 0;
  326.                 free(cp);
  327.             } else if(m->stype == 'B' || m->stype == 'T')
  328.                 if(m->stype != ind.type)
  329.                     list  = 0;
  330.             if(list) {
  331. #ifdef USERLOG
  332.                 /* Check the ID number of this message and
  333.                  * adjust new lastread count, if needed - WG7J
  334.                  */
  335.                 if(cmsg->msgid > m->lastread)
  336.                     m->newlastread = cmsg->msgid;
  337. #endif
  338.                 if(!header) {
  339.                     tputs(ListHeader);
  340.                     lin--;
  341.                     header = 1;
  342.                 }
  343.                 listed = 1;
  344.   
  345.                 /* Format date */
  346.                 datestr = ctime(&ind.date);
  347.                 datestr[10] = '\0';
  348.   
  349.                 /* Format from */
  350.                 if((cp = strchr(ind.from,'@')) != NULL)
  351.                     *cp = '\0';
  352.                 if((cp = strchr(ind.from,'%')) != NULL)
  353.                     *cp = '\0';
  354.   
  355.                 tputc((i == m->current) ? '>' : ' ');
  356.                 tputc(cmsg->status & BM_DELETE ? 'D' : ' ');
  357.                 tputc(cmsg->status & BM_HOLD ? 'H':(cmsg->status & BM_READ ? 'Y' : 'N'));
  358.                 tprintf(" %3d %-13.13s %-8.8s %-6.6s %4ld %-35.35s\n",
  359.                 i,ind.to,ind.from,&datestr[4],ind.size,ind.subject);
  360.   
  361.                 lin--;
  362.   
  363.                 /* More prompting added - WG7J */
  364.                 if(usemore && lin <= 0){
  365.                     if(charmode_ok(m))
  366.                         c = tkeywait(TelnetMorePrompt,0);
  367.                     else  /* For AX.25 and NET/ROM connects - WG7J */
  368.                         c = mykeywait(BbsMorePrompt,m);
  369.                     if(c == -1 || c == 'q' || c == 'Q')
  370.                         break;
  371.                     if(c == '\n' || c == '\r')
  372.                         lin = 1;
  373.                     else
  374.                         lin = m->morerows-1;
  375.   
  376.                     header = 0;
  377.                 }
  378.             }
  379.         }
  380.         /* Done with this index, clear it */
  381.         default_index(m->area,&ind);
  382.     }
  383.     else
  384. irerr:
  385.         tprintf("Error reading index of %s\n", m->area);
  386.  
  387.     close(idx);
  388.     if(!listed)
  389.         tputs(Nomail);
  390.   
  391.     return 0;
  392. }
  393.   
  394. /*  save msg on stream - if noheader set don't output the header */
  395. int
  396. msgtofile(m)
  397. struct mbx *m;
  398. {
  399.     FILE *fp;
  400.     char *area;
  401.     char buf[LINELEN];
  402.   
  403.     if (m->nmsgs == 0) {
  404.         tputs(Nomail);
  405.         return -1;
  406.     }
  407.   
  408.     /* Open the mailbox and go to start of message */
  409.     area = strdup(m->area);
  410.     dirformat(area);
  411.     sprintf(buf,"%s/%s.txt",Mailspool,area);
  412.     if ((fp=fopen(buf,READ_TEXT)) == NULLFILE) {
  413.         free(area);
  414.         return -1;
  415.     }
  416.     free(area);
  417.     fseek(fp,m->mbox[m->current].start,0);
  418.   
  419.     /* skip header */
  420.     while(fgets(buf,sizeof(buf),fp) != NULLCHAR)
  421.         if (*buf == '\n')
  422.             break;
  423.   
  424.     /* Copy the body */
  425.     while (fgets(buf,sizeof(buf),fp) != NULLCHAR) {
  426.         if(!strncmp(buf,"From ",5))
  427.             break;
  428.         fputs(buf,m->tfile);
  429.         if (ferror(m->tfile)) {
  430.             tputs("Error writing mail file\n");
  431.             fclose(fp);
  432.             return -1;
  433.         }
  434.     }
  435.     fclose(fp);
  436.     return 0;
  437. }
  438.   
  439. /* dodelmsg - delete message in current notesfile */
  440. /* Modified to allow the 'KM' command. 920307 -  WG7J */
  441. int
  442. dodelmsg(argc,argv,p)
  443. int argc;
  444. char *argv[];
  445. void *p;
  446. {
  447.     struct mbx *m;
  448.     int msg,i;
  449.     char *myargv[NARG];
  450.     int myargc;
  451.     int maxmsg;
  452.     struct let *cmsg;
  453.     char *tmpbuf;
  454.     int start;
  455.     int end;
  456.   
  457.     m = (struct mbx *) p;
  458.   
  459.     if (m->nmsgs == 0) {
  460.         tputs(Nomail);
  461.         return 0;
  462.     }
  463.     /* If this user doesn't have read-permissions,
  464.      * we're not going to let him kill anything;
  465.      * allow anyone to kill messages in areas
  466.      * who's names start with 'nts' - WG7J
  467.      */
  468.     /* Check if we have permission to delete others mail */
  469.     if( (m->privs & NO_SENDCMD) ||
  470.         (m->privs & NO_READCMD) ||
  471.         ( !(m->privs & FTP_WRITE) &&
  472.         !(m->areatype == PRIVATE) &&
  473.     strnicmp(m->area,"nts",3)) ){
  474.         tputs(Noperm);
  475.         return 0;
  476.     }
  477.     /* If this is KA, Kill All messages */
  478.     if(m->stype == 'A') {
  479.         if(m->nmsgs) {
  480.             for(i=1,cmsg=&m->mbox[1];i<=m->nmsgs;i++,cmsg++)
  481.                 cmsg->status |= BM_DELETE;
  482.             m->change = 1;
  483.             tprintf("%d message%s killed!\n",m->nmsgs,(m->nmsgs==1) ? "" : "s");
  484.         }
  485.         return 0;
  486.     }
  487.     /* If this is the KM command, setup myargv[]
  488.      * to contain up to NARG message numbers - WG7J
  489.      */
  490.     if(m->stype == 'M') {
  491.         /* scan all messsages to find unread ones */
  492.         cmsg = &m->mbox[1];
  493.         myargc = 1;
  494.         i = 0;
  495.         while(myargc < NARG && i < m->nmsgs) {
  496.             if(cmsg->status & BM_READ) { /*found a read msg!*/
  497.                 tmpbuf = mallocw(17); /*allocate space for the new argument*/
  498.                 myargv[myargc++] = itoa(i+1,tmpbuf,10);
  499.             }
  500.             i++;
  501.             cmsg++;
  502.         }
  503.         if(myargc == 1) {
  504.             tputs("Nothing to kill\n");
  505.             return 0;
  506.         }
  507.         argc = myargc;
  508.     } else {
  509.         if(argc == 1) {
  510.             msg = m->current;
  511.             if(m->stype == 'U')
  512.                 m->mbox[msg].status &= ~BM_DELETE;
  513.             else {
  514.                 m->mbox[msg].status |= BM_DELETE;
  515.                 m->change = 1;
  516.             }
  517.             tprintf("Msg %d %sKilled.\n", msg,(m->stype=='U') ? "Un-" : "");
  518.             return 0;
  519.         }
  520.         /*simply point to the old arguments*/
  521.         for(i=1;i<argc;i++)
  522.             myargv[i] = argv[i];
  523.     }
  524.     /* See if x - y format was used and use a for i = x to y loop */
  525.     if(myargv[2][0] == '-') {
  526.         start = atoi(myargv[1]);
  527.         end   = atoi(myargv[3]);
  528.         if(start < 0 || start > m->nmsgs || end < 0 || end > m->nmsgs ) {
  529.             tprintf(Badmsg,start);
  530.             start = end+1;
  531.         }
  532.         for(i=start;i<=end;i++) {
  533.             msg = i;
  534.             if(m->stype == 'U')
  535.                 m->mbox[msg].status &= ~BM_DELETE;
  536.             else {
  537.                 m->mbox[msg].status |= BM_DELETE;
  538.                 m->change = 1;
  539.             }
  540.             tprintf("Msg %d %sKilled.\n", msg,(m->stype=='U') ? "Un-" : "");
  541.         } /* endfor */
  542.     } else for(i = 1; i < argc; ++i) {
  543.             tmpbuf = strchr(myargv[i],'-'); /* N5KNX: allow from-to msg specification */
  544.             msg = atoi(myargv[i]);
  545.             if (tmpbuf == NULLCHAR)
  546.                 maxmsg = msg;
  547.             else
  548.                 maxmsg = atoi(++tmpbuf);
  549.             if (maxmsg < msg) {
  550.                 tprintf(Badmsg,maxmsg);
  551.                 continue;
  552.             }
  553.             for (; msg <= maxmsg; msg++) {
  554.                 if(msg < 0 || msg > m->nmsgs) {
  555.                     tprintf(Badmsg,msg);
  556.                     continue;
  557.                 }
  558.                 if(m->stype == 'U')
  559.                     m->mbox[msg].status &= ~BM_DELETE;
  560.                 else {
  561.                     m->mbox[msg].status |= BM_DELETE;
  562.                     m->change = 1;
  563.                 }
  564.                 tprintf("Msg %d %sKilled.\n", msg,(m->stype=='U') ? "Un-" : "");
  565.             }
  566.            }
  567.     /* If this was 'KM'
  568.      * free the memory allocated for myargv[] - WG7J
  569.      */
  570.     if(m->stype == 'M') {
  571.         for(i=1;i<argc;i++)
  572.             free(myargv[i]);
  573.     }
  574.     return 0;
  575. }
  576.   
  577. void no_area(struct mbx *m) {
  578.   
  579.     m->area[0] = '\0';
  580.     m->nmsgs = m->current = m->newmsgs = 0;
  581.     m->mboxsize = 0;
  582.     free(m->mbox);
  583.     m->mbox = NULL;
  584. }
  585.   
  586. /* close the temp file while copying mail back to the mailbox */
  587. int
  588. closenotes(m)
  589. struct mbx *m;
  590. {
  591.     struct let *cmsg;
  592.     char *area;
  593.     int i,msgs,keep,error;
  594.     long start,pos,size;
  595.     int idx,idxnew;
  596.     FILE *txt,*new;
  597.     char len[10],lens[7];
  598.     char buf[LINELEN];
  599.     char old[LINELEN];
  600.     struct fwdbbs *newbbs;
  601.     struct indexhdr hdr;
  602.     struct mailindex ind;
  603.   
  604.     if(m->nmsgs == 0)
  605.         return 0;
  606.   
  607.     if(lockit(m))
  608.         return -1;
  609.  
  610.     if(!m->change || (isnewmail(m) < 0L)) {
  611.         /* no changes were made,
  612.          * or some messages were deleted !
  613.          * In the latter we cannot continue !
  614.          */
  615. #ifdef DEBUG_HDR
  616.         if (m->change) log(m->user,"NOUPDATE for %s: msgs deleted in %s",m->name,m->area);
  617. #endif
  618.     unlockit(m);
  619.         no_area(m);
  620.         return 0;
  621.     }
  622.     scanmail(m);
  623.     area = strdup(m->area);
  624.     dirformat(area);
  625.     sprintf(buf,"%s/%s.txt",Mailspool,area);
  626.     if((txt = fopen(buf,READ_BINARY)) == NULLFILE) {
  627.         free(area);
  628.         log(m->user,OpenError,m->name,errno,buf);
  629.         unlockit(m);
  630.         no_area(m);
  631.         return -1;
  632.     }
  633.     sprintf(buf,"%s/%s.ind",Mailspool,area);
  634.     if((idx = open(buf,READBINARY)) == -1) {
  635.         free(area);
  636.         fclose(txt);
  637.         log(m->user,OpenError,m->name,errno,buf);
  638.         unlockit(m);
  639.         no_area(m);
  640.         return -1;
  641.     }
  642.     sprintf(buf,"%s/%s.new",Mailspool,area);
  643.     if((new = fopen(buf,WRITE_TEXT)) == NULLFILE) {
  644.         free(area);
  645.         fclose(txt);
  646.         close(idx);
  647.         log(m->user,OpenError,m->name,errno,buf);
  648.         unlockit(m);
  649.         no_area(m);
  650.         return -1;
  651.     }
  652.     sprintf(buf,"%s/%s.idn",Mailspool,area);
  653.     if((idxnew = open(buf,CREATEBINARY,CREATEMODE)) == -1) {
  654.         free(area);
  655.         fclose(txt);
  656.         close(idx);
  657.         fclose(new);
  658.         log(m->user,OpenError,m->name,errno,buf);
  659.         unlockit(m);
  660.         no_area(m);
  661.         return -1;
  662.     }
  663.   
  664.     msgs = error = 0;
  665.  
  666.     memset(&ind,0,sizeof(ind));
  667.     default_index(m->area,&ind);
  668.     if (read_header(idx,&hdr) == -1) {
  669.         error++;
  670. #ifdef DEBUG_HDR
  671.         log(-1,"read_header err %d for %s", errno, m->area);
  672. #endif
  673.         goto cleanup;
  674.     }
  675.   
  676.     /* write the header first to new index file */
  677.     default_header(&hdr);
  678.     if (write_header(idxnew,&hdr) == -1) {
  679.         error++;
  680. #ifdef DEBUG_HDR
  681.         log(-1,"write_header err %d for %s", errno, m->area);
  682. #endif
  683.         goto cleanup;
  684.     }
  685.   
  686.   
  687.     /* Copy messages and delete msgs, add status or fwd headers */
  688.     for(cmsg=&m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++) {
  689.         default_index("",&ind); /* Free memory from previous index */
  690.         /* Read the index for this message */
  691.         if(read_index(idx,&ind) == -1) {
  692.             puts("\n\007\007 Warning: Index files not in sync ! Run MAIL2IND asap!!\n");
  693. #ifdef MAILERROR
  694.             mail_error("Warning: Index files not in sync ! Run MAIL2IND asap!!\n");
  695. #endif
  696. #ifdef DEBUG_HDR
  697.             log(m->user,"NOUPDATE for %s: %s.ind out-of-sync",m->name,m->area);
  698. #endif
  699.             free(area);
  700.             close(idx);
  701.             fclose(txt);
  702.             fclose(new);
  703.             close(idxnew);
  704.             unlockit(m);
  705.             no_area(m);
  706.             return -1;
  707.         }
  708.         keep = 0;
  709.         if(!(cmsg->status & BM_DELETE)) {
  710.             /* Keep this message ! */
  711.             keep = 1;
  712.             msgs++;
  713.             start = ftell(new);
  714.             fseek(txt,cmsg->start,0);
  715.             /* Copy this one to the new file,
  716.              * start with the smtp header
  717.              * The received: line is first
  718.              */
  719.             while(bgets(buf,sizeof(buf),txt) != NULL) {
  720.                 pwait(NULL);
  721.                 if(*buf == '\0') {
  722.                     /* End of headers */
  723.                     if(cmsg->status & BM_FORWARDED) {
  724.                         fprintf(new,"%s%s\n",Hdrs[XFORWARD],m->name);
  725.                         newbbs = mallocw(sizeof(struct fwdbbs));
  726.                         strcpy(newbbs->call,m->name);
  727.                         newbbs->next = ind.bbslist;
  728.                         ind.bbslist = newbbs;
  729.                     }
  730.                     if(!(ind.status & BM_READ) && (cmsg->status & BM_READ) &&
  731.                     (m->areatype == PRIVATE)) {
  732.                         fprintf(new,"%sR\n",Hdrs[STATUS]);
  733.                         ind.status |= BM_READ;
  734.                     }
  735.                     fputc('\n',new);
  736.                     break;
  737.                 }
  738.                 fprintf(new,"%s\n",buf);
  739.             }
  740.             /* Now do the message body */
  741.             pos = ftell(new);
  742.             while(bgets(buf,sizeof(buf),txt) != NULL) {
  743.                 pwait(NULL);
  744.                 if(!strncmp(buf,"From ",5)) {
  745.                     /* End of message, write index */
  746.                     ind.size = pos-start;
  747.                     if (WriteIndex(idxnew,&ind)) error++;
  748.                     keep=0;  /* should be redundant, but... */
  749.                     break;
  750.                 }
  751.                 fprintf(new,"%s\n",buf);
  752.                 pos = ftell(new);
  753.             }
  754.         } /* If not message deleted */
  755.     } /* for all messages */
  756.     /* do we need to keep the last one ? */
  757.     if(keep) {
  758.         /* End of message, rewrite index line */
  759.         ind.size = pos-start;
  760.         if (WriteIndex(idxnew,&ind)) error++;
  761.     }
  762.     /* Free the last index */
  763.     default_index("",&ind);
  764.   
  765.     size = ftell(new);
  766.     /* If we have no errors, then delete the old mail and index files,
  767.      * and rename the new one.
  768.      */
  769.     if(ferror(new)) error++;
  770.  
  771. cleanup:  
  772.     fclose(txt);
  773.     close(idx);
  774.     fclose(new);
  775.     close(idxnew);
  776.   
  777.     if(!error) {
  778.         sprintf(buf,"%s/%s.txt",Mailspool,area);
  779.         sprintf(old,"%s/%s.new",Mailspool,area);
  780.         unlink(buf);
  781.         if(size)
  782.             rename(old,buf);
  783.         else
  784.             /* remove a zero length file */
  785.             unlink(old);
  786.         sprintf(buf,"%s/%s.ind",Mailspool,area);
  787.         sprintf(old,"%s/%s.idn",Mailspool,area);
  788.         unlink(buf);
  789.         if(size)
  790.             rename(old,buf);
  791.         else {
  792.             /* remove a zero length file */
  793.             unlink(old);
  794. #ifdef USERLOG
  795.             sprintf(buf,"%s/%s.inf",Mailspool,area);
  796.             unlink(buf);
  797. #endif
  798.         }
  799.     }
  800. #ifdef DEBUG_HDR
  801.     else
  802.         log(m->user,"NOUPDATE for %s: error writing new %s.txt",m->name,m->area);
  803. #endif
  804.     unlockit(m);
  805.     no_area(m);
  806.     free(area);
  807.     if(m->areatype == PRIVATE)
  808.         m->mycnt = msgs;    /* Update the size of our private mailbox */
  809.     return (error ? -1 : 0);
  810. }
  811.   
  812. static int
  813. unlockit(m)
  814. struct mbx *m;
  815. {
  816.     if(--m->lockcnt) return(0);
  817.     return(rmlock(Mailspool, m->area));
  818. }
  819.  
  820. static int
  821. lockit(m)
  822. struct mbx *m;
  823. {
  824.     int c, cnt = 0;
  825.     char *area;
  826.     char MailFileBusy[] = "Mail file is busy. Retry? (y/n)";
  827.  
  828.     if(m->lockcnt++) return(0);    /* already locked, just incr cntr */
  829.     area = strdup(m->area);
  830.     dirformat(area);
  831.     while(mlock(Mailspool,area)) {
  832.         pause(1000L);   /* Wait one second */
  833.         if(++cnt == 10) {
  834.             cnt = 0;
  835.             switch (m->state) {
  836.                 case MBX_REVFWD:
  837.                 case MBX_FORWARD:
  838. #ifdef DEBUG_HDR
  839.                 log(m->user,"NOUPDATE for %s: can't lock %s",m->name,m->area);
  840. #endif
  841.                 case MBX_TRYING:
  842.                     c='n';
  843.                     break;
  844.                 default:
  845.                     if(charmode_ok(m))
  846.                         c = tkeywait(MailFileBusy,1);
  847.                     else  /* For AX.25 and NET/ROM connects - WG7J */
  848.                         c = mykeywait(MailFileBusy,m);
  849.                     break;
  850.             }
  851.             if (c == -1 || c == 'n' || c == 'N') {
  852.                 m->nmsgs = 0;
  853.                 m->mboxsize = 0;
  854.                 free(area);
  855.                 m->lockcnt = 0;
  856.                 return 1;
  857.             }
  858.         }
  859.     }
  860.     free(area);
  861.     return 0;
  862. }
  863.   
  864. /* read the next message or the current one if new */
  865. int
  866. doreadnext(argc,argv,p)
  867. int argc;
  868. char *argv[];
  869. void *p;
  870. {
  871.     struct mbx *m;
  872.     char buf[10], *newargv[2];
  873.   
  874.     m = (struct mbx *) p;
  875.   
  876.     if(m->nmsgs == 0)   /* No mail ! */
  877.         return 0;
  878.   
  879.     if((m->mbox[m->current].status & BM_READ) != 0) {
  880.         if (m->current == 1 && m->anyread == 0)
  881.             ;
  882.         else if (m->current < m->nmsgs) {
  883.             m->current++;
  884.         } else {
  885.             tputs("Last message\n");
  886.             return 0;
  887.         }
  888.     }
  889.     sprintf(buf,"%d",m->current);
  890.     newargv[0] = "r";
  891.     newargv[1] = buf;
  892.     m->anyread = 1;
  893.     return doreadmsg(2,newargv,p);
  894. }
  895.   
  896. extern int MbRead;
  897.   
  898. /* display message on the crt given msg number */
  899. /* Modified to allow the 'RM' command, 920307 - WG7J */
  900. int
  901. doreadmsg(argc,argv,p)
  902. int argc;
  903. char *argv[];
  904. void *p;
  905. {
  906.     struct mbx *m;
  907.     int c, col, lin;
  908.     char *area, *cp, *cp2;
  909.     int msg, cnt, i, usemore=0, verbose;
  910.     int smtpheader, mbxheader, pathheader, print;
  911.     FILE *txt;
  912.     char *myargv[NARG];
  913.     int myargc;
  914.     int maxmsg;
  915.     struct let *cmsg;
  916.     char *tmpbuf;
  917.     char buf[LINELEN];
  918.   
  919.     m = (struct mbx *) p;
  920.   
  921.     /*Check for read-permissions - WG7J */
  922.     if(m->privs & NO_READCMD) {
  923.         tputs(Noperm);
  924.         return 0;
  925.     }
  926.     if (m->nmsgs == 0) {
  927.         tputs(Nomail);
  928.         return 0;
  929.     }
  930.     if((lin=m->morerows) != 0)
  931.         usemore = 1;    /* Display More prompt */
  932.   
  933.     /*If this is the RM or VM command, setup myargv[]
  934.      *to contain up to NARG message numbers - WG7J
  935.      */
  936.     if(m->stype == 'M') {
  937.         if(!m->newmsgs) {
  938.             tputs(Nomail);
  939.             return 0;
  940.         }
  941.         /* scan all messsages to find unread ones */
  942.         cmsg = &m->mbox[1];
  943.         myargc = 1;
  944.         i = 0;
  945.         while(myargc < NARG && i < m->nmsgs) {
  946.             if(!(cmsg->status & BM_READ)) { /*found an unread msg!*/
  947.                 tmpbuf = mallocw(17); /*allocate space for the new argument*/
  948.                 myargv[myargc++] = itoa(i+1,tmpbuf,10);
  949.             }
  950.             i++;
  951.             cmsg++;
  952.         }
  953.         argc = myargc;
  954.     } else {
  955.         /*simply point to the old arguments*/
  956.         for(i=1;i<argc;i++)
  957.             myargv[i] = argv[i];
  958.     }
  959.     if(argc == 1) {
  960.         tputs("Usage: Read/Verbose #\n");
  961.         return 0;
  962.     }
  963.     m->state = MBX_READ;
  964.   
  965.     /* Open the text file */
  966.     area = strdup(m->area);
  967.     dirformat(area);
  968.     sprintf(buf,"%s/%s.txt",Mailspool,area);
  969.     free(area);
  970.     if((txt=fopen(buf,READ_TEXT)) == NULLFILE) {
  971.         tprintf("Cannot open mail file %s\n",area);
  972.         return 0;
  973.     }
  974.   
  975.     if((*argv[0] == 'v') || (m->stype == 'H'))
  976.         verbose = 1;    /* display all header lines */
  977.     else
  978.         verbose = 0;
  979.   
  980.     for(i = 1; i < argc; ++i) {
  981.         tmpbuf = strchr(myargv[i],'-');   /* N5KNX: allow from-to msg specification */
  982.         msg = atoi(myargv[i]);
  983.         if (tmpbuf == NULLCHAR)
  984.             maxmsg = msg;
  985.         else
  986.             maxmsg = atoi(++tmpbuf);
  987.         if (maxmsg < msg) {
  988.             tprintf(Badmsg,maxmsg);
  989.             continue;
  990.         }
  991.         for (; msg <= maxmsg; msg++) {
  992.             if(msg < 1 || msg > m->nmsgs) {
  993.                 tprintf(Badmsg,msg);
  994.                 goto iamdone;
  995.             }
  996.             cmsg = &m->mbox[msg];
  997.             /* if the message is on hold, only show to sysops - WG7J */
  998.             if((cmsg->status & BM_HOLD) && !(m->privs & SYSOP_CMD)) {
  999.                 tprintf("Msg %d:",msg);
  1000.                 tputs(Noperm);
  1001.                 continue;
  1002.             }
  1003.             MbRead++;
  1004. #ifdef USERLOG
  1005.             /* Check the ID number of this message and
  1006.              * adjust new lastread count, if needed - WG7J
  1007.              */
  1008.             if(cmsg->msgid > m->lastread)
  1009.                 m->newlastread = cmsg->msgid;
  1010. #endif
  1011.             m->current = msg;
  1012.   
  1013.             /* Only mark your own private area as read and changed.
  1014.              * other areas, only mark as read, NOT changed !
  1015.              * 910312 - WG7J
  1016.              */
  1017.             if(!(cmsg->status & BM_READ)) {
  1018.                 cmsg->status |= BM_READ;
  1019.                 m->newmsgs--;
  1020.                 if(m->areatype == PRIVATE)
  1021.                     m->change = 1;
  1022.             }
  1023.             tprintf("Message #%d %s\n", msg,
  1024.             cmsg->status & BM_DELETE ? "[Deleted]" : "");
  1025.             --lin;
  1026.   
  1027.             fseek(txt,cmsg->start,0);
  1028.             fgets(buf,sizeof(buf),txt);      /* the 'From ' line */
  1029.             if(verbose) {
  1030.                 tputs(buf);
  1031.                 lin--;
  1032.             }
  1033.             smtpheader = 1;
  1034.             while(fgets(buf,sizeof(buf),txt) != NULL) {
  1035.                 if(!strncmp(buf,"From ",5))
  1036.                     break;
  1037.                 print = 1;
  1038.                 if(!verbose) {
  1039.                     if(smtpheader) {
  1040.                         if(*buf == '\n') {
  1041.                             smtpheader = 0;
  1042.                             mbxheader = 1;
  1043.                             pathheader = 0;
  1044.                         } else {
  1045.                             switch(htype(buf)) {
  1046.                                 case TO:
  1047.                                 case CC:
  1048.                                 case FROM:
  1049.                                 case DATE:
  1050.                                 case SUBJECT:
  1051.                                 case REPLYTO:
  1052.                                 case APPARTO:
  1053.                                     break;
  1054.                                 default:
  1055.                                     print = 0;
  1056.                             }
  1057.                         }
  1058.                     } else if(mbxheader) {
  1059.                         if(*buf == '\n') {
  1060.                             mbxheader = 0;
  1061.                         }
  1062.                         print = 0;
  1063.                         if(strncmp(buf,"R:",2) || \
  1064.                         ((cp=strchr(buf,'@')) == NULL) ) {
  1065.                             print = 1;
  1066.                             mbxheader = 0;
  1067.                             if(pathheader)
  1068.                                 tputc('\n');
  1069.                         } else {
  1070.                             if(pathheader > 7)
  1071.                                 continue;
  1072.                             if(*++cp == ':')
  1073.                                 cp++;
  1074.                             cp2 = cp;
  1075.                             while(*cp2 != '.' && *cp2 != ' ' && *cp2 != '\n')
  1076.                                 cp2++;
  1077.                             *cp2 = 0;
  1078.                             if(++pathheader == 1) {
  1079.                                 tputs(Hdrs[PATH]);
  1080.                                 tputs(cp);
  1081.                             } else {
  1082.                                 pathheader++;
  1083.                                 tputc('!');
  1084.                                 tputs(cp);
  1085.                             }
  1086.                         }
  1087.                     }
  1088.                 }
  1089.                 if(print) {
  1090.                     tputs(buf);
  1091.                     if(usemore && --lin <= 0){
  1092.                         if(charmode_ok(m))
  1093.                             c = tkeywait(TelnetMorePrompt,0);
  1094.                         else  /* For AX.25 and NET/ROM connects - WG7J */
  1095.                             c = mykeywait(BbsMorePrompt,m);
  1096.                         lin = m->morerows;
  1097.                         if(c == -1 || c == 'q' || c == 'Q')
  1098.                             break;
  1099.                         if(c == '\n' || c == '\r')
  1100.                             lin = 1;
  1101.                     }
  1102.                 }
  1103.             }
  1104.         }
  1105.     }
  1106.     iamdone:
  1107.     fclose(txt);
  1108.     /* If this was 'RM' or 'VM',
  1109.      * free the memory allocated for myargv[] - WG7J
  1110.      */
  1111.     if(m->stype == 'M') {
  1112.         for(i=1;i<argc;i++)
  1113.             free(myargv[i]);
  1114.     }
  1115.     return 0;
  1116. }
  1117.   
  1118. /* Set up m->to when replying to a message. The subject is returned in
  1119.  * m->line.
  1120.  */
  1121. int
  1122. mbx_reply(argc,argv,m,cclist,rhdr)
  1123. int argc;
  1124. char *argv[];
  1125. struct mbx *m;
  1126. struct list **cclist;   /* Pointer to buffer for pointers to cc recipients */
  1127. char **rhdr;        /* Pointer to buffer for extra reply headers */
  1128. {
  1129.     char *cp;
  1130.     int msg;
  1131.     struct cclist *cc;
  1132.     struct mailindex ind;
  1133.   
  1134.     if(argc == 1)
  1135.         msg = m->current;
  1136.     else
  1137.         msg = atoi(argv[1]);
  1138.   
  1139.     if(msg < 1 || msg > m->nmsgs) {
  1140.         if(m->sid & MBX_SID)
  1141.             tputs("NO - ");
  1142.         tprintf(Badmsg,msg);
  1143.         return -1;
  1144.     }
  1145.   
  1146.     /* clear index */
  1147.     memset(&ind,0,sizeof(struct mailindex));
  1148.   
  1149.     /* Get the index for this message */
  1150.     cp = strdup(m->area);
  1151.     dirformat(cp);
  1152.     if(get_index(msg,cp,&ind) == -1) {
  1153.         free(cp);
  1154.         return -1;
  1155.     }
  1156.     free(cp);
  1157.   
  1158.     /* Free anything that might be allocated
  1159.      * since the last call to mbx_to() or mbx_reply()
  1160.      */
  1161.     free(m->to);
  1162.     m->to = NULLCHAR;
  1163.     free(m->tofrom);
  1164.     m->tofrom = NULLCHAR;
  1165.     free(m->tomsgid);
  1166.     m->tomsgid = NULLCHAR;
  1167.     free(m->origto);
  1168.     m->origto = NULLCHAR;
  1169.   
  1170.     /* Assign data from the index */
  1171.     if(strlen(ind.replyto))
  1172.         m->to = strdup(ind.replyto);
  1173.     else
  1174.         m->to = strdup(ind.from);
  1175.   
  1176.     if(strncmp(ind.subject,"Re: ",4))
  1177.         sprintf(m->line,"Re: %s",ind.subject);
  1178.     else
  1179.         strcpy(m->line,ind.subject);
  1180.   
  1181.     for(cc=ind.cclist;cc;cc=cc->next)
  1182.         addlist(cclist,cc->to,0);
  1183.   
  1184.     *rhdr = mallocw(LINELEN);
  1185.     sprintf(*rhdr,"In-Reply-To: your message of %s"
  1186.     "             <%s>\n",
  1187.     ctime(&ind.date),ind.messageid);
  1188.     /* Free the index */
  1189.     default_index("",&ind);
  1190.     return 0;
  1191. }
  1192.   
  1193. #ifdef USERLOG
  1194.   
  1195. /*get the last message listed/read
  1196.  *from the areaname.USR file
  1197.  *keeps track for each user.
  1198.  *February '92, WG7J
  1199.  */
  1200. void
  1201. getlastread(m)
  1202. struct mbx *m;
  1203. {
  1204.     FILE *Alog;
  1205.     char buf[256];
  1206.     char *cp;
  1207.     int found=0;
  1208.   
  1209.     m->lastread = m->newlastread = 0L;
  1210.   
  1211.     sprintf(buf,"%s/%s.usr",Mailspool,m->area);
  1212.     if ((Alog = fopen(buf,"r+")) == NULLFILE) {
  1213.         /* USR file doesn't exist, create it */
  1214.         if((Alog = fopen(buf,"w")) == NULLFILE)
  1215.             return;
  1216.         /* Add this user as first one */
  1217.         sprintf(buf,"%s 0\n",m->name);
  1218.         fputs(buf,Alog);
  1219.         fclose(Alog);
  1220.         return;
  1221.     }
  1222.     /*Find user in the usr file for this area*/
  1223.     for(;;) {
  1224.         if(fgets(buf,sizeof(buf),Alog) == NULLCHAR)
  1225.             break;
  1226.         if((cp=strchr(buf,' ')) != NULLCHAR)
  1227.             *cp = '\0';
  1228.         if(!stricmp(m->name,buf)) {
  1229.             /*found user*/
  1230.             cp++;
  1231.             while(*cp == ' ')   /*skip blanks*/
  1232.                 cp++;
  1233.             m->lastread = atol(cp);
  1234.             found = 1;
  1235.             break;
  1236.         }
  1237.     }
  1238.     if(!found) {
  1239.         /*Add user*/
  1240.         sprintf(buf,"%s 0\n",m->name);
  1241.         fputs(buf,Alog);
  1242.     }
  1243.     fclose(Alog);
  1244.     return;
  1245. }
  1246.   
  1247. /* Write the new last read id number to the USR file - WG7J
  1248.  * only update if this is not a bbs,
  1249.  * current area is a public area and not 'help',
  1250.  * or anything that starts with 'sys',
  1251.  * and a new message was actually listed/read
  1252.  */
  1253. void
  1254. setlastread(m)
  1255. struct mbx *m;
  1256. {
  1257.     FILE *Alog, *tfile;
  1258.     char *cp;
  1259.     char buf[80];
  1260.     char tmpname[80];
  1261.   
  1262.     if((m->sid & MBX_SID) || (m->newlastread <= m->lastread) )
  1263.         return;
  1264.   
  1265.     /* Rename the USR file to a tempfile */
  1266.     sprintf(buf,"%s/%s.usr",Mailspool,m->area);
  1267.   
  1268.     /* N5KNX: change suffix from .usr to .tmp */
  1269.     sprintf(tmpname,"%s/%s.tmp",Mailspool,m->area);
  1270.     if(rename(buf,tmpname))
  1271.         /* Can't rename ??? */
  1272.         return;
  1273.   
  1274.     if((Alog = fopen(buf,"w")) == NULLFILE) {
  1275.         /* can't creat new USR file ???*/
  1276.         rename(tmpname,buf);    /* try to undo the damage */
  1277.         return;
  1278.     }
  1279.   
  1280.     if((tfile = fopen(tmpname,"r")) == NULLFILE)
  1281.         /* can't open renamed file ??? */
  1282.         return;
  1283.   
  1284.     /*Write all users back, but update this one!*/
  1285.     while(fgets(buf,sizeof(buf),tfile) != NULLCHAR) {
  1286.         if((cp=strchr(buf,' ')) != NULLCHAR)
  1287.             *cp = '\0';
  1288.         if(!stricmp(m->name,buf)) {
  1289.             /*found this user*/
  1290.             sprintf(buf,"%s %lu\n",m->name,m->newlastread);
  1291.         } else
  1292.             *cp = ' '; /* restore the space !*/
  1293.         fputs(buf,Alog);
  1294.     }
  1295.     fclose(tfile);
  1296.     unlink(tmpname);
  1297.     fclose(Alog);
  1298.   
  1299.     return;
  1300. }
  1301.   
  1302. #endif /*USERLOG*/
  1303.   
  1304. void
  1305. scanmail(m)      /* Get any new mail */
  1306. struct mbx *m;
  1307. {
  1308.     int idx;
  1309.     char *area;
  1310.     int ret;
  1311.     char buf[FILE_PATH_SIZE];
  1312.     long diff;
  1313.   
  1314.     if(lockit(m))
  1315.         return;
  1316.     if ((diff = isnewmail(m)) == 0L) {
  1317.         unlockit(m);
  1318.         return;
  1319.     }
  1320.     if(diff < 0L) {
  1321.         /* Area wasn't open yet, or the file size has decreased.
  1322.          * Any changes we did to this area will be lost,
  1323.          * but this is not fatal.
  1324.          */
  1325. #ifdef DEBUG_HDR
  1326.         if (diff < -1L) log(m->user,"NOUPDATE for %s: msgs deleted in %s [scanmail] %ld,%ld,%d",m->name,m->area,diff,m->mboxsize,errno);
  1327. #endif
  1328.         initnotes(m);
  1329.         unlockit(m);
  1330.         return;
  1331.     }
  1332.     area = strdup(m->area);
  1333.     dirformat(area);
  1334.     sprintf(buf,"%s/%s.ind",Mailspool,area);
  1335.     if ((idx = open(buf,READBINARY)) == -1)
  1336.         log(m->user,OpenError,m->name,errno,buf);
  1337.     else {
  1338.         /* Reread all messages since they may have changed
  1339.          * in size after an X-Forwarded-To line was added.
  1340.          */
  1341.         ret = readnotes(m,idx);   /* get the mail */
  1342.         close(idx);
  1343.         if(m->areatype == PRIVATE)
  1344.             m->mycnt = m->nmsgs;
  1345.         if (ret != 0)
  1346.             tputs("Error updating mail file\n");
  1347.     }
  1348.     unlockit(m);
  1349.     free(area);
  1350. }
  1351.   
  1352. /* Check the current mailbox to see if new mail has arrived.
  1353.  * Returns the difference in size.
  1354.  */
  1355. static long
  1356. isnewmail(m)
  1357. struct mbx *m;
  1358. {
  1359.     int idx;
  1360.     long size;
  1361.     char *area;
  1362.     char buf[FILE_PATH_SIZE];
  1363.  
  1364.     if(lockit(m)) return(-1); /* SyncIndex assumes a lock */
  1365.     SyncIndex(m->area);       /* ensure index file is current */
  1366.     unlockit(m);
  1367.   
  1368.     area = strdup(m->area);
  1369.     dirformat(area);
  1370.     sprintf(buf,"%s/%s.ind",Mailspool,area);
  1371.     free(area);
  1372.   
  1373.     if((idx = open(buf,READBINARY)) == -1) {
  1374.         if(m->mboxsize == 0)
  1375.             return 0;
  1376.         return -1;
  1377.     }
  1378.     close(idx);
  1379.   
  1380.     /* index file exists, check mailbox */
  1381.     strcpy(&buf[strlen(buf) - 3],"txt");
  1382.     size = fsize(buf);
  1383.     if(m->mboxsize == 0) {
  1384.         if(size > 0)
  1385.             return -1;  /* New open of mailbox */
  1386.         return 0;       /* No mail; no change */
  1387.     }
  1388.     /* Others */
  1389.     return size - m->mboxsize;
  1390. }
  1391.   
  1392. /* Check if the private mail area has changed */
  1393. long
  1394. isnewprivmail(m)
  1395. struct mbx *m;
  1396. {
  1397.     int idx,msgcnt;
  1398.     struct indexhdr hdr;
  1399.     char buf[FILE_PATH_SIZE];
  1400.   
  1401.     sprintf(buf,"%s/%s.ind",Mailspool,m->name);
  1402.     if((idx=open(buf,READBINARY)) == -1)
  1403.         hdr.msgs = 0;
  1404.     else {
  1405.         read_header(idx,&hdr);
  1406.         close(idx);
  1407.     }
  1408.   
  1409.     return hdr.msgs - m->mycnt; /* != 0 not more than once */
  1410. }
  1411.   
  1412. #endif /* MAILCMDS */
  1413.   
  1414. /* This function returns the length of a file. The proper thing would be
  1415.  * to use stat(), but it fails when using DesqView together with Turbo-C
  1416.  * code.
  1417.  */
  1418. long
  1419. fsize(name)
  1420. char *name;
  1421. {
  1422.     long cnt;
  1423.     FILE *fp;
  1424.   
  1425.     if((fp = fopen(name,READ_TEXT)) == NULLFILE)
  1426.         return -1L;
  1427.     fseek(fp,0L,2);
  1428.     cnt = ftell(fp);
  1429.     fclose(fp);
  1430.     return cnt;
  1431. }
  1432.  
  1433. /* Print prompt and read one character, telnet version */
  1434. int
  1435. tkeywait(prompt,flush)
  1436. char *prompt;   /* Optional prompt */
  1437. int flush;  /* Flush queued input? */
  1438. {
  1439.     int c, i, oldimode,oldomode;
  1440.   
  1441.     if(flush && socklen(Curproc->input,0) != 0)
  1442.         recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0); /* flush */
  1443.     if(prompt == NULLCHAR)
  1444.         prompt = "Hit enter to continue";
  1445.     usflush(Curproc->output);    /* BSD-derived telnets need opts in separate pkt */
  1446.     while (socklen(Curproc->output, 1) > 0)    /* else CRs in pkt are ignored */
  1447.         pause(250L);
  1448.     tprintf("%s%c%c%c%c%c%c",prompt,IAC,WILL,TN_ECHO,IAC,WILL,TN_SUPPRESS_GA);
  1449.     usflush(Curproc->output);
  1450.   
  1451.     /* discard the response */
  1452.   
  1453.     oldimode = sockmode(Curproc->input,SOCK_BINARY);
  1454.     oldomode = sockmode(Curproc->output,SOCK_BINARY);
  1455.   
  1456.     while((c = rrecvchar(Curproc->input)) == IAC){
  1457.         c = rrecvchar(Curproc->input);
  1458.         if(c > 250 && c < 255)
  1459.             rrecvchar(Curproc->input);
  1460.     }
  1461.   
  1462.     sockmode(Curproc->output,oldomode);
  1463.     sockmode(Curproc->input,oldimode);
  1464.   
  1465.     /* Get rid of the prompt */
  1466.     for(i=strlen(prompt);i != 0;i--)
  1467.         tputc('\b');
  1468.     for(i=strlen(prompt);i != 0;i--)
  1469.         tputc(' ');
  1470.     for(i=strlen(prompt);i != 0;i--)
  1471.         tputc('\b');
  1472.     tprintf("%c%c%c%c%c%c",IAC,WONT,TN_ECHO,IAC,WONT,TN_SUPPRESS_GA);
  1473.     usflush(Curproc->output);
  1474.     return c;
  1475. }
  1476.   
  1477. /* Print prompt and read reply,
  1478.  * AX.25 and NETROM version - WG7J
  1479.  * 'N' or 'n' returns -1, everything else return 0.
  1480.  */
  1481. int
  1482. mykeywait(prompt,m)
  1483. char *prompt;
  1484. struct mbx *m;
  1485. {
  1486.     tputs(prompt);
  1487.     usflush(Curproc->output);
  1488.     if(recvline(m->user, m->line, MBXLINE) == -1)
  1489.         return -1;
  1490.   
  1491.     /* Only 'N' or 'n' really matters */
  1492.     if(strchr(m->line,'N') || strchr(m->line,'n'))
  1493.         return -1;
  1494.     return 0;
  1495. }
  1496.   
  1497. #ifdef notdef
  1498.   
  1499. /* Echo some stuff for debugging */
  1500. void eout(char *s) {
  1501.   
  1502.     puts(s);
  1503.     fflush(stdout);
  1504.     while(!kbhit());
  1505.     getch();
  1506. }
  1507.   
  1508. #endif
  1509.   
  1510. /* Delete mail.lck files. This currently does NOT recurse - WG7J */
  1511. void RemoveMailLocks() {
  1512.     int done;
  1513.     struct ffblk ff;
  1514.     char *buf;
  1515.   
  1516.     buf = mallocw(BUFSIZ);
  1517.     sprintf(buf,"%s/*.lck",Mailspool);
  1518.     done = findfirst(buf,&ff,0);
  1519.     while(!done) {
  1520.         sprintf(buf,"%s/%s",Mailspool,ff.ff_name);
  1521.         unlink(buf);
  1522.         done=findnext(&ff);
  1523.     }
  1524.     free(buf);
  1525. }
  1526.   
  1527.