/****************************************************************************/
/*                                                                          */
/*    Config.c    User configuration routines for Maxmail                   */
/*                                                                          */
/****************************************************************************/

#include "MaxMail.h"

int _FAR_ _cdecl inp(unsigned);
int _FAR_ _cdecl outp(unsigned, int);

int msgnum,handle,areas_sel;
int Usercount;
char msgstr[81];
struct user_cfg uscfg;
struct msgupd_st *msgupd;
struct msgupd_st *prev;

#define TIMERMODE 182		/* code to put timer in right mode */
#define FREQSCALE 1190000L	/* basic time frequency in hertz   */
#define TIMESCALE 1230L		/* number of counts in 0.1 second  */
#define T_MODEPORT 67		/* port controls timer mode        */
#define FREQPORT   66		/* port controls tone frequency    */
#define BEEPPORT   97		/* port controls speaker           */
#define ON         79		/* signal to turn speaker on       */

void _pascal configmenu(void)
{
   int choice = TRUE;
   char resp;
   int good,x;
   struct packer_st *pack1;
   struct proto_st  *proto1;

   do
   {
      clearscreen();
      proto1 = get_curprotolnk();
      pack1 = get_curpacklnk();
      setcolor(TextAttr[STD_TEXT]);
      strout("\r\nMaxMail configuration menu\r\n");
      strout("----------------------------------------------------\r\n");
      setcolor(TextAttr[MENU_KEY]);
      strout("[A]dd message areas\r\n");
      if (USERCFG.totselareas) {
         setcolor(TextAttr[MENU_KEY]);
         strout("[D]elete message areas\r\n");
         strout("[E]rase all current selected message areas\r\n");
      }
      setcolor(TextAttr[MENU_KEY]);
      strout("[H]ang up after download            :");
      setcolor(TextAttr[HILITE_TEXT]);
      if (USERCFG.flags & DLHANGUP)
         strout(" Always, if sysop has it enabled\r\n");
      else strout(" Ask every time\r\n");
      setcolor(TextAttr[MENU_KEY]);
      strout("[L]ist message areas                :");
      setcolor(TextAttr[HILITE_TEXT]);
      if (USERCFG.totselareas)
         sprintf(temp," Currently, %d selected\r\n",USERCFG.totselareas);
      else strcpy(temp," No message areas are currently selected\r\n");
      strout(temp);
      setcolor(TextAttr[MENU_KEY]);
      strout("[M]essage style                     :");
      setcolor(TextAttr[HILITE_TEXT]);
      if (USERCFG.msgfrmt == 1)
         strout(" QWK\r\n");
      else strout(" Standard Text\r\n");
      setcolor(TextAttr[MENU_KEY]);
      strout("[N]ewfiles list included            :");
      setcolor(TextAttr[HILITE_TEXT]);
      if (USERCFG.flags & NEWFILES_INC)
         strout(" Yes\r\n");
      else strout(" No\r\n");
      setcolor(TextAttr[MENU_KEY]);
      strout("[P]acking method                    :");
      setcolor(TextAttr[HILITE_TEXT]);
      if (USERCFG.packer)
         sprintf(temp," %s\r\n",pack1->packname);
      else strcpy(temp," NONE, always ask.\r\n");
      setcolor(TextAttr[HILITE_TEXT]);
      strout(temp);
      if (USERCFG.msgfrmt == 1) {
         setcolor(TextAttr[MENU_KEY]);
         strout("[T]otal messages packed per area    :");
         setcolor(TextAttr[HILITE_TEXT]);
         if (USERCFG.maxareamsgs == 0)
            strout(" ALL\r\n");
         else {
            sprintf(temp," %u\r\n",USERCFG.maxareamsgs);
            strout(temp);
         }
      }
      setcolor(TextAttr[MENU_KEY]);
      strout("[X]fer protocol                     :");
      if (USERCFG.protocol)
         sprintf(temp," %s\r\n",proto1->protoname);
      else strcpy(temp," NONE, always ask.\r\n");
      setcolor(TextAttr[HILITE_TEXT]);
      strout(temp);
      strout("\r\n");
      setcolor(TextAttr[STD_TEXT]);
      strout("[Q]uit to main menu\r\n");
      good = FALSE;
      strout("\r\n");
      while (!good) {
         timeremain();
         setcolor(TextAttr[PROMPT_TEXT]);
         strout("Choice --> ");
         ChatOk = TRUE;
         x = chrin();
         ChatOk = FALSE;
         resp = (char) x;
         if(resp == '\r')
            resp = '0';
         good = TRUE;
         chrout(resp);
         strout("\r\n");
         setcolor(TextAttr[STD_TEXT]);
         switch (toupper((int) resp)) {
            case 'A':		/* add message areas */
               add_msgareas();
               break;

            case 'D':		/* delete message areas */
               if (USERCFG.totselareas) 
                  del_msgareas();
               break;

            case 'E':		/* Erase all current message areas */
               if (!USERCFG.totselareas)
                  break;
               setcolor(TextAttr[HILITE_TEXT]);
               strout("\r\nAre you sure you wish to erase ALL your currently select message areas?\r\n");
               if (getyn(TRUE)) {
                  memset(&USERCFG.msgarea,0,64);		/* Clear out table */
                  USERCFG.totselareas = 0;
                  msgupd = MSGUPD_1;
                  while (msgupd) {
                     prev = msgupd->next;
                     free(msgupd);
                     msgupd = prev;
                  }
                  MSGUPD_1 = NULL;
               }
               break;

            case 'H':		/* Toggle hangup after download */
               USERCFG.flags ^= DLHANGUP;
               break;

            case 'L':		/* List msg areas */
               strout("\r\nCurrently selected areas:\r\n\r\n");
               show_areas(FALSE);
               presskey();
               break;

            case 'M':		/* Change message format */
               get_msgtype();
               break;

            case 'N':		/* Get newfiles type */
               USERCFG.flags ^= NEWFILES_INC;
               break;

            case 'P':		/* change packer type */
               get_packer(TRUE);
               break;

            case 'Q':
               choice = FALSE;
               break;

            case 'T':
               if (USERCFG.msgfrmt == 1) 
                  get_totperarea();
               break;

            case 'X':		/* Change download protocol */
               get_proto(TRUE);
               break;

            case '!':
            case '0':		/* Redisplay */
               break;
         }
      }
   }
   while (choice);
   USERCFG.flags &= ~USRCFG_UPD;		/* Turn off update flags */
   USERCFG.flags &= ~USRCFG_FUPD;  	/* Turn off forced update flags */
}

