#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <dos.h>
#include <fcntl.h>
#include <fctype.h>
#include <sys/stat.h>
#include <exec/types.h>
#include <libraries/dosextens.h>

#include <dlg/dlg.h>
#include <dlg/msg.h>
#include <dlg/log.h>
#include <dlg/resman.h>
#include <dlg/user.h>
#include <dlg/menu.h>
#include <dlg/file.h>
#include <dlg/portconfig.h>

#include <devices/tpt.h>

#include <link/io.h>
#include <link/lang.h>

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/dlg.h>

#include <pragmas/dlg.h>

#include <private/Version.h>
#define  ObjRev "2"
const UBYTE version[]="\0$VER: Renumber " BUILDVER "." ObjRev " ©" COPYRIGHT " by Digerati Dreams "__AMIGADATE__;

void  main          (int, char **);
BOOL  Renumber      (long, long, char, char, long, char);
long  RawRenumber   (long, long, long, long, long *);
BOOL  ShiftMessage  (long, long, char *, char *, long);
BOOL  FixLinks      (char *, long, long, long);
BOOL  FixComment    (char *, char *, long, long);

void  GetPointers   (long area, LONG *low, LONG *high);
BOOL  PutPointers   (long area, LONG  low, LONG  high);
long  ReadHighWater (long);
BOOL  WriteHighWater(long, long);
BOOL  WriteUsers    (long, char);
BOOL  KillStrays    (long, long);

long  MakeAreaArray (long *, char *);
long  MakeEchoNet   (long *, long, unsigned char);

int   cmp           (long *, long *);
int   CmpNumbers    (struct Msg_Log *, struct Msg_Log *);
int   CmpNames      (struct Msg_Log *, struct Msg_Log *);

void  Usage         (char *);
void _CXBRK         (void);


struct  Ram_File   RStruct;
struct  Msg_Area   Area;

long    hw = TRUE;
char    device[6];
char    fext  [5];
char    aext  [7];

char    LockFlag = MSGLOCK;
#define RMESS LockFlag == MSGLOCK
#define RFILE LockFlag == FILELOCK

#define NumAreas 100000
long   *AreaArray;

ULONG   size;

long    uindex           =   0;
long    FirstFile        = TRUE;
ULONG   usize            =   0;
ULONG   unumbr;
struct  Msg_Log *uarray  = NULL;

long    numusers         =  0;
char   *userlist         = NULL;

BPTR             sout;
struct  Library *DLGBase = NULL;
char           **SA;

/// main
void main(int argc, char *argv[])
{
   char *s;
   char *alist;
   char  forceflag = FALSE;
   char  found;

   long  area;
   long  numareas;

   int   fp;
   char  areafile[80];

   alist = "";
   sout  = Output();

   if (!(DLGBase=OpenLibrary(DLGNAME,DLGVERSION)))  exit(5);
   if (!(SA = getlang(NULL)))                       exit(5);

   AFPrintf(NULL, sout, "\n");

/// Parse command line
   while(--argc>0)
   {
      s = *++argv;
      if (*s++ == '-')
      {
         while(*s)
         {
            switch(*s++)
            {
               case 'd':
               case 'D':  hw = FALSE;
               break;

               case 'a':
               case 'A':  if (!--argc) break;
               alist = *++argv;
               break;

               case 'r':
               case 'R':  forceflag = TRUE;
               break;

               case 'm':
               case 'M':  LockFlag  = MSGLOCK;
               break;

               case 'f':
               case 'F':  LockFlag  = FILELOCK;
               break;
            }
         }
      }
      else
      {
         Usage("Bad Syntax");
      }
   }
//-

   if (LockFlag == MSGLOCK)
   {
      if (!*alist) alist = "ECHO NET LOCAL";
      strcpy(device, "MSG");
      strcpy(fext,   "msg");
      strcpy(aext,   "msg");
   }
   else
   {
      if (!*alist) alist = "LOCAL";
      strcpy(device, "FILE");
      strcpy(fext,   "fd");
      strcpy(aext,   "file");
   }

   /* Load users into an array */
   if (FileSize("DLGConfig:Misc/Users.bbs", &size))
   {
      AFPrintf(NULL, sout, SA[1773]);  
      _CXBRK();
   }

   numusers = size / sizeof(struct NameStruct);

   if (!(userlist = malloc(size)))
   {
      AFPrintf(NULL, sout, SA[1774]);
      _CXBRK();
   }

   if (GetFirstStruct("DLGConfig:Misc/Users.bbs", userlist, size))  _CXBRK();


   /* Get Areas to Renumber */

   if(! (AreaArray = calloc(NumAreas,sizeof(long))))
      _CXBRK();

   numareas = MakeAreaArray(AreaArray, alist);
   qsort(AreaArray, numareas, 4, cmp);

   ASPrintf(NULL, areafile, "%s:Area.bbs", device);

   for(area=0; area < numareas; area++)
   {
      found = FALSE;

      if ((fp=open(areafile,O_RDONLY))==EOF)
      {
         AFPrintf(NULL, sout, SA[1775],areafile);
         _CXBRK();
      }

      while(read(fp,&Area,sizeof(Area))==sizeof(Area))
      {
         signal(SIGINT, SIG_DFL);
         Chk_Abort();
         signal(SIGINT, SIG_IGN);

         if (Area.Number==AreaArray[area])
         {
            Renumber(Area.Number,Area.Capacity,(Area.Flag&ECHO_AREA || Area.Flag&NETMAIL_AREA)?1:0,Area.Flag,Area.UpperLimit,forceflag);
            found = TRUE;
            break;
         }
      }

      if (!found)
         AFPrintf(NULL, sout, SA[1776],AreaArray[area]);

      close(fp);
   }

   _CXBRK();
}
//-

