/***************************************************************************
 *                                                                         *
 *   OUTPOST.C                                                             *
 *                                                                         *
 *   Copyright (c) 1992-1996 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   Deliver MHS Mail to directory for Worldgroup processing,              *
 *   along with file attachments.                                          *
 *                                                                         *
 *                                        - R. Skurnick 2/6/92             *
 *                                        - C. Kotacka 10/92 File Att's    *
 *                                                                         *
 ***************************************************************************/

#include <fcntl.h>
#include "gcomm.h"
#include "netdir.h"

VOID doreset(VOID);
VOID scandir(VOID);
VOID procmsg(VOID);
VOID scanhdr(VOID);
VOID badfile(VOID);
VOID procdata(CHAR *text);
INT wrnadm(VOID);
INT notify(struct hdrentry *hdrrec);
VOID proctext(VOID);
VOID hdlmult(VOID);
VOID hdlmula(VOID);
VOID copymsg(CHAR *ptr);
VOID copyatt(CHAR *ptr);
VOID moveatt(VOID);
VOID savetext(VOID);
struct hdrstf *keywdok(CHAR *stgptr);
VOID opnout(VOID);
INT chkhdr(VOID);
INT chk4bad(CHAR *fname);
VOID sendto(VOID);
VOID whofrm(VOID);
VOID subject(VOID);
VOID summary(VOID);
VOID mcbopt(VOID);
VOID mcbtyp(VOID);
VOID attmnt(VOID);
VOID dtepst(VOID);
VOID errcod(VOID);
VOID init(INT argc,CHAR *argv[]);
VOID initdir(INT argc,CHAR *argv[]);
VOID readcfg(CHAR *argv[]);
VOID getdir(FILE *fp,CHAR **dir);
VOID initpth(VOID);
CHAR *maldir(CHAR *dname);
CHAR *malfil(INT siz);
INT clfile(FILE *fp);
VOID errext(INT excode);
#ifdef GCDOS
INT netseterror(INT mode);
#else
#define netseterror(m) ((VOID)0)
#endif

#define LF          0x0A           /* Line Feed character                  */
#define CTRLC       0x03           /* Control-C character                  */
#define MAXLINE     514            /* Maximum allowed line size            */
#define MAXHDRC     4096           /* Maximum header component size        */
#define FNMSIZE     (12+1)         /* DOS file name size                   */

                                   /* errorlevel codes                     */
#define NONE        0              /*   everything is ok                   */
#define NOMEM       1              /*   insufficient memory                */
#define BADARG      2              /*   invalid command line arguments     */
#define OPENCFG     3              /*   unable to open OUTPOST.CFG         */
#define BADCFG      4              /*   invalid OUTPOST.CFG                */
#define OPENSRC     5              /*   unable to open source message      */
#define OPENSRCA    6              /*   unable to open source attachment   */
#define OPENDST     7              /*   unable to open destination message */
#define SETMV       8              /*   no MV environment variable         */
#define UNKNOWN     255            /*   Unknown error                      */

CHAR optsp[MAXLINE],               /* Current option specifications        */
     keywd[MAXLINE],               /* Current header keyword info          */
     attch[MAXHDRC],               /* attachement list - raw format        */
     tofld[MAXHDRC],               /* Hold other to id's for writing to    */
     orgat[MAXHDRC];               /* list of files to move                */

CHAR *valfld;                      /* Value for current keyword            */

CHAR *bbsdir,                      /* Dir to write BBS bound messages      */
     *gtwdir,                      /* Dir with MHS messages to convert     */
     *prcdir,                      /* Dir with Parcels in it               */
     *swpdir,                      /* Dir for temporary storage            */
     *smtdir,                      /* Dir for submitting "BAD" messages    */
     *ifname,                      /* Name of input file                   */
     *ofname,                      /* Name of file being output to         */
     *cfname,                      /* Name of file after renamed to BAD    */
     *sfname;                      /* Name of file for reporting a "BAD"   */

CHAR *lckfil,                      /* MHS.LCK file name                    */
     *netfil;                      /* NETDIR.TAB file name                 */

FILE *infp,                        /* MHS file pointer                     */
     *outfp;                       /* MBBS file pointer                    */

struct hdrstf {                    /* struct for dealing with MHS keyword  */
     CHAR *hdrwrd;                 /*   keyword name                       */
     VOID (*routine)();            /*   routine to execute                 */
};

