/****************************************************************************/
/*    Init.c      MaxMail initialization stuff                              */
/*                                                                          */
/****************************************************************************/

#include "MaxMail.h"

char dummy[81];
char adrive[_MAX_DRIVE];

extern int  fido_init;
extern int Command;
extern char  _far *msgbuffer;

/* Initialize MaxMail */

void _pascal init()
{

   int x;
   struct find_t fbuf;

   startsecs = clock();
   parmread = FALSE;
   get_currents();   		/* Get the current directory,drive and save */

   LogMode = 0;		/* Turn off logging by default */

   NewHelpFil[0] = 0;		/* Turn off newusers help file */
   HelpFile[0] = 0;		/* Turn off std help file */
   LogFile[0] = 0;		/* Turn Off logfile by default */
   SignOff[0] = 0;
   MsgHdrFile[0] = 0;
   statline[0] = 0;
   BullFile[0] = 0;
   BBSid[0] = 0;
   QWKWelcome[0] = 0;
   QWKnews[0] = 0;
   QWKbye[0] = 0;
   QWKDir[0] = 0;
   NewFiles[0] = 0;
   Command = FALSE;
   strcpy(BBSphone,"555-1212");
   tdir[0] = 0;		/* Temporary directory for Packing program */
   PACKER_1 = NULL;
   PROTO_1  = NULL;
   ZIPREP = NULL;
   LHAREP = NULL;
   ARCREP = NULL;
   ExtendOk = TRUE;
   ReDirect = FALSE;
   MaxDaily = 0;
   StripTags = TRUE;

   SkipCount = 0;
   ForceCount = 0;

/* Establish Default color attributes */

   TextAttr[STD_TEXT] = 6;   		/* Cyan on black */
   TextAttr[HILITE_TEXT] = 3;		/* Yellow on black */
   TextAttr[MENU_KEY] = 2;		/* Green on black */
   TextAttr[TIME_LEFT] = 87;		/* White on Magenta */
   TextAttr[PROMPT_TEXT] = 4;		/* Blue on black */
   TextAttr[ATTN_TEXT] = 1;		/* Red on black */
   TextAttr[VIEW_TEXT] = 71;		/* White on Blue */

   load_cfgfile(MCfgFile);

   if (tdir[0]) {		/* Was a temp dir specified? */
      x = strlen(tdir) - 1;		/* Bump to tail end of string */
      if (tdir[x] == '\\')
         tdir[x] = 0;		/* Remove it! We will add it when necessary */
   }

   if (Task && LogFile[0]) {		/* Redo logfile name with task # */
      _splitpath(LogFile,adrive,dummy,temp,temp1);
      temp[6] = 0;		/* Trim out 2 chars */
      sprintf(LogFile,"%s%s%s%02x%s",adrive,dummy,temp,Task,temp1);
   }

   if (!parmread) {
      if(read_prm(PrmFile) < 0)
         aborterror(FILEOPEN,"Error opening PRM file!\r\n");

      if(switch_dir(PRM(sys_path)))		/* Change to Maximus home dir */
         deinit(2);
   }

/* Now test the temp subdirectory and see if it's legal */
   if (tdir[0]) {
      if (switch_dir(tdir)) {		/* Uh oh! */
         logit("Invalid temp dir specified",'!');
         tdir[0] = 0;		/* Terminate it! */
      }
      switch_dir(PRM(sys_path));		/* Return to Maximus root */
   }

   if (IsLocal >= 2) 
      MaxMsgs = 9999;		/* Allow tons of messages in local mode */

   sprintf(temp,"MxMlAct.%03x",Task);		/* Create a task id */
   x = sopen(temp,O_RDWR | O_BINARY | O_CREAT,SH_DENYWR,S_IWRITE);
   close(x);		/* Create just a null file */

   if (Task && SumFile[0]) {
      sprintf(temp,".%03x",Task);
      strcat(SumFile,temp);
   }

   /* See if helpfile exists */
   if (_dos_findfirst(HelpFile,_A_NORMAL,&fbuf) && HelpFile[0])
      HelpFile[0] = 0;		/* Disable */

}