void _pascal getconfig(void)
{
   areas_sel = FALSE;

	/* Now ask user to set up message areas to read */
   if (USERCFG.flags & USRCFG_MSGUPD  && !newuser) {
      setcolor(TextAttr[ATTN_TEXT]);
      strout("\r\nSysop has changed available message areas. You are required to redo\r\n");
      strout("your areas selection again,sorry.");
      presskey();
      memset(&USERCFG.msgarea,0,64);		/* Clear out table */
      USERCFG.totselareas = 0;
      msgupd = MSGUPD_1;
      while (msgupd) {
         prev = msgupd->next;
         free(msgupd);
         msgupd = prev;
      }
      MSGUPD_1 = NULL;
      MarkForce();
      add_msgareas();
   }

   if (newuser) {
      MarkForce();
      add_msgareas();
      get_msgtype();
      if (USERCFG.msgfrmt == 1) 
         get_totperarea();
      get_packer(TRUE);
      get_proto(TRUE);
   }
   else if (USERCFG.flags & USRCFG_FUPD) {
      setcolor(TextAttr[ATTN_TEXT]);
      strout("\r\nSorry, but the Sysop needs you to re-do your configuration again.");
      presskey();
      memset(&USERCFG.msgarea,0,64);		/* Clear out table */
      USERCFG.totselareas = 0;
      msgupd = MSGUPD_1;
      while (msgupd) {
         prev = msgupd->next;
         free(msgupd);
         msgupd = prev;
      }
      MSGUPD_1 = NULL;
      MarkForce();
      configmenu();
   }
}

void _pascal list_config()
{
   struct packer_st *pack1;
   struct proto_st  *proto1;

   strout("\r\nYour current MaxMail configuration\r\n");
   strout("-------------------------------------------------------\r\n");

   strout("Message areas selected:\r\n");
   show_areas(FALSE);
   proto1 = get_curprotolnk();
   pack1 = get_curpacklnk();

   strout("-------------------------------------------------------\r\n");
   if (USERCFG.msgfrmt == 1) 
      strout("Message Format: QWK");
   else strout("Message Format: Standard text");
   if (USERCFG.maxareamsgs) {
      sprintf(temp,"\r\nYou will pack up a maximum of %u messages per area",USERCFG.maxareamsgs);
      strout(temp);
   }
   else strout("\r\nYou will pack up ALL new messages in each area, if possible");
   if (USERCFG.flags & NEWFILES_INC)
      strout("\r\nYou are including a newfiles listing in your mail packet");
   if (USERCFG.protocol)
      sprintf(temp,"\r\nDefault protocol: %s\r\n",proto1->protoname);
   else strcpy(temp,"\r\nDefault protocol: NONE, always ask.\r\n");
   strout(temp);
   if (USERCFG.packer)
      sprintf(temp,"Default packer: %s\r\n",pack1->packname);
   else strcpy(temp,"Default packer: NONE, always ask.\r\n");
   strout(temp);
   if (USERCFG.flags & DLHANGUP) {
      strcpy(temp,"You have turned on automatic Hangup after download\r\n");
      strout(temp);
   }
   strout("-------------------------------------------------------\r\n");
   presskey();
}

int _pascal new_user(int filenum)
{
   int x,y;

   x = 0;
   USERCFG.flags |= USRCFG_UPD;		/* Force the user to update his configuration */

/* Seek to start of file and count records */
   if(lseek(filenum,0L,SEEK_SET) >= 0L)	 {	/* Rewind to begginning */
      y = read(filenum,(char *) &uscfg,sizeof(struct user_cfg));
      while (y == sizeof(struct user_cfg)) {
         x++;		/* Simple count */
         y = read(filenum,(char *) &uscfg,sizeof(struct user_cfg));
      }
   }
   return(x);
}

void _pascal update_usercfg(int filenum)
{
   lseek(filenum,(long) (UserCfgnum * sizeof(struct user_cfg)),SEEK_SET);		/* Append to tail of file */
   write(filenum,(struct user_cfg *) &USERCFG,sizeof(struct user_cfg));
}

/* Convert message number to bitmap location and turn it on */
void _pascal msgmark(int num)
{
   word *bitp;
   int x,mask;

   if (isskiparea(num))
      return;
   
   bitp = &USERCFG.msgarea[num / 16];		/* Point to proper slot, 16 bits per slot */
   mask = 1;
   for (x=0; x < (num % 16); x++)
      mask = mask << 1;
   *bitp = *bitp | mask;		/* Turn it on */
   areas_sel = TRUE;
   return;
}