/// Renumber
BOOL Renumber(long area, long capacity, char echo, char status, long trigger, char forceflag)
{
   BOOL  USEROK = FALSE;
   
   long  Low;
   long  High;
   long  Base;

   long newhigh;
   long highwater = 0;

   char  userfile[128];

   if (!RMESS)  echo = 0;
   FirstFile =  TRUE;
   Base      = (echo)?2:1;


   /* Lock the area */
   AFPrintf(NULL, sout, SA[1777], (RMESS)?SA[1778]:SA[1779], area);
   if (LockArea(area, "RENUMBER", "Area Is Being Renumbered", 1, LockFlag | WRITELOCK) !=RMNOERR)
   {
      AFPrintf(NULL, sout, SA[1809],area);
      AFPrintf(NULL, sout, SA[1784]);
      return(FALSE);
   }


   /* Read high/low message pointers for area */
   AFPrintf(NULL, sout, SA[1780]);
   GetPointers(area, &Low, &High);
   AFPrintf(NULL, sout, SA[1781], Low, High);

   /* Check to see if it needs renumbering */
   if (High <= Base)
   {
      AFPrintf(NULL, sout, SA[1783]);
      FreeArea(area,"RENUMBER",LockFlag|WRITELOCK);
      return(FALSE);
   }

   if (RMESS)
   {
      if (High < trigger && !forceflag)
      {
         AFPrintf(NULL, sout, SA[1782]);
         FreeArea(area,"RENUMBER",LockFlag|WRITELOCK);
         return(FALSE);
      }
   }

   /* Load the user pointers into memory */
   AFPrintf(NULL, sout, SA[1785]);

   ASPrintf(NULL, userfile, "%s:%ld/User.%s", device, area, aext);

   if (FileSize(userfile, &size))
   {
      AFPrintf(NULL, sout, SA[1786]);
      USEROK = FALSE;
   }
   else
   {
      USEROK = TRUE;
   }

   if(USEROK)
   {
      if (usize < size)
      {
         if (usize)
         {
            free(uarray);
            usize = 0;
         }

         if (!(uarray = malloc(size)))
         {
            AFPrintf(NULL, sout, SA[1787]);
            FreeArea(area,"RENUMBER",LockFlag|WRITELOCK);
            return(FALSE);
         }

         usize = size;
      }

      if (GetFirstStruct(userfile, (char *)uarray, size))
      {
         USEROK = FALSE;
         AFPrintf(NULL, sout, SA[1786]);
      }
      
      if(USEROK)
      {
         unumbr = size / (ULONG)sizeof(struct Msg_Log);

         AFPrintf(NULL, sout, SA[1788], unumbr);
         qsort(uarray, unumbr, sizeof(struct Msg_Log), CmpNumbers);
      }
   }

   if(!USEROK)
   {
      BPTR ufh = NULL;
      
      ufh = Open(userfile,MODE_READWRITE);
      
      if(ufh)
      {
         Close(ufh);
      }
   }


   /* Read highwater (1.msg) if it is not disabled */

   if (hw && echo)
   {
      highwater = ReadHighWater(area);
      AFPrintf(NULL, sout, SA[1789], highwater);
   }


   /* Do a low level renumber of an area */
   if (!(newhigh = RawRenumber(Base,Low,High,area,&highwater)))
   {
      AFPrintf(NULL, sout, "\n");
      FreeArea(area,"RENUMBER",LockFlag|WRITELOCK);
      return(FALSE);
   }


   /* Clean up for the rest of the users */

   if(USEROK)
   {
      for(;uindex < unumbr; uindex++)
      (uarray+uindex)->High_Mess = newhigh - 1;
   }

   /* Write highwater (1.msg) if it is not disabled */
   if (hw && echo)
   {
      AFPrintf(NULL, sout, SA[1790], highwater);

      if (WriteHighWater(area, highwater))
         AFPrintf(NULL, sout, SA[1791]);
      else
         AFPrintf(NULL, sout, SA[1792]);
   }


   /* Write the user pointers back for the area */
   if(USEROK)
   {
      WriteUsers(area, echo);
      AFPrintf(NULL, sout, "\n");
   }

   newhigh--;

   if (!PutPointers(area, Base, newhigh))
      AFPrintf(NULL, sout, SA[1793]);

   FreeArea(area, "RENUMBER", LockFlag|WRITELOCK);
   return(TRUE);
}
//-