/* Close up MaxMail, clean up loose ends */
void _pascal deinit(int errcode)
{
   int x,y,z;
   long secdiff;
   struct _restart *rst;
   struct find_t fbuf;

   if (fido_init)
      _ffree(msgbuffer);

   switch_dir(PRM(sys_path));		/* Return to Maximus root */

   if (tdir[0])
      switch_dir(tdir);

   if (QWKDir[0])
      if(chdir(QWKDir) != 0)
         QWKDir[0] = 0;

   if(packer_del) 
      unlink(ArcFile);

   if (USERCFG.msgfrmt == 1) {
      if (QWKDir[0]) {		/* We are in private subdir */
         if (IsLocal) {		/* We gotta keep qwk file! */
            sprintf(temp,"%s.qwk",BBSid);
            chmod(temp,S_IREAD);	/* Thus make it read only */
         }
         if (!_dos_findfirst("*.*",_A_NORMAL,&fbuf)) {	/* Kill everything in subdir */
            unlink(fbuf.name);
            while (!_dos_findnext(&fbuf)) 
               unlink(fbuf.name);
         }
         if (IsLocal) 		/* We gotta keep qwk file! */
            chmod(temp,S_IWRITE);	/* restore it */
      }
      else {		/* Try to do a decent cleanup */
         sprintf(temp,"%s.rep",BBSid);
         unlink(temp);
         unlink("control.dat");
         unlink("messages.dat");
         unlink("NewFiles.dat");
         unlink("Door.id");

         _splitpath(QWKnews,dummy,dummy,temp,temp1);
         sprintf(dummy,"%s%s",temp,temp1);
         unlink(dummy);		/* Kill all the special files */

         _splitpath(QWKbye,dummy,dummy,temp,temp1);
         sprintf(dummy,"%s%s",temp,temp1);
         unlink(dummy);		/* Kill all the special files */

         _splitpath(QWKWelcome,dummy,dummy,temp,temp1);
         sprintf(dummy,"%s%s",temp,temp1);
         unlink(dummy);		/* Kill all the special files */

         if (!_dos_findfirst("???.ndx",_A_NORMAL,&fbuf)) {
            unlink(fbuf.name);
            while (!_dos_findnext(&fbuf)) 
               unlink(fbuf.name);
         }
         if (!_dos_findfirst("blt-*.*",_A_NORMAL,&fbuf)) {
            unlink(fbuf.name);
            while (!_dos_findnext(&fbuf)) 
               unlink(fbuf.name);
         }
      }
   }
   else {
      unlink(TxtFile);
      unlink(StatName);
   }


   if(QWKDir[0]) {
      chdir("..");
      rmdir(QWKDir);		/* Remove temp directory */
      QWKDir[0] = 0;
   }

   homedir();

   x = USRCFG_UPD | USRCFG_FUPD | USRCFG_MSGUPD;
   x ^= 0xffff;
   USERCFG.flags &= x;		/* Turn off forced update flags */

   if (newuser) {
      printf("Building new user message areas\n");
      build_areas(FALSE,FALSE);		/* Recalc totareas */
   }

   sprintf(temp,"MxMlAct.%03x",Task);		/* Create a task id */
   unlink(temp);
   if (!SysopMode) {
      x = sopen(CfgFile,O_RDWR | O_BINARY,SH_DENYWR,S_IWRITE);
      if (x != -1) {
         time(&USERCFG.lasttime);
         USERCFG.totprotos = totprotocols;
         USERCFG.totpackers = totpackers;
         USERCFG.calls++;
         strcpy(USERCFG.name,LastUser.name);
         if (USERCFG.calls < USERCFG.packcount)
            USERCFG.calls = USERCFG.packcount;
         update_usercfg(x);
         close(x);
      }
      else logit("Error updating User Config file",'!');
      sprintf(temp,"%s off-line. Calls=%u, Len=%u",UserName,USERCFG.calls,timeon());
   }
   else {
      sprintf(temp,"Local Sysop off-line. Calls=~, Len=~");
      errcode = 7;
   }
   logit(temp,':');
   sprintf(temp,"End, (%d)",errcode);
   logit(temp,':');

   if (LogFile[0]) {
      x = sopen(LogFile,O_BINARY | O_RDWR | O_APPEND,SH_DENYWR,S_IWRITE);
      if (x > 0) {
         write(x,"\r\n",2);
         close(x);
      }
   }

   if (TimeAdjust) {
      sprintf(temp,"Restar%02x.bbs",Task); 
      if(_dos_findfirst(temp,_A_NORMAL,&fbuf) == 0 ) { 
         rst = (struct _restart *) malloc(sizeof(struct _restart));
         if (rst != NULL) {
            x = sopen(temp,O_BINARY | O_RDWR,SH_DENYWR,S_IWRITE);
            if (x != -1) {
               if(read(x,(char *)rst,sizeof(struct _restart)) != 0) {
                  secdiff = rst->timeoff - rst->timeon;
                  z = (int) (secdiff / 60L);		/* convert to minutes */
                  y = timeon();
                  if ((unsigned long)(y + z) <= rst->max_time){ /* We can bump it up */
                     rst->timeoff += 60 * timeon();
                     rst->timeon += 60 * timeon();
                  }
                  lseek(x,0L,SEEK_SET);		/* Rewind the file */
                  write(x,(struct _restart *) rst,sizeof(struct _restart));
               }
               close(x);
            }
         }
      }
      else {		/* RestarXX doesn't exist so we muck LastUser instead */
         x = sopen(LastUse,O_RDWR | O_BINARY ,SH_DENYWR,S_IWRITE); 
         if (x != -1) {
            lseek(x,0L,SEEK_SET);		/* Rewind the file */
            LastUser.timeremaining += timeon();
            write(x,(char *) &LastUser,user_slen);
            close(x);
         }
      }
   }

   fclose(afile);
   sprintf(temp,"%s%s",sdrive,sdir);
   switch_dir(temp);		/* Change back to startup dir */
   FossilDeInit();
   setcolor(TextAttr[STD_TEXT]);
   exit(errcode);
}