/* Convert message number to bitmap location and turn it off */
void _pascal msgunmark(int num)
{
   word *bitp;
   int x,mask;
   
   bitp = &USERCFG.msgarea[num / 16];		/* Point to proper slot, 16 bits per slot */
   mask = 1;
   for (x=0; x < (num % 16); x++)
      mask = mask << 1;
   *bitp &= ~mask;		/* Turn it off */
}


int _pascal screen_areas(int flag)
{
   int  x,keys,col;
   int  msgpos,anum,index;
   int  areas;
   struct _aidx IDX;

   index = sopen(PRM(aidx_name),O_BINARY | O_RDONLY,SH_DENYNO,S_IREAD);
   if (index == -1)
      aborterror(FILEOPEN,"Error opening Area index file");
   keys = read(index,(char *)&IDX,sizeof(struct _aidx));
   fseek(afile,IDX.offset,SEEK_SET);
   fread(&AREA,astrlen,1,afile);
   areas = 0;
   anum = 0;
   while (keys) {
      msgpos = 0;
      col = 0;
      while (keys && (msgpos < 20)) {
         keys = testlock();
         if (isskiparea(anum))
            keys = FALSE; 		/* If Sysop set skip, don't show this area */
         x = atoi(AREA.name);		/* Get Message area */
         if (AREA.msgpath[0] && (LastUser.priv >= AREA.msgpriv) && keys ) {
            if (flag) {		/* If true show areas we don't already have selected */
               if (is_selarea(anum)) {		/* We already have this area */
                  keys = read(index,(char *)&IDX,sizeof(struct _aidx));
                  fseek(afile,IDX.offset,SEEK_SET);
                  fread(&AREA,astrlen,1,afile);
                  anum++;
                  continue;
               }
            }
            areas++;
            if (!col) { 	/* 1st column */
               strncpy(temp,AREA.msginfo,20);
               temp[20] = 0;
               sprintf(msgstr,"[%d] %s",anum,temp);
               x = strlen(msgstr);
               while (x++ < 26) 
                  strcat(msgstr," ");		/* Pad it for formatting */
            }
            else {		/* 2nd or 3rd column */
               strncpy(temp1,AREA.msginfo,20);
               temp1[20] = 0;
               sprintf(temp,"[%d] %s",anum,temp1);
               x = strlen(temp);
               while (x++ < 26) 
                  strcat(temp," ");		/* Pad it for formatting */
               strcat(msgstr,temp);
               if (col == 2) {
                  strcat(msgstr,"\r\n");
                  setcolor(TextAttr[STD_TEXT]);
                  strout(msgstr);
                  msgpos++;		/* Another row is spit out */
                  col = -1;
               }
            }
            col++;
         }
         keys = read(index,(char *)&IDX,sizeof(struct _aidx));
         fseek(afile,IDX.offset,SEEK_SET);
         fread(&AREA,astrlen,1,afile);		/* Read next area */
         anum++;
      }
      if (col) {		/* Some message areas left */
         setcolor(TextAttr[STD_TEXT]);
         strcat(msgstr,"\r\n");
         strout(msgstr);
      }
      if (keys) {		/* More areas than a pageful */
         setcolor(TextAttr[PROMPT_TEXT]);
         strout("\r\nMore areas?  ");
         if (getyn(FALSE)) {
            strout("\r\n");
            continue;
         }
         else break;
      }
      else break;
   }
   close(index);
   setcolor(TextAttr[STD_TEXT]);
   return areas;
}

void _pascal get_proto(int flag)
{
   byte x;
   char *p;

   setcolor(TextAttr[HILITE_TEXT]);
   strout("\r\n\r\nEnter default protocol to use\r\n");
   strout("-----------------------------\r\n");
   setcolor(TextAttr[MENU_KEY]);
   display_protos();
   if (flag)
      strout("[0] Always ask\r\n");
   while (1) {
      timeremain();
      setcolor(TextAttr[PROMPT_TEXT]);
      strout("--> ");
      strin(msgstr);
      if (!IsLocal)
         strout("\r\n");
      p = strtok(msgstr," \r");
      if (!(isdigit(*p)) && p != NULL) {
         setcolor(TextAttr[ATTN_TEXT]);
         strout("You must enter digits only!\r\n");
         continue;
      }
      x = (byte) atoi(p);
      if ((int) x <= totprotocols) {
         if (flag) 		/* Allow 0(Always Ask) */
            break;
         if (!flag && x != 0)
            break;
      }
   }
   USERCFG.protocol = x;

   USERCFG.totprotos = totprotocols;
}

void _pascal get_packer(int flag)
{
   byte x;
   char *p;

   x = 0;
   setcolor(TextAttr[HILITE_TEXT]);
   strout("\r\n\r\nEnter packing method you wish to use\r\n");
   strout("------------------------------------\r\n");
   setcolor(TextAttr[MENU_KEY]);
   display_packers();
   if (flag)
      strout("[0] Always ask\r\n");
   while (1) {
      timeremain();
      setcolor(TextAttr[PROMPT_TEXT]);
      strout("--> ");
      strin(msgstr);
      if (!IsLocal)
         strout("\r\n");
      p = strtok(msgstr," \r");
      if (!(isdigit(*p)) && p != NULL) {
         setcolor(TextAttr[ATTN_TEXT]);
         strout("You must enter digits only!\r\n");
         continue;
      }
      x = (byte) atoi(p);
      if ((int) x <= totpackers ) {
         if (flag) 		/* Allow 0(Always Ask) */
            break;
         if (!flag && x != 0) 
            break;
      }
   }

   if (USERCFG.packer != x && PackDone) {
      PackDone = FALSE;
      erase_arc();
      msgupd = MSGUPD_1;
      while (msgupd) {
         msgupd->update = FALSE;
         msgupd = msgupd->next;
      }
   }
   USERCFG.packer = x;
   USERCFG.totpackers = totpackers;
}