struct attlst {
     CHAR attnme[64][128];         /* struct of poss. up to 64 attachments */
};

#define HDRSIZ (sizeof(hdrarr)/sizeof(struct hdrstf))

struct hdrstf hdrarr[]={           /* structure of MHS keywords to act on  */
     {"Attachment",       attmnt},
     {"Date-posted",      dtepst},
     {"Error-report",     errcod},
     {"MCB-options",      mcbopt},
     {"MCB-type",         mcbtyp},
     {"Send-to",          sendto},
     {"Sender",           whofrm},
     {"Subject",          subject},
     {"Summary",          summary}
};

CHAR allflds;                      /* are all fields present for a MHS msg */

INT multo;                         /* are there multiple receipients?      */
INT multat;                        /* are there multiple attachments?      */

                                   /* bit definitions for complete message */
#define VFRM   0x01                /*   valid "from" field found           */
#define VTOF   0x02                /*   valid "to" field found             */
#define VSUB   0x04                /*   valid "subject" field              */

#define ALLOK (VFRM+VTOF+VSUB)     /* value when all fields are present    */

VOID
main(                              /* main routine                         */
INT argc,
CHAR *argv[])
{
     init(argc,argv);
     scandir();
     errext(NONE);
}

VOID
doreset(VOID)                      /* reset things for another file        */
{
     allflds=0;
     multo=0;
     multat=0;
}

VOID
scandir(VOID)                      /* scan directory for msgs to process   */
{
     INT handle;
     struct ffblk fb;
     extern INT errno;

     strcpy(ifname,gtwdir);
     strcat(ifname,STAR);
     if (findfirst(ifname,&fb,0) == 0) {
          do {
               if (stricmp(fb.ff_name,"MAIL.FLG") != 0) {
                    if (!chk4bad(fb.ff_name)) {
                         strcpy(ifname,gtwdir);
                         strcat(ifname,fb.ff_name);
                         netseterror(1);
                         if ((handle=sopen(ifname,O_RDONLY,SH_COMPAT,0)) > -1) {
                              netseterror(0);
                              if ((infp=fdopen(handle,"r")) == NULL) {
                                   close(handle);
                              }
                              else {
                                   procmsg();
                                   doreset();
                              }
                         }
                         else {
                              netseterror(0);
                         }
                    }
               }
          } while (findnext(&fb) == 0);
     }
}

VOID
procmsg(VOID)                      /* process a message - control sequence */
{
     opnout();
     if (chkhdr()) {
          scanhdr();
     }
     else {
          badfile();
     }
}

VOID
scanhdr(VOID)                      /* scan input file                      */
{
     INT c,cnt=0;
     static CHAR text[MAXHDRC];

     setmem(orgat,sizeof(orgat),0);
     setmem(attch,sizeof(attch),0);
     setmem(text,sizeof(text),0);
     while ((c=fgetc(infp)) != EOF) {
          if (c == LF) {
               if (strlen(text) > 0) {
                    c=fgetc(infp);
                    if (c != LF && isspace(c)) {
                         text[cnt++]=c;
                         while (isspace(c=fgetc(infp))) {
                         }
                         ungetc(c,infp);
                    }
                    else {
                         ungetc(c,infp);
                         procdata(text);
                         cnt=0;
                         setmem(text,sizeof(text),0);
                    }
               }
               else {
                    proctext();
                    return;
               }
          }
          else {
               text[cnt++]=c;
          }
          if (cnt > MAXHDRC-1) {
               badfile();
               return;
          }
     }
     badfile();
}

VOID
badfile(VOID)                      /* handle corrupt file processing       */
{
     CHAR *ptr;

     if (clfile(outfp)) {
          unlink(ofname);
     }
     clfile(infp);
     setmem(cfname,sizeof(cfname),0);
     strcpy(cfname,ifname);
     if ((ptr=strchr(cfname,'.')) == NULL) {
          strcat(cfname,".BAD");
     }
     else {
          *++ptr='B';
          *++ptr='A';
          *++ptr='D';
          *ptr='\0';
     }
     if (wrnadm()) {
          rename(ifname,cfname);
     }
}