void _pascal aborterror(int code,char *strng)
{
   int exitcode;

   fclose(outfile);
   exitcode = 1;


   switch (code) {
      case BADALLOC:
         strcpy(temp,"Error allocating memory");
         break;

      case BADEXEC:
         strcpy(temp,"Error executing external program");
         break;

      case FILEOPEN:
         strcpy(temp,"Error opening file");
         exitcode = 4;
         break;

      case FILECREATE:
         strcpy(temp,"Error creating file");
         exitcode = 4;
         break;

      case FILEWRITE:
         strcpy(temp,"Error writing file");
         exitcode = 4;
         break;

      case DROPCARRIER:
         strcpy(temp,"User dropped carrier!");
         IsLocal = TRUE;
         exitcode = 3;
         break;

      case DEADMODEM:
         strcpy(temp,"Modem output appears dead!");
         IsLocal = TRUE;
         exitcode = 3;
         break;

      case USERIDLE:
         sprintf(temp,"User was idle more than %d minutes!",IDLETIME);
         IsLocal = TRUE;
         exitcode = 3;
         break;

      default:
         strcpy(temp,"General failure");
         break;
   }

   if (code != DEADMODEM) {

      setcolor(TextAttr[ATTN_TEXT]);
      strout("\r\n");
      if (strng)  {
         strout(strng);
         logit(strng,'!');
      }
      else {
         strout(temp);
         logit(temp,'!');
      }
      strout("\r\n");
      setcolor(TextAttr[STD_TEXT]);
   }
   else logit(strng,'!');

   deinit(exitcode);
}