/// RawRenumber
long RawRenumber(long Base, long Low, long High, long area, long *highwater)
{
   long fromnumber;
   long tonumber;
   long hwprocessed = FALSE;
   char fromname[64];
   char toname  [64];


   /* Set index of userarray past the Low message in area */
   for(uindex = 0; uindex < unumbr && (uarray+uindex)->High_Mess < Low; uindex++)
   (uarray+uindex)->High_Mess = Base - 1;


   /* Scan up from bottom to find the first hole (first toname) */
   tonumber = Base - 1;
   while(tonumber < High)
   {
      tonumber++;
      ASPrintf(NULL, toname, "%s:%ld/%ld.%s", device, area, tonumber, fext);

      if (!Exists(toname))  break;
   }

   if (tonumber >= High)
      if (Exists(toname))
      {
         AFPrintf(NULL, sout, SA[1794]);
         return(0);
      }


   /* tonumber has been established, renumber the rest of the base */
   fromnumber = (tonumber>Low)?tonumber:Low;

   while(TRUE)
   {
      fromnumber++;

      /* Renumber the highwater mark if needed */
      if (hw  &&  !hwprocessed  &&  *highwater <= fromnumber)
      {
         AFPrintf(NULL, sout, SA[1797], *highwater, tonumber);
         *highwater = tonumber;
         hwprocessed++;
      }

      /* Hit the end */
      if (fromnumber > High)
      {
         if (RMESS)  KillStrays(tonumber,area);
         return(tonumber);
      }

      ASPrintf(NULL, fromname,"%s:%ld/%ld.%s",device,area,fromnumber,fext);

      /* Found the next high message, do the renumber */
      if (Exists(fromname))
      {
         ASPrintf(NULL, toname,"%s:%d/%ld.%s",device,area,tonumber,fext);

         /* Found a stray message, delete it... */
         if (RMESS && Exists(toname))
         {
            AFPrintf(NULL, sout, SA[1795], tonumber);
            DeleteFile(toname);
         }

         /* Found a stray file, ????... */
         if (RFILE && Exists(toname))
         {
            AFPrintf(NULL, sout, SA[1796], tonumber);
            return(FALSE);
         }

         if (!ShiftMessage(fromnumber, tonumber, fromname, toname, area))
            return(FALSE);

         FirstFile = FALSE;
         tonumber++;
      }
   }
}
//-

