home *** CD-ROM | disk | FTP | other *** search
/ The Unsorted BBS Collection / thegreatunsorted.tar / thegreatunsorted / programming / asm_programming / MJRDEVEL.ARC / ESGUTL.C < prev    next >
Text File  |  1989-03-20  |  39KB  |  1,361 lines

  1. /***************************************************************************
  2.  *                                                                         *
  3.  *   ESGUTL.C                                                              *
  4.  *                                                                         *
  5.  *   Copyright (C) 1988,1989 GALACTICOMM, Inc.    All Rights Reserved.     *
  6.  *                                                                         *
  7.  *   E-Mail and SIG utilities and common-code segments.                    *
  8.  *                                                                         *
  9.  *                                  - T. Stryker 7/28/88                   *
  10.  *                                                                         *
  11.  ***************************************************************************/
  12.  
  13. #include "stdio.h"
  14. #include "ctype.h"
  15. #include "majorbbs.h"
  16. #include "usracc.h"
  17. #include "btvstf.h"
  18. #include "esigs.h"
  19. #include "message.h"
  20. #include "dosface.h"
  21. #include "portable.h"
  22.  
  23. static
  24. int reclen[]={                /* array of byte counts for download records */
  25.      0,                       /*   NULL position for dnltyp[0] index       */
  26.      0,                       /*   ASCII download, no byte count needed    */
  27.      128+4,                   /*   XMODEM (128 byte blocks)                */
  28.      128+5,                   /*   XMODEM CRC (128 byte blocks)            */
  29.      1024+5                   /*   YMODEM CRC (1K blocks)                  */
  30. };
  31.  
  32. static
  33. int blksiz[]={                /* array of byte counts for download blocks  */
  34.      0,                       /*   NULL position for dnltyp[0] index       */
  35.      0,                       /*   ASCII download, no byte count needed    */
  36.      128,                     /*   XMODEM (128 byte blocks)                */
  37.      128,                     /*   XMODEM CRC (128 byte blocks)            */
  38.      1024                     /*   YMODEM CRC (1K blocks)                  */
  39. };
  40.  
  41. #define ACK  6                /* ASCII controls chars used in XMODEM       */
  42. #define NAK 21
  43. #define CCC 67                /*   'C' (rep's NAK) tells sender use CRC-16 */
  44. #define SOH  1
  45. #define STX  2                /*   (rep's SOH) tells rcver 1024-byte block */
  46. #define EOT  4
  47. #define CAN 24
  48.  
  49. #define NAKSTG (esgptr->fxftyp == UPLTYPS+2 ? "\25" : "\103")
  50.  
  51. FILE *esgmb;                  /* esigs named-message file block ptr        */
  52. BTVFILE *esgbb;               /* esigs btrieve message file block ptr      */
  53. BTVFILE *qscbb;               /* esigs quickscan/config btrieve file ptr   */
  54. struct compos compos;         /* concrete allocation of composite struct   */
  55. long filen;                   /* length of attachment found, from opnatt() */
  56. int esgstt;                   /* current/new usrptr->substt hold register  */
  57. struct sigdat *sigdat,        /* ram-resident SIG data tables base address */
  58.               *sdtptr;        /* scratch ptr for scanning thru sigdat      */
  59. struct sofars *sfrptr;        /* scratch ptr for scanning thru sofars      */
  60. struct qscfg *sopqsc,         /* singular SYSOP/SIG-Op scratch area        */
  61.              *qscfgs,         /* base ptr to dynam allocated array         */
  62.              *qscptr;         /* ptr to current user's qscfgs entry        */
  63. struct usracc *sopusa;        /* singular SYSOP/SIG-Op scratch acct        */
  64.  
  65. char dftnlv[MAXSIG/2],       /* default non-live SIG access bits     */
  66.      dftliv[MAXSIG/2],       /* default live SIG access bits         */
  67.      maxnlv[MAXSIG/2];       /* maximum non-live SIG access bits     */
  68.  
  69. char *accstg[]={"Zero","","Read","","Download","","Write","",
  70.                 "Upload","","Co-Op","","SIG-Op","","SYSOP","<unassigned>"};
  71.  
  72. char uptmrs[64];              /* array of upload/download timers per usrnum*/
  73.  
  74. #define either(x,y) (esgptr->usigno == NOSIG ? (x) : (y)) /* E-Mail vs SIG */
  75.  
  76. #define MEMENU REPRMT
  77. #define MSMENU (readac() >= OPAXES ? ORSPRMT : RSPRMT)
  78. #define MMENU  either(MEMENU,MSMENU)
  79. #define HUH    either(EMLHUH,SIGHUH)
  80.  
  81. iniesg()                      /* initialize email and sigs                 */
  82. {
  83.      if (esgmb == NULL) {
  84.           esgmb=opnmsg("esigs.mcv");
  85.           dclvda(sizeof(struct esgusr));
  86.           qscbb=opnbtv("qscfg.dat",sizeof(struct qscfg));
  87.           esgbb=opnbtv("esigs.dat",sizeof(struct message));
  88.           emrtcy();
  89.           inieml();
  90.           inisig();
  91.      }
  92. }
  93.  
  94. fireup()                      /* fire up status 3 input handling           */
  95. {
  96.      setmbk(esgmb);
  97.      setbtv(esgbb);
  98.      esgstt=usrptr->substt;
  99.      qscptr=&qscfgs[usrnum];
  100.  
  101.      if (usrptr->flags&INJOIP) {
  102.           prompt(esgstt);
  103.      }
  104.      else if (esgstt == UPASC) {
  105.           usrptr->pfnacc=0;
  106.           return(1);
  107.      }
  108.      else if (usrptr->pfnacc > MAXPFN) {
  109.           byenow(MUCH2P);
  110.      }
  111.      else if (usrptr->pfnacc > WRNPFN && pfnlvl > 0) {
  112.           errmsg(RAUNCH);
  113.      }
  114.      else if (pfnlvl > 2) {
  115.           errmsg(PFNMSG);
  116.      }
  117.      else {
  118.           chkdft(esgptr->dftinp);
  119.           return(1);
  120.      }
  121.      return(0);
  122. }
  123.  
  124. hdlesg()                      /* handle common email/sigs substates        */
  125. {
  126.      switch (esgstt) {
  127.      case DNLNOW:
  128.      case DWNAGN:
  129.           sdnldq();
  130.           break;
  131.      case ASCORX:
  132.           sascorx();
  133.           break;
  134.      case GOASC:
  135.           abodnl();
  136.           break;
  137.      case EDITING:
  138.           sediting();
  139.           break;
  140.      case ATTFIQ:
  141.      case UPLAGN:
  142.           sattfiq();
  143.           break;
  144.      case UPMODE:
  145.      case UPMSOP:
  146.           supmode();
  147.           break;
  148.      case SOPFSP:
  149.           ssopfsp();
  150.           break;
  151.      case UPASC:
  152.           supasc();
  153.           break;
  154.      case UPXMDM:
  155.      case GOXMDM:
  156.      case COMPLT:
  157.           prf("");
  158.           break;
  159.      default:
  160.           catastro("E/SIGS STATE ERROR (esgstt=%d)",esgstt);
  161.      }
  162. }
  163.  
  164. dnload(whndun)                /* download attachment, invoke arg when done */
  165. int (*whndun)();
  166. {
  167.      if (attfs() != NULL && filen >= 0) {
  168.           prfmsg(ATTMNT,ltoa(filen));
  169.           prompt(DNLNOW);
  170.           esgptr->whndun=whndun;
  171.      }
  172.      else {
  173.           prfmsg(ATTNF,ltoa(esgptr->msg.msgno));
  174.           cncall();
  175.           (*whndun)();
  176.      }
  177. }
  178.  
  179. sdnldq()                      /* state: do you want to download file now?  */
  180. {
  181.      switch (cncyesno()) {
  182.      case 'Y':
  183.           prompt(ASCORX);
  184.           break;
  185.      case 'N':
  186.           (*esgptr->whndun)();
  187.           break;
  188.      default:
  189.           errmsg(YORN);
  190.      }
  191. }
  192.  
  193. sascorx()                     /* state: ascii or xmodem flavor choice      */
  194. {
  195.      char c;
  196.      char *ostyle;
  197.  
  198.      switch (c=cncchr()) {
  199.      case '?':
  200.           prohlp(ASCXHL);
  201.           return;
  202.      case '1':
  203.           if (cncchr() == 'C') {
  204.                btuxnf(usrnum,0,19);
  205.           }
  206.           cncall();
  207.           prompt(GOASC);
  208.           btuinj(usrnum,CYCLE);
  209.           ostyle=FOPRA;
  210.           btuech(usrnum,0);
  211.           break;
  212.      case '2':
  213.      case '3':
  214.      case '4':
  215.           cncall();
  216.           prompt(GOXMDM);
  217.           btutrg(usrnum,1);
  218.           esgptr->blknum=1;
  219.           esgptr->lstsiz=0;
  220.           esgptr->curpos=0L;
  221.           ostyle=FOPRB;
  222.           break;
  223.      default:
  224.           errmsg(HUH);
  225.           return;
  226.      }
  227.      esgptr->fxftyp=c-'0';
  228.      usrptr->flags|=NOINJO;
  229.      if ((esgptr->fp=fopen(attfs(),ostyle)) == NULL || filen < 0) {
  230.           dnloff();
  231.           clrprf();
  232.           esgstt=REFPN;
  233.           errmsg(ATTNF,ltoa(esgptr->msg.msgno));
  234.      }
  235. }
  236.  
  237. dnloff()                      /* turn downloading process off              */
  238. {
  239.      if (esgptr->fxftyp > 0 && esgptr->fxftyp < UPLTYPS) {
  240.           esgptr->fxftyp=0;
  241.           btuoes(usrnum,0);
  242.           btutrg(usrnum,0);
  243.           echon();
  244.           btucli(usrnum);
  245.           usrptr->flags&=~(NOINJO+NOZAP);
  246.           rstrxf();
  247.           if (esgptr->fp != NULL) {
  248.                fclose(esgptr->fp);
  249.                esgptr->fp=NULL;
  250.           }
  251.      }
  252. }
  253.  
  254. emrtcy()                      /* once-a-second real-time cycler            */
  255. {
  256.      for (usrnum=0 ; usrnum < nterms ; usrnum++) {
  257.           if (uptmrs[usrnum] != 0 && --uptmrs[usrnum] == 0) {
  258.                btuinj(usrnum,CYCLE);
  259.           }
  260.      }
  261.      rtkick(1,emrtcy);
  262. }
  263.  
  264. emsthn()                      /* email/sigs status handler                 */
  265. {
  266.      char ch;
  267.      int ibw;
  268.  
  269.      setmbk(esgmb);
  270.      setbtv(esgbb);
  271.      qscptr=&qscfgs[usrnum];
  272.      esgstt=usrptr->substt;
  273.      switch (esgstt) {
  274.      case GOASC:
  275.           switch (status) {
  276.           case CYCLE:
  277.                btucli(usrnum);
  278.                if (btuoba(usrnum) < 1024) {
  279.                     btuinj(usrnum,CYCLE);
  280.                     break;
  281.                }
  282.                else if (fgets(prfbuf,1024,esgptr->fp) != NULL) {
  283.                     prfbuf[strlen(prfbuf)-1]='\r';
  284.                     outprf(usrnum);
  285.                     btuinj(usrnum,CYCLE);
  286.                }
  287.                else {
  288.                     btuoes(usrnum,1);
  289.                     if (btuoba(usrnum) == OUTSIZ-1) {
  290.                          btuinj(usrnum,OUTMT);
  291.                     }
  292.                     esgstt=COMPLT;
  293.                }
  294.                break;
  295.           default:
  296.                dfsthn();
  297.           }
  298.           break;
  299.      case GOXMDM:
  300.           switch (status) {
  301.           case INBLK:
  302.                btuict(usrnum,&ch);
  303.                switch (ch) {
  304.                case CCC:
  305.                     if (esgptr->fxftyp == 2) {
  306.                          esgptr->fxftyp=3;
  307.                     }
  308.                case NAK:
  309.                     esgptr->curpos-=esgptr->lstsiz;
  310.                     if (fseek(esgptr->fp,esgptr->curpos,0) != 0) {
  311.                          catastro("GOXMDM FSEEK ERROR");
  312.                     }
  313.                     esgptr->blknum-=1;
  314.                case ACK:
  315.                     setmem(prfbuf+3,blksiz[esgptr->fxftyp],0);
  316.                     if ((esgptr->lstsiz=fread(prfbuf+3,1,
  317.                        blksiz[esgptr->fxftyp],esgptr->fp)) > 0) {
  318.                          esgptr->blknum=((esgptr->blknum+1)&0xFF);
  319.                          prfbuf[0]=(blksiz[esgptr->fxftyp] == 1024 ? STX : SOH);
  320.                          prfbuf[1]=(char)(esgptr->blknum);
  321.                          prfbuf[2]=(char)(esgptr->blknum^0xFF);
  322.                          switch (esgptr->fxftyp) {
  323.                          case 2:
  324.                               prfbuf[131]=cksumv(prfbuf+3,128);
  325.                               break;
  326.                          case 3:
  327.                               mkcrc(128);
  328.                               break;
  329.                          case 4:
  330.                               mkcrc(1024);
  331.                               break;
  332.                          }
  333.                          btuxct(usrnum,reclen[esgptr->fxftyp],prfbuf);
  334.                          esgptr->curpos+=esgptr->lstsiz;
  335.                     }
  336.                     else {
  337.                          prfbuf[0]=EOT;
  338.                          btuxct(usrnum,1,prfbuf);
  339.                          uptmrs[usrnum]=2;
  340.                          esgstt=COMPLT;
  341.                     }
  342.                     break;
  343.                case CAN:
  344.                     abodnl();
  345.                     outprf(usrnum);
  346.                     break;
  347.                }
  348.                break;
  349.           default:
  350.                dfsthn();
  351.           }
  352.           break;
  353.      case COMPLT:
  354.           switch (status) {
  355.           case CYCLE:
  356.                btuoes(usrnum,1);
  357.                setmem(prfbuf,10,EOT);
  358.                btuxct(usrnum,10,prfbuf);
  359.                break;
  360.           case OUTMT:
  361.                goodnl();
  362.                outprf(usrnum);
  363.                break;
  364.           default:
  365.                dfsthn();
  366.           }
  367.           break;
  368.      case UPXMDM:
  369.           switch (status) {
  370.           case CYCLE:
  371.                ibw=btuibw(usrnum);
  372.                if (esgptr->lstsiz == ibw) {
  373.                     prfbuf[0]=0;
  374.                     btuict(usrnum,prfbuf);
  375.                     if (prfbuf[0] == EOT || prfbuf[0] == CAN) {
  376.                          btubsz(usrnum,INPSIZ,OUTSIZ);
  377.                          btuxct(usrnum,1,"\6");          /* ACK, done */
  378.                          if (prfbuf[0] == CAN) {
  379.                               donupl(0);
  380.                               prompt(UPLAGN);
  381.                          }
  382.                          else {
  383.                               donupl(1);
  384.                               (*esgptr->whndun)();
  385.                          }
  386.                          outprf(usrnum);
  387.                          break;
  388.                     }
  389.                     btuxct(usrnum,1,NAKSTG);             /* NAK */
  390.                     btucli(usrnum);
  391.                }
  392.                else {
  393.                     esgptr->lstsiz=ibw;
  394.                }
  395.                uptmrs[usrnum]=3;
  396.                break;
  397.           case INBLK:
  398.                btuict(usrnum,prfbuf);
  399.                if (prfbuf[0] != SOH && prfbuf[0] != STX) {
  400.                     break;
  401.                }
  402.                else if (prfbuf[1] == (char)((esgptr->blknum-1)&0xFF)
  403.                      && prfbuf[2] == (char)(((esgptr->blknum-1)^0xFF)&0xFF)) {
  404.                     btuxct(usrnum,1,"\6");               /* ACK but ignore */
  405.                }
  406.                else if (prfbuf[1] == (char)(esgptr->blknum&0xFF)
  407.                  && prfbuf[2] == (char)((esgptr->blknum^0xFF)&0xFF)) {
  408.                     if (cksmok()) {
  409.                          btuxct(usrnum,1,"\6");          /* ACK and accept */
  410.                          esgptr->blknum+=1;
  411.                          fwrite(prfbuf+3,1,blksiz[esgptr->fxftyp-UPLTYPS],
  412.                                         esgptr->fp);
  413.                     }
  414.                }
  415.                break;
  416.           default:
  417.                dfsthn();
  418.           }
  419.           break;
  420.      default:
  421.           if (status == CYCLE) {
  422.                cycmed();
  423.           }
  424.           else {
  425.                dfsthn();
  426.           }
  427.      }
  428.      usrptr->substt=esgstt;
  429. }
  430.  
  431. abodnl()                      /* abort download                            */
  432. {
  433.      btuclo(usrnum);
  434.      dnloff();
  435.      esgstt=DWNAGN;
  436.      errmsg(ABORTD);
  437. }
  438.  
  439. goodnl()                      /* good download, finish up and go on        */
  440. {
  441.      sv.dwnlds+=1;
  442.      if (either(ednaud,sdnaud)) {
  443.           shocst(1,"%s D:%s",usaptr->userid,attfs());
  444.      }
  445.      dnloff();
  446.      prfmsg(COMPLT);
  447.      (*esgptr->whndun)();
  448. }
  449.  
  450. mkcrc(len)                    /* make CRC from prfbuf record, len long     */
  451. int len;
  452. {
  453.      int crc;
  454.  
  455.      crc=ckscrc(prfbuf+3,len);
  456.      prfbuf[len+3]=(char)(crc>>8);
  457.      prfbuf[len+4]=(char)(crc&0xFF);
  458. }
  459.  
  460. cksmok()                      /* check if record in prfbuf checksum is ok  */
  461. {
  462.      int typ,crc,len;
  463.  
  464.      switch (typ=esgptr->fxftyp-UPLTYPS) {
  465.      case 2:
  466.           return(cksumv(prfbuf+3,128) == prfbuf[131]);
  467.      case 3:
  468.      case 4:
  469.           len=blksiz[typ];
  470.           crc=ckscrc(prfbuf+3,len);
  471.           return((char)(crc>>8) == prfbuf[len+3]
  472.               && (char)(crc&0xFF) == prfbuf[len+4]);
  473.      }
  474.      return(0);
  475. }
  476.  
  477. cksumv(stg,len)               /* compute XMODEM checksum value             */
  478. char *stg;
  479. int len;
  480. {
  481.      int cks=0;
  482.  
  483.      while (--len >= 0) {
  484.           cks+=*stg++;
  485.      }
  486.      return(cks&0xFF);
  487. }
  488.  
  489. int ckscrc(stg,len)           /* compute CRC value                         */
  490. char *stg;
  491. int len;
  492. {
  493.      int crc,i;
  494.  
  495.      crc=0;
  496.      while (--len >= 0) {
  497.           crc=crc^((int)*stg++<<8);
  498.           for (i=0 ; i < 8 ; i++) {
  499.                if (crc&0x8000) {
  500.                     crc=(crc<<1)^0x1021;
  501.                }
  502.                else {
  503.                    crc=crc<<1;
  504.                }
  505.           }
  506.      }
  507.      return(crc);
  508. }
  509.  
  510. possat(rouptr)                /* possibly begin attachment proceedings     */
  511. int (*rouptr)();
  512. {
  513.      int sn;
  514.  
  515.      if ((sn=findsig(esgptr->msg.to)) == NOSIG || rdautl(sn) >= ULAXES) {
  516.           prompt(ATTFIQ);
  517.           esgptr->whndun=rouptr;
  518.      }
  519.      else {
  520.           (*rouptr)();
  521.      }
  522. }
  523.  
  524. sattfiq()                     /* state: attach file to this msg?           */
  525. {
  526.      switch (cncyesno()) {
  527.      case 'Y':
  528.           if (either(credok(nlveat,eattck),credsf(esgptr->sattck))) {
  529.                prompt((usrptr->flags&ISYSOP) ? UPMSOP : UPMODE);
  530.           }
  531.           break;
  532.      case 'N':
  533.           if (esgstt != ATTFIQ) {
  534.                prfmsg(NUPLD);
  535.           }
  536.           (*esgptr->whndun)();
  537.           break;
  538.      default:
  539.           errmsg(YORN);
  540.      }
  541. }
  542.  
  543. supmode()                     /* state: what upload mode?                  */
  544. {
  545.      char c;
  546.      char *ostyle;
  547.  
  548.      switch (c=cncchr()) {
  549.      case '?':
  550.           prohlp(esgstt == UPMODE ? UPMODH : UPMSPH);
  551.           return;
  552.      case '1':
  553.           cncall();
  554.           prompt(UPASC);
  555.           btumil(usrnum,INPSIZ);
  556.           ostyle=FOPWA;
  557.           break;
  558.      case '2':
  559.      case '3':
  560.      case '4':
  561.           cncall();
  562.           prompt(UPXMDM);
  563.           uptmrs[usrnum]=2;
  564.           btubsz(usrnum,OUTSIZ,INPSIZ);
  565.           btutrg(usrnum,reclen[c-'0']);
  566.           esgptr->lstsiz=-1;
  567.           esgptr->blknum=1;
  568.           ostyle=FOPWB;
  569.           break;
  570.      case '5':
  571.           if (usrptr->flags&ISYSOP) {
  572.                prompt(SOPFSP);
  573.                return;
  574.           }
  575.      default:
  576.           errmsg(HUH);
  577.           return;
  578.      }
  579.      esgptr->fxftyp=c-'0'+UPLTYPS;
  580.      usrptr->flags|=NOINJO;
  581.      if ((esgptr->fp=fopen(attfs(),ostyle)) == NULL) {
  582.           uploff(0);
  583.           clrprf();
  584.           esgstt=UPLAGN;
  585.           errmsg(UPLFER);
  586.      }
  587. }
  588.  
  589. ssopfsp()                     /* state: SYSOP file spec entry (opt 5)      */
  590. {
  591.      FILE *fp;
  592.  
  593.      setmem(prfbuf,FSPSIZ,0);
  594.      strcpy(prfbuf,cncall());
  595.      if ((fp=fopen(prfbuf,FOPRA)) == NULL) {
  596.           esgstt=UPLAGN;
  597.           errmsg(SFSNXS);
  598.      }
  599.      else {
  600.           fclose(fp);
  601.           if ((fp=fopen(attfsd(),FOPWA)) == NULL) {
  602.                esgstt=UPLAGN;
  603.                errmsg(SOPFER);
  604.           }
  605.           else {
  606.                fwrite(prfbuf,1,FSPSIZ-1,fp);
  607.                fclose(fp);
  608.                esgptr->msg.flags|=INDRCT+FILATT+APPVED;
  609.                prfmsg(IATTAP);
  610.                (*esgptr->whndun)();
  611.           }
  612.      }
  613. }
  614.  
  615. supasc()                      /* state: uploading ascii file               */
  616. {
  617.      cncall();
  618.      if (sameas(input,"OK")) {
  619.           uploff(1);
  620.           (*esgptr->whndun)();
  621.      }
  622.      else {
  623.           fprintf(esgptr->fp,"%s\n",input);
  624.           prf("");
  625.      }
  626. }
  627.  
  628. uploff(keep)                  /* turn uploading off, keep or delete file   */
  629. int keep;
  630. {
  631.      btumil(usrnum,DFTIMX);
  632.      if (esgptr->fxftyp > UPLTYPS) {
  633.           btubsz(usrnum,INPSIZ,OUTSIZ);
  634.           donupl(keep);
  635.      }
  636. }
  637.  
  638. donupl(keep)                  /* done with upload, keep or delete file     */
  639. int keep;
  640. {
  641.      int sn;
  642.  
  643.      esgptr->fxftyp=0;
  644.      usrptr->flags&=~NOINJO;
  645.      btutrg(usrnum,0);
  646.      if (esgptr->fp != NULL) {
  647.           fclose(esgptr->fp);
  648.           esgptr->fp=NULL;
  649.           if (keep) {
  650.                if ((sn=findsig(esgptr->msg.to)) == NOSIG) {
  651.                     esgptr->msg.flags|=FILATT+APPVED;
  652.                     prfmsg(UPDONE);
  653.                }
  654.                else if (rdautl(sn) >= COAXES) {
  655.                     esgptr->msg.flags|=FILATT+APPVED;
  656.                     prfmsg(FILAVL);
  657.                }
  658.                else {
  659.                     esgptr->msg.flags|=FILATT;
  660.                     prfmsg(FILNVL);
  661.                }
  662.                sv.uplds+=1;
  663.                if (either(eupaud,supaud)) {
  664.                     shocst(1,"%s U:%s",usaptr->userid,attfs());
  665.                }
  666.           }
  667.           else {
  668.                prfmsg(UPLCAN);
  669.                unlink(attfsd());
  670.           }
  671.      }
  672. }
  673.  
  674. edimsg(clr,tpc,whndun)        /* fire up editor, invoke whndun when done   */
  675. int clr,tpc,(*whndun)();
  676. {
  677.      if (clr) {
  678.           mkmsgn();
  679.           esgptr->msg.flags=0;
  680.      }
  681.      bgnedt(clr,TXTSIZ,esgptr->msg.text,TPCSIZ,tpc ? esgptr->msg.topic : NULL);
  682.      esgptr->whndun=whndun;
  683.      esgstt=EDITING;
  684.      esgptr->dftinp='\0';
  685. }
  686.  
  687. sediting()                    /* state: in the editor                      */
  688. {
  689.      if (dunedt()) {
  690.           (*esgptr->whndun)();
  691.      }
  692.      else {
  693.           prf("");
  694.      }
  695. }
  696.  
  697. uidxst(uid)                   /* does this User-ID exist?                  */
  698. char *uid;
  699. {
  700.      int retval;
  701.  
  702.      setbtv(accbb);
  703.      retval=qeqbtv(uid,0);
  704.      setbtv(esgbb);
  705.      return(retval);
  706. }
  707.  
  708. char *
  709. attfsd()                      /* attachment filespec, "direct" only        */
  710. {
  711.      static char filespec[FSPSIZ];
  712.      char *fnp;
  713.      int fnplen;
  714.  
  715.      strcpy(filespec,esgptr->msg.to[0] == SIGIDC ? esgptr->msg.to+1 : "email");
  716.      fnp=spr("\\%ld.att",esgptr->msg.msgno);
  717.      while ((fnplen=strlen(fnp)) >= 14) {         /* ensures over 2 billion */
  718.           fnp[fnplen-2]=fnp[fnplen-1];            /*   unique filenames     */
  719.           fnp[fnplen-1]=fnp[1];
  720.           movmem(fnp+2,fnp+1,strlen(fnp+1));
  721.      }
  722.      strcat(filespec,fnp);
  723.      return(filespec);
  724. }
  725.  
  726. char *
  727. attfs()                       /* attachment filespec, net (may be indirect)*/
  728. {
  729.      FILE *indrfp;
  730.      struct fndblk fb;
  731.      char *filespec;
  732.  
  733.      filespec=attfsd();
  734.      if (esgptr->msg.flags&INDRCT) {
  735.           if ((indrfp=fopen(filespec,FOPRA)) == NULL) {
  736.                return(NULL);
  737.           }
  738.           if (fread(filespec,1,FSPSIZ-1,indrfp) != FSPSIZ-1) {
  739.                fclose(indrfp);
  740.                return(NULL);
  741.           }
  742.           fclose(indrfp);
  743.      }
  744.      if (fnd1st(&fb,filespec,0)) {
  745.           filen=fb.size;
  746.      }
  747.      else {
  748.           filen=-1L;
  749.      }
  750.      return(filespec);
  751. }
  752.  
  753. findsig(name)                 /* find sig number, given name and access    */
  754. char *name;
  755. {
  756.      return(findsigu(name,1));
  757. }
  758.  
  759. findsigu(name,cond)           /* find sig number utility, conditionally    */
  760. char *name;
  761. int cond;
  762. {
  763.      int retval;
  764.  
  765.      for (retval=0,sdtptr=sigdat ; retval < nsigs ; retval++,sdtptr++) {
  766.           if (sameas(name,sdtptr->signam)) {
  767.                movmem(sdtptr->signam,name,UIDSIZ);
  768.                if (!cond) {
  769.                     return(retval);
  770.                }
  771.                return(rdautl(retval) == NOAXES ? NOSIG : retval);
  772.           }
  773.      }
  774.      return(NOSIG);
  775. }
  776.  
  777. addaux(newaux)                /* add on to existing auxillary msg topic    */
  778. char *newaux;
  779. {
  780.      char auxbuf[AXTSIZ*2];
  781.  
  782.      strcpy(auxbuf,newaux);
  783.      if (strlen(esgptr->msg.auxtpc) != 0 && !(esgptr->msg.flags&ISSHDR)) {
  784.           strcat(auxbuf,", ");
  785.           strcat(auxbuf,esgptr->msg.auxtpc);
  786.           if (strlen(auxbuf) > AXTSIZ-1) {
  787.                auxbuf[AXTSIZ-2]='*';
  788.                auxbuf[AXTSIZ-1]='\0';
  789.           }
  790.      }
  791.      strcpy(esgptr->msg.auxtpc,auxbuf);
  792. }
  793.  
  794. char *
  795. formax(leader)                /* form aux topic fragment, 15 chars max     */
  796. char *leader;
  797. {
  798.      static char auxbuf[AXTSIZ/2+1],*ltoap;
  799.  
  800.      strcpy(auxbuf,leader);
  801.      ltoap=ltoa(esgptr->msg.msgno);
  802.      strcpy(auxbuf+min(strlen(auxbuf),AXTSIZ/2-strlen(ltoap)-1),ltoap);
  803.      return(auxbuf);
  804. }
  805.  
  806. mkmsgn()                      /* make msg number                           */
  807. {
  808.      esgptr->msg.msgno=++sv.msgtot;
  809. }
  810.  
  811. postit()                      /* post the msg built                        */
  812. {
  813.      movmem(usaptr->userid,esgptr->msg.from,UIDSIZ);
  814.      esgptr->msg.crdate=today();
  815.      esgptr->msg.crtime=now();
  816.      esgptr->msg.nreply=0;
  817.      setbtv(esgbb);
  818.      insbtv(&esgptr->msg);
  819. }
  820.  
  821. stdcnf()                      /* standard confirmation after posting       */
  822. {
  823.      prfmsg(WCONFM,ltoa(esgptr->msg.msgno));
  824.      pstpst(SWRITU,SNOTIFD);
  825. }
  826.  
  827. pstpst(recip,sender)          /* "post-posting" cleanup                    */
  828. int recip,sender;
  829. {
  830.      outprf(usrnum);
  831.      figin(1);
  832.      if (onsys(esgptr->msg.to)) {
  833.           prfmsg(recip,usaptr->userid);
  834.           if (injoth()) {
  835.                prfmsg(sender,esgptr->msg.to);
  836.                outprf(usrnum);
  837.           }
  838.      }
  839. }
  840.  
  841. figin(addend)                 /* figure in the current msg to totals       */
  842. int addend;
  843. {
  844.      if (esgptr->msg.to[0] == SIGIDC) {
  845.           sv.sigopn+=addend;
  846.           if (findsigu(esgptr->msg.to,0) == NOSIG) {
  847.                catastro("FIGIN: NO SIG!");
  848.           }
  849.           sdtptr->nmsgs+=addend;
  850.           switch (esgptr->msg.flags&(FILATT+APPVED)) {
  851.           case FILATT:
  852.                sdtptr->nw4app+=addend;
  853.                break;
  854.           case FILATT+APPVED:
  855.                sdtptr->nfiles+=addend;
  856.                break;
  857.           }
  858.      }
  859.      else {
  860.           sv.emlopn+=addend;
  861.      }
  862. }
  863.  
  864. strtup(hlpmsn)                /* start up a scan or list utility           */
  865. int hlpmsn;
  866. {
  867.      long begin;
  868.  
  869.      if (isdigit(morcnc())) {
  870.           begin=cnclon();
  871.           alomsg(esgptr->keynum,begin);
  872.           if (esgptr->msg.msgno != begin) {
  873.                prfmsg(MISS,ltoa(begin));
  874.           }
  875.      }
  876.      else {
  877.           switch (cncchr()) {
  878.           case '?':
  879.                prohlp(hlpmsn);
  880.                return(0);
  881.           case '.':
  882.                estabc();
  883.                break;
  884.           default:
  885.                errmsg(HUH);
  886.                return(0);
  887.           }
  888.      }
  889.      return(1);
  890. }
  891.  
  892. estabc()                      /* establish current esigs.dat msg again     */
  893. {
  894.      gabbtv(&esgptr->msg,esgptr->fpos,esgptr->keynum);
  895. }
  896.  
  897. estabn()                      /* establish position but don't load text    */
  898. {
  899.      gabbtv(NULL,esgptr->fpos,esgptr->keynum);
  900. }
  901.  
  902. /* The following routine spits out the message summary lines like this:
  903.  
  904. #88888  04-JUN-88 14:03  From: Tiponeill  To: Darkshade  RRR ATT (32 replies)
  905. Re: Hamburger Waffles in the Sunshine (Reply to #55555)                    */
  906.  
  907. sumams()
  908. {
  909.      int flags,nr;
  910.  
  911.      flags=esgptr->msg.flags;
  912.      if (flags&ISSHDR) {
  913.           prf("\r#%s   SIG HEADER: %s   SIG-Op: %s   Created %s %02d:%02d\rSIG Topic: %s\r",
  914.             ltoa(esgptr->msg.msgno),
  915.             esgptr->msg.to,
  916.             esgptr->msg.from,
  917.             ncedat(esgptr->msg.crdate),
  918.             dthour(esgptr->msg.crtime),
  919.             dtmin(esgptr->msg.crtime),
  920.             esgptr->msg.topic);
  921.      }
  922.      else {
  923.           nr=esgptr->msg.nreply;
  924.           prf("\r#%s  %s %02d:%02d  From: %s  To: %s %s%s%s\rRe: %s %s\r",
  925.             ltoa(esgptr->msg.msgno),
  926.             ncedat(esgptr->msg.crdate),
  927.             dthour(esgptr->msg.crtime),
  928.             dtmin(esgptr->msg.crtime),
  929.             esgptr->msg.from,
  930.             esgptr->msg.to,
  931.             (flags&RECREQ) && esgptr->msg.to[0] != SIGIDC ? " RRR" : "",
  932.             (flags&APPVED) ? " ATT" : "",
  933.             (nr == 0) ? "" : spr(" (%d repl%s)",nr,(nr == 1) ? "y" : "ies"),
  934.             esgptr->msg.topic,
  935.             axtstg());
  936.      }
  937. }
  938.  
  939. char *
  940. axtstg()                      /* auxillary topic string formatter          */
  941. {
  942.      return(esgptr->msg.auxtpc[0] == '\0' ? ""
  943.                                           : spr("(%s)",esgptr->msg.auxtpc));
  944. }
  945.  
  946. sumnew()                      /* summarize new msg, set fpos, prompt       */
  947. {
  948.      esgptr->fpos=absbtv();
  949.      sumams();
  950.      prompt(either(SCOSCN,SCOSIG));
  951. }
  952.  
  953. alomsg(keyno,msgno)           /* acquire highest msg less than msgno, or?  */
  954. int keyno;
  955. long msgno;
  956. {
  957.      char *tffield;
  958.  
  959.      tffield=either(usaptr->userid,sigdat[esgptr->usigno].signam);
  960.      movmem(tffield,compos.userid,UIDSIZ);
  961.      compos.msgno=msgno;
  962.      if (msgno == FIRSTM
  963.        || !alebtv(&esgptr->msg,&compos,keyno)
  964.        || !sameas(esgbb->key,compos.userid)) {
  965.           if (!agebtv(&esgptr->msg,&compos,keyno)
  966.             || !sameas(esgbb->key,compos.userid)) {
  967.                return(0);
  968.           }
  969.      }
  970.      esgptr->fpos=absbtv();
  971.      esgptr->keynum=keyno;
  972.      return(1);
  973. }
  974.  
  975. prompt(news)                  /* prompt user, set new state, default input */
  976. int news;
  977. {
  978.      int i,sn;
  979.      char *lstchp;
  980.  
  981.      esgstt=news;
  982.      if (status != CRSTG || !morcnc() || (usrptr->flags&INJOIP)) {
  983.           sdtptr=&sigdat[esgptr->usigno];
  984.           switch (news) {
  985.           case EINFO:
  986.                prfmsg(news,emltck,eattck,rrrtck,emllif);
  987.                break;
  988.           case GOASC:
  989.                prfmsg(news,bbsttl,ncedat(today()),nctime(now()));
  990.                break;
  991.           case ERTFQ:
  992.           case ERFHLP:
  993.           case ERTHLP:
  994.           case STARTS:
  995.           case STARTL:
  996.           case RTSHLP:
  997.           case RTLHLP:
  998.                prfmsg(news,ltoa(esgptr->msg.msgno));
  999.                break;
  1000.           case EDITING:
  1001.                dunedt();
  1002.                break;
  1003.           case OPSTART:
  1004.                if (usrptr->flags&ISYSOP) {
  1005.                     news=SYSTART;
  1006.                }
  1007.           case SSTART:
  1008.                prfmsg(news,sdtptr->signam,sdtptr->descrp,sdtptr->nw4app);
  1009.                break;
  1010.           case SRKEY:
  1011.                prfmsg(esgptr->keywds[0] == '\0' ? SRKEY : SRKYWD,esgptr->keywds);
  1012.                break;
  1013.           case SRCHNG:
  1014.                if (!(esgptr->sflags&SCNQUI)) {
  1015.                     prfmsg(news,sdtptr->signam,esgptr->keywds);
  1016.                     break;
  1017.                }
  1018.                news=SRCHQS;
  1019.           case SCANNG:
  1020.           case LISTNG:
  1021.                prfmsg(news,sdtptr->signam);
  1022.                break;
  1023.           case QUICKC:
  1024.                prfmsg(news);
  1025.                for (i=0 ; (sn=qsigno(i)) != NOSIG ; i++) {
  1026.                     prf("      %-9s ",sigdat[sn].signam);
  1027.                }
  1028.                prfmsg(QUICKC2);
  1029.                break;
  1030.           case QCKWDS:
  1031.                prfmsg(news);
  1032.                for (i=0 ; i < NQSKWG ; i++) {
  1033.                     prf("   %d. %s\r",i+1,qscptr->qskwds[i]);
  1034.                }
  1035.                prfmsg(QCKWDS2);
  1036.                break;
  1037.           case SIGCON:
  1038.           case SIGCONH:
  1039.           case SIG123H:
  1040.           case SYS123H:
  1041.                prfmsg(news,accstg[dftlvl(dftnlv)],
  1042.                            accstg[dftlvl(dftliv)],
  1043.                            accstg[dftlvl(maxnlv)]);
  1044.                break;
  1045.           case DELRUS:
  1046.                sdtptr=&sigdat[esgptr->blknum];
  1047.                prfmsg(news,sdtptr->signam,sdtptr->descrp,
  1048.                            sdtptr->nmsgs,sdtptr->nfiles);
  1049.                break;
  1050.           default:
  1051.                prfmsg(news);
  1052.           }
  1053.           lstchp=prfptr-1;
  1054.           if (!isspace(*lstchp)) {
  1055.                esgptr->dftinp=*lstchp;
  1056.                *(prfptr=lstchp)='\0';
  1057.           }
  1058.           else {
  1059.                esgptr->dftinp='\0';
  1060.           }
  1061.      }
  1062. }
  1063.  
  1064. prohlp(news)                  /* prompt with help msg (don't change state) */
  1065. int news;
  1066. {
  1067.      int xstt;
  1068.  
  1069.      cncall();
  1070.      xstt=esgstt;
  1071.      prompt(news);
  1072.      esgstt=xstt;
  1073. }
  1074.  
  1075. errmsg(msgnum,parm1,parm2)    /* error msg, then re-prompt current state   */
  1076. int msgnum;
  1077. long parm1,parm2;
  1078. {
  1079.      prfmsg(msgnum,parm1,parm2);
  1080.      outprf(usrnum);
  1081.      cncall();
  1082.      btucli(usrnum);
  1083.      clrinp();
  1084.      prompt(esgstt);
  1085. }
  1086.  
  1087. blwoff(msgnum,parm)           /* blow off back to main e/s menu, with msg  */
  1088. int msgnum;
  1089. long parm;
  1090. {
  1091.      esgstt=MMENU;
  1092.      errmsg(msgnum,parm);
  1093. }
  1094.  
  1095. xtext()                       /* transmit text of current msg to user      */
  1096. {
  1097.      char *cp;
  1098.      int sn;
  1099.  
  1100.      for (cp=esgptr->msg.text ; *cp != '\0' ; cp++) {
  1101.           if (*cp == '\r' && isalpha(*(cp+1))) {
  1102.                *cp='\n';
  1103.           }
  1104.      }
  1105.      btuxmt(usrnum,esgptr->msg.text);
  1106.      btuxmt(usrnum,"\r");
  1107.      if ((sn=esgptr->usigno) != NOSIG && findqs(sn) < NSOFAR) {
  1108.           if (esgptr->msg.msgno > sfrptr->msgno) {
  1109.                sfrptr->msgno=esgptr->msg.msgno;
  1110.           }
  1111.      }
  1112. }
  1113.  
  1114. tovalid()                     /* check if proposed msg recipient is valid  */
  1115. {
  1116.      movmem(cncuid(),esgptr->msg.to,UIDSIZ);
  1117.      return(validwr(esgptr->msg.to));
  1118. }
  1119.  
  1120. validwr(dest)                 /* ck if msg destination is ok, leave "to" be */
  1121. char *dest;
  1122. {
  1123.      int signo,attach;
  1124.  
  1125.      if ((signo=findsig(dest)) != NOSIG) {
  1126.           attach=(esgptr->msg.flags&FILATT);
  1127.           if (rdautl(signo) < (attach ? ULAXES : WRAXES)) {
  1128.                errmsg(attach ? FWUNUP : FWUNWR,either("E-Mail","SIG"));
  1129.                return(0);
  1130.           }
  1131.           return(1);
  1132.      }
  1133.      if (!uidxst(dest)) {
  1134.           errmsg(FWUNXI,either("E-Mail","SIG"));
  1135.           return(0);
  1136.      }
  1137.      return(1);
  1138. }
  1139.  
  1140. isalon()                      /* check if input is a "long", prep compos   */
  1141. {
  1142.      if (!isdigit(morcnc())) {
  1143.           errmsg(HUH);
  1144.           return(0);
  1145.      }
  1146.      compos.msgno=cnclon();
  1147.      movmem(either(usaptr->userid,sigdat[esgptr->usigno].signam),
  1148.             compos.userid,UIDSIZ);
  1149.      return(1);
  1150. }
  1151.  
  1152. moddun()                      /* modify-msg done, update and go on         */
  1153. {
  1154.      estabn();
  1155.      updbtv(&esgptr->msg);
  1156.      prfmsg(WCONFM,ltoa(esgptr->msg.msgno));
  1157.      prompt(MMENU);
  1158. }
  1159.  
  1160. fwdit(recip)                  /* forward current message to new recipient  */
  1161. char *recip;
  1162. {
  1163.      long tmno;
  1164.      char oldnam[FSPSIZ];
  1165.  
  1166.      strcpy(oldnam,attfsd());
  1167.      movmem(recip,esgptr->msg.to,UIDSIZ);
  1168.      addaux(spr("Fw by %s",usaptr->userid));
  1169.      tmno=esgptr->msg.msgno;
  1170.      mkmsgn();
  1171.      if (esgptr->msg.flags&FILATT) {
  1172.           rename(oldnam,attfsd());
  1173.           dwfwdf();
  1174.      }
  1175.      insbtv(&esgptr->msg);
  1176.      prfmsg(FWDCNF,ltoa(tmno),ltoa(esgptr->msg.msgno),esgptr->msg.to);
  1177.      pstpst(SFWDDU,SNOTIFD);
  1178. }
  1179.  
  1180. dwfwdf()                      /* deal with forwarding of file              */
  1181. {
  1182.      int sn;
  1183.  
  1184.      esgptr->msg.flags|=APPVED;
  1185.      if ((sn=findsig(esgptr->msg.to)) != NOSIG) {
  1186.           if (rdautl(sn) >= COAXES) {
  1187.                prfmsg(FWDCAP);
  1188.           }
  1189.           else {
  1190.                esgptr->msg.flags&=~APPVED;
  1191.                prfmsg(FWDCNA);
  1192.           }
  1193.      }
  1194. }
  1195.  
  1196. delwck()                      /* delete msg, with sighdr and collision cks */
  1197. {
  1198.      esgptr->fpos=absbtv();
  1199.      if (esgptr->msg.flags&ISSHDR) {
  1200.           blwoff(NDELHD);
  1201.      }
  1202.      else if (esgcfl()) {
  1203.           blwoff(USING);
  1204.      }
  1205.      else {
  1206.           delmsg();
  1207.           prfmsg(OKGONE,ltoa(compos.msgno));
  1208.           prompt(MMENU);
  1209.      }
  1210. }
  1211.  
  1212. delmsg()                      /* delete msg and any direct attachment      */
  1213. {
  1214.      delbtv();
  1215.      unlink(attfsd());
  1216.      figin(-1);
  1217. }
  1218.  
  1219. esgmcu()                      /* email/sigs midnight cleanup               */
  1220. {
  1221.      int ctoday,age,smslif;
  1222.  
  1223.      ctoday=cofdat(today());
  1224.      setbtv(esgbb);
  1225.      esgptr=((struct esgusr *)vdarea);
  1226.      usrptr=user;
  1227.      if (qlobtv(TONUM)) {
  1228.           do {
  1229.                gcrbtv(&esgptr->msg,TONUM);
  1230.                age=ctoday-cofdat(esgptr->msg.crdate);
  1231.                if (esgptr->msg.to[0] == SIGIDC) {
  1232.                     if (esgptr->msg.flags&ISSHDR) {
  1233.                          smslif=sigopt("message-lifetime:",siglif);
  1234.                     }
  1235.                     else if (smslif >= 0 && age > smslif) {
  1236.                          delmsg();
  1237.                     }
  1238.                }
  1239.                else if (emllif >= 0 && age > emllif) {
  1240.                     delmsg();
  1241.                }
  1242.           } while (qnxbtv());
  1243.      }
  1244. }
  1245.  
  1246. char *
  1247. sigtpc(signo)                 /* sig topic (for use by teleconference)     */
  1248. int signo;
  1249. {
  1250.      if (signo <= 0 || signo >= nsigs) {
  1251.           return("");
  1252.      }
  1253.      else {
  1254.           return(sigdat[signo].descrp);
  1255.      }
  1256. }
  1257.  
  1258. esgmod(whndun)                /* email/sigs modify-msg utility             */
  1259. int (*whndun)();
  1260. {
  1261.      esgptr->fpos=absbtv();
  1262.      if (esgcfl()) {
  1263.           blwoff(USING);
  1264.      }
  1265.      else {
  1266.           if (esgptr->msg.flags&ISSHDR) {
  1267.                if (!sopmhd && !(usrptr->flags&ISYSOP)) {
  1268.                     blwoff(NOMODH);
  1269.                     return;
  1270.                }
  1271.                if (!morcnc()) {
  1272.                     prfmsg(EHDPFX,sigccr,siglif,sigtck,sattck);
  1273.                     outprf(usrnum);
  1274.                }
  1275.           }
  1276.           edimsg(0,1,whndun);
  1277.      }
  1278. }
  1279.  
  1280. esgcfl()                      /* email/sigs "conflict" (collision) detect  */
  1281. {
  1282.      long recpos;
  1283.      struct esgusr *othesg;
  1284.  
  1285.      recpos=esgptr->fpos;
  1286.      for (othusn=0,othusp=user ; othusn < nterms ; othusn++,othusp++) {
  1287.           if (othusn != usrnum
  1288.            && othusp->class > SUPIPG
  1289.            && (othusp->state == EMLSTT || othusp->state == SIGSTT)) {
  1290.                switch (othusp->substt) {
  1291.                case ESTART:
  1292.                case REPRMT:
  1293.                case SSTART:
  1294.                case RSPRMT:
  1295.                case OPSTART:
  1296.                case ORSPRMT:
  1297.                     break;
  1298.                default:
  1299.                     othesg=esgarr(othusn);
  1300.                     if (recpos == othesg->fpos
  1301.                      || recpos == othesg->prethr) {
  1302.                          return(1);
  1303.                     }
  1304.                }
  1305.           }
  1306.      }
  1307.      return(0);
  1308. }
  1309.  
  1310. esghup()                      /* email/sigs hang-up-phone vector           */
  1311. {
  1312.      setmbk(esgmb);
  1313.      if (usrptr->state == EMLSTT || usrptr->state == SIGSTT) {
  1314.           uploff(0);
  1315.           dnloff();
  1316.           cpyoff();
  1317.           clrprf();
  1318.      }
  1319.      qscptr=&qscfgs[usrnum];
  1320.      if (qscptr->userid[0] != '\0') {
  1321.           setbtv(qscbb);
  1322.           geqbtv(NULL,usaptr->userid,0);
  1323.           updbtv(qscptr);
  1324.           setmem(qscptr,sizeof(struct qscfg),0);
  1325.      }
  1326. }
  1327.  
  1328. credok(nlvflg,howmny)         /* credits ok for this operation?            */
  1329. int nlvflg;
  1330. int howmny;
  1331. {
  1332.      if (nlvflg) {
  1333.           return(1);
  1334.      }
  1335.      if (usrptr->class > FRELOA && usaptr->tckavl >= howmny) {
  1336.           usaptr->tckavl-=howmny;
  1337.           return(1);
  1338.      }
  1339.      if (howmny == 0) {
  1340.           errmsg(NOTLIV,either("E-Mail","SIG"));
  1341.      }
  1342.      else {
  1343.           errmsg(usrptr->class == FRELOA ? NOCREDS : NECREDS,
  1344.                                            howmny,either("E-Mail","SIG"));
  1345.      }
  1346.      return(0);
  1347. }
  1348.  
  1349. credsf(howmny)                /* credits sufficient for this operation?  */
  1350. int howmny;
  1351. {
  1352.      if (usaptr->tckavl >= howmny) {
  1353.           usaptr->tckavl-=howmny;
  1354.           return(1);
  1355.      }
  1356.      errmsg(usrptr->class == FRELOA ? NOCREDS : NECREDS,
  1357.                                       howmny,either("E-Mail","SIG"));
  1358.      return(0);
  1359. }
  1360.  
  1361.