int _pascal load_cfgfile(char *cfgfile)
{
   FILE *cfile;
   char *p1,*p2,*p3;
   int x,y;

   cfile = _fsopen(cfgfile,"rt",SH_DENYNO);
   if (cfile == NULL) {		/* Try to open it in executable maxmail dir */
      _splitpath(cfgfile,dummy,dummy,temp,temp1);		/* Extract just filename */
      _makepath(dummy,hdrive,hdir,temp,temp1);
      cfile = _fsopen(dummy,"rt",SH_DENYNO);
      if (cfile == NULL) {		/* Not there? Then its hopeless! */
         sprintf(temp1,"Error opening '%s' config file!\r\n",dummy);
         aborterror(FILEOPEN,temp1);
      }
   }

   fgets(temp,81,cfile);
   while (!feof(cfile)) {
      if (*temp != '\0') {		/* Parse out token string */
         p1 = strtok(temp," \n\t");
         p2 = strtok(NULL," \n\t;");
         if (strcmpi(p1,";") == 0) {		/* Just ignore comment lines */
            fgets(temp,81,cfile);
            continue;
         }
         if (strcmpi(p1,"TxtFile") == 0) {
            if (p2) strcpy(TxtFile,p2);
         }
         else if (strcmpi(p1,"CfgFile") == 0) {
            if (p2) strcpy(CfgFile,p2);
         }
         else if (strcmpi(p1,"LogFile") == 0) {
            if (p2) strcpy(LogFile,p2);
            LogMode = VERBOSE;		/* Default mode */
         }
         else if (strcmpi(p1,"NewHelpFile") == 0) {
            if (p2) strcpy(NewHelpFil,p2);
         }
         else if (strcmpi(p1,"HelpFile") == 0) {
            if (p2) strcpy(HelpFile,p2);
         }
         else if (strcmpi(p1,"MaximumMessages") == 0) {
            if (p2) MaxMsgs = atoi(p2);
         }
         else if (strcmpi(p1,"MessageHeader") == 0) {
            if (p2) strcpy(MsgHdrFile,p2);
         }
         else if (strcmpi(p1,"NewFilesList") == 0) {
            if (p2) strcpy(NewFiles,p2);
         }
         else if (strcmpi(p1,"SignOutMsg") == 0) {
            x = 0;
            p3 = strtok(p2," ;_\n\t");
            while (p3) {
               x += strlen(p3);
               strncat(SignOff,p3,79);
               strcat(SignOff," ");
               p3 = strtok(NULL," ;_\n\t");
               if (strlen(SignOff) >= 80)
                  break;
            }
         }
         else if (strcmpi(p1,"Packer") == 0) {
            x = 0;
            temp1[0] = '\0';
            while (p2) {
               strcat(temp1,p2);		/* Description string */
               strcat(temp1," ");		/* Add a blank for safety */
               if (++x > 4)		/* Packer requires 4 parameter fields */
                  break;
               p2 = strtok(NULL," ;\n\t");
            }
            if (x >= 4) enable_packer(temp1);
         }
         else if (strcmpi(p1,"Protos") == 0) {
            x = 0;
            temp1[0] = '\0';
            while (p2) {
               strcat(temp1,p2);		/* Description string */
               strcat(temp1," ");		/* Add a blank for safety */
               if (++x >= 3)		/* Packer requires 3 parameter fields */
                  break;
               p2 = strtok(NULL," ;\n\t");
            }
            if (x >= 3) enable_proto(temp1);
         }
         else if (strcmpi(p1,"RepUpload") == 0) {
            x = 0;
            temp1[0] = '\0';
            while (p2) {
               strcat(temp1,p2);		/* Description string */
               strcat(temp1," ");		/* Add a blank for safety */
               if (++x >= 3)		/* Packer requires 3 parameter fields */
                  break;
               p2 = strtok(NULL," ;\n\t");
            }
            if (x >= 3) enable_upl(temp1);
         }
         else if (strcmpi(p1,"SkipAreas") == 0) {
            strcpy(temp1,p2);		/* Copy area numbers */
            p2 = strtok(temp1,", \t");
            y = 1;
            while (p2) {
               if (!SkipCount)
                  SkipAreas = (int **) calloc(1,sizeof(int *));
               else SkipAreas = (int **) realloc(SkipAreas,sizeof(int *) * (y+1));
               if (SkipAreas == NULL)
                  aborterror(BADALLOC,NULL);
               SkipAreas[y-1] = (int *) malloc(sizeof(int));
               if (SkipAreas[y-1] == NULL)
                  aborterror(BADALLOC,NULL);
               *(SkipAreas[y-1]) = atoi(p2);		/* Plug in the area number */
               y++;
               SkipCount++;
               p2 = strtok(NULL,", \t");
            }
         }
         else if (strcmpi(p1,"ForceAreas") == 0) {
            strcpy(temp1,p2);		/* Copy area numbers */
            p2 = strtok(temp1,", \t");
            y = 1;
            while (p2) {
               if (!ForceCount)
                  ForceAreas = (int **) calloc(1,sizeof(int *));
               else ForceAreas = (int **) realloc(ForceAreas,sizeof(int *) * (y+1));
               if (ForceAreas == NULL)
                  aborterror(BADALLOC,NULL);
               ForceAreas[y-1] = (int *) malloc(sizeof(int));
               if (ForceAreas[y-1] == NULL)
                  aborterror(BADALLOC,NULL);
               *(ForceAreas[y-1]) = atoi(p2);		/* Plug in the area number */
               y++;
               ForceCount++;
               p2 = strtok(NULL,", \t");
            }
         }
         else if (strcmpi(p1,"TempDir") == 0) {
            if (p2) strcpy(tdir,p2);
         }
         else if (strcmpi(p1,"ExtendedBarrier") == 0) {
            if (p2) {
               if(strcmpi(p2,"yes") == 0)
                  ExtendOk = TRUE;
               else ExtendOk = FALSE;
            }
         }
         else if (strcmpi(p1,"WatchDog") == 0) {
            if (p2) {
               if(strcmpi(p2,"yes") == 0)
                  WatchDog = TRUE;
            }
         }
         else if(strcmpi(p1,"Colors") == 0) {
            strcpy(temp1,p2);		/* Copy colors numbers */
            p2 = strtok(temp1,", \t");
            for (x=0; x < 7; x++) {
               if (p2) TextAttr[x] = (byte) atoi(p2);
               else {		/* Sysop didn't give full set! */
                  y = TextAttr[x-1];		/* Fetch last attribute */
                  while (x < 7) 
                     TextAttr[x++] = (byte) y;		/* And store to remainder */
                  break;
               }
               p2 = strtok(NULL,", \t");		/* Fetch next token */
            }
         }
         else if (strcmpi(p1,"Bulletin") == 0) {
            if (p2) strcpy(BullFile,p2);
         }
         else if (strcmpi(p1,"DownloadHangup") == 0) {
            if (strcmpi(p2,"STRING") == 0) {
               Hangup = 1;
               HangupMode = 1;
            }
            else if (strcmpi(p2,"DTR") == 0){
               Hangup = 2;
               HangupMode = 2;
            }
            else Hangup = 0;		/* Disable it */
         }
         else if (strcmpi(p1,"MaxDailyCalls") == 0) {
            if (p2) MaxDaily = atoi(p2);
         }
         else if (strcmpi(p1,"ReDirectPacker") == 0) {
            if (p2) {
               if(strcmpi(p2,"yes") == 0)
                  ReDirect = TRUE;
            }
         }
         else if (strcmpi(p1,"UseCommand") == 0) {
            if (p2) {
               if(strcmpi(p2,"yes") == 0)
                  Command = TRUE;
            }
         }
         else if (strcmpi(p1,"StripTags") == 0) {
            if (p2) {
               if(strcmpi(p2,"no") == 0)
                  StripTags = FALSE;
            }
         }
         else if (strcmpi(p1,"QWKWelcome") == 0) {
            if (p2) {
               strcpy(QWKWelcome,p2);
            }
         }
         else if (strcmpi(p1,"QWKnews") == 0) {
            if (p2) {
               strcpy(QWKnews,p2);
            }
         }
         else if (strcmpi(p1,"QWKbye") == 0) {
            if (p2) {
               strcpy(QWKbye,p2);
            }
         }
         else if (strcmpi(p1,"BBSphone") == 0) {
            if (p2) {
               memset(BBSphone,0,15);
               strncpy(BBSphone,p2,14);
            }
         }
         else if (strcmpi(p1,"BBSid") == 0) {
            if (p2) {
               memset(BBSid,0,15);
               strncpy(BBSid,p2,8);
            }
         }
         else if (strcmpi(p1,"RepZip") == 0) {
            if (p2 && ZIPREP == NULL) {
               ZIPREP = (struct reparc_st *) malloc(sizeof(struct reparc_st));
               if (ZIPREP == NULL)
                  aborterror(BADALLOC,NULL);
               ZIPREP->packexe = (char *) malloc(strlen(p2) + 1);
               if (ZIPREP->packexe == NULL)
                  aborterror(BADALLOC,NULL);
               strcpy(ZIPREP->packexe,p2);
               p3 = strtok(NULL," \n\t;");
               if (p3) {
                  p2 = strchr(p3,'_');		/* Look for replacements */
                  while (p2) {
                     *p2 = ' ';            		/* Put a blank instead */
                     p2++;
                     p2 = strchr(p2,'_');		/* Look for replacements */
                  }
                  ZIPREP->packstring = (char *) malloc(strlen(p3) + 1);
                  if (ZIPREP->packstring == NULL)
                     aborterror(BADALLOC,NULL);
                  strcpy(ZIPREP->packstring,p3);
               }
            }
         }
         else if (strcmpi(p1,"RepLha") == 0) {
            if (p2 && LHAREP == NULL) {
               LHAREP = (struct reparc_st *) malloc(sizeof(struct reparc_st));
               if (LHAREP == NULL)
                  aborterror(BADALLOC,NULL);
               LHAREP->packexe = (char *) malloc(strlen(p2) + 1);
               if (LHAREP->packexe == NULL)
                  aborterror(BADALLOC,NULL);
               strcpy(LHAREP->packexe,p2);
               p3 = strtok(NULL," \n\t;");
               if (p3) {
                  p2 = strchr(p3,'_');		/* Look for replacements */
                  while (p2) {
                     *p2 = ' ';            		/* Put a blank instead */
                     p2++;
                     p2 = strchr(p2,'_');		/* Look for replacements */
                  }
                  LHAREP->packstring = (char *) malloc(strlen(p3) + 1);
                  if (LHAREP->packstring == NULL)
                     aborterror(BADALLOC,NULL);
                  strcpy(LHAREP->packstring,p3);
               }
            }
         }
         else if (strcmpi(p1,"RepArc") == 0) {
            if (p2 && ARCREP == NULL) {
               ARCREP = (struct reparc_st *) malloc(sizeof(struct reparc_st));
               if (ARCREP == NULL)
                  aborterror(BADALLOC,NULL);
               ARCREP->packexe = (char *) malloc(strlen(p2) + 1);
               if (ARCREP->packexe == NULL)
                  aborterror(BADALLOC,NULL);
               strcpy(ARCREP->packexe,p2);
               p3 = strtok(NULL," \n\t;");
               if (p3) {
                  p2 = strchr(p3,'_');		/* Look for replacements */
                  while (p2) {
                     *p2 = ' ';            		/* Put a blank instead */
                     p2++;
                     p2 = strchr(p2,'_');		/* Look for replacements */
                  }
                  ARCREP->packstring = (char *) malloc(strlen(p3) + 1);
                  if (ARCREP->packstring == NULL)
                     aborterror(BADALLOC,NULL);
                  strcpy(ARCREP->packstring,p3);
               }
            }
         }
      }
      fgets(temp,81,cfile);
   }
   fclose(cfile);
   return(TRUE);
}