/// ShiftMessage
BOOL ShiftMessage(long fromnumber, long tonumber, char *fromname, char *toname, long area)
{
   char valfrom[50];
   char valto  [50];

   /* If the first time through the loop (lowest file) */
   if (FirstFile)
   {
      for(; uindex < unumbr && (uarray+uindex)->High_Mess<fromnumber; uindex++)
         (uarray+uindex)->High_Mess = tonumber-1L;
   }

   /* Renumber the user array pointers */
   for(; uindex < unumbr && (uarray+uindex)->High_Mess<fromnumber;  uindex++)
      (uarray+uindex)->High_Mess=tonumber;

   for(; uindex < unumbr && (uarray+uindex)->High_Mess==fromnumber; uindex++)
      (uarray+uindex)->High_Mess=tonumber;

   AFPrintf(NULL, sout, SA[1798], fromnumber, tonumber);

   /* Fix message links or file comments*/
   if (RMESS)
      FixLinks  (fromname, fromnumber, tonumber, area);
   else
      FixComment(fromname, toname,     area,     tonumber);


   /* Rename item */
   if (!Rename(fromname,toname))
   {
      AFPrintf(NULL, sout, SA[1799],fromname,toname);
      return(FALSE);
   }

   /* Rename .val file if renumbering files */
   if (!RMESS)
   {
      ASPrintf(NULL, valfrom, "FILE:%ld/%ld.val", area, fromnumber);
      ASPrintf(NULL, valto,   "FILE:%ld/%ld.val", area, tonumber);
      Rename(valfrom,valto);
   }

   return(TRUE);
}
//-

/// FixLinks
BOOL FixLinks(char *fromname, long fromnumber, long tonumber, long area)
{
   struct Msg_Header  Header;
   struct Msg_Header  THeader;
   struct WaitingMail MW;

   int  fp;
   int  tp;
   char linkname[64];
   char mwfile[64];


   if ((fp=open(fromname,O_RDWR))==EOF)
   {
      AFPrintf(NULL, sout, SA[1800]);
      return(FALSE);
   }

   read(fp,&Header,sizeof(Header));

   /* fix the waiting mail links */
   if (!(Header.Attribute&Received))
   {
      if (DLGBinSearch(userlist, Header.To, 36, 36, (int)numusers))
      {
         ASPrintf(NULL, mwfile, "USER:%s/WaitingMail.dat", Header.To);
         UnderScore(mwfile);
         ASPrintf(NULL, MW.msgid, "%04d:%05ld", area, fromnumber); 

         if (GetStruct(mwfile, (char *)&MW, sizeof(MW), 11)!=-1)
         {
            DeleteStruct(mwfile, (char *)&MW, sizeof(MW), 11);

            ASPrintf(NULL, MW.msgid, "%04ld:%05ld", area, tonumber);
            MW.messagenum = tonumber;
            AddStruct(mwfile, (char *)&MW, sizeof(MW), 11);

            AFPrintf(NULL, sout, SA[1801]);
         }
      }
   }


   /* Message link fixing */
   if (Header.ReplyTo)
   {
      ASPrintf(NULL, linkname,"MSG:%ld/%ld.msg",area,Header.ReplyTo);
      if ((tp=open(linkname,O_RDWR))==EOF)
      Header.ReplyTo=0;
      else
      {
         read(tp,&THeader,sizeof(THeader));
         lseek(tp,0L,0);
         THeader.NextReply=(int)tonumber;
         write(tp,&THeader,sizeof(THeader));
         AFPrintf(NULL, sout, SA[1802],Header.ReplyTo,tonumber);
         close(tp);
      }
   }
   
   if (Header.NextReply)
   {
      ASPrintf(NULL, linkname,"MSG:%ld/%ld.msg",area,Header.NextReply);

      if ((tp=open(linkname,O_RDWR))==EOF)
         Header.NextReply=0;
      else
      {
         read(tp,&THeader,sizeof(THeader));
         lseek(tp,0L,0);
         THeader.ReplyTo=(int)tonumber;
         write(tp,&THeader,sizeof(THeader));
         AFPrintf(NULL, sout, SA[1802],Header.NextReply,tonumber);
         close(tp);
      }
   }
   
   lseek(fp,0L,0);
   write(fp,&Header,sizeof(Header));
   close(fp);
   AFPrintf(NULL, sout, "\n");
   return(TRUE);
}
//-