int _pascal reset_config(word flag)
{
   int x;
   long pos;

   Usercount = 0;
   x = sopen(CfgFile,O_RDWR | O_BINARY | O_CREAT,SH_DENYWR,S_IWRITE);
   if (x == -1) {
      strout("\r\nError opening config file! Try later.\r\n");
      return(FALSE);
   }
   logit("Sysop is reseting all current users",'#');
   lseek(x,0L,SEEK_SET);		/* Rewind to begginning */
   read(x,(char *) &uscfg,sizeof(struct user_cfg));
   while (!eof(x)) {
      pos = tell(x) - (long) sizeof(struct user_cfg);	/* Get position */
      if (uscfg.name[0]) {
         Usercount++;
         uscfg.flags |= flag;
         lseek(x,pos,SEEK_SET); 	/* Rewind back to this record */
         write(x,(struct user_cfg *) &uscfg,sizeof(struct user_cfg));
      }
      read(x,(char *) &uscfg,sizeof(struct user_cfg)); /* Next record */
   }
   close(x);
   return(TRUE);
}

int _pascal delete_users(void)
{
   int x,User;
   char *p1;
   struct user_cfg USCFG;

   if (test_task()) {
      setcolor(TextAttr[ATTN_TEXT]);
      strout("\r\nSorry, but someone else is using MaxMail currently. Try later!\r\n");
   }
   setcolor(TextAttr[STD_TEXT]);
   strout("Enter user's name ---> ");
   strin(temp);
   if (!IsLocal)
      strout("\r\n");
   p1 = strtok(temp,"\t\r\n");
   if (p1) {
      if (strcmpi(p1,LastUser.name) == 0) {
         setcolor(TextAttr[ATTN_TEXT]);
         strout("Whoah there pardner! You can't delete yourself!\r\n");
         return FALSE;
      }
      x = sopen(CfgFile,O_RDWR | O_BINARY | O_CREAT,SH_DENYNO,S_IWRITE);
      if (x == -1)
         aborterror(FILEOPEN,"Error opening/creating User config file");
      User = find_config(x,p1,&USCFG);
      if (User < 0) {
         setcolor(TextAttr[ATTN_TEXT]);
         strout("Sorry but that user name does not exist.\r\n");
      }
      else {
         strout("User is now being deleted.\r\n");
         sprintf(temp1,"Sysop is deleting user: %s",p1);
         logit(temp1,'#');
         memset(USCFG.name,0,36);		/* Delete */
         lseek(x,(long) User * sizeof(struct user_cfg),SEEK_SET);
         write(x,(struct user_cfg *) &USCFG,sizeof(struct user_cfg));
      }
      close(x);
   }
   return(TRUE);
}