/* Setup a protocol using string format as follows:
   "Description Filename Commandline"
        |           |          |----------- Command line for program.
        |           |
        |           |---------------------- Full filename (No path)
        |
        |---------------------------------- Desribe protocol in 1-2 words
*/

void _pascal enable_proto(char *strng)
{
   char cmndline[40];
   char describe[20];
   char fname[14];
   char *p,*p1;
   int x;
   struct proto_st *proto1;


   p = strtok(strng," \t");		/* Fetch description */
   if (!p)
      return;		/* Invalid */
   p1 = strchr(p,'_');		/* Look for replacements */
   while (p1) {
      *p1 = ' ';            		/* Put a blank instead */
      p1++;
      p1 = strchr(p1,'_');		/* Look for replacements */
   }
   x = strlen(p);
   x = x > 29 ? 29 : x;
   strncpy(describe,p,x);
   describe[x] = '\0';
   
   p = strtok(NULL," \t");		/* Fetch filename */
   if (!p)
      return;		/* Invalid */
   p1 = strchr(p,'_');		/* Look for replacements */
   while (p1) {
      *p1 = ' ';            		/* Put a blank instead */
      p1++;
      p1 = strchr(p1,'_');		/* Look for replacements */
   }
   x = strlen(p);
   x = x > 13 ? 13 : x;
   strncpy(fname,p,x);
   fname[x] = '\0';
   
   p = strtok(NULL," \t");		/* Fetch command line */
   if (!p)
      return;		/* Invalid */
   p1 = strchr(p,'_');		/* Look for replacements */
   while (p1) {
      *p1 = ' ';            		/* Put a blank instead */
      p1++;
      p1 = strchr(p1,'_');		/* Look for replacements */
   }
   x = strlen(p);
   x = x > 39 ? 39 : x;
   strncpy(cmndline,p,x);
   cmndline[x] = '\0';
   

   proto1 = (struct proto_st *) malloc(sizeof(struct proto_st));
   if (proto1 == NULL)
      aborterror(BADALLOC,NULL);

   if (totprotocols)
      PROTO_cur->next = proto1;
   else PROTO_1 = proto1;

   proto1->protoexe = (char *) malloc(strlen(fname) + 1);
   if (proto1->protoexe == NULL)
      aborterror(BADALLOC,NULL);
   strcpy(proto1->protoexe,fname);

   proto1->protostring = (char *) malloc(strlen(cmndline) + 1);
   if (proto1->protostring == NULL)
      aborterror(BADALLOC,NULL);
   strcpy(proto1->protostring,cmndline);

   proto1->protoname = (char *) malloc(strlen(describe) + 1);
   if (proto1->protoname == NULL)
      aborterror(BADALLOC,NULL);
   strcpy(proto1->protoname,describe);

   PROTO_cur = proto1;
   proto1->next = NULL;

   totprotocols++;
}