/// FixComment
BOOL FixComment(char *fromname, char *toname, long area, long tonumber)
{
   struct FileInfoBlock fib;
   BPTR                 lock;
   char                 path[24];
   char                 filename[128];
   char                 qfile[24];
   struct File_Header   Header;
   struct QuickFile     QF;

   if (GetFirstStruct(fromname, (char *)&Header, sizeof(Header)))
   {
      AFPrintf(NULL, sout, SA[1803],fromname);
      return(FALSE);
   }

   ASPrintf(NULL, qfile,"FILE:%ld/File.dat",area);
   strcpy(QF.filename,Header.Filename);

   if (GetStruct(qfile, (char *)&QF, sizeof(QF), 36))
      AFPrintf(NULL, sout, SA[1804]);
   else
   {
      QF.number=tonumber;
      AddStruct(qfile, (char *)&QF, sizeof(QF), 36);
   }

   GetPath(path,area,NULL,Header.Filename);
   ASPrintf(NULL, filename,"%s%s",path,Header.Filename);

   lock = Lock(filename, ACCESS_READ);

   if (lock)
   {
      Examine(lock, &fib);
      UnLock(lock);

      if (!(fib.fib_Protection & FIBF_WRITE))
      {
         if (!SetComment(filename,toname))
         {
            AFPrintf(NULL, sout, SA[1805],filename);
            return(FALSE);
         }
         AFPrintf(NULL, sout, SA[1806],filename);
      }
      else
         AFPrintf(NULL, sout, SA[1807],filename);
   }
   else
      AFPrintf(NULL, sout, SA[1808], filename);

   return(TRUE);
}
//-

/// GetPointers
void GetPointers(long area, LONG *low, LONG *high)
{
   BPTR fh;
   char filename[80];

   ASPrintf(NULL, filename, "%s:%ld/Pointers.%s", device, area, aext);

   if (!(fh = Open(filename, MODE_OLDFILE)))
   {
      *high = 0;
      *low  = 1;
   }
   else
   {
      if (!FGets(fh, filename, 20))
         *low = 1;
      else
         StrToLong(filename, low);

      if (!FGets(fh, filename, 20))
         *high = 1;
      else
         StrToLong(filename, high);

      Close(fh);
   }
}
//-

/// PutPointers
BOOL PutPointers(long area, LONG low, LONG high)
{
   BPTR fh;
   char filename[80];

   ASPrintf(NULL, filename, "%s:%ld/Pointers.%s", device, area, aext);

   if (!(fh = Open(filename, MODE_OLDFILE)))
   fh = Open(filename, MODE_NEWFILE);

   if (fh)
   {
      AFPrintf(NULL, fh, "%ld\n%ld\n", low, high);
      Close(fh);
   }

   if (!fh)  return(FALSE);
   return(TRUE);
}
//-

/// ReadHighWater
long ReadHighWater(long area)
{
   int   fp;
   long  highwater;
   char  filename[128];

   ASPrintf(NULL, filename,"%s:%ld/1.%s",device,area,fext);
   if ((fp = open(filename,O_RDONLY)) == EOF)  return(0);

   lseek(fp, 184L, 0);
   read (fp, &highwater, 2);
   close(fp);

   return(highwater);
}
//-

/// WriteHighWater
BOOL WriteHighWater(long area, long highwater)
{
   int  fp;
   char filename[128];

   ASPrintf(NULL, filename,"%s:%d/1.%s",device,area,fext);
   if ((fp = open(filename,O_RDWR))==EOF)  return(0);

   lseek(fp,184L,0);
   write(fp,&highwater,2);
   close(fp);

   return(TRUE);
}
//-

/// WriteUsers
BOOL WriteUsers(long area, char echo)
{
   char userfile[64];
   int  fp;

   qsort(uarray, unumbr, sizeof(struct Msg_Log), CmpNames);
   ASPrintf(NULL, userfile,"%s:%d/User.%s",device,area,aext);

   DeleteFile(userfile);
   if ((fp=open(userfile,O_RDWR+O_CREAT))==EOF)
   {
      AFPrintf(NULL, sout, SA[1810],userfile);
      return(FALSE);
   }

   Upper(uarray->Name);
   DeScore(uarray->Name);

   for(uindex = 0; uindex < unumbr; uindex++)
   {
      if ((uarray+uindex)->High_Mess< (1L+(long)echo)  &&  (!(uarray+uindex)->uflag && !(uarray+uindex)->dflag && !(uarray+uindex)->special))
      continue;

      if (uindex < unumbr-1)
      {
         Upper((uarray+uindex+1)->Name);
         DeScore((uarray+uindex+1)->Name);
         if (!strcmp((uarray+uindex)->Name, (uarray+uindex+1)->Name))  continue;
      }

      write(fp, (uarray+uindex), sizeof(struct Msg_Log));
   }

   close(fp);
   return(TRUE);
}
//-