VOID
procdata(                          /* Lets see what data we got            */
CHAR *text)
{
     struct hdrstf *hptr;
     CHAR *sptr,*dptr;
     INT len=0;

     sptr=text;
     dptr=optsp;
     setmem(optsp,sizeof(optsp),0);
     setmem(keywd,sizeof(keywd),0);
     while (isdigit(*sptr)) {
          *dptr++=*sptr++;
          len++;
     }
     while (len++ < 3) {
          *dptr++='0';
     }
     if (isspace(*sptr)) {
          do {
          } while (isspace(*++sptr));
     }
     if (!isalpha(*sptr)) {
          return;
     }
     else {
          dptr=keywd;
          *dptr++=*sptr++;
     }
     while (isalnum(*sptr) || *sptr == '-') {
          *dptr++=*sptr++;
     }
     if (isspace(*sptr)) {
          do {
          } while (isspace(*++sptr));
     }
     if (*sptr != ':') {
          return;
     }
     if ((hptr=keywdok(keywd)) == NULL) {
          return;
     }
     while (isspace(*++sptr)) {
     }
     valfld=sptr;
     (*(hptr->routine))();
}

INT
wrnadm(VOID)                       /* prepare to warn admin about BAD file */
{
     INT handle,handle2;
     INT byts;
     struct hdrentry hdr;

     netseterror(1);
     if ((handle=sopen(lckfil,O_RDONLY,SH_DENYNO,0)) < 0) {
          if ((handle=sopen(lckfil,O_RDONLY,SH_DENYNO,0)) < 0) {
               netseterror(0);
               return(0);
          }
     }
     netseterror(0);
     if (!lock(handle,0L,1L)) {
          netseterror(1);
          if ((handle2=sopen(netfil,O_RDONLY+O_BINARY,SH_DENYNO,0)) < 0) {
               if ((handle2=sopen(netfil,O_RDONLY+O_BINARY,SH_DENYNO,0)) < 0) {
                    netseterror(0);
                    unlock(handle,0L,1L);
                    close(handle);
                    return(0);
               }
          }
          do {
               byts=read(handle2,&hdr,127);
               if (byts == 127) {
                    if (hdr.e_etype == 0) {
                         if (!notify(&hdr)) {
                              return(0);
                         }
                         break;
                    }
               }
               else {
                    close(handle2);
                    unlock(handle,0L,1L);
                    close(handle);
                    return(0);
               }
          } while (!eof(handle2));
          close(handle2);
          unlock(handle,0L,1L);
          close(handle);
          return(1);
     }
     close(handle);
     return(0);
}

INT
notify(                            /* notify administrator about a "BAD"   */
struct hdrentry *hdrrec)
{
     FILE *fp;
     INT handle;
     static CHAR msg[]="Unable to process file \"%s\" in the MBBS Gateway.\n";

     strcpy(sfname,smtdir);
     if ((handle=creattemp(sfname,0)) != -1) {
          if ((fp=fdopen(handle,"w")) != NULL) {
               fprintf(fp,"SMF-70\n");
               fprintf(fp,"To: %s @ %s\n",hdrrec->s_admin,hdrrec->s_hname);
               fprintf(fp,"From: -MAISER-@%s \n",hdrrec->s_hname);
               fprintf(fp,"Subject: Invalid Message in MBBS Gateway\n");
               fprintf(fp,"MCB-options: NNNNPNP\n\n");
               fprintf(fp,msg,ifname);
               clfile(fp);
               return(1);
          }
          else {
               close(handle);
          }
     }
     return(0);
}

VOID
proctext(VOID)                     /* complete header and process text     */
{
     if ((allflds&ALLOK) == ALLOK) {
          savetext();
          if (orgat[0] != '\0') {
               moveatt();
          }
          if (multo) {
               hdlmult();
               if (multat) {
                    hdlmula();
               }
          }
          else if (multat) {
               hdlmula();
          }
          clfile(infp);
          unlink(ifname);          /* delete the original message when done*/
     }
     else {
          badfile();
     }
}

VOID
hdlmult(VOID)                      /* handle multiple "Send-To's"          */
{
     CHAR *bptr,*eptr;

     bptr=tofld;
     while (isspace(*bptr)) {
          bptr++;
     }
     eptr=strchr(bptr+1,',');
     do {
          if (eptr != NULL) {
               *eptr='\0';
               copymsg(bptr);
               bptr=eptr+1;
               if ((eptr=strchr(bptr+1,',')) == NULL) {
                    copymsg(bptr);
                    break;
               }
          }
          else {
               copymsg(bptr);
               break;
          }
     } while (1);
}