/* Setup an upload protocol using string format as follows:
   "Filename Commandline"
        |          |----------- Command line for program.
        |---------------------- Full filename (No path)
*/

void _pascal enable_upl(char *strng)
{
   char cmndline[40];
   char fname[14];
   char describe[20];
   char *p,*p1;
   int x;
   struct repupl_st *upl1;

   p = strtok(strng," \t");		/* Fetch description */
   if (!p)
      return;		/* Invalid */
   p1 = strchr(p,'_');		/* Look for replacements */
   while (p1) {
      *p1 = ' ';            		/* Put a blank instead */
      p1++;
      p1 = strchr(p1,'_');		/* Look for replacements */
   }
   x = strlen(p);
   x = x > 29 ? 29 : x;
   strncpy(describe,p,x);
   describe[x] = '\0';
   
   p = strtok(NULL," \t");		/* Fetch filename */
   if (!p)
      return;		/* Invalid */
   p1 = strchr(p,'_');		/* Look for replacements */
   while (p1) {
      *p1 = ' ';            		/* Put a blank instead */
      p1++;
      p1 = strchr(p1,'_');		/* Look for replacements */
   }
   x = strlen(p);
   x = x > 13 ? 13 : x;
   strncpy(fname,p,x);
   fname[x] = '\0';
   
   p = strtok(NULL," \t");		/* Fetch command line */
   if (!p)
      return;		/* Invalid */
   p1 = strchr(p,'_');		/* Look for replacements */
   while (p1) {
      *p1 = ' ';            		/* Put a blank instead */
      p1++;
      p1 = strchr(p1,'_');		/* Look for replacements */
   }
   x = strlen(p);
   x = x > 39 ? 39 : x;
   strncpy(cmndline,p,x);
   cmndline[x] = '\0';
   

   upl1 = (struct repupl_st *) malloc(sizeof(struct repupl_st));
   if (upl1 == NULL)
      aborterror(BADALLOC,NULL);

   if (!totuplreps)
      REPUPL_1 = upl1;
   else REPUPL_cur->next = upl1;

   upl1->protoexe = (char *) malloc(strlen(fname) + 1);
   if (upl1->protoexe == NULL)
      aborterror(BADALLOC,NULL);
   strcpy(upl1->protoexe,fname);

   upl1->protostring = (char *) malloc(strlen(cmndline) + 1);
   if (upl1->protostring == NULL)
      aborterror(BADALLOC,NULL);
   strcpy(upl1->protostring,cmndline);

   upl1->protoname = (char *) malloc(strlen(describe) + 1);
   if (upl1->protoname == NULL)
      aborterror(BADALLOC,NULL);
   strcpy(upl1->protoname,describe);

   REPUPL_cur = upl1;
   upl1->next = NULL;

   totuplreps++;
}