void _pascal user_stats(void)
{
   int x,row,handle,y;
   byte z;
   struct tm  *newtime;
   char ttemp[40];
   char *month;
   char *day;
   struct packer_st *packer1;
   struct proto_st *proto1;

   setcolor(TextAttr[STD_TEXT]);
   if (!Usercount) {		/* We have to count the active users */
      EmptyRecs = 0;
      handle = sopen(CfgFile,O_RDWR | O_BINARY,SH_DENYNO,S_IREAD);
      if (handle == -1) {
         setcolor(TextAttr[ATTN_TEXT]);
         strout("\r\nError opening config file! Try later.\r\n");
         return;
      }
      y = read(handle,(char *) &uscfg,sizeof(struct user_cfg));
      while (y == sizeof(struct user_cfg)) {
         if (uscfg.name[0])
            Usercount++;
         else{
            EmptyRecs++;
         }
         y = read(handle,(char *) &uscfg,sizeof(struct user_cfg));
      }
      lseek(handle,0L,SEEK_SET);		/* Rewind file */
   }
   else {
      handle = sopen(CfgFile,O_RDWR | O_BINARY,SH_DENYNO,S_IREAD);
      if (handle == -1) {
         strout("\r\nError opening config file! Try later.\r\n");
         return;
      }
   }
   sprintf(temp,"\r\nCurrently, there are %d active users for MaxMail.\r\n",Usercount);
   setcolor(TextAttr[HILITE_TEXT]);
   strout(temp);
   if (EmptyRecs) {
      sprintf(temp,"There are %d empty records in the user file. Use the Pack function to clean.\r\n",EmptyRecs);
      strout(temp);
   }

/* Read all the users and display pertinent data */

   y = read(handle,(char *) &uscfg,sizeof(struct user_cfg));
   while (y == sizeof(struct user_cfg)) {
      setcolor(TextAttr[STD_TEXT]);
      strout("__________________________________________________________________________\r\n");
      strout("User Name          Lasttime  Frmt Calls Packs  Packer  Protocol  Flags\r\n");
      strout("--------------------------------------------------------------------------\r\n");
      row = 3;
      setcolor(TextAttr[HILITE_TEXT]);
      while (row < 23 && y == sizeof(struct user_cfg)) {
         while (uscfg.name[0] == 0 && y == sizeof(struct user_cfg)) 
            y = read(handle,(char *) &uscfg,sizeof(struct user_cfg));
         if (y != sizeof(struct user_cfg)) 
            break;
         strncpy(temp,uscfg.name,15);
         temp[15] = 0;
         while (strlen(temp) < 18)
            strcat(temp," ");
         newtime = localtime(&uscfg.lasttime);
         strcpy(ttemp,asctime(newtime));
         strtok(ttemp," ");               /* Strip Day of week */
         month = strtok(NULL," ");
         day = strtok(NULL," ");
         if (uscfg.calls < uscfg.packcount)
            uscfg.calls = uscfg.packcount;
         if (!uscfg.calls)
            uscfg.calls = 1;
         sprintf(temp1," %s %s    ",month,day);
         strcat(temp,temp1);
         if (uscfg.msgfrmt == 0)
            strcat(temp,"STD");
         else strcat(temp,"QWK");
         sprintf(temp1,"  %5d %5d  ",uscfg.calls,uscfg.packcount);
         strcat(temp,temp1);
         z = USERCFG.packer;
         USERCFG.packer = uscfg.packer; 	/* Temporary fix */
         packer1 = get_curpacklnk();
         USERCFG.packer = z;
         if (packer1 == NULL)
            strcat(temp,"None  ");
         else {
            strcpy(temp1,packer1->packname);
            day = strtok(temp1," "); 		/* Get 1st name only */
            while (strlen(day) < 6)
               strcat(day," ");
            strcat(temp,day);
         }
         uscfg.packer = (byte) x;
         strcat(temp,"  ");
         z = USERCFG.protocol;
         USERCFG.protocol = uscfg.protocol; 	/* Temporary fix */
         proto1 = get_curprotolnk();
         USERCFG.protocol = z;
         if (proto1 == NULL)
            strcat(temp,"None  ");
         else {
            strcpy(temp1,proto1->protoname);
            day = strtok(temp1," "); 		/* Get 1st name only */
            strcat(temp,day);
         }
         uscfg.protocol = (byte) x;
         strcat(temp,"    ");
      /* Tack on flags */
         if (uscfg.flags & LASTREAD_UPD)
            strcat(temp,"L");
         if (uscfg.flags & USRCFG_UPD)
            strcat(temp,"U");
         if (uscfg.flags & USRCFG_FUPD)
            strcat(temp,"F");
         if (uscfg.flags & USRCFG_MSGUPD)
            strcat(temp,"M");
         if (uscfg.flags & NEWFILES_INC)
            strcat(temp,"N");
         if (uscfg.flags & DLHANGUP)
            strcat(temp,"H");
         temp[79] = 0;
         strcat(temp,"\r\n");
         strout(temp);
         row++;
         y = read(handle,(char *) &uscfg,sizeof(struct user_cfg));
      }
      if (y == sizeof(struct user_cfg)) {		/* Still more records */
         strout("\r\nPress ESC to stop or any other key for more");
         x = chrin();
         strout("\r\n");
         if (x == 0x1b) 
            break;
      }
      else break;
   }
   close(handle);
   if (x != 0x1b) {
      presskey();
   }
}

void _pascal del_msgareas(void)
{
   char *p;
   int x;

   setcolor(TextAttr[STD_TEXT]);
   strout("\r\nYour currently selected message areas\r\n");
   strout("-----------------------------------------\r\n");
   setcolor(TextAttr[HILITE_TEXT]);
   show_areas(FALSE);
   setcolor(TextAttr[STD_TEXT]);
   strout("\r\nEnter message area(s) you wish to delete (Use comma or space to sep)\r\n");
   timeremain();
   setcolor(TextAttr[PROMPT_TEXT]);
   strout("--> ");
   strin(msgstr);
   strout("\r\n");
   p = strtok(msgstr," ,\0");
   while (p) {
      if (isdigit(*p)) {
         msgnum = atoi(p);
         x = is_selarea(msgnum);
         if(x && !(isForcearea(x))) {
            USERCFG.totselareas--;
            msgunmark(msgnum);		/* Delete it */
            x--;
            msgupd = MSGUPD_1;
            if (!x)
               MSGUPD_1 = msgupd->next;
            else {
               while (x) {
                  prev = msgupd;
                  msgupd = msgupd->next;
                  x--;
               }
               prev->next = msgupd->next;		/* Skip current one */
            }
            free(msgupd);
            if (PackDone) {
               logit("User is deleting message areas",'#');
               erase_arc();
               while (msgupd) {
                  msgupd->update = FALSE;
                  msgupd = msgupd->next;
               }
               PackDone = FALSE;
            }
         }
         else if(isForcearea(x)){
            sprintf(temp,"\r\nSorry, but Sysop wants you to pack area #%03d",x);
            setcolor(TextAttr[ATTN_TEXT]);
            strout(temp);
            presskey();
         }
      }
      p = strtok(NULL," ,\0");
   }
   strout("\r\n");
}