VOID
hdlmula(VOID)                      /* handle multiple "Attachments"        */
{
     CHAR *bptr,*eptr;

     bptr=attch;
     while (isspace(*bptr)) {
          bptr++;
     }
     eptr=strchr(bptr+1,',');
     do {
          if (eptr != NULL) {
               *eptr='\0';
               copyatt(bptr);
               bptr=eptr+1;
               eptr=strchr(bptr+1,',');
               if (eptr == NULL) {
                    copyatt(bptr);
                    break;
               }
          }
          else {
               copyatt(bptr);
               break;
          }
     } while (1);
}


VOID
copymsg(                           /* copy an MHS to a new "To"            */
CHAR *ptr)
{
     INT ihd;
     FILE *ifp;
     static CHAR infile[120];
     CHAR buff[MAXLINE];

     if (infile[0] == '\0') {
          strcpy(infile,ofname);
     }
     netseterror(1);
     if ((ihd=sopen(infile,O_RDONLY,SH_COMPAT,0)) > -1) {
          netseterror(0);
          if ((ifp=fdopen(ihd,"r")) == NULL) {
               close(ihd);
               errext(OPENSRC);
          }
     }
     opnout();
     while (fgets(buff,MAXLINE,ifp) != NULL) {
          if (strnicmp(buff,"TO:",3)) {
               fprintf(outfp,"%s",buff);
          }
          else {
               fprintf(outfp,"TO: %s\n",ptr);
          }
     }
     fclose(ifp);
     fclose(outfp);
}

VOID
copyatt(                           /* copy an MHS attachment to new recp. */
CHAR *ptr)
{
     INT ihd;
     FILE *ifp;
     static CHAR infile[120];
     CHAR buff[MAXLINE];

     if (infile[0] == '\0') {
          strcpy(infile,ofname);
     }
     netseterror(1);
     if ((ihd=sopen(infile,O_RDONLY,SH_COMPAT,0)) > -1) {
          netseterror(0);
          if ((ifp=fdopen(ihd,"r")) == NULL) {
               close(ihd);
               errext(OPENSRCA);
          }
     }
     opnout();
     while (fgets(buff,MAXLINE,ifp) != NULL) {
          if (strnicmp(buff,"ATTACHMENT:",11)) {
               fprintf(outfp,"%s",buff);
          }
          else {
               fprintf(outfp,"ATTACHMENT: %s\n",ptr);
          }
     }
     fclose(ifp);
     fclose(outfp);
}

VOID
moveatt(VOID)                      /* deliver the attachments              */
{
     INT c;
     INT src=0,dest=0,cnt=0;
     CHAR outpar[256];
     CHAR atname[256];
     CHAR *atnme;

     if (orgat[0] != '\0') {
          while (orgat[src] != '\0') {
               setmem(outpar,sizeof(outpar),0);
               setmem(keywd,sizeof(keywd),0);
               setmem(atname,sizeof(atname),0);
               do {
                    keywd[dest++]=orgat[src++];
                    cnt++;
               } while ((c=orgat[src]) != ',' && c != '\0');
               if (cnt > 12) {
                    break;
               }
               atnme=keywd;
               while (isspace(*atnme)) {
                    atnme++;
               }
               strcpy(outpar,bbsdir);
               strcat(outpar,"PARCEL" SLS);
               strcat(outpar,atnme);
               strcpy(atname,prcdir);
               strcat(atname,atnme);
               copyfile(atname,outpar);    /* move it to parcel directory */
               unlink(atname);
               if (c != '\0') {
                    src++;
                    cnt=dest=0;
                    while (isspace(c=orgat[src])) {
                         src++;
                    }
               }
          }
     }
}

VOID
savetext(VOID)                     /* save the body of the text            */
{
     INT c;

     fputc('\n',outfp);
     while ((c=fgetc(infp)) != EOF) {
          fputc(c,outfp);
     }
     clfile(infp);
     fclose(outfp);
}

struct hdrstf *
keywdok(                           /* check valid keyword list - our subset*/
CHAR *stgptr)
{
     INT cond;
     struct hdrstf *low,*mid,*high;

     low=&hdrarr[0];
     high=&hdrarr[HDRSIZ-1];
     while (low <= high) {
          mid=low+((INT)(high-low))/2;
          if ((cond=stricmp(stgptr,mid->hdrwrd)) < 0) {
               if (mid == low) {
                    break;
               }
               high=mid-1;
          }
          else if (cond > 0) {
               if (mid == high) {
                    break;
               }
               low=mid+1;
          }
          else {
               return(mid);
          }
     }
     return(NULL);
}