/* Setup a packer using string format as follows:
   "Description Filename ArcFname Commandline"
        |           |       |        |------ Command line for program.
        |           |       |
        |           |       |--------------- Name of packed file
        |           |
        |           |---------------------- Full filename (No path)
        |
        |---------------------------------- Desribe packer in 1-2 words
*/

void _pascal enable_packer(char *strng)
{
   char cmndline[40];
   char viewline[40];
   char describe[20];
   char fname[14];
   char aname[14];
   char *p,*p1;
   int x;
   struct packer_st *pack1;


   p = strtok(strng," \t");		/* Fetch description */
   if (!p)
      return;		/* Invalid */
   p1 = strchr(p,'_');		/* Look for replacements */
   while (p1) {
      *p1 = ' ';            		/* Put a blank instead */
      p1++;
      p1 = strchr(p1,'_');		/* Look for replacements */
   }
   x = strlen(p);
   x = x > 29 ? 29 : x;
   strncpy(describe,p,x);
   describe[x] = '\0';
   
   p = strtok(NULL," \t");		/* Fetch filename */
   if (!p)
      return;		/* Invalid */
   p1 = strchr(p,'_');		/* Look for replacements */
   while (p1) {
      *p1 = ' ';            		/* Put a blank instead */
      p1++;
      p1 = strchr(p1,'_');		/* Look for replacements */
   }
   x = strlen(p);
   x = x > 13 ? 13 : x;
   strncpy(fname,p,x);
   fname[x] = '\0';
   
   p = strtok(NULL," \t");		/* Fetch packed filename */
   if (!p)
      return;		/* Invalid */
   p1 = strchr(p,'_');		/* Look for replacements */
   while (p1) {
      *p1 = ' ';            		/* Put a blank instead */
      p1++;
      p1 = strchr(p1,'_');		/* Look for replacements */
   }
   x = strlen(p);
   x = x > 13 ? 13 : x;
   strncpy(aname,p,x);
   aname[x] = '\0';
   
   p = strtok(NULL," \t");		/* Fetch command line */
   if (!p)
      return;		/* Invalid */
   p1 = strchr(p,'_');		/* Look for replacements */
   while (p1) {
      *p1 = ' ';            		/* Put a blank instead */
      p1++;
      p1 = strchr(p1,'_');		/* Look for replacements */
   }
   x = strlen(p);
   x = x > 39 ? 39 : x;
   strncpy(cmndline,p,x);
   cmndline[x] = '\0';
   
   viewline[0] = '\0';
   p = strtok(NULL," \t");		/* Fetch viewline */
   if (p) {
      p1 = strchr(p,'_');		/* Look for replacements */
      while (p1) {
         *p1 = ' ';            		/* Put a blank instead */
         p1++;
         p1 = strchr(p1,'_');		/* Look for replacements */
      }
      x = strlen(p);
      x = x > 39 ? 39 : x;
      strncpy(viewline,p,x);
      viewline[x] = '\0';
   }
   
   pack1 = (struct packer_st *) malloc(sizeof(struct packer_st));
   if (pack1 == NULL)
      aborterror(BADALLOC,NULL);

   if (totpackers) 
      PACKER_cur->next = pack1;
   else PACKER_1 = pack1;		/* Start up linked list */

   pack1->viewstring = NULL;

   pack1->packexe = (char *) malloc(strlen(fname) + 1);
   if (pack1->packexe == NULL)
      aborterror(BADALLOC,NULL);
   strcpy(pack1->packexe,fname);

   pack1->packstring = (char *) malloc(strlen(cmndline) + 1);
   if (pack1->packstring == NULL)
      aborterror(BADALLOC,NULL);
   strcpy(pack1->packstring,cmndline);

   if (viewline[0]) {
      pack1->viewstring = (char *) malloc(strlen(viewline) + 1);
      if (pack1->viewstring == NULL)
         aborterror(BADALLOC,NULL);
      strcpy(pack1->viewstring,viewline);
   }

   pack1->packname = (char *) malloc(strlen(describe) + 1);
   if (pack1->packname == NULL)
      aborterror(BADALLOC,NULL);
   strcpy(pack1->packname,describe);

   pack1->packpname = (char *) malloc(strlen(aname) + 1);
   if (pack1->packpname == NULL)
      aborterror(BADALLOC,NULL);
   strcpy(pack1->packpname,aname);

   PACKER_cur = pack1;
   pack1->next = NULL;

   totpackers++;
}