void _pascal add_msgareas(void)
{
   char *p;
   struct msgupd_st *new;
   int first;

   first = TRUE;
   setcolor(TextAttr[HILITE_TEXT]);
   if (USERCFG.totselareas) {
      strout("\r\nYour currently selected message areas\r\n");
      strout("-----------------------------------------\r\n");
      setcolor(TextAttr[MENU_KEY]);
      show_areas(FALSE);
      setcolor(TextAttr[HILITE_TEXT]);
      strout("\r\nOther message areas available\r\n");
   }
   else strout("\r\nMessage areas available\r\n");
   strout("-----------------------------------------\r\n");
   setcolor(TextAttr[MENU_KEY]);
   if(screen_areas(TRUE)) {
      setcolor(TextAttr[HILITE_TEXT]);
      strout("\r\nEnter message area(s) you wish to add (Use comma or space to sep)\r\n");
      timeremain();
      setcolor(TextAttr[PROMPT_TEXT]);
      strout("--> ");
      strin(msgstr);
      strout("\r\n");
      p = strtok(msgstr," ,\0");
      while (p) {
         if (isdigit(*p)) {
            msgnum = atoi(p);
            if(!is_selarea(msgnum)) {
               msgupd = MSGUPD_1;
               if (first) {
                  setcolor(TextAttr[STD_TEXT]);
                  strout("\r\nHang on, I'm scanning the new message areas you selected.....\r\n");
                  first = FALSE;
               }
               new = build1_area(msgnum,TRUE);
               if (new) {
                  if (MSGUPD_1 == NULL) 
                     MSGUPD_1 = new;
                  else {		/* Attach it to the end */
                     prev = msgupd;
                     while (msgupd) {
                        prev = msgupd;
                        msgupd = msgupd->next;
                     }
                     prev->next = new;
                  }
                  msgmark(msgnum);		/* Add it */
                  new->next = NULL;
                  new->update = FALSE;
                  if (PackDone) {
                     logit("User is adding new message areas",'#');
                     erase_arc();
                     msgupd = MSGUPD_1;
                     while (msgupd) {
                        msgupd->update = FALSE;
                        msgupd = msgupd->next;
                     }
                     PackDone = FALSE;
                  }
               }
            }
         }
         p = strtok(NULL," ,\0");
      }
      strout("\r\n");
   }
   else {
      setcolor(TextAttr[ATTN_TEXT]);
      strout("Sorry, you have no other areas you can add at this time.\r\n");
   }
   get_msgcount();		/* Just re-do totselareas */
}

void _pascal edit_msgptrs(void)
{
   char *p1;
   char resp;
   int firsttime;
   int good = TRUE;
   int doupdate = FALSE;
   int rows,x;

   while (good) {
      firsttime = TRUE;
      msgupd = MSGUPD_1;
      while (msgupd) {
         setcolor(TextAttr[STD_TEXT]);
         strout("\r\n---------------------------------------------------");
         strout("\r\nCurrently selected            Start    High   New  ");
         strout("\r\nMessage Areas                   Msg     Msg   Msgs ");
         strout("\r\n---------------------------------------------------\r\n");
         rows = 0;
         while (msgupd && rows < 17) {
            fseek(afile,msgupd->areaindex,SEEK_SET);
            fread(&AREA,astrlen,1,afile);
            strncpy(temp1,AREA.msginfo,24);
            temp1[24] = 0;
            while (strlen(temp1) < 24)
               strcat(temp1," ");
            sprintf(temp,"[%03d] %s %04d    %04d   %04d\r\n",msgupd->areano,temp1,msgupd->startmsg,msgupd->himsg,msgupd->msgcount);      
            strout(temp);
            msgupd = msgupd->next;
            rows++;
            firsttime = FALSE;
         }
         if(msgupd) {		/* Still some more, so page it */
            strout("\r\nPress ESC to stop or any other key for more");
            x = chrin();
            strout("\r\n");
            if (x == 0x1b)
               msgupd = NULL;		/* Force a stop */
         }
      }
      if (firsttime) {
         setcolor(TextAttr[ATTN_TEXT]);
         strout("\r\nYou have no currently selected message areas\r\n");
         return;
      }
      else {
         setcolor(TextAttr[STD_TEXT]);
         strout("---------------------------------------------------\r\n");
         setcolor(TextAttr[HILITE_TEXT]);
         strout("\r\nEnter message area # you wish to change ...\r\n");
         strout("Or type 'Q' to exit back to main menu\r\n\r\n");
         timeremain();
         setcolor(TextAttr[PROMPT_TEXT]);
         strout("Message area to change --> ");
         strin(temp);
         if (*temp == '\r')
            break;
         stripwhite(temp);		/* Trim off spaces */
         if (temp) {
            p1 = strtok(temp," \t\r\n");
            if (p1) resp = (char) toupper(*p1);
            else break;		/* No answer, default */
         }
         else break;
         if (resp == 'Q') 
            break;
         else {		/* Parse out message area */
            msgupd = find_area(atoi(p1));
            if (isdigit(resp) && msgupd) {
               setcolor(TextAttr[HILITE_TEXT]);
               strout("\r\n                              Start    High   New  ");
               strout("\r\nMessage Area                    Msg     Msg   Msgs \r\n");
               strout("---------------------------------------------------\r\n");
               fseek(afile,msgupd->areaindex,SEEK_SET);
               fread(&AREA,astrlen,1,afile);
               strncpy(temp1,AREA.msginfo,24);
               temp1[24] = 0;
               while (strlen(temp1) < 24)
                  strcat(temp1," ");
               sprintf(temp,"[%03d] %s %04d    %04d   %04d\r\n",
                  msgupd->areano,temp1,msgupd->startmsg,msgupd->himsg,msgupd->msgcount);      
               strout(temp);
               strout("\r\n");
               timeremain();
               setcolor(TextAttr[PROMPT_TEXT]);
               strout("Start message # --> ");
               strin(temp);
               if (!IsLocal)
                  strout("\r\n");
               p1 = strtok(temp," \t\r\n");
               if (p1) {
                  firsttime = atoi(p1);
                  if (isdigit(*p1) && (firsttime != (int) msgupd->startmsg)) {
                     firsttime = firsttime >= 1 ? firsttime : 1;
                     firsttime = firsttime <= (int) msgupd->himsg ? firsttime : (int) msgupd->himsg;
                     msgupd->startmsg = firsttime;
                     msgupd->msgcount = msgupd->himsg - msgupd->startmsg;
                     if (msgupd->msgcount < 0)
                        msgupd->msgcount = 0;
                     doupdate = TRUE;
                     msgupd->readmsgs = 0;
                     if (PackDone) {
                        logit("User is resetting message area pointers",'#');
                        PackDone = FALSE;
                        erase_arc();
                     }
                     else if (msg_update)
                        msgupd->update = TRUE;
                  }
               }
            }
         }
      }
   }
   if (doupdate)
      update_msgs();
   setcolor(TextAttr[STD_TEXT]);
}