/// KillStrays
BOOL KillStrays(long from, long area)
{
   char                 path[32];
   char                *filename;
   char                 pathfilename[128];
   struct SearchCookie *sc;

   ASPrintf(NULL, path, "MSG:%d", area);

   sc = SearchStart(path, "*.msg");

   while(filename = SearchNext(sc))
   {
      if (atol(filename) >= from)
      {
         ASPrintf(NULL, pathfilename, "%s/%s", path, filename);
         AFPrintf(NULL, sout, SA[1811], pathfilename);
         DeleteFile(pathfilename);
      }
   }
   SearchEnd(sc);

   return(TRUE);
}
//-

/// MakeAreaArray
long MakeAreaArray(long *array, char *alist)
{
   long          area;
   char         *s;

   unsigned char EchoFlag  = 0;
   unsigned char NetFlag   = 0;
   unsigned char LocalFlag = 0;

   s = alist;

   for(area=0; area < NumAreas; area++)
   {
      while(*s==32) s++;
      if (!*s) break;

      if (!Strnicmp(s,"ECHO",4))
      {
         if (EchoFlag)
         {
            AFPrintf(NULL, sout, SA[1812]);
            area--;
         }
         else
            if (LockFlag==FILELOCK)
            {
               AFPrintf(NULL, sout, SA[1813]);
               area--;
            }
            else
            {
               EchoFlag = 1;
               area     = MakeEchoNet(array, area, ECHO_AREA);
            }
      }
      else
         if (!Strnicmp(s,"NET",3))
         {
            if (NetFlag)
            {
               AFPrintf(NULL, sout, SA[1814]);
               area--;
            }
            else
               if (LockFlag==FILELOCK)
               {
                  AFPrintf(NULL, sout, SA[1815]);
                  area--;
               }
               else
               {
                  NetFlag = 1;
                  area    = MakeEchoNet(array, area, NETMAIL_AREA);
               }
         }
         else
            if (!Strnicmp(s,"LOCAL",5))
            {
               if (LocalFlag)
               {
                  AFPrintf(NULL, sout, SA[1816]);
                  area--;
               }
               else
               {
                  LocalFlag = 1;
                  area      = MakeEchoNet(array, area, 0);
               }
            }
            else
               array[area] = atoi(s);

      while((*s)&&(*s!=32)) s++;
   }

   if (area == NumAreas)
      AFPrintf(NULL, sout, SA[1817], NumAreas);

   return(area);
}
//-

/// MakeEchoNet
long MakeEchoNet(long *array, long area, unsigned char type)
{
   char areafile[80];
   int  fp;

   ASPrintf(NULL, areafile, "%s:Area.bbs", device);

   if ((fp = open(areafile,O_RDONLY)) == EOF)
      AFPrintf(NULL, sout, SA[1818], areafile);
   else
   {
      while(((read(fp, &Area, sizeof(Area))) == sizeof(Area)) && (area < NumAreas))
      {
         if ((Area.Flag & type)  ||  (!type && !(Area.Flag & (ECHO_AREA + NETMAIL_AREA))))
         {
            array[area] = Area.Number;
            area++;
         }
      }

      close(fp);
   }

   --area;
   return(area);
}
//-

/// cmp
int cmp(long *i, long *j)
{
   return((*i)-(*j));
}
//-

/// CmpNumbers
int CmpNumbers(struct Msg_Log *a, struct Msg_Log *b)
{
   return(a->High_Mess - b->High_Mess);
}
//-

/// CmpNames
int CmpNames(struct Msg_Log *a, struct Msg_Log *b)
{
   return(Stricmp(a->Name,b->Name));
}
//-

/// Usage
void Usage(char *string)
{
   AFPrintf(NULL, sout, SA[1819],string);
   AFPrintf(NULL, sout, SA[1820]);
   AFPrintf(NULL, sout, SA[1821]);
   AFPrintf(NULL, sout, SA[1822]);
   AFPrintf(NULL, sout, SA[1823]);
   _CXBRK();
}
//-

/// _CXBRK
void _CXBRK()
{
   if (userlist)  free(userlist);
   if (usize)     free(uarray);

   CloseLibrary(DLGBase);
   exit(0);
}
//-


