home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 September / PCO_0998.ISO / filesbbs / dos / sbbs_src.exe / SBBS / MAIL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-25  |  24.9 KB  |  899 lines

  1. #line 1 "MAIL.C"
  2.  
  3. /* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
  4.  
  5. #include "sbbs.h"
  6.  
  7. /****************************************************************************/
  8. /* Returns the number of pieces of mail waiting for usernumber              */
  9. /* If sent is non-zero, it returns the number of mail sent by usernumber    */
  10. /* If usernumber is 0, it returns all mail on the system                    */
  11. /****************************************************************************/
  12. int getmail(int usernumber, char sent)
  13. {
  14.     char    str[128];
  15.     int     i=0;
  16.     long    l;
  17.     idxrec_t idx;
  18.  
  19. smb_stack(&smb,SMB_STACK_PUSH);
  20. sprintf(smb.file,"%sMAIL",data_dir);
  21. smb.retry_time=smb_retry_time;
  22. sprintf(str,"%s.SID",smb.file);
  23. l=flength(str);
  24. if(l<sizeof(idxrec_t))
  25.     return(0);
  26. if(!usernumber) {
  27.     smb_stack(&smb,SMB_STACK_POP);
  28.     return(l/sizeof(idxrec_t)); }    /* Total system e-mail */
  29. if(smb_open(&smb)) {
  30.     smb_stack(&smb,SMB_STACK_POP);
  31.     return(0); }
  32. while(!feof(smb.sid_fp)) {
  33.     if(!fread(&idx,sizeof(idxrec_t),1,smb.sid_fp))
  34.         break;
  35.     if(idx.attr&MSG_DELETE)
  36.         continue;
  37.     if((!sent && idx.to==usernumber)
  38.      || (sent && idx.from==usernumber))
  39.         i++; }
  40. smb_close(&smb);
  41. smb_stack(&smb,SMB_STACK_POP);
  42. return(i);
  43. }
  44.  
  45. /***************************/
  46. /* Delete file attachments */
  47. /***************************/
  48. void delfattach(uint to, char *title)
  49. {
  50.     char str[128],str2[128],*tp,*sp,*p;
  51.     uint i;
  52.  
  53. strcpy(str,title);
  54. tp=str;
  55. while(1) {
  56.     p=strchr(tp,SP);
  57.     if(p) *p=0;
  58.     sp=strrchr(tp,'/');              /* sp is slash pointer */
  59.     if(!sp) sp=strrchr(tp,'\\');
  60.     if(sp) tp=sp+1;
  61.     sprintf(str2,"%sFILE\\%04u.IN\\%s"  /* str2 is path/fname */
  62.         ,data_dir,to,tp);
  63.     remove(str2);
  64.     if(!p)
  65.         break;
  66.     tp=p+1; }
  67. sprintf(str,"%sFILE\\%04u.IN",data_dir,to);
  68. rmdir(str);                     /* remove the dir if it's empty */
  69. }
  70.  
  71.  
  72. /****************************************************************************/
  73. /* Deletes all mail messages for usernumber that have been marked 'deleted' */
  74. /* smb_locksmbhdr() should be called prior to this function                 */
  75. /****************************************************************************/
  76. int delmail(uint usernumber, int which)
  77. {
  78.     ulong     i,l,now;
  79.     idxrec_t HUGE16 *idxbuf;
  80.     smbmsg_t msg;
  81.  
  82. now=time(NULL);
  83. if((i=smb_getstatus(&smb))!=0) {
  84.     errormsg(WHERE,ERR_READ,smb.file,i);
  85.     return(2); }
  86. if(!smb.status.total_msgs)
  87.     return(0);
  88. if((idxbuf=(idxrec_t *)LMALLOC(smb.status.total_msgs*sizeof(idxrec_t)))==NULL) {
  89.     errormsg(WHERE,ERR_ALLOC,smb.file,smb.status.total_msgs*sizeof(idxrec_t));
  90.     return(-1); }
  91. if((i=smb_open_da(&smb))!=0) {
  92.     errormsg(WHERE,ERR_OPEN,smb.file,i);
  93.     LFREE(idxbuf);
  94.     return(i); }
  95. if((i=smb_open_ha(&smb))!=0) {
  96.     smb_close_da(&smb);
  97.     errormsg(WHERE,ERR_OPEN,smb.file,i);
  98.     LFREE(idxbuf);
  99.     return(i); }
  100. rewind(smb.sid_fp);
  101. for(l=0;l<smb.status.total_msgs;) {
  102.     if(!fread(&msg.idx,sizeof(idxrec_t),1,smb.sid_fp))
  103.         break;
  104.     if(which==MAIL_ALL && !(msg.idx.attr&MSG_PERMANENT)
  105.         && smb.status.max_age && now>msg.idx.time
  106.         && (now-msg.idx.time)/(24L*60L*60L)>smb.status.max_age)
  107.         msg.idx.attr|=MSG_DELETE;
  108.     if(msg.idx.attr&MSG_DELETE && !(msg.idx.attr&MSG_PERMANENT)
  109.         && ((which==MAIL_SENT && usernumber==msg.idx.from)
  110.         || (which==MAIL_YOUR && usernumber==msg.idx.to)
  111.         || (which==MAIL_ANY
  112.             && (usernumber==msg.idx.to || usernumber==msg.idx.from))
  113.         || which==MAIL_ALL)) {
  114.         /* Don't need to lock message because base is locked */
  115.         if(which==MAIL_ALL && !online)
  116.             lprintf(" #%lu",msg.idx.number);
  117.         if((i=smb_getmsghdr(&smb,&msg))!=0)
  118.             errormsg(WHERE,ERR_READ,smb.file,i);
  119.         else {
  120.             if(msg.hdr.attr!=msg.idx.attr) {
  121.                 msg.hdr.attr=msg.idx.attr;
  122.                 if((i=smb_putmsghdr(&smb,&msg))!=0)
  123.                     errormsg(WHERE,ERR_WRITE,smb.file,i); }
  124.             if((i=smb_freemsg(&smb,&msg))!=0)
  125.                 errormsg(WHERE,ERR_REMOVE,smb.file,i);
  126.             if(msg.hdr.auxattr&MSG_FILEATTACH)
  127.                 delfattach(msg.idx.to,msg.subj);
  128.             smb_freemsgmem(&msg); }
  129.         continue; }
  130.     idxbuf[l]=msg.idx;
  131.     l++; }
  132. rewind(smb.sid_fp);
  133. chsize(fileno(smb.sid_fp),0);
  134. for(i=0;i<l;i++)
  135.     fwrite(&idxbuf[i],sizeof(idxrec_t),1,smb.sid_fp);
  136. LFREE(idxbuf);
  137. smb.status.total_msgs=l;
  138. smb_putstatus(&smb);
  139. fflush(smb.sid_fp);
  140. smb_close_ha(&smb);
  141. smb_close_da(&smb);
  142. return(0);
  143. }
  144.  
  145.  
  146. /***********************************************/
  147. /* Tell the user that so-and-so read your mail */
  148. /***********************************************/
  149. void telluser(smbmsg_t msg)
  150. {
  151.     char str[256],*p;
  152.     uint usernumber,n;
  153.     node_t node;
  154.  
  155. if(msg.from_net.type)
  156.     return;
  157. if(msg.from_ext)
  158.     usernumber=atoi(msg.from_ext);
  159. else {
  160.     usernumber=matchuser(msg.from);
  161.     if(!usernumber)
  162.         return; }
  163. for(n=1;n<=sys_nodes;n++) { /* Tell user */
  164.     getnodedat(n,&node,0);
  165.     if(node.useron==usernumber
  166.     && (node.status==NODE_INUSE
  167.     || node.status==NODE_QUIET)) {
  168.         sprintf(str
  169.             ,text[UserReadYourMailNodeMsg]
  170.             ,node_num,useron.alias);
  171.         putnmsg(n,str);
  172.         break; } }
  173. if(n>sys_nodes) {
  174.     now=time(NULL);
  175.     sprintf(str,text[UserReadYourMail]
  176.         ,useron.alias,timestr(&now));
  177.     putsmsg(usernumber,str); }
  178. }
  179.  
  180. /****************************************************************************/
  181. /* Loads mail waiting for user number 'usernumber' into the mail array of   */
  182. /* of pointers to mail_t (message numbers and attributes)                   */
  183. /* smb_open(&smb) must be called prior                                            */
  184. /****************************************************************************/
  185. ulong loadmail(mail_t **mail, uint usernumber, int which, int mode)
  186. {
  187.     int         i;
  188.     ulong        l=0;
  189.     idxrec_t    idx;
  190.  
  191. if((i=smb_locksmbhdr(&smb))!=0) {                /* Be sure noone deletes or */
  192.     errormsg(WHERE,ERR_LOCK,smb.file,i);        /* adds while we're reading */
  193.     return(0); }
  194. (*mail)=NULL;
  195. rewind(smb.sid_fp);
  196. while(!feof(smb.sid_fp)) {
  197.     if(!fread(&idx,sizeof(idxrec_t),1,smb.sid_fp))
  198.         break;
  199.     if((which==MAIL_SENT && idx.from!=usernumber)
  200.         || (which==MAIL_YOUR && idx.to!=usernumber)
  201.         || (which==MAIL_ANY && idx.from!=usernumber && idx.to!=usernumber))
  202.         continue;
  203.     if(idx.attr&MSG_DELETE) {
  204.         if(mode&LM_QWK)                 /* Don't included deleted msgs */
  205.             continue;                    /* in QWK packet */
  206.         if(!(sys_misc&SM_SYSVDELM))     /* Noone can view deleted msgs */
  207.             continue;                    
  208.         if(!SYSOP                        /* not sysop */
  209.             && !(sys_misc&SM_USRVDELM)) /* users can't view deleted msgs */
  210.             continue; }
  211.     if(mode&LM_UNREAD && idx.attr&MSG_READ)
  212.         continue;
  213.     if(((*mail)=(mail_t *)REALLOC((*mail),sizeof(mail_t)*(l+1)))
  214.         ==NULL) {
  215.         smb_unlocksmbhdr(&smb);
  216.         errormsg(WHERE,ERR_ALLOC,smb.file,sizeof(mail_t)*(l+1));
  217.         return(i); }
  218.     (*mail)[l].offset=idx.offset;
  219.     (*mail)[l].number=idx.number;
  220.     (*mail)[l].to=idx.to;
  221.     (*mail)[l].from=idx.from;
  222.     (*mail)[l].subj=idx.subj;
  223.     (*mail)[l].time=idx.time;
  224.     (*mail)[l].attr=idx.attr;
  225.     l++; }
  226. smb_unlocksmbhdr(&smb);
  227. return(l);
  228. }
  229.  
  230. /************************************************************************/
  231. /* Deletes all mail waiting for user number 'usernumber'                */
  232. /************************************************************************/
  233. void delallmail(uint usernumber)
  234. {
  235.     int     i;
  236.     ulong    l,msgs,deleted=0;
  237.     mail_t    *mail;
  238.     smbmsg_t msg;
  239.  
  240. if((i=smb_stack(&smb,SMB_STACK_PUSH))!=0) {
  241.     errormsg(WHERE,ERR_OPEN,"MAIL",i);
  242.     return; }
  243. sprintf(smb.file,"%sMAIL",data_dir);
  244. smb.retry_time=smb_retry_time;
  245. if((i=smb_open(&smb))!=0) {
  246.     errormsg(WHERE,ERR_OPEN,smb.file,i);
  247.     smb_stack(&smb,SMB_STACK_POP);
  248.     return; }
  249.  
  250. msgs=loadmail(&mail,usernumber,MAIL_ANY,0);
  251. if(!msgs) {
  252.     smb_close(&smb);
  253.     smb_stack(&smb,SMB_STACK_POP);
  254.     return; }
  255. if((i=smb_locksmbhdr(&smb))!=0) {            /* Lock the base, so nobody */
  256.     smb_close(&smb);
  257.     smb_stack(&smb,SMB_STACK_POP);
  258.     FREE(mail);
  259.     errormsg(WHERE,ERR_LOCK,smb.file,i);    /* messes with the index */
  260.     return; }
  261. for(l=0;l<msgs;l++) {
  262.     msg.idx.offset=0;                        /* search by number */
  263.     if(loadmsg(&msg,mail[l].number)) {       /* message still there */
  264.         msg.hdr.attr|=MSG_DELETE;
  265.         msg.hdr.attr&=~MSG_PERMANENT;
  266.         msg.idx.attr=msg.hdr.attr;
  267.         if((i=smb_putmsg(&smb,&msg))!=0)
  268.             errormsg(WHERE,ERR_WRITE,smb.file,i);
  269.         else
  270.             deleted++;
  271.         smb_freemsgmem(&msg);
  272.         smb_unlockmsghdr(&smb,&msg); } }
  273.  
  274. if(msgs)
  275.     FREE(mail);
  276. if(deleted && sys_misc&SM_DELEMAIL)
  277.     delmail(usernumber,MAIL_ANY);
  278. smb_unlocksmbhdr(&smb);
  279. smb_close(&smb);
  280. smb_stack(&smb,SMB_STACK_POP);
  281. }
  282.  
  283. /****************************************************************************/
  284. /* Reads mail waiting for usernumber.                                       */
  285. /****************************************************************************/
  286. void readmail(uint usernumber, int which)
  287. {
  288.     char    str[256],str2[256],str3[256],done=0,domsg=1
  289.             ,*buf,*p,*tp,*sp,ch;
  290.     int     file,msgs,curmsg,i,j,k,n,m,mismatches=0,act;
  291.     long    length,l;
  292.     ulong    last;
  293.     file_t    fd;
  294.     mail_t    *mail;
  295.     smbmsg_t msg;
  296.  
  297. msg.total_hfields=0;            /* init to NULL, cause not allocated yet */
  298.  
  299. fd.dir=total_dirs+1;            /* temp dir for file attachments */
  300.  
  301. if((i=smb_stack(&smb,SMB_STACK_PUSH))!=0) {
  302.     errormsg(WHERE,ERR_OPEN,"MAIL",i);
  303.     return; }
  304. sprintf(smb.file,"%sMAIL",data_dir);
  305. smb.retry_time=smb_retry_time;
  306. if((i=smb_open(&smb))!=0) {
  307.     smb_stack(&smb,SMB_STACK_POP);
  308.     errormsg(WHERE,ERR_OPEN,smb.file,i);
  309.     return; }
  310.  
  311. msgs=loadmail(&mail,usernumber,which,0);
  312. if(!msgs) {
  313.     if(which==MAIL_SENT)
  314.         bputs(text[NoMailSent]);
  315.     else if(which==MAIL_ALL)
  316.         bputs(text[NoMailOnSystem]);
  317.     else
  318.         bputs(text[NoMailWaiting]);
  319.     smb_close(&smb);
  320.     smb_stack(&smb,SMB_STACK_POP);
  321.     return; }
  322.  
  323. last=smb.status.last_msg;
  324.  
  325. if(which==MAIL_SENT)
  326.     act=NODE_RSML;
  327. else if(which==MAIL_ALL)
  328.     act=NODE_SYSP;
  329. else
  330.     act=NODE_RMAL;
  331. action=act;
  332. if(msgs>1 && which!=MAIL_ALL) {
  333.     if(which==MAIL_SENT)
  334.         bputs(text[MailSentLstHdr]);
  335.     else
  336.         bputs(text[MailWaitingLstHdr]);
  337.  
  338.     for(curmsg=0;curmsg<msgs && !msgabort();curmsg++) {
  339.         if(msg.total_hfields)
  340.             smb_freemsgmem(&msg);
  341.         msg.total_hfields=0;
  342.         msg.idx.offset=mail[curmsg].offset;
  343.         if(!loadmsg(&msg,mail[curmsg].number))
  344.             continue;
  345.         smb_unlockmsghdr(&smb,&msg);
  346.         bprintf(text[MailWaitingLstFmt],curmsg+1
  347.             ,which==MAIL_SENT ? msg.to
  348.             : (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP ? text[Anonymous]
  349.             : msg.from
  350.             ,msg.hdr.attr&MSG_DELETE ? '-' : msg.hdr.attr&MSG_READ ? ' '
  351.                 : msg.from_net.type || msg.to_net.type ? 'N':'*'
  352.             ,msg.subj);
  353.         smb_freemsgmem(&msg);
  354.         msg.total_hfields=0; }
  355.  
  356.     ASYNC;
  357.     if(!(sys_status&SS_ABORT)) {
  358.         bprintf(text[StartWithN],1L);
  359.         if((curmsg=getnum(msgs))>0)
  360.             curmsg--;
  361.         else if(curmsg==-1) {
  362.             FREE(mail);
  363.             smb_close(&smb);
  364.             smb_stack(&smb,SMB_STACK_POP);
  365.             return; } }
  366.     sys_status&=~SS_ABORT; }
  367. else {
  368.     curmsg=0;
  369.     if(which==MAIL_ALL)
  370.         domsg=0; }
  371. if(which==MAIL_SENT)
  372.     logline("E","Read sent mail");
  373. else if(which==MAIL_ALL)
  374.     logline("S+","Read all mail");
  375. else
  376.     logline("E","Read mail");
  377. if(useron.misc&RIP) {
  378.     strcpy(str,which==MAIL_YOUR ? "MAILREAD" : which==MAIL_ALL ?
  379.         "ALLMAIL" : "SENTMAIL");
  380.     menu(str); }
  381. while(online && !done) {
  382.     action=act;
  383.  
  384.     if(msg.total_hfields)
  385.         smb_freemsgmem(&msg);
  386.     msg.total_hfields=0;
  387.  
  388.     msg.idx.offset=mail[curmsg].offset;
  389.     msg.idx.number=mail[curmsg].number;
  390.     msg.idx.to=mail[curmsg].to;
  391.     msg.idx.from=mail[curmsg].from;
  392.     msg.idx.subj=mail[curmsg].subj;
  393.  
  394.     if((i=smb_locksmbhdr(&smb))!=0) {
  395.         errormsg(WHERE,ERR_LOCK,smb.file,i);
  396.         break; }
  397.  
  398.     if((i=smb_getstatus(&smb))!=0) {
  399.         smb_unlocksmbhdr(&smb);
  400.         errormsg(WHERE,ERR_READ,smb.file,i);
  401.         break; }
  402.     smb_unlocksmbhdr(&smb);
  403.  
  404.     if(smb.status.last_msg!=last) {     /* New messages */
  405.         last=smb.status.last_msg;
  406.         FREE(mail);
  407.         msgs=loadmail(&mail,usernumber,which,0);   /* So re-load */
  408.         if(!msgs)
  409.             break;
  410.         for(curmsg=0;curmsg<msgs;curmsg++)
  411.             if(mail[curmsg].number==msg.idx.number)
  412.                 break;
  413.         if(curmsg>=msgs)
  414.             curmsg=(msgs-1);
  415.         continue; }
  416.  
  417.     if(!loadmsg(&msg,mail[curmsg].number)) {    /* Message header gone */
  418.         if(mismatches>5) {    /* We can't do this too many times in a row */
  419.             errormsg(WHERE,ERR_CHK,"message number",mail[curmsg].number);
  420.             break; }
  421.         FREE(mail);
  422.         msgs=loadmail(&mail,usernumber,which,0);
  423.         if(!msgs)
  424.             break;
  425.         if(curmsg>(msgs-1))
  426.             curmsg=(msgs-1);
  427.         mismatches++;
  428.         continue; }
  429.     smb_unlockmsghdr(&smb,&msg);
  430.     msg.idx.attr=msg.hdr.attr;
  431.  
  432.     mismatches=0;
  433.  
  434.     if(domsg && !(sys_status&SS_ABORT)) {
  435.  
  436.         show_msg(msg
  437.             ,msg.from_ext && msg.idx.from==1 && !msg.from_net.type
  438.                 ? 0:P_NOATCODES);
  439.  
  440.         if(msg.hdr.auxattr&MSG_FILEATTACH) {  /* Attached file */
  441.             smb_getmsgidx(&smb,&msg);
  442.             strcpy(str,msg.subj);                    /* filenames in title */
  443.             strupr(str);
  444.             tp=str;
  445.             while(online) {
  446.                 p=strchr(tp,SP);
  447.                 if(p) *p=0;
  448.                 sp=strrchr(tp,'/');              /* sp is slash pointer */
  449.                 if(!sp) sp=strrchr(tp,'\\');
  450.                 if(sp) tp=sp+1;
  451.                 padfname(tp,fd.name);
  452.                 sprintf(str2,"%sFILE\\%04u.IN\\%s"  /* str2 is path/fname */
  453.                     ,data_dir,msg.idx.to,tp);
  454.                 length=flength(str2);
  455.                 if(length<1)
  456.                     bputs(text[FileNotFound]);
  457.                 else if(!(useron.exempt&FLAG('T')) && cur_cps && !SYSOP
  458.                     && length/(ulong)cur_cps>timeleft)
  459.                     bputs(text[NotEnoughTimeToDl]);
  460.                 else {
  461.                     sprintf(str3,text[DownloadAttachedFileQ]
  462.                         ,tp,ultoac(length,tmp));
  463.                     if(length>0L && yesno(str3)) {
  464.                         if(online==ON_LOCAL) {
  465.                             bputs(text[EnterPath]);
  466.                             if(getstr(str3,60,K_LINE|K_UPPER)) {
  467.                                 backslashcolon(str3);
  468.                                 sprintf(tmp,"%s%s",str3,tp);
  469.                                 if(!mv(str2,tmp,which!=MAIL_YOUR)) {
  470.                                     logon_dlb+=length;
  471.                                     logon_dls++;
  472.                                     useron.dls=adjustuserrec(useron.number
  473.                                         ,U_DLS,5,1);
  474.                                     useron.dlb=adjustuserrec(useron.number
  475.                                         ,U_DLB,10,length);
  476.                                     bprintf(text[FileNBytesSent]
  477.                                         ,fd.name,ultoac(length,tmp)); } } }
  478.  
  479.                         else {    /* Remote User */
  480.                             menu("DLPROT");
  481.                             mnemonics(text[ProtocolOrQuit]);
  482.                             strcpy(str3,"Q");
  483.                             for(i=0;i<total_prots;i++)
  484.                                 if(prot[i]->dlcmd[0]
  485.                                     && chk_ar(prot[i]->ar,useron)) {
  486.                                     sprintf(tmp,"%c",prot[i]->mnemonic);
  487.                                     strcat(str3,tmp); }
  488.                             ch=getkeys(str3,0);
  489.                             for(i=0;i<total_prots;i++)
  490.                                 if(prot[i]->dlcmd[0] && ch==prot[i]->mnemonic
  491.                                     && chk_ar(prot[i]->ar,useron))
  492.                                     break;
  493.                             if(i<total_prots) {
  494.                                 j=protocol(cmdstr(prot[i]->dlcmd,str2,nulstr
  495.                                     ,NULL),0);
  496.                                 if((prot[i]->misc&PROT_DSZLOG
  497.                                     && checkprotlog(fd))
  498.                                     || (!(prot[i]->misc&PROT_DSZLOG) && !j)) {
  499.                                         if(which==MAIL_YOUR)
  500.                                             remove(str2);
  501.                                         logon_dlb+=length;    /* Update stats */
  502.                                         logon_dls++;
  503.                                         useron.dls=adjustuserrec(useron.number
  504.                                             ,U_DLS,5,1);
  505.                                         useron.dlb=adjustuserrec(useron.number
  506.                                             ,U_DLB,10,length);
  507.                                         bprintf(text[FileNBytesSent]
  508.                                             ,fd.name,ultoac(length,tmp));
  509.                                         sprintf(str3
  510.                                             ,"Downloaded attached file: %s"
  511.                                             ,fd.name);
  512.                                         logline("D-",str3); }
  513.                                 autohangup(); } } } }
  514.                     if(!p)
  515.                         break;
  516.                     tp=p+1;
  517.                     while(*tp==SP) tp++; }
  518.             sprintf(str,"%sFILE\\%04u.IN",data_dir,usernumber);
  519.             rmdir(str); }
  520.         if(which==MAIL_YOUR && !(msg.hdr.attr&MSG_READ)) {
  521.             if(thisnode.status==NODE_INUSE)
  522.                 telluser(msg);
  523.             if(msg.total_hfields)
  524.                 smb_freemsgmem(&msg);
  525.             msg.total_hfields=0;
  526.             msg.idx.offset=0;                        /* Search by number */
  527.             if(!smb_locksmbhdr(&smb)) {             /* Lock the entire base */
  528.                 if(loadmsg(&msg,msg.idx.number)) {
  529.                     msg.hdr.attr|=MSG_READ;
  530.                     msg.idx.attr=msg.hdr.attr;
  531.                     if((i=smb_putmsg(&smb,&msg))!=0)
  532.                         errormsg(WHERE,ERR_WRITE,smb.file,i);
  533.                     smb_unlockmsghdr(&smb,&msg); }
  534.                 smb_unlocksmbhdr(&smb); }
  535.             if(!msg.total_hfields) {                /* unsuccessful reload */
  536.                 domsg=0;
  537.                 continue; } }
  538.         }
  539.     else domsg=1;
  540.  
  541.     if(useron.misc&WIP) {
  542.         strcpy(str,which==MAIL_YOUR ? "MAILREAD" : which==MAIL_ALL ?
  543.             "ALLMAIL" : "SENTMAIL");
  544.         menu(str); }
  545.  
  546.     ASYNC;
  547.     if(which==MAIL_SENT)
  548.         bprintf(text[ReadingSentMail],curmsg+1,msgs);
  549.     else if(which==MAIL_ALL)
  550.         bprintf(text[ReadingAllMail],curmsg+1,msgs);
  551.     else
  552.         bprintf(text[ReadingMail],curmsg+1,msgs);
  553.     sprintf(str,"ADFLNQRT?<>[]{}-+");
  554.     if(SYSOP)
  555.         strcat(str,"CUSP");
  556.     if(which!=MAIL_YOUR)
  557.         strcat(str,"E");
  558.     l=getkeys(str,msgs);
  559.     if(l&0x80000000L) {
  560.         if(l==-1)    /* ctrl-c */
  561.             break;
  562.         curmsg=(l&~0x80000000L)-1;
  563.         continue; }
  564.     switch(l) {
  565.         case 'A':   /* Auto-reply to last piece */
  566.             if(which==MAIL_SENT)
  567.                 break;
  568.             if((msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP) {
  569.                 bputs(text[CantReplyToAnonMsg]);
  570.                 break; }
  571.  
  572.             quotemsg(msg,1);
  573.  
  574.             if(msg.from_net.type==NET_FIDO)         /* FidoNet type */
  575.                 sprintf(str,"%s @%s",msg.from
  576.                 ,faddrtoa(*(faddr_t *)msg.from_net.addr));
  577.             else if(msg.from_net.type==NET_INTERNET)
  578.                 strcpy(str,msg.from_net.addr);
  579.             else if(msg.from_net.type)
  580.                 sprintf(str,"%s@%s",msg.from,msg.from_net.addr);
  581.             else                                    /* No net */
  582.                 strcpy(str,msg.from);
  583.  
  584.             strcpy(str2,str);
  585.  
  586.             bputs(text[Email]);
  587.             if(!getstr(str,64,K_EDIT|K_AUTODEL))
  588.                 break;
  589.             msg.hdr.number=msg.idx.number;
  590.             smb_getmsgidx(&smb,&msg);
  591.  
  592.             if(!stricmp(str2,str))        /* Reply to sender */
  593.                 sprintf(str2,text[Regarding],msg.subj);
  594.             else                        /* Reply to other */
  595.                 sprintf(str2,text[RegardingBy],msg.subj,msg.from
  596.                     ,timestr((time_t *)&msg.hdr.when_written.time));
  597.  
  598.             p=strrchr(str,'@');
  599.             if(p) {                             /* name @addr */
  600.                 netmail(str,msg.subj,WM_QUOTE);
  601.                 sprintf(str2,text[DeleteMailQ],msg.from); }
  602.             else {
  603.                 if(!msg.from_net.type && !stricmp(str,msg.from))
  604.                     email(msg.idx.from,str2,msg.subj,WM_EMAIL|WM_QUOTE);
  605.                 else if(!stricmp(str,"SYSOP"))
  606.                     email(1,str2,msg.subj,WM_EMAIL|WM_QUOTE);
  607.                 else if((i=finduser(str))!=0)
  608.                     email(i,str2,msg.subj,WM_EMAIL|WM_QUOTE);
  609.                 sprintf(str2,text[DeleteMailQ],msg.from); }
  610.             if(!yesno(str2)) {
  611.                 if(curmsg<msgs-1) curmsg++;
  612.                 else done=1;
  613.                 break;    }
  614.             /* Case 'D': must follow! */
  615.         case 'D':   /* Delete last piece (toggle) */
  616.             if(msg.hdr.attr&MSG_PERMANENT) {
  617.                 bputs("\r\nPermanent message.\r\n");
  618.                 domsg=0;
  619.                 break; }
  620.             if(msg.total_hfields)
  621.                 smb_freemsgmem(&msg);
  622.             msg.total_hfields=0;
  623.             msg.idx.offset=0;
  624.             if(loadmsg(&msg,msg.idx.number)) {
  625.                 msg.hdr.attr^=MSG_DELETE;
  626.                 msg.idx.attr=msg.hdr.attr;
  627. //                  mail[curmsg].attr=msg.hdr.attr;
  628.                 if((i=smb_putmsg(&smb,&msg))!=0)
  629.                     errormsg(WHERE,ERR_WRITE,smb.file,i);
  630.                 smb_unlockmsghdr(&smb,&msg); }
  631.             if(curmsg<msgs-1) curmsg++;
  632.             else done=1;
  633.             break;
  634.         case 'F':  /* Forward last piece */
  635.             domsg=0;
  636.             bputs(text[ForwardMailTo]);
  637.             if(!getstr(str,LEN_ALIAS,K_UPRLWR))
  638.                 break;
  639.             i=finduser(str);
  640.             if(!i)
  641.                 break;
  642.             domsg=1;
  643.             if(curmsg<msgs-1) curmsg++;
  644.             else done=1;
  645.             smb_getmsgidx(&smb,&msg);
  646.             forwardmail(&msg,i);
  647.             if(msg.hdr.attr&MSG_PERMANENT)
  648.                 break;
  649.             sprintf(str2,text[DeleteMailQ],msg.from);
  650.             if(!yesno(str2))
  651.                 break;
  652.             if(msg.total_hfields)
  653.                 smb_freemsgmem(&msg);
  654.             msg.total_hfields=0;
  655.             msg.idx.offset=0;
  656.             if(loadmsg(&msg,msg.idx.number)) {
  657.                 msg.hdr.attr|=MSG_DELETE;
  658.                 msg.idx.attr=msg.hdr.attr;
  659. //                  mail[curmsg].attr=msg.hdr.attr;
  660.                 if((i=smb_putmsg(&smb,&msg))!=0)
  661.                     errormsg(WHERE,ERR_WRITE,smb.file,i);
  662.                 smb_unlockmsghdr(&smb,&msg); }
  663.  
  664.             break;
  665.         case 'L':     /* List mail */
  666.             domsg=0;
  667.             bprintf(text[StartWithN],(long)curmsg+1);
  668.             if((i=getnum(msgs))>0)
  669.                 i--;
  670.             else if(i==-1)
  671.                 break;
  672.             else
  673.                 i=curmsg;
  674.             if(which==MAIL_SENT)
  675.                 bputs(text[MailSentLstHdr]);
  676.             else if(which==MAIL_ALL)
  677.                 bputs(text[MailOnSystemLstHdr]);
  678.             else
  679.                 bputs(text[MailWaitingLstHdr]);
  680.             for(;i<msgs && !msgabort();i++) {
  681.                 if(msg.total_hfields)
  682.                     smb_freemsgmem(&msg);
  683.                 msg.total_hfields=0;
  684.                 msg.idx.offset=mail[i].offset;
  685.                 if(!loadmsg(&msg,mail[i].number))
  686.                     continue;
  687.                 smb_unlockmsghdr(&smb,&msg);
  688.                 if(which==MAIL_ALL)
  689.                     bprintf(text[MailOnSystemLstFmt]
  690.                         ,i+1,msg.from,msg.to
  691.                         ,msg.hdr.attr&MSG_DELETE ? '-'
  692.                             : msg.hdr.attr&MSG_READ ? SP
  693.                             : msg.from_net.type || msg.to_net.type ? 'N':'*'
  694.                         ,msg.subj);
  695.                 else
  696.                     bprintf(text[MailWaitingLstFmt],i+1
  697.                         ,which==MAIL_SENT ? msg.to
  698.                         : (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
  699.                         ? text[Anonymous] : msg.from
  700.                         ,msg.hdr.attr&MSG_DELETE ? '-'
  701.                             : msg.hdr.attr&MSG_READ ? SP
  702.                             : msg.from_net.type || msg.to_net.type ? 'N':'*'
  703.                         ,msg.subj);
  704.                 smb_freemsgmem(&msg);
  705.                 msg.total_hfields=0; }
  706.             break;
  707.         case 'Q':
  708.             done=1;
  709.             break;
  710.         case 'C':   /* Change attributes of last piece */
  711.             i=chmsgattr(msg.hdr.attr);
  712.             if(msg.hdr.attr==i)
  713.                 break;
  714.             if(msg.total_hfields)
  715.                 smb_freemsgmem(&msg);
  716.             msg.total_hfields=0;
  717.             msg.idx.offset=0;
  718.             if(loadmsg(&msg,msg.idx.number)) {
  719.                 msg.hdr.attr=msg.idx.attr=i;
  720.                 if((i=smb_putmsg(&smb,&msg))!=0)
  721.                     errormsg(WHERE,ERR_WRITE,smb.file,i);
  722.                 smb_unlockmsghdr(&smb,&msg); }
  723.             break;
  724.         case '>':
  725.             for(i=curmsg+1;i<msgs;i++)
  726.                 if(mail[i].subj==msg.idx.subj)
  727.                     break;
  728.             if(i<msgs)
  729.                 curmsg=i;
  730.             else
  731.                 domsg=0;
  732.             break;
  733.         case '<':   /* Search Title backward */
  734.             for(i=curmsg-1;i>-1;i--)
  735.                 if(mail[i].subj==msg.idx.subj)
  736.                     break;
  737.             if(i>-1)
  738.                 curmsg=i;
  739.             else
  740.                 domsg=0;
  741.             break;
  742.         case '}':   /* Search Author forward */
  743.             strcpy(str,msg.from);
  744.             for(i=curmsg+1;i<msgs;i++)
  745.                 if(mail[i].from==msg.idx.from)
  746.                     break;
  747.             if(i<msgs)
  748.                 curmsg=i;
  749.             else
  750.                 domsg=0;
  751.             break;
  752.         case 'N':   /* Got to next un-read message */
  753.             for(i=curmsg+1;i<msgs;i++)
  754.                 if(!(mail[i].attr&MSG_READ))
  755.                     break;
  756.             if(i<msgs)
  757.                 curmsg=i;
  758.             else
  759.                 domsg=0;
  760.             break;
  761.         case '{':   /* Search Author backward */
  762.             strcpy(str,msg.from);
  763.             for(i=curmsg-1;i>-1;i--)
  764.                 if(mail[i].from==msg.idx.from)
  765.                     break;
  766.             if(i>-1)
  767.                 curmsg=i;
  768.             else
  769.                 domsg=0;
  770.             break;
  771.         case ']':   /* Search To User forward */
  772.             strcpy(str,msg.to);
  773.             for(i=curmsg+1;i<msgs;i++)
  774.                 if(mail[i].to==msg.idx.to)
  775.                     break;
  776.             if(i<msgs)
  777.                 curmsg=i;
  778.             else
  779.                 domsg=0;
  780.             break;
  781.         case '[':   /* Search To User backward */
  782.             strcpy(str,msg.to);
  783.             for(i=curmsg-1;i>-1;i--)
  784.                 if(mail[i].to==msg.idx.to)
  785.                     break;
  786.             if(i>-1)
  787.                 curmsg=i;
  788.             else
  789.                 domsg=0;
  790.             break;
  791.         case 0:
  792.         case '+':
  793.             if(curmsg<msgs-1) curmsg++;
  794.             else done=1;
  795.             break;
  796.         case '-':
  797.             if(curmsg>0) curmsg--;
  798.             break;
  799.         case 'S':
  800.             domsg=0;
  801. /*
  802.             if(!yesno(text[SaveMsgToFile]))
  803.                 break;
  804. */
  805.             bputs(text[FileToWriteTo]);
  806.             if(getstr(str,40,K_LINE|K_UPPER))
  807.                 msgtotxt(msg,str,1,1);
  808.             break;
  809.         case 'E':
  810.             editmsg(&msg,INVALID_SUB);
  811.             break;
  812.         case 'T':
  813.             domsg=0;
  814.             i=curmsg;
  815.             if(i) i++;
  816.             j=i+10;
  817.             if(j>msgs)
  818.                 j=msgs;
  819.  
  820.             if(which==MAIL_SENT)
  821.                 bputs(text[MailSentLstHdr]);
  822.             else if(which==MAIL_ALL)
  823.                 bputs(text[MailOnSystemLstHdr]);
  824.             else
  825.                 bputs(text[MailWaitingLstHdr]);
  826.             for(;i<j;i++) {
  827.                 if(msg.total_hfields)
  828.                     smb_freemsgmem(&msg);
  829.                 msg.total_hfields=0;
  830.                 msg.idx.offset=mail[i].offset;
  831.                 if(!loadmsg(&msg,mail[i].number))
  832.                     continue;
  833.                 smb_unlockmsghdr(&smb,&msg);
  834.                 if(which==MAIL_ALL)
  835.                     bprintf(text[MailOnSystemLstFmt]
  836.                         ,i+1,msg.from,msg.to
  837.                         ,msg.hdr.attr&MSG_DELETE ? '-'
  838.                             : msg.hdr.attr&MSG_READ ? SP
  839.                             : msg.from_net.type || msg.to_net.type ? 'N':'*'
  840.                         ,msg.subj);
  841.                 else
  842.                     bprintf(text[MailWaitingLstFmt],i+1
  843.                         ,which==MAIL_SENT ? msg.to
  844.                         : (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
  845.                         ? text[Anonymous] : msg.from
  846.                         ,msg.hdr.attr&MSG_DELETE ? '-'
  847.                             : msg.hdr.attr&MSG_READ ? SP
  848.                             : msg.from_net.type || msg.to_net.type ? 'N':'*'
  849.                         ,msg.subj);
  850.                 smb_freemsgmem(&msg);
  851.                 msg.total_hfields=0; }
  852.             curmsg=(i-1);
  853.             break;
  854.         case 'U':   /* user edit */
  855.             msg.hdr.number=msg.idx.number;
  856.             smb_getmsgidx(&smb,&msg);
  857.             useredit(which==MAIL_SENT ? msg.idx.to : msg.idx.from,0);
  858.             break;
  859.         case 'P':   /* Purge author and all mail to/from */
  860.             if(noyes(text[AreYouSureQ]))
  861.                 break;
  862.             msg.hdr.number=msg.idx.number;
  863.             smb_getmsgidx(&smb,&msg);
  864.             purgeuser(msg.idx.from);
  865.             if(curmsg<msgs-1) curmsg++;
  866.             break;
  867.         case '?':
  868.             strcpy(str,which==MAIL_YOUR ? "MAILREAD" : which==MAIL_ALL
  869.                     ? "ALLMAIL" : "SENTMAIL");
  870.             menu(str);
  871.             if(SYSOP && which==MAIL_SENT)
  872.                 menu("SYSSMAIL");
  873.             else if(SYSOP && which==MAIL_YOUR)
  874.                 menu("SYSMAILR");   /* Sysop Mail Read */
  875.             domsg=0;
  876.             break;
  877.             } }
  878.  
  879. if(msg.total_hfields)
  880.     smb_freemsgmem(&msg);
  881.  
  882. if(msgs)
  883.     FREE(mail);
  884.  
  885. /***************************************/
  886. /* Delete messages marked for deletion */
  887. /***************************************/
  888.  
  889. if(sys_misc&SM_DELEMAIL) {
  890.     if((i=smb_locksmbhdr(&smb))!=0)             /* Lock the base, so nobody */
  891.         errormsg(WHERE,ERR_LOCK,smb.file,i);    /* messes with the index */
  892.     else
  893.         delmail(usernumber,which); }
  894.  
  895. smb_close(&smb);
  896. smb_stack(&smb,SMB_STACK_POP);
  897. }
  898.  
  899.