/* Delete users who are no longer active on Maximus user file */

void _pascal kill_oldusers(void)
{
   int handl1,handl2;
   int x,y;
   long pos;

   if (test_task()) {
      setcolor(TextAttr[ATTN_TEXT]);
      strout("\r\nSorry, but someone else is using MaxMail currently. Try later!\r\n");
   }

   handl1 = sopen(CfgFile,O_RDWR | O_BINARY,SH_DENYWR,S_IWRITE);
   if (handl1 == -1) {
      setcolor(TextAttr[ATTN_TEXT]);
      strout("\r\nCan't write to user file");
      aborterror(FILEOPEN,"Error opening User config file");
   }

   handl2 = sopen(PRM(user_file),O_RDWR | O_BINARY,SH_DENYNO,S_IREAD);
   if (handl1 == -1) {
      setcolor(TextAttr[ATTN_TEXT]);
      strout("\r\nCan't open User.bbs file\r\n");
      close(handl1);
   }
   y = read(handl1,(char *) &uscfg,sizeof(struct user_cfg));
   x = 0;
   while (y == sizeof(struct user_cfg)) {
      if (uscfg.name[0]) {
         if (!find_realuser(uscfg.name,handl2)) {
            memset(uscfg.name,0,36);		/* Null out name */
            pos = tell(handl1) - (long) sizeof(struct user_cfg);	/* Get position */
            lseek(handl1,pos,SEEK_SET); 	/* Rewind back to this record */
            write(handl1,(struct user_cfg *) &uscfg,sizeof(struct user_cfg));
            x++;
            strout(".");
         }
         else strout("*");
      }
      else strout("E");
      y = read(handl1,(char *) &uscfg,sizeof(struct user_cfg));
   }
   strout("\r\n");
   close(handl1);
   close(handl2);
   if (x) {
      setcolor(TextAttr[HILITE_TEXT]);
      sprintf(temp,"Sysop has deleted %d users from config file",x);
      strout(temp);
      strout(".\r\n");
      logit(temp,'#');
   }
   else {
      setcolor(TextAttr[ATTN_TEXT]);
      strout("No users are inactive at this time.\r\n");
   }
   setcolor(TextAttr[STD_TEXT]);
}

/* See if another MaxMail user is currently active */
int _pascal test_task(void)
{
   struct find_t c_file;
   int x;

   sprintf(temp,"MxMlAct.%03x",Task);		/* Create a task id */
   unlink(temp);		/* Delete our own task file */

   if (_dos_findfirst("MxMlAct.*",_A_NORMAL,&c_file) == 0) { /* Uh oh. Someone else is using MaxMail! */
      x = sopen(temp,O_RDWR | O_BINARY | O_CREAT,SH_DENYWR,S_IWRITE);
      close(x);		/* Re-Create task file */
      return(TRUE);
   }
   x = sopen(temp,O_RDWR | O_BINARY | O_CREAT,SH_DENYWR,S_IWRITE);
   close(x);		/* Re-Create task file */
   return(FALSE);
}

void _pascal examine_user(void)
{
   int x,y,User,mask,bitloop,areas;
   int handl1,index;
   int col,line,anum;
   char *p1;
   word *bitp;
   struct _aidx IDX;

   setcolor(TextAttr[STD_TEXT]);
   strout("Enter user's name ---> ");
   strin(temp);
   if (!IsLocal)
      strout("\r\n");
   p1 = strtok(temp,"\t\r\n");
   if (p1) {
      handl1 = sopen(CfgFile,O_RDWR | O_BINARY | O_CREAT,SH_DENYNO,S_IREAD);
      if (handl1 == -1)
         aborterror(FILEOPEN,"Error opening User config file");
      User = find_config(handl1,p1,&uscfg);
      if (User < 0) {
         setcolor(TextAttr[ATTN_TEXT]);
         strout("Sorry but that user name does not exist.\r\n");
      }
      else {		/* Display possible message areas */
         col = 0;
         line = 0;
         areas = 0;
         index = sopen(PRM(aidx_name),O_BINARY | O_RDONLY,SH_DENYNO,S_IREAD);
         if (index == -1)
            aborterror(FILEOPEN,"Error opening Area index file");
         setcolor(TextAttr[STD_TEXT]);
         for (bitloop=0; bitloop < 64; bitloop++ ) {
            bitp = &uscfg.msgarea[bitloop];
            mask = 1;
            for (x=0; x < 16; x++) {		/* Bitmask loop */
               if (*bitp & mask) {		/* User selected area */
                  anum = (bitloop * 16) + x;
                  lseek(index,(long) (anum * sizeof(struct _aidx)),SEEK_SET);
                  read(index,(char *)&IDX,sizeof(struct _aidx));
                  fseek(afile,IDX.offset,SEEK_SET);
                  y = fread(&AREA,astrlen,1,afile);
                  if (AREA.msginfo[0]){
                     areas++;
                     if (!areas) {		/* First time */
                        strout("\r\nUser message areas: \r\n");
                        strout("-------------------\r\n");
                        rewind(afile);		/* Rewind AREA file */
                     }
                     if (!col) { 	/* 1st column */
                        strncpy(temp,AREA.msginfo,20);
                        temp[20] = 0;
                        sprintf(msgstr,"[%d] %s",anum,temp);
                        y = strlen(msgstr);
                        while (y++ < 26) 
                           strcat(msgstr," ");		/* Pad it for formatting */
                     }
                     else {		/* 2nd or 3rd column */
                        strncpy(temp1,AREA.msginfo,20);
                        temp1[20] = 0;
                        sprintf(temp,"[%d] %s",anum,temp1);
                        y = strlen(temp);
                        while (y++ < 26) 
                           strcat(temp," ");		/* Pad it for formatting */
                        strcat(msgstr,temp);
                        if (col == 2) {
                           strcat(msgstr,"\r\n");
                           strout(msgstr);
                           line++;		/* Another row is spit out */
                           if (line > 23) {
                              presskey();
                              line = 0;
                           }
                           col = -1;
                        }
                     }
                     col++;
                  }
               }
               mask = mask << 1;
            }
         }
         if (col) {
            strcat(msgstr,"\r\n");
            strout(msgstr);
         }
         close(index);
         if (areas) {
            sprintf(temp,"\r\nTotal areas selected: %d \r\n",areas);
            strout(temp);
         }
      }
      close(handl1);
   }
}