VOID
opnout(VOID)                       /* open the output file for writing     */
{
     INT handle;

     strcpy(ofname,bbsdir);
     if ((handle=creattemp(ofname,0)) == -1) {
          errext(OPENDST);
     }
     if ((outfp=fdopen(handle,"w")) == NULL) {
          close(handle);
          errext(OPENDST);
     }
}

INT
chkhdr(VOID)                       /* check for valid message header       */
{
     if (fgetc(infp) == CTRLC) {
          if (fgetc(infp) == LF) {
               return(1);
          }
     }
     return(0);
}

INT
chk4bad(                           /* check for ".BAD" extension           */
CHAR *fname)
{
     CHAR *ptr;

     ptr=strchr(fname,'.');
     if (ptr != NULL) {
          if (strnicmp(ptr,".BAD",4)) {
               return(1);
          }
     }
     return(0);
}

VOID
sendto(VOID)                       /* handle "Send-To" keyword             */
{
     INT chg=0;
     CHAR *ptr;

     if (!(allflds&VTOF)) {
          ptr=strchr(valfld,',');
          if (ptr != NULL) {
               multo=chg=1;
               *ptr='\0';
          }
          fprintf(outfp,"TO: %s\n",valfld);
          if (chg) {
               strcpy(tofld,ptr+1);
          }
          allflds|=VTOF;
     }
}

VOID
whofrm(VOID)                       /* handle "From" keyword                */
{
     if (!(allflds&VFRM)) {
          fprintf(outfp,"FROM: %s\n",valfld);
          allflds|=VFRM;
     }
}

VOID
subject(VOID)                      /* handle "Subject" keyword             */
{
     if (!(allflds&VSUB)) {
          fprintf(outfp,"SUBJECT: %s\n",valfld);
          allflds|=VSUB;
     }
}

VOID
summary(VOID)                      /* handle "Summary" keyword             */
{
     if (strstr(valfld,"MBBS: ")) {
          fprintf(outfp,"SUMMARY: %s\n",valfld);
     }
}

VOID
mcbopt(VOID)                       /* handle "MCB-Options" keyword         */
{
     INT i;
     CHAR optfld[8]={"NNYNANA"};
     CHAR *ptr;

     for (i=0,ptr=valfld ; i < 8 && *ptr != '\0' ; i++,ptr++) {
          optfld[i]=toupper(*ptr);
     }
     fprintf(outfp,"ROC: %c\n",optfld[0] == 'Y' ? 'Y' : 'N');
     fprintf(outfp,"RRN: %c\n",optfld[1] == 'Y' ? 'Y' : 'N');
     fprintf(outfp,"NDN: %c\n",optfld[2] == 'Y' ? 'Y' : 'N');
}

VOID
mcbtyp(VOID)                       /* handle "MCB-Options" keyword         */
{
     fprintf(outfp,"TYPE: %c\n",*valfld == '1' ? '1' : '0');
}

VOID
attmnt(VOID)                       /* handle "Attachment" keyword          */
{
     INT achg=0;
     CHAR *ptr;

     strcpy(orgat,valfld);         /* get entire attachment line           */
     ptr=strchr(valfld,',');
     if (ptr != NULL) {
          multat=achg=1;
          *ptr='\0';
     }
     fprintf(outfp,"ATTACHMENT: %s\n",valfld);
     if (achg) {
          strcpy(attch,ptr+1);
     }
     else {
          strcpy(attch,valfld);
     }
}

VOID
dtepst(VOID)                       /* handle "Date-posted" keyword         */
{
     fprintf(outfp,"DATE: %s\n",valfld);
}

VOID
errcod(VOID)                       /* handle "Error-report" keyword        */
{
     fprintf(outfp,"ERC: ");
     for (; isdigit(*valfld) ; valfld++) {
          fprintf(outfp,"%c",*valfld);
     }
     fprintf(outfp,"\n");
}

VOID
init(                              /* perform initialization procedure     */
INT argc,
CHAR *argv[])
{
     initdir(argc,argv);
     initpth();
}