/* Generate a tone of given frequency and length, time is in 10ths of seconds */
void _pascal tone (int freq, int time)
{

   int  hibyte, lowbyte, port;
   long divisor;

   divisor = FREQSCALE / freq;	/* scale freq to timer units  */
   lowbyte = (int) (divisor % 256); /* break integer into         */
   hibyte  = (int) (divisor >> 8);		/*  two bytes                 */

   outp (T_MODEPORT, TIMERMODE);	/* prepare timer for input    */
   outp (FREQPORT, lowbyte);	/* set low byte of timer reg  */
   outp (FREQPORT, hibyte); /* set high byte of timer reg */

   port = inp(BEEPPORT);		/* save port setting          */
   outp (BEEPPORT, ON);		/* turn speaker on            */
   delay_ms(time);
   outp (BEEPPORT, port);		/* turn speaker off, restore  */
 			   /*  original setting          */
}


void _pascal get_msgtype(void)
{
   int x;
   unsigned oldfrmt;

   do
   {
      setcolor(TextAttr[HILITE_TEXT]);
      strout("Enter message format you wish to use\r\n");
      strout("------------------------------------\r\n");
      strout("[0]Standard Text      [1]QWK packets\r\n");
      timeremain();
      setcolor(TextAttr[PROMPT_TEXT]);
      strout("--> ");
      x = chrin();
      if (x == '\r')
         x = '0';
      else if (!(isdigit(x))) {
         setcolor(TextAttr[ATTN_TEXT]);
         strout("\r\nYou must enter digits only!\r\n");
         continue;
      }
      setcolor(TextAttr[STD_TEXT]);
      sprintf(temp,"%c\r\n",x);
      strout(temp);
   }
   while (x != '1' && x != '0' );
   oldfrmt = USERCFG.msgfrmt;
   USERCFG.msgfrmt = x - 0x30;
   if (USERCFG.msgfrmt == 1)
      qwkinit();

   if (oldfrmt != USERCFG.msgfrmt && PackDone)
      erase_arc();
}

void _pascal get_nfiles(void)
{
   int x;

   setcolor(TextAttr[HILITE_TEXT]);
   strout("\r\nDo you wish to include a newfiles list\r\n");
   strout("  in your packet?\r\n");
   if (getyn(TRUE))
      USERCFG.flags |= NEWFILES_INC;
   else {
      x = NEWFILES_INC ^ 0xffff;
      USERCFG.flags &= x;		/* Turn it off */
   }
}

void _pascal get_totperarea(void)
{

   if(USERCFG.msgfrmt == 1) {		/* This is only needed for QWK */
      while (1) {
         setcolor(TextAttr[HILITE_TEXT]);
         strout("\r\nEnter maximum # of messages you want to pack in each area\r\n");
         timeremain();
         setcolor(TextAttr[PROMPT_TEXT]);
         strout(" or enter a '0' for full pack per area --> ");
         strin(msgstr);
         if (!IsLocal)
            strout("\r\n");
         setcolor(TextAttr[STD_TEXT]);
         stripwhite(msgstr);
         if (!(isdigit(msgstr[0])) && msgstr[0]) {
            setcolor(TextAttr[ATTN_TEXT]);
            strout("You must enter digits only!\r\n");
            continue;
         }
         switch (msgstr[0]) {
            case 0:
               USERCFG.maxareamsgs = 0;
               break;

            default:
               if (isdigit(msgstr[0]))
                  USERCFG.maxareamsgs = (word) (atoi(msgstr));
               else USERCFG.maxareamsgs = 0;
         }
         break;
      }
   }
}

/* Get a yes/no anser from user. Return TRUE for yes,FALSE for no.
   If flag is true add timeremain key */

int _pascal getyn(int flag)
{
   int x;

   if (flag) 
      timeremain();
   setcolor(TextAttr[PROMPT_TEXT]);
   strout("[y,N] ");
   x = chrin();
   chrout((char) x);
   strout("\r\n");
   if (toupper(x) == 'Y')
      return TRUE;
   else return FALSE;
}


void _pascal presskey(void)
{
   strout("\r\nPress any key");
   chrin();
   strout("\r\n");
}

/* Test a message area for locks/keys */

int _pascal testlock(void)
{
   int result;
   unsigned x,y;

   result = TRUE;		/* Assume yes */
   if (AREA.msglock) {
      y = AREA.msglock;
      x = LastUser.key;
      if ((x & y) != y)
         result = FALSE;
   }
   return result;
}