VOID
initdir(                           /* perform directory initialization     */
INT argc,
CHAR *argv[])
{
     INT len;

     if (argc != 4) {
          errext(BADARG);
     }
     readcfg(argv);
     ofname=malfil(strlen(bbsdir));
     sfname=malfil(strlen(smtdir));
     len=strlen(argv[2])+5;
     if ((gtwdir=(CHAR *)malloc(len)) == NULL) {
          errext(NOMEM);
     }
     else {
          strcpy(gtwdir,argv[2]);
          strcat(gtwdir,"OUT" SLS);
          ifname=malfil(len);
          cfname=malfil(len);
     }
     len=strlen(argv[2])+9;
     if ((prcdir=(CHAR *)malloc(len)) == NULL) {
          errext(NOMEM);
     }
     else {
          strcpy(prcdir,argv[2]);
          strcat(prcdir,"OPARCEL" SLS);
     }
     len=strlen(argv[3])+1;
     if ((swpdir=(CHAR *)malloc(len)) == NULL) {
          errext(NOMEM);
     }
     else {
          strcpy(swpdir,argv[3]);
     }
}

VOID
readcfg(                           /* read OUTPOST.CFG file                */
CHAR *argv[])
{
     CHAR cfgfile[128];
     INT handle;
     FILE *fp;

     strcpy(cfgfile,argv[2]);
     strcat(cfgfile,"PUBLIC" SLS "OUTPOST.CFG");
     netseterror(1);
     if ((handle=sopen(cfgfile,O_RDONLY,SH_COMPAT,0)) > -1) {
          netseterror(0);
          if ((fp=fdopen(handle,"r")) == NULL) {
               close(handle);
               errext(OPENCFG);
          }
          else {
               getdir(fp,&bbsdir);
               getdir(fp,&smtdir);
               fclose(fp);
          }
     }
     else {
          errext(OPENCFG);
     }
}

VOID
getdir(                            /* grab a entry from config file        */
FILE *fp,
CHAR **dir)
{
     CHAR buff[40],*ptr;
     struct ffblk fb;

     fgets(buff,40,fp);
     if ((ptr=strchr(buff,'\n')) == NULL) {
          fclose(fp);
          errext(BADCFG);
     }
     *ptr='\0';
     *dir=maldir(buff);
     if (findfirst(buff,&fb,FA_DIREC) != 0) {
          fclose(fp);
          errext(BADCFG);
     }
}

VOID
initpth(VOID)                      /* initialize path for MHS System Files */
{
     CHAR *env,dirpth[]=SLS "MHS" SLS "MAIL" SLS "PUBLIC" SLS;

     env=getenv("MV");
     if (env == NULL) {
          errext(SETMV);
     }
     if ((lckfil=(CHAR *)malloc(strlen(env)+strlen(dirpth)+FNMSIZE)) == NULL) {
          errext(NOMEM);
     }
     strcpy(lckfil,env);
     strcat(lckfil,dirpth);
     strcat(lckfil,"MHS.LCK");
     if ((netfil=(CHAR *)malloc(strlen(env)+strlen(dirpth)+FNMSIZE)) == NULL) {
          errext(NOMEM);
     }
     strcpy(netfil,env);
     strcat(netfil,dirpth);
     strcat(netfil,"NETDIR.TAB");
}

CHAR *
maldir(                            /* create a directory setup             */
CHAR *dname)
{
     CHAR *dest;
     INT len,byt;

     len=strlen(dname);
     byt=(dname[len-1] == SL ? len : len+1);
     if ((dest=(CHAR *)malloc(byt+1)) == NULL) {
          errext(NOMEM);
     }
     else {
          strcpy(dest,dname);
          len=strlen(dest)-1;
          if (*(dest+len-1) != SL) {
               strcat(dest,SLS);
          }
     }
     return(dest);
}

CHAR *
malfil(                            /* malloc room for a full file name     */
INT siz)
{
     CHAR *fptr;

     if ((fptr=(CHAR *)malloc(siz+FNMSIZE)) == NULL) {
          errext(NOMEM);
     }
     return(fptr);
}

INT
clfile(                            /* close a file                         */
FILE *fp)
{
     if (fp != NULL) {
          fclose(fp);
          fp=NULL;
          return(1);
     }
     return(0);
}

VOID
errext(                            /* Exit with errorlevel                 */
INT excode)
{
     exit(excode);
}

#ifdef GCDOS
INT
netseterror(                       /* set network error mode               */
INT mode)
{
     CHAR rv;

     asm  mov  ah,0x0DD
     asm  mov  dx,mode
     asm  INT  21h
     asm  xor  ah,ah
     asm  mov  rv,al
     return(rv);
}
#endif
