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

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

#include <link/io.h>
#include <link/user.h>
#include <link/area.h>
#include <link/config.h>
#include <link/file.h>
#include <link/util.h>

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

#include <pragmas/dlg.h>

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

void                main(int, char **);

void                Write_Pointers(void);
BYTE                Read_Pointers(long);
BOOL                Read_Area(long, char *);
void                New_Area(void);
void                EnterPrivateArea(void);

BYTE                Read_Message(void);
BYTE                UploadFile(void);
BYTE                Kill_File(void);
void                Edit_Signature(void);
BYTE                DownloadFile(void);
BOOL                CheckResume(int, long, char);

BOOL                AskListStuff(char);
BYTE                List_Files(void);
BYTE                ListFiles(char, char, int, char, char *, char *);
int                 SortAgedUp(struct QuickFile *, struct QuickFile *);
int                 SortAgedDown(struct QuickFile *, struct QuickFile *);
int                 SortAlphUp(struct QuickFile *, struct QuickFile *);
int                 SortAlphDown(struct QuickFile *, struct QuickFile *);

void                Add_Comment(void);
BOOL                Hurl_File(char);
void                NoAbility(void);
BOOL                Check_Write_Access(struct Msg_Area *);
BOOL                RenumberDir(char *);
void                Read_Search_Areas(void);
LONG                Add_Batch(void);
BYTE                List_Batch(long *);
BYTE                Batch_Remove(void);
BYTE                ChargeForFiles(char *);
void                Refuse_Download(long, long);
long                GetFilename(long);
BYTE                GetFileInfo(char *);
BYTE                ReadFile(void);
BOOL                SelectSIG(void);
SHORT               MenuLen(void);
BOOL                PvtOK(char *);
void                _CXBRK(void);
int                 HandleBuiltIn(UBYTE);
int                 FileSubstitute(char *, char *);

#define INSTACK     RStruct.Command_Stack[0]
#define STK         RStruct.Command_Stack
#define HOT         UserDat.Hot_Keys
#define LAST        UserDat.Last_File_Area
#define LEVEL       UserDat.User_Level
#define KILLPRIV    100

/* GLOBALS */
BPTR                sout;
struct Library     *DLGBase = NULL;
struct LangStruct  *ls;
char              **SA;
char                Ext[4];

struct Ram_File     RStruct;
struct USER_DATA    UserDat;
struct Msg_Log      Log;
struct SIG_Def      Sig;
struct Msg_Area     MsgArea;
struct File_Header  Header;
struct Global_Settings Globals;

/// Order menu
struct ShortMenu    Order[4] =
{
   {'F', "Natural Order", 1},
   {'B', "Inverse Order", 1},
   {'A', "Alpha Forward", 1},
   {'R', "Alpha Reverse", 1}
};
//-

/// Filter menu
struct ShortMenu    Filter[8] =
{
   {'A', "All files", 1},
   {'N', "New files", 1},
   {'S', "Last Call", 1},
   {'#', "Num Days", 1},
   {'C', "Since Date", 1},
   {'R', "Date Range", 1},
   {'F', "Filename", 1},
   {'D', "Filename/Desc", 1}
};
//-

/// Main menu
struct NewShortMenu Menu[23] =
{
   {"AAA", 1},             //0
   {"File_ChangeArea", 1}, //1
   {"File_Comment", 0},    //2
   {"File_Download", 1},   //3
   {"File_Edit", 0},       //4
   {"File_EditSig", 1},    //5
   {"File_GlobalList", 1}, //6
   {"File_Kill", 0},       //7
   {"File_List", 1},       //8
   {"File_ListBatch", 0},  //9
   {"File_NewScan", 0},    //10
   {"File_PvtArea", 1},    //11
   {"File_Read", 1},       //12
   {"File_RemoveBatch", 0},//13
   {"File_SelectSig", 1},  //14
   {"File_Subscribe",0},   //15
   {"File_Tag", 0},        //16
   {"File_Transfer", 1},   //17
   {"File_Unsubscribe",0}, //18
   {"File_Upload", 0},     //19
   {"File_Validate", 0},   //20
   {"File_ViewArchive", 0},//21
   {"File_ViewNext", 1}    //22
};
//-

/// Menu piointer defs
#define FA        1
#define FC        2
#define FD        3
#define FE        4
#define FO        5
#define FEQUAL    6
#define FK        7
#define FF        8
#define FL        9
#define FN        10
#define FP        11
#define FR        12
#define FZ        13
#define FS        14
#define FSUB      15
#define FPERIOD   16
#define FT        17
#define FUNSUB    18
#define FU        19
#define FV        20
#define FI        21
#define FNEXT     22
//-

/// Translation types
#define NUMELEMENTS 12
char                File_Trans[NUMELEMENTS][21] =
{
   {"File_FileNumber"},
   {"File_AreaNumber"},
   {"File_AreaName"},
   {"File_LowFile"},
   {"File_HighFile"},
   {"File_SigNumber"},
   {"File_SigName"},
   {"File_UserHighFile"},
   {"File_FileName"},
   {"File_FilePath"},
   {"File_From"},
   {"File_UFrom"}
};
//-

char                renumberflag = 0;
char                InGlobalScan = FALSE;
char                shortmenuflag = FALSE;
char                jgt[256];

char                LPswd[8];
char                scanstack[32] = "";
char                scanstring[18] = "";

short               PvtSendLevel = 0;
long                ScanStart;
long                StartMsg;

short               contmore = 1;
USHORT              contpos;

long                Message = 0;
long                High_Message = 0;
long                Low_Message = 0;
char                AutoDownload = 0;
char                highestfile = 0;

SHORT               SearchAreas[1024];
SHORT               LastSearchArea;
SHORT               HighSearchArea;

char                FileTo[128] = "";
char                areafile[128] = "File:Area.bbs";
char                batchfile[128] = "";
char                tempuploads[128] = "";
char                tempdownloads[128] = "";

SHORT               StopClock = FALSE;
char                MenuName[13] = "FILE_Main";

char                achangesig = 0;
SHORT              *sigarray = NULL;
long                numsigareas;
long                signumber = 0;
short               sigrestoreflag = FALSE;
long                sigrestore;

/// Main
void                main(int argc, char *argv[])
{
   long                Last = 0;
   char                FStack[36] = "";
   char                exitflag = FALSE;

   char                SetSigFlag = FALSE;
   short               sigforce = 0;

   sout = Output();

   if (!(DLGBase = OpenLibrary(DLGNAME, 4L)))
      exit(5);

/// parse args
   while (--argc > 0)
   {
      char               *s;

      s = *++argv;
      if (*s++ == '-')
      {
         while (*s)
         {
            switch (toupper(*s))
            {
               case 'S':
                  if (!--argc)
                     break;

                  SetSigFlag++;
                  signumber = atol(*(++argv));
                  sigrestoreflag = TRUE;
                  break;

               case 'M':
                  if (!--argc)
                     break;

                  strncpy(MenuName, *++argv, 12);
                  MenuName[12] = '\0';
                  break;

               case 'F':
                  sigforce++;
                  Menu[FS].status = 0;
                  break;

               case 'T':
                  StopClock = TRUE;
                  break;

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

               case 'P':
                  if (!--argc)
                     break;
                  PvtSendLevel = atoi(*++argv);
                  break;

               case 'C':
                  if (!--argc)
                     break;
                  if (strlen(*++argv) < 35)
                     strcpy(FStack, *argv);
                  break;
            }
            s++;
         }
      }
   }
//-

   if (GetDevName(Ext) == -1)
   {
      AFPrintf(NULL, sout, "Unable to determine port");
      _CXBRK();
   }

   if (!(ls = GetLang(Ext)))
      _CXBRK();
   
   SA = ls->strings;

   BCPend(Ext);

   if (!ReadUser(&RStruct, &UserDat, Ext))
   {
      AFPrintf(NULL, sout, SA[128]);
      _CXBRK();
   }

   if (ReadGlobals(Ext, &Globals) == -1)
   {
      AFPrintf(&UserDat, sout, SA[129]);
      _CXBRK();
   }

   sigrestore = UserDat.filesig;
   Sig.number = (SetSigFlag) ? signumber : UserDat.filesig;
   
   if (!sigforce && SetSigFlag)
      UserDat.filesig = signumber;

   if (!SetSigFlag)
      signumber = UserDat.filesig;

   if (Sig.number)
   {
      if (GetStruct("DLGCONFIG:SIGS/SIGS.file", (char *) &Sig, sizeof(Sig), 1) || Sig.level > LEVEL)
      {
         if (!sigforce)
            UserDat.filesig = 0;
   
         signumber = 0;
         strcpy(areafile, "File:Area.bbs");
      }
      else
      {
         ASPrintf(NULL, areafile, "DLGCONFIG:SIGS/%s.file", Sig.name);
      }
   }

   numsigareas = MakeSigArray(areafile, &sigarray, 1);

   if (Last)
      LAST = Last;
   
   if (FStack[0])
      InsertStack(STK, FStack);

   Read_Search_Areas();
   
   // Check to see if INSPECT ARCHIVE option is viable
   if (Exists("DLGCONFIG:Batch/ViewArchive.batch"))
      Menu[FI].status = 1; 
   
   if (HighSearchArea > 0)
   {
      Menu[FN].status = 1;
      Menu[FEQUAL].status = 1;
   }

   ASPrintf(NULL, LPswd, "%sFILE", Ext);

   ASPrintf(NULL, tempuploads, "FILE:TempUploads/%s", RStruct.Name);
   UnderScore(tempuploads);

   ASPrintf(NULL, tempdownloads, "FILE:TempDownloads/%s", RStruct.Name);
   UnderScore(tempdownloads);

   ASPrintf(NULL, batchfile, "USER:%s/Batch.File", RStruct.Name);
   UnderScore(batchfile);

   if (RStruct.Command_Stack[0] == '~')
   {
      movmem(STK + 1, STK, strlen(STK));
   }
   else
   {
      GetHiLowFPointers((USHORT)PVTAREA, RStruct.Name, &Low_Message, &High_Message, LPswd);

      if (High_Message)
      {
         AFPrintf(&UserDat, sout, SA[130]);
         AFPrintf(&UserDat, sout, SA[131]);
         LAST = PVTAREA;

         if (INSTACK)
         {
            AFPrintf(&UserDat, sout, SA[132], STK);
            STK[0] = 0;
         }
      }
   }

   if (Read_Pointers(LAST))
      LAST = PVTAREA;

   if (LAST != PVTAREA)
   {
      New_Area();
   }
   else
   {
      if (!INSTACK)
        AFPrintf(&UserDat, sout, SA[134]);
      
      EnterPrivateArea();
   }

   if (Exists(tempuploads))
   {
      struct SearchCookie *sc;

      sc = SearchStart(tempuploads, "*");
      
      if (SearchNext(sc))
      {
         AFPrintf(&UserDat, sout, SA[137]);
         SearchEnd(sc);
         DescribeFiles(RStruct.Name, &UserDat, &MsgArea, &RStruct, Ext, STK, LPswd, 0L, &Log);
      }
      else
      {
         SearchEnd(sc);
         DeleteFile(tempuploads);
      }

      GetHiLowFPointers(LAST, RStruct.Name, &Low_Message, &High_Message, LPswd);
   }

   while (!exitflag)
   {
      int                 hlev;
      ULONG               templong;
      char                TempMenuName[13];

      Chk_Abort();

      hlev = UserDat.Help_Level;

      if ((hlev == NOVICE) && shortmenuflag)
         hlev = INTERMEDIATE;

      strcpy(TempMenuName, MenuName);

      Menu[FL].status = 0;
      Menu[FZ].status = 0;

      if (!FileSize(batchfile, &templong))
      {
         if (templong)
         {
            Menu[FL].status = 1;
            Menu[FZ].status = 1;
         }
      }

      if (MenuInput(MenuName, Ext, "FILE", Menu, 23, HandleBuiltIn,
                    &UserDat, &RStruct, hlev, FileSubstitute) == MENUNOTFOUND)
      _CXBRK();

      if (Stricmp(MenuName, TempMenuName))
         shortmenuflag = FALSE;
   }
}
//-

/// Write_Pointers
void Write_Pointers()
{
   char                filename[128];
   char                path[128];

   FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);

   if (LAST != PVTAREA)
   {
      ASPrintf(NULL, filename, "FILE:%ld/User.File", LAST);
      BorrowArea(LAST, LPswd, "1", 64, FILELOCK | WRITELOCK);
   }
   else
   {
      ASPrintf(NULL, filename, "USER:%s/User.File", RStruct.Name);
      UnderScore(filename);

      if (renumberflag)
      {
         ASPrintf(NULL, path, "USER:%s", RStruct.Name);
         UnderScore(path);
         RenumberDir(path);
      }
   }

   renumberflag = 0;
   Upper(Log.Name);
   AddStruct(filename, (char *) &Log, sizeof(struct Msg_Log), 36);

   if (LAST != PVTAREA)
   {
      FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);
      LeaveArea(LAST, FILELOCK | WRITELOCK);
   }
}
//-

/// Read_Pointers
BYTE Read_Pointers(long area)
{
   char                filename[128];
   struct Msg_Log      TempLog;

   if (area != PVTAREA)
   {
      if (!Read_Area(area, areafile))
         return (1);

      if (_EnterArea(area, FILELOCK | WRITELOCK, 1) == -1)
         return (1);

      ASPrintf(NULL, filename, "FILE:%ld/User.File", area);
      BorrowArea(area, LPswd, "2", 64, FILELOCK | WRITELOCK);
   }
   else
   {
      MsgArea.Flag = AUTO_ACCESS_AREA;
      MsgArea.Number = PVTAREA;

      ASPrintf(NULL, filename, "USER:%s/User.File", RStruct.Name);
      UnderScore(filename);
   }

   strcpy(TempLog.Name, RStruct.Name);
   Upper(TempLog.Name);

   if (!GetStruct(filename, (char *) &TempLog, sizeof(struct Msg_Log), 36))
   {
      movmem(&TempLog, &Log, sizeof(struct Msg_Log));
      BuildFPrivFlag(&MsgArea, &Log, LEVEL);
      if (area == PVTAREA)
         Log.Priv_Flag = 255;

// Bug reported by Allen Wit... cannot edit private files

      if (Log.Priv_Flag & Sysop_Access && area != PVTAREA) // Original
//      if (Log.Priv_Flag & Sysop_Access)
         Menu[FE].status = 1;
      else
         Menu[FE].status = 0;

      if (Log.Priv_Flag & Download_Priv || Log.Priv_Flag & Sysop_Access)
      {
         Menu[FD].status = 1;
         Menu[FR].status = 1;
      }
      else
      {
         Menu[FD].status = 0;
         Menu[FR].status = 0;
      }

      if (Log.Priv_Flag & Upload_Priv || Log.Priv_Flag & Sysop_Access)
         Menu[FU].status = 1;
      else
         Menu[FU].status = 0;

      FreeArea(area, LPswd, FILELOCK | WRITELOCK);
      return (0);
   }

   if ((MsgArea.Flag & AUTO_ACCESS_AREA) && (LEVEL >= MsgArea.llevel && LEVEL <= MsgArea.ulevel) || LEVEL == 255 || area == PVTAREA)
   {
      movmem(&TempLog, &Log, sizeof(Log));
      Log.High_Mess = 0;
      Log.uflag = 0;
      Log.dflag = 0;
      Log.special = 0;
      BuildFPrivFlag(&MsgArea, &Log, LEVEL);
      if (area == PVTAREA)
      Log.Priv_Flag = 255;

      if (Log.Priv_Flag & Sysop_Access && area != PVTAREA)
         Menu[FE].status = 1;
      else
         Menu[FE].status = 0;

      if (Log.Priv_Flag & Download_Priv || Log.Priv_Flag & Sysop_Access)
      {
         Menu[FD].status = 1;
         Menu[FR].status = 1;
      }
      else
      {
         Menu[FD].status = 0;
         Menu[FR].status = 0;
      }

      if (Log.Priv_Flag & Upload_Priv || Log.Priv_Flag & Sysop_Access)
         Menu[FU].status = 1;
      else
         Menu[FU].status = 0;

      AddStruct(filename, (char *) &Log, sizeof(Log), 36);

      FreeArea(area, LPswd, FILELOCK | WRITELOCK);
      return (0);
   }

   if (area != PVTAREA)
   {
      FreeArea(area, LPswd, FILELOCK | WRITELOCK);
      LeaveArea(area, FILELOCK | WRITELOCK);
   }

   return (1);
}
//-

/// Read_Area
BOOL Read_Area(long area, char *filename)
{
   FILE               *fp;
   struct Msg_Area     temparea;

   if ((fp = fopen(filename, "r")))
   {
      while (fread(&temparea, sizeof(temparea), 1, fp))

      if (temparea.Number == area)
      {
         movmem(&temparea, &MsgArea, sizeof(temparea));
         fclose(fp);
         return (TRUE);
      }

      fclose(fp);
   }

   return (FALSE);
}
//-

/// New_Area
void New_Area(void)
{
   char  ramfile[128];
   char  scanfile[128];

   strcpy(Header.From, "");

   GetHiLowFPointers(LAST, RStruct.Name, &Low_Message, &High_Message, LPswd);

   if (Log.High_Mess > High_Message)
      Log.High_Mess = High_Message;

   Message = (Log.High_Mess < Low_Message) ? Low_Message - 1 : Log.High_Mess;


   highestfile = 0;
   AutoDownload = 0;
   shortmenuflag = 0;

   Menu[FK].status = 0;
   Menu[FPERIOD].status = 0;
   Menu[FC].status = 0;

   RStruct.area = LAST;
   WriteRam(&RStruct, Ext);

   if(LAST == PVTAREA)
   {
      Menu[FSUB].status = 0;
      Menu[FUNSUB].status = 0;
   }
   else
   {
      ASPrintf(NULL,scanfile,"User:%s/globalareas.file",RStruct.Name);
      UnderScore(scanfile);

      if(ExistsGlobalArea(scanfile,LAST))
      {
         Menu[FSUB].status = 0;
         Menu[FUNSUB].status = 1;
      }
      else
      {
         Menu[FSUB].status = 1;
         Menu[FUNSUB].status = 0;
      }
   }

   if (!INSTACK)
   {
      ASPrintf(NULL, ramfile, "FILE:%ld/EnterArea.txt", LAST);
      DispForm(ramfile, &UserDat, &UserDat, &RStruct, Ext);

      AFPrintf(&UserDat, sout, SA[254], LAST, MsgArea.Name);
      AFPrintf(&UserDat, sout, SA[255], (High_Message - Low_Message) + 1);
      AFPrintf(&UserDat, sout, SA[136], High_Message - Log.High_Mess);
   }
}
//-

/// EnterPrivateArea
void EnterPrivateArea(void)
{
   strcpy(Header.From, "");

   Read_Pointers(PVTAREA);
   GetHiLowFPointers((USHORT)PVTAREA, RStruct.Name, &Low_Message, &High_Message, LPswd);

   if (Log.High_Mess > High_Message)
      Log.High_Mess = High_Message;

   Message = (Log.High_Mess < Low_Message) ? Low_Message - 1 : Log.High_Mess;

   highestfile = 0;
   AutoDownload = 0;
   shortmenuflag = 0;

   Menu[FK].status = 0;
   Menu[FPERIOD].status = 0;
   Menu[FC].status = 0;
   Menu[FSUB].status = 0;
   Menu[FUNSUB].status = 0;

   LAST = PVTAREA;
   RStruct.area = LAST;
   WriteRam(&RStruct, Ext);

   if (!INSTACK)
   {
      AFPrintf(&UserDat, sout, SA[135], (High_Message - Low_Message) + 1);
      AFPrintf(&UserDat, sout, SA[136], High_Message - Log.High_Mess);
   }

   return;
}
//-

/// Read_Message
BYTE Read_Message(void)
{
   FILE               *fp;
   long                downloadtime;
   long                len;
   long                status;

   USHORT              pos;
   long                valarea = 0;

   char                hb[1024];
   char                temptime[12];
   char                valname[128];
   char                filename[128];

   if (LAST == PVTAREA)
   {
      ASPrintf(NULL, filename, "USER:%s/%ld.fd", RStruct.Name, Message);
      UnderScore(filename);
   }
   else
   {
      ASPrintf(NULL, filename, "FILE:%ld/%ld.fd", LAST, Message);
      BorrowArea(LAST, LPswd, "3", 64, FILELOCK | WRITELOCK);
   }

   if (!(fp = fopen(filename, "r")))
   {
      FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);
      return (1);
   }

   fread(&Header, sizeof(Header), 1, fp);
   fclose(fp);
   FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);

   if (Header.Attribute & UNVALIDATED)
   {
      if (!(Log.Priv_Flag & Sysop_Access))
      return (1);

      ASPrintf(NULL, valname, "FILE:%ld/%ld.val", LAST, Message);
      GetFirstStruct(valname, (char *) &valarea, 4);
   }

   Capitalize(Header.From);
   len = ASPrintf(&UserDat, hb, SA[138], Header.From);
   Upper(Header.From);

   len += ASPrintf(&UserDat, hb + len, SA[139], Header.Filename, Message, High_Message);

   if (Header.Attribute & NORATIO)
      len += ASPrintf(&UserDat, hb + len, SA[140]);

   len += ASPrintf(&UserDat, hb + len, SA[141], Header.Size, Header.Date);

   downloadtime = DLTime(Header.Size, RStruct.Baud_Rate, 90, Ext);
   TimeString(downloadtime, temptime);

   len += ASPrintf(&UserDat, hb + len, SA[142], Header.Times_Downloaded, temptime);
   ASPrintf(&UserDat, hb + len, SA[143]);

   pos = 1;
   if (!INSTACK)
   DispBuffer(sout, hb, &pos, 0, NULL, 0, "\x1a\x03\x0d\x0e", &UserDat);

   if (valarea)
   {
      AFPrintf(&UserDat, sout, SA[144], valarea);
      pos += 2;
      Menu[FV].status = 1;
   }
   else
      Menu[FV].status = 0;

   if (!INSTACK)
      status = Display_Msg(LAST, NULL, LPswd, MSG_FILEAREA, filename, UserDat.Screen_Width - 1, UserDat.Screen_Len, UserDat.More_Flag, &pos, 100L, UserDat.Ansi_Flag & ~ANSI_NOFREEZE, "\x1a\x03\x0d\x0e");
   else
      status = 0;

   OneLine();

   if (status > 0 && status != 3)
      Clr(UserDat.Ansi_Flag);

   if (UserDat.More_Flag && pos + MenuLen() > UserDat.Screen_Len)
      Pause();

   if ((Log.Priv_Flag & Sysop_Access) || (Log.Priv_Flag & Kill_Priv && (!Stricmp(RStruct.Name, Header.From))))
      Menu[FK].status = 1;
   else
      Menu[FK].status = 0;

   if ((Log.Priv_Flag & Sysop_Access) || (Log.Priv_Flag & Hurl_Priv && (!Stricmp(RStruct.Name, Header.From))))
      Menu[FT].status = 1;
   else
      Menu[FT].status = 0;

   Menu[FC].status = 1;

   if (Menu[FD].status)
      Menu[FPERIOD].status = 1;

   if (status > 0)
      return (2);

   return (0);
}
//-

/// UploadFile
BYTE UploadFile(void)
{
   long lock;
   long available;

   long zflag;
   char privateflag = 0;

   char filename[128];
   char path[128];
   char textfilename[128];

   char protocol;
   SHORT success;

   struct Protocol     proto;
   struct USER_DATA    User;

   if (!CD(tempuploads))
   {
      if (!(lock = CreateDir(tempuploads)))
      {
         AFPrintf(&UserDat, sout, SA[145]);
         return (1);
      }

      UnLock(lock);

      if (!CD(tempuploads))
      {
         AFPrintf(&UserDat, sout, SA[146]);
         return (1);
      }
   }

   if (LAST != PVTAREA)
   {
      if (finput(0, SA[147]))
      {
         AFPrintf(&UserDat, sout, SA[148]);
         privateflag = 1;
      }
      else
      {
         AFPrintf(&UserDat, sout, SA[149]);
      }
   }
   else
   {
      privateflag = 1;
   }

   if (privateflag)
   {
         // "Upload to ->"
      DLGInput(NULL, FileTo, NULL, 36, 36, 3, SA[150]);
    
      if (!FileTo[0])
      {
         AFPrintf(&UserDat, sout, SA[151]);
         CD("File:");
         DeleteFile(tempuploads);
         return (FALSE);
      }

      if (CheckUser(FileTo) != 1)
      {
         struct Group_Def    Group;

         Capitalize(FileTo);
         strcpy(Group.name, FileTo);
         
         if (GetStruct("DLGCONFIG:Group/Group.bbs", (char *) &Group, sizeof(Group), 36))
         {
            AFPrintf(&UserDat, sout, SA[152], FileTo);
            CD("File:");
            DeleteFile(tempuploads);
            return (1);
         }
         else
         {
            AFPrintf(&UserDat, sout, SA[153], Group.gop);
            strcpy(FileTo, Group.gop);
         }
      }

      Upper(FileTo);
      TwoLines();

      if (!PvtOK(FileTo))
      {
         CD("File:");
         DeleteFile(tempuploads);
         return (1);
      }

      ASPrintf(NULL, path, "User:%s/User.data", FileTo);
      UnderScore(path);
      GetFirstStruct(path, (char *) &User, sizeof(struct USER_DATA));

      ASPrintf(NULL, path, "User:%s/", FileTo);
      UnderScore(path);

      AFPrintf(&UserDat, sout, SA[154], FileTo);
      AFPrintf(&UserDat, sout, SA[155]);
      
      available = ((long) User.DirLimit * 1024L) - DirSize(path);
      
      if (available < 1 && LEVEL < 255)
      {
         AFPrintf(&UserDat, sout, SA[156]);
         CD("File:");
         DeleteFile(tempuploads);
         return (1);
      }

      AFPrintf(&UserDat, sout, SA[157], available, available / 1024L);
      
      if (LEVEL < 255)
      {
         AFPrintf(&UserDat, sout, SA[158]);
         zflag = finput(0, SA[159]);
         TwoLines();
      
         if (!zflag)
         {
            AFPrintf(&UserDat, sout, SA[160]);
            CD("File:");
            DeleteFile(tempuploads);
            return (1);
         }
      }
   }

   if (!(protocol = GetProtocol(SA[161], &UserDat, PROTO_REC, 0, Ext, STK)))
   {
      CD("File:");
      DeleteFile(tempuploads);
      return (1);
   }

   LoadProtocol(&proto, protocol);

   ASPrintf(NULL, textfilename, "FILE:%d/UploadFile.txt", LAST);

   if (!Exists(textfilename))
      strcpy(textfilename, "DLGConfig:text/UploadFile.txt");
   
   if (Exists(textfilename))
      DispForm(textfilename, &UserDat, &UserDat, &RStruct, Ext);

   if ((proto.flags & PROTO_FNAME) || protocol == 1)
   {
      if (DLGInput(NULL, Header.Filename, NULL, 28, 28, 0, SA[162]) == 0)
      {
         AFPrintf(&UserDat, sout, SA[163]);   // "Aborted"
         CD("File:");
         DeleteFile(tempuploads);
         return (1);
      }
   
      TwoLines();
      ScreenPath(Header.Filename);
   }

   if (protocol == 1)
   {
      zflag = DLGInput(NULL, filename, NULL, 36, 255, 0, SA[164]);
      TwoLines();
   
      if (!zflag)
      {
         CD("File:");
         DeleteFile(tempuploads);
         return (1);
      }

      if (filename[zflag - 1] == ':' || filename[zflag - 1] == '/')
         strcpy(&filename[zflag], Header.Filename);

      if (Copy(filename, Header.Filename)) 
      {
         AFPrintf(&UserDat, sout, SA[165], filename, Header.Filename);
         success = 0;
      }
      else
      {
         success = 1;
      }
   }
   else
   {
      AFPrintf(&UserDat, sout, SA[166], proto.name);
      zflag = finput(1, SA[159]);
      TwoLines();
      
      if (!zflag)
         return (FALSE);

      if (StopClock)
         SuspendTime(&RStruct, Ext);

      success = ReceiveFile(tempuploads, &proto, &Header, &UserDat, &RStruct, Ext);
      
      if (StopClock)
         ResumeTime(&RStruct, Ext);
   }

   ScanUp(tempuploads, (privateflag) ? PVTAREA : LAST,
         (privateflag) ? FileTo : NULL, success);

   DescribeFiles(RStruct.Name, &UserDat, &MsgArea, &RStruct, Ext, STK, LPswd, (privateflag) ? available : 0L, &Log);
   GetHiLowFPointers(LAST, RStruct.Name, &Low_Message, &High_Message, LPswd);
   return (0);
}
//-

/// Kill_File
BYTE Kill_File(void)
{
   long                zflag;

   zflag = finput(0, SA[167], Header.Filename);
   TwoLines();

   if (!zflag)
      return (FALSE);

   zflag = FALSE;

   if (Log.Priv_Flag & Sysop_Access && LAST != PVTAREA)
   {
      zflag = finput(0, SA[168]);
      TwoLines();
   }

   if (KillFile(LAST, RStruct.Name, Message, LPswd, zflag, &MsgArea, 0, &UserDat, Ext))
   {
      AFPrintf(&UserDat, sout, SA[169], Header.Filename);
      Menu[FPERIOD].status = 0;
      renumberflag++;
   }
   else
      AFPrintf(&UserDat, sout, SA[170], Header.Filename);

   return (0);
}
//-

/// Edit_Signature
void Edit_Signature(void)
{
   char                filename[128];

   AFPrintf(&UserDat, sout, SA[171]);
   ASPrintf(NULL, filename, "USER:%s/Signature.File", RStruct.Name);
   UnderScore(filename);

   if (finput(0, SA[172]))
      DeleteFile(filename);
   TwoLines();

   if (CallEditor(NULL, NULL, filename, SIGNATURE, &UserDat, &RStruct, Ext))
   TwoLines();
   WriteLog(EDITED_SIGNATURE, RStruct.Name, Ext, "");
}
//-

/// DownloadFile
BYTE DownloadFile(void)
{
   BPTR                lock;
   long                inpflag;

   char                altpath[128];
   char                filename[128];
   char                FileString[256];
   char                destfile[256];
   char                ramname[12];

   char                protocol;
   char                resume;
   char                logoutflag = 0;
   char                batchflag = 0;
   char                limitflag = 0;

   SHORT               success = 1;
   SHORT               sendtype;
   SHORT               timeleft;

   long                filenum;
   long                batchsize;
   long                maxdownload = 0;

   struct Protocol     proto;

   if (UserDat.Ratio)
   {
      maxdownload = ((UserDat.Bytes_Uploaded * (long) UserDat.Ratio) - UserDat.Bytes_Downloaded);

      if (maxdownload < 0)
         maxdownload = 0;

      limitflag = 1;
   }

   if (Exists(batchfile))
      batchflag = 1;

   timeleft = TimeLeft(Ext);

   if (batchflag)
   {
      AFPrintf(&UserDat, sout, SA[173]);
      CheckBatch(batchfile, Ext);

      if (!Exists(batchfile))
         return (1);

      List_Batch(&batchsize);

      if (!finput(1, SA[174]))
      {
         TwoLines();
         batchflag = 0;
      }
      else
      {
         if (limitflag && batchsize > maxdownload)
         {
            TwoLines();
            Refuse_Download(batchsize, maxdownload);
            return (1);
         }

         TwoLines();
      }
   }

   if (!batchflag)
   {
      FILE               *fp;

      filenum = Message;

      if (!AutoDownload)
      {
         if (!(filenum = GetFilename(LAST)))
         {
            AFPrintf(&UserDat, sout, SA[176]);
            return (1);
         }

         if (filenum < 0)
         {
            AFPrintf(&UserDat, sout, SA[163]);
            return (1);
         }

         TwoLines();
      }

      if (LAST == PVTAREA)
      {
         ASPrintf(NULL, filename, "USER:%s/%ld.fd", RStruct.Name, filenum);
         UnderScore(filename);
      }
      else
      {
         ASPrintf(NULL, filename, "FILE:%ld/%ld.fd", LAST, filenum);
         BorrowArea(LAST, LPswd, "4", 64, FILELOCK | WRITELOCK);
      }

      if (!(fp = fopen(filename, "r")))
      {
         AFPrintf(&UserDat, sout, SA[175]);
         FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);
         return (1);
      }

      fread(&Header, sizeof(Header), 1, fp);
      fclose(fp);

      FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);

      if (LAST != PVTAREA)
      {
         GetPath(altpath, LAST, &MsgArea, Header.Filename);
         ASPrintf(NULL, FileString, "%s%s", altpath, Header.Filename);
      }
      else
      {
         ASPrintf(NULL, FileString, "USER:%s/%s", RStruct.Name, Header.Filename);
         UnderScore(FileString);
      }

      if (!Exists(FileString))
      {
         AFPrintf(&UserDat, sout, SA[176]);
         return (1);
      }

      if (limitflag && Header.Size > maxdownload && !(Header.Attribute & NORATIO))
      {
         Refuse_Download(Header.Size, maxdownload);
         return (1);
      }

      sendtype = PROTO_SEND;
   }
   else
      sendtype = PROTO_SEND | PROTO_BATCH;

   if (!(protocol = GetProtocol(SA[161], &UserDat, sendtype, 0, Ext, STK)))
      return (1);

   resume = CheckResume(timeleft, (batchflag) ? batchsize : Header.Size, 100);

   if (resume == -1)
      return (1);

   if (protocol != 1)
   {
      LoadProtocol(&proto, protocol);

      if (resume == 1)
         if (CheckResume(timeleft, (batchflag) ? batchsize : Header.Size, proto.sendrate) == -1)
            return (1);

      logoutflag = 0;

      if (Strnicmp(Ext, "TL", 2))
      {
         logoutflag = finput(0, SA[177]);
         TwoLines();
      }
   }

   if (batchflag)
   {
      ASPrintf(NULL, ramname, "T:%s.Batch", Ext);
      Copy(batchfile, ramname);
   }

   if (protocol == 1)
   {
      char                localpath[255];

      inpflag = DLGInput(NULL, localpath, NULL, 254, 255, 0, SA[178]);
      TwoLines();

      if (!inpflag)
         return (-1);

      if (localpath[inpflag - 1] != ':' && localpath[inpflag - 1] != '/')
         strcpy(&localpath[inpflag], "/");

      if (batchflag)
      {
         struct Batch        Entry;
         char                destfile[128];
         char                sourcefile[128];

         while (!GetFirstStruct(batchfile, (char *) &Entry, sizeof(Entry)))
         {
            ASPrintf(NULL, destfile, "%s%s", localpath, Entry.filename);
            ASPrintf(NULL, sourcefile, "%s%s", Entry.path, Entry.filename);
            AFPrintf(&UserDat, sout, SA[179], sourcefile, destfile);

            if (!Copy(sourcefile, destfile))
            {
               if (DeleteStruct(batchfile, (char *) &Entry, sizeof(Entry), 36))
               break;
               AFPrintf(&UserDat, sout, SA[155]);
            }
            else
            {
               AFPrintf(&UserDat, sout, SA[180]);
               return (-1);
            }
         }

         OneLine();
      }
      else
      {
         ASPrintf(NULL, destfile, "%s%s", localpath, Header.Filename);
         AFPrintf(&UserDat, sout, SA[179], Header.Filename, destfile);

         if (!Copy(FileString, destfile))
            AFPrintf(&UserDat, sout, SA[155]);
         else
         {
            AFPrintf(&UserDat, sout, SA[180]);
            return (-1);
         }
      }
   }
   else
   {
      if (!batchflag)
      {
         char                temptime[12];

         AFPrintf(&UserDat, sout, SA[181], Header.Filename, proto.name);
         TimeString(DLTime(Header.Size, RStruct.Baud_Rate, proto.sendrate, Ext), temptime);
         AFPrintf(&UserDat, sout, SA[182], temptime);

         if ((MsgArea.Flag & TEMP_DOWNLOAD))
         {
            if (!Exists(tempdownloads))
            {
               if (!(lock = CreateDir(tempdownloads)))
               {
                  AFPrintf(&UserDat, sout, SA[183]);
                  return (-1);
               }

               UnLock(lock);
            }

            ASPrintf(NULL, destfile, "%s/%s", tempdownloads, Header.Filename);

            if (Copy(FileString, destfile))
            {
               AFPrintf(&UserDat, sout, SA[184]);
               return (-1);
            }

            strcpy(FileString, destfile);
         }
      }
      else
         AFPrintf(&UserDat, sout, SA[185], proto.name);

      success = SendFile(&proto, FileString, (batchflag) ? batchfile : NULL, &UserDat, &RStruct, Ext);
   }

   signal(SIGINT, SIG_IGN);

   if (protocol != 1 && !batchflag)
      if (MsgArea.Flag & TEMP_DOWNLOAD)
         DeleteFile(FileString);

   TwoLines();

   if (success && !batchflag)
   {
      FILE               *fp;

      if (LAST != PVTAREA)
         BorrowArea(LAST, LPswd, "5", 64, FILELOCK | WRITELOCK);

      if (!(fp = fopen(filename, "r+")))
         AFPrintf(&UserDat, sout, SA[186]);
      else
      {
         fread(&Header, sizeof(Header), 1, fp);
         Header.Times_Downloaded++;
         fseek(fp, 0, SEEK_SET);
         fwrite(&Header, sizeof(Header), 1, fp);
         fclose(fp);

         if (!(Header.Attribute & NORATIO))
         {
            UserDat.Bytes_Downloaded += Header.Size;
            UserDat.Files_Downloaded++;
         }
      }

      FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);
      WriteLog(DOWNLOADED_FILE, RStruct.Name, Ext, Header.Filename);
   }
   else if (batchflag)
   {
      ChargeForFiles(batchfile);
      AutoDownload = 0;
      shortmenuflag = 0;
   }

   WriteUser(RStruct.Name, &UserDat);
   signal(SIGINT, SIG_DFL);

   if (success)
      if (logoutflag)
         return (2);
      else
         return (0);

   AFPrintf(&UserDat, sout, SA[187]);
   return (1);
}
//-

/// CheckResume
BOOL CheckResume(int timeleft, long size, char eff)
{
   long                zflag;

   if (timeleft < (DLTime(size, RStruct.Baud_Rate, eff, Ext) / 60))
   {
      AFPrintf(&UserDat, sout, SA[188]);
      zflag = finput(1, SA[189]);
      TwoLines();

      if (!zflag)
         return (-1);
   }

   return (FALSE);
}
//-

/// AskListStuff
BOOL AskListStuff(char mode)
{
   /* ==================================================
      Called by FILE_LIST
   */
   
   char                number[8];
   char                order[2];
   char                since[2];
   char                torder[2];
   char                tsince[2];
   char                temp[10];
   char                start[22];
   char                end[22];
   SHORT               days;

   if (LAST == PVTAREA && !mode)
   {
      List_Files();
      return (TRUE);
   }

   order[0] = UserDat.fileorder;
   torder[0] = UserDat.fileorder;
   order[1] = 0;
   torder[1] = 0;

   since[0] = UserDat.filesince;
   tsince[0] = UserDat.filesince;
   since[1] = 0;
   tsince[1] = 0;

   if (!INSTACK)
   {
      menu(Order, 4, 0);
      OneLine();
      AFPrintf(&UserDat, sout, SA[190], torder[0]);
   }
   
   DLGInput((char *) 1, order, torder, 1, 255, 1, "");
   UserDat.fileorder = order[0];
   TwoLines();

   if (!INSTACK)
   {
      menu(Filter, 8, 0);
      OneLine();
      AFPrintf(&UserDat, sout, SA[191], tsince[0]);
   }
   
   DLGInput((char *) 1, since, tsince, 1, 255, 1, "");
   UserDat.filesince = since[0];
   
   if (!InGlobalScan)
      TwoLines();

   ASPrintf(NULL, scanstack, "\0018;%c%c;", UserDat.fileorder, UserDat.filesince);

   switch (since[0])
   {
      case '#':
         if (!(days = iinput(1, 30000, 0, SA[192])))
         {
            AFPrintf(&UserDat, sout, SA[193]);
            return (FALSE);
         }

         ASPrintf(NULL, number, "%d", days);
         strcat(scanstack, number);
      
         if (!InGlobalScan)
            TwoLines();
         break;

      case 'C':
         DLGInput(NULL, temp, NULL, 9, 9, 3, SA[194]);
      
         if (!InGlobalScan)
            TwoLines();
      
         if (temp[0] == '\0')
            return (FALSE);
      
         strcat(scanstack, temp);
         strcat(scanstack, ";");
      
         ASPrintf(&UserDat, start, "Mon %s 00:00", temp);
         break;

      case 'F':
      case 'D':
         DLGInput(NULL, scanstring, scanstring, 18, 255, 1, SA[195]);
      
         if (!InGlobalScan)
            TwoLines();
      
         if (!scanstring[0])
            return (FALSE);
      
         strcat(scanstack, scanstring);
         ASPrintf(NULL, start, "*%s*", scanstring);
         break;

      case 'R':
         DLGInput(NULL, temp, NULL, 9, 255, 3, SA[196]);
   
         if (!InGlobalScan)
            TwoLines();
      
         if (!temp[0])
            return (FALSE);
      
         strcat(scanstack, temp);
         strcat(scanstack, ";");
         ASPrintf(&UserDat, start, "Mon %s 00:00", temp);

         DLGInput(NULL, temp, NULL, 9, 255, 3, SA[197]);
      
         if (!InGlobalScan)
            TwoLines();
      
         if (!temp[0])
            return (FALSE);
      
         strcat(scanstack, temp);
         ASPrintf(&UserDat, end, "Mon %s 00:00", temp);
         break;
   }

   if (mode)
   {
      InsertStack(STK, "\00110;");
      InGlobalScan = TRUE;
      LastSearchArea = 0;
      contmore = 1;
      ScanStart = LAST;
      StartMsg = Message;
      contpos = 1;
      return (TRUE);
   }

   if (ListFiles(order[0], since[0], days, mode, start, end) != -1 && (mode || InGlobalScan))
   {
      InsertStack(STK, "\00110;");
      InGlobalScan = TRUE;
      return (TRUE);
   }

   if (InGlobalScan)
   {
      Write_Pointers();
      LAST = ScanStart;
      Message = StartMsg;
      Read_Pointers(LAST);
      GetHiLowFPointers(LAST, RStruct.Name, &Low_Message, &High_Message, LPswd);
      InGlobalScan = FALSE;
   }

   return (TRUE);
}
//-

/// ListFiles
BYTE ListFiles(char order, char since, int days, char mode, char *start, char *end)
{
   long                b;
   long                retval;
   long                lastend;
   long                lastin;
   long                temphigh;

   long                a;
   long                numfiles;
   SHORT               descwidth;

   struct QuickFile   *QF = NULL;
   char                ramfile[256];
   char                description[60];
   char                Listed = 0;

   if (!InGlobalScan)
   {
      contmore = 1;
      contpos = 1;
   }

   if (!(numfiles = LoadFiles(LAST, (char **) &QF, LPswd)))
   {
      if (QF)
         free(QF);
      return (0);
   }

   switch (order)
   {
      case 'F':
         qsort(QF, numfiles, sizeof(struct QuickFile), SortAgedUp);
         break;

      case 'B':
         qsort(QF, numfiles, sizeof(struct QuickFile), SortAgedDown);
         break;

      case 'A':
         qsort(QF, numfiles, sizeof(struct QuickFile), SortAlphUp);
         break;

      case 'R':
         qsort(QF, numfiles, sizeof(struct QuickFile), SortAlphDown);
         break;
   }

   ASPrintf(&UserDat, ramfile, SA[198], LAST, MsgArea.Name);
   retval = DisplayBuffer(sout, ramfile, UserDat.Screen_Width, UserDat.Screen_Len, (UserDat.More_Flag && contmore), UserDat.Ansi_Flag, &contpos, 0, NULL, 1, "\x03");

   if (retval == -2)
      contmore = 0;
   else if (retval)
   {
      OneLine();

      if (QF)
         free(QF);

      return (-1);
   }

   temphigh = Log.High_Mess;

   for (a = 0; a < numfiles; a++)
   {
      switch (since)
      {
         case 'N':
            if ((QF + a)->number <= temphigh)
               continue;

            if ((QF + a)->number > Log.High_Mess)
               Log.High_Mess = (QF + a)->number;

            break;

         case 'S':
            StringToDate(UserDat.Last_Login, &lastin);

            if ((QF + a)->date < lastin)
               continue;

            break;

         case '#':
            if ((QF + a)->date < ((long) AmigaTime() - (long) (86400L * days)))
               continue;

            break;

         case 'C':
            StringToDate(start, &lastin);

            if ((QF + a)->date < lastin)
               continue;

            break;

         case 'F':
            if (!DLGPatternMatch(start, (QF + a)->filename))
               continue;

            break;

         case 'D':
            if (!DLGPatternMatch(start, (QF + a)->filename) && !DLGPatternMatch(start, (QF + a)->desc))
               continue;

            break;

         case 'R':
            StringToDate(start, &lastin);
            StringToDate(end, &lastend);

            if ((QF + a)->date < lastin || (QF + a)->date > lastend)
               continue;

            break;
      }

      if (!Listed)
      {
         Listed = 1;
         contpos++;
         OneLine();
      }

      descwidth = UserDat.Screen_Width - 31;

      if (descwidth < 20)
         descwidth = 20;

      if (descwidth > 56)
         descwidth = 56;

      strcpy(description, (QF + a)->desc);
      b = 0;

      while ((description[b] == ' ' || description[b] == 10 || description[b] == 13))
         b++;

      if (b)
         movmem(&description[b], description, sizeof(description) - b);

      for (b = 0; b < (descwidth); b++)
         if (description[b] == 10 || description[b] == 13)
         {
            description[b] = '\0';
         }

      description[descwidth] = '.';
      description[descwidth + 1] = '.';
      description[descwidth + 2] = '.';
      description[descwidth + 3] = '\0';

      ASPrintf(&UserDat, ramfile, SA[199], (QF + a)->number, (QF + a)->filename,
               ((QF + a)->size / 1024) + 1, description);

      retval = DisplayBuffer(sout, ramfile, UserDat.Screen_Width, UserDat.Screen_Len, (UserDat.More_Flag && contmore), UserDat.Ansi_Flag, &contpos, 0, NULL, 1, "\x03");

      if (ReadChar(0) == 3)
      {
         AFPrintf(&UserDat, sout, SA[200]);

         if (QF)
            free(QF);

         return (-1);
      }

      if (retval == -2)
         contmore = 0;
      else if (retval)
      {
         OneLine();

         if (QF)
            free(QF);

         return (-1);
      }
   }

   if (Listed || !InGlobalScan)
   {
      OneLine();
      contpos++;
   }

   if (QF)
      free(QF);

   return (Listed);
}
//-

/// List_Files
BYTE List_Files(void)
{
   long                a;
   long                retval;

   SHORT               descwidth;
   SHORT               moreon = 1;
   USHORT              len = 2;

   char                fline[200];
   char                description[128];

   if (!High_Message)
   {
      AFPrintf(&UserDat, sout, "No files to list\n\n");
      return (0);
   }

   AFPrintf(&UserDat, sout, SA[201]);

   descwidth = UserDat.Screen_Width - 31;

   if (descwidth < 5)
      descwidth = 20;

   if (descwidth > 47)
      descwidth = 47;

   for (a = 1; a <= High_Message; a++)
   {
      {
         FILE               *fp;
         char                filename[128];

         ASPrintf(NULL, filename, "USER:%s/%ld.fd", RStruct.Name, a);
         UnderScore(filename);

         if (!(fp = fopen(filename, "r")))
            continue;

         fread(&Header, sizeof(Header), 1, fp);
         fread(&description, sizeof(description), 1, fp);
         fclose(fp);
      }

      {
         long                b;

         description[99] = 0;
         b = 0;

         while ((description[b] == ' ' || description[b] == 10 || description[b] == 13))
            b++;

         if (b)
            movmem(&description[b], description, sizeof(description) - b);

         for (b = 0; b < descwidth; b++)
         {
            if (description[b] == 10 || description[b] == 13)
            {
               description[b] = 0;
               b++;
               break;
            }
         }

         description[b] = '.';
         description[b + 1] = '.';
         description[b + 2] = '.';
         description[b + 3] = 0;
      }

      ASPrintf(&UserDat, fline, SA[202], a, Header.Filename, (Header.Size / 1024) + 1L, description);
      retval = DisplayBuffer(sout, fline, UserDat.Screen_Width, UserDat.Screen_Len, (UserDat.More_Flag && moreon), UserDat.Ansi_Flag, &len, 0, NULL, 1, "\x03");

      if (ReadChar(0) == 3)
      {
         AFPrintf(&UserDat, sout, SA[200]);
         return (0);
      }

      if (retval == -2)
         moreon = 0;
      else if (retval)
      {
         OneLine();
         return (0);
      }
   }

   OneLine();
   return (0);
}
//-

/// SortAgedUp
int                 SortAgedUp(struct QuickFile *st1, struct QuickFile *st2)
{
   return (st1->number - st2->number);
}
//-

/// SortAgedDown
int                 SortAgedDown(struct QuickFile *st1, struct QuickFile *st2)
{
   return (st2->number - st1->number);
}
//-

/// SortAlphUp
int                 SortAlphUp(struct QuickFile *st1, struct QuickFile *st2)
{
   return (Stricmp(st1->filename, st2->filename));
}
//-

/// SortAlphDown
int                 SortAlphDown(struct QuickFile *st1, struct QuickFile *st2)
{
   return (Stricmp(st2->filename, st1->filename));
}
//-

/// Add_Comment
void                Add_Comment()
{
   ULONG               size = 0;

   char                ramname[128];
   char                filename[128];
   char                date[20];
   char                comment[256];

   ASPrintf(NULL, ramname, "T:%s.Comment", Ext);
   ASPrintf(NULL, filename, "FILE:%ld/%ld.fd", LAST, Message);

   AFPrintf(&UserDat, sout, SA[203]);

   DeleteFile(ramname);
   CallEditor(NULL, "::", ramname, FILE_DESC, &UserDat, &RStruct, Ext);
   OneLine();

   if (!FileSize(ramname, &size))
   {
      if (LAST != PVTAREA)
         BorrowArea(LAST, LPswd, "6", 64, FILELOCK | WRITELOCK);

      MDate(date);
      ASPrintf(&UserDat, comment, SA[206], RStruct.Name, date);
      Cat(filename, ramname, comment);
      FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);
   }

   DeleteFile(ramname);
}
//-

/// Hurl_File
BOOL                Hurl_File(char mode)
{
   FILE               *fp;
   long                filenum;
   long                zflag;
   ULONG               size;
   long                varea;
   long                destarea;
   SHORT               retval;
   SHORT               leavefile = 0;

   char               *body;
   char                ifile[128];
   char                idesc[128];
   char                toname[40];
   char                altpath[128];
   char                path[128];
   char                vfile[20];
   char                ifilepath[40];
   struct File_Header  Header;

   filenum = Message;

   if (!(AutoDownload))
   {
      filenum = GetFilename(LAST);

      if (filenum <= 0)
         return (FALSE);
   }

   /* Calculate description filename */
   if (LAST == PVTAREA)
   {
      ASPrintf(NULL, idesc, "USER:%s/%ld.fd", RStruct.Name, filenum);
      ASPrintf(NULL, path, "USER:%s", RStruct.Name);
      UnderScore(path);
      UnderScore(idesc);
   }
   else
   {
      ASPrintf(NULL, idesc, "FILE:%ld/%ld.fd", LAST, filenum);
      ASPrintf(NULL, path, "FILE:%ld", LAST);
      BorrowArea(LAST, LPswd, "7", 64, FILELOCK | WRITELOCK);
   }

   /* Load header of file description */
   if (GetFirstStruct(idesc, (char *) &Header, sizeof(Header)))
   {
      AFPrintf(&UserDat, sout, SA[207], idesc);
      FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);
      return (FALSE);
   }

   FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);

   /* Check to see if uploader matches or user has Sysop Access */
   if (Stricmp(Header.From, RStruct.Name) && !(Log.Priv_Flag & Sysop_Access))
   {
      AFPrintf(&UserDat, sout, SA[208]);
      return (FALSE);
   }

   /* Calculate actual file name and check for the files existance */
   if (LAST == PVTAREA)
   {
      ASPrintf(NULL, ifile, "USER:%s/%s", RStruct.Name, Header.Filename);
      ASPrintf(NULL, ifilepath, "USER:%s", RStruct.Name);
      UnderScore(ifile);
      UnderScore(ifilepath);
   }
   else
   {
      int jgpath;
      jgpath = GetPath(altpath, LAST, &MsgArea, Header.Filename);
      
      if(jgpath == 2)
         leavefile = 1;
      else
         leavefile = 0;

      strcpy(ifile,altpath);
      AddPart(ifile,Header.Filename,127);

      strcpy(ifilepath, altpath);

      if (ifilepath[strlen(ifilepath) - 1] == '/')
         ifilepath[strlen(ifilepath) - 1] = '\0';
   }

   if (!Exists(ifile))
   {
      AFPrintf(&UserDat, sout, SA[209]);
      return (FALSE);
   }

   zflag = 0;

   if (!mode)
   {
      zflag = finput(0, SA[210]);
      TwoLines();
   }

   if (!zflag)
   {
      if (mode)
      {
         ASPrintf(NULL, vfile, "FILE:%ld/%ld.val", LAST, Message);
         GetFirstStruct(vfile, (char *) &varea, 4);
         Read_Area(varea, "File:Area.bbs");

         if (!INSTACK)
            AFPrintf(&UserDat, sout, SA[211], varea, MsgArea.Name);
      }
      else
      {
         if (!INSTACK)
            AFPrintf(&UserDat, sout, SA[212], 1, 9999, 0, STK);

         varea = 0;
      }

      destarea = iinput(1, 9999, varea, " => ");
      TwoLines();

      if (!destarea)
         return (FALSE);

      if (!Read_Area(destarea, "File:Area.bbs"))
      {
         Read_Area(LAST, "File:Area.bbs");
         return (FALSE);
      }
   }
   else
   {
      DLGInput(NULL, toname, NULL, 36, 255, 3, SA[213]);
      TwoLines();

      if (!toname[0])
         return (FALSE);

      if (!CheckUser(toname))
      {
         AFPrintf(&UserDat, sout, SA[214]);
         return (FALSE);
      }

      if (!PvtOK(toname))
         return (FALSE);
   }

   if (!zflag)
   {
      if (!Check_Write_Access(&MsgArea))
      {
         AFPrintf(&UserDat, sout, SA[215], destarea);
         return (1);
      }
   }
   else
   {
      char                path[80];
      struct USER_DATA    User;

      ASPrintf(NULL, path, "User:%s/User.data", toname);
      UnderScore(path);
      GetFirstStruct(path, (char *) &User, sizeof(User));
      ASPrintf(NULL, path, "User:%s/", toname);
      UnderScore(path);

      if (!(Log.Priv_Flag & Sysop_Access))
      {
         AFPrintf(&UserDat, sout, SA[154], toname);
         AFPrintf(&UserDat, sout, SA[155]);

         if (Header.Size > ((long) User.DirLimit * 1024L) - DirSize(path))
         {
            AFPrintf(&UserDat, sout, SA[216]);
            return (FALSE);
         }
      }
   }

   /* Allocate memory and load body of description */
   if (FileSize(idesc, &size))
      return (FALSE);

   if (!(body = malloc(size - sizeof(Header) + 1)))
      return (FALSE);

   if (LAST != PVTAREA)
      BorrowArea(LAST, LPswd, "8", 64, FILELOCK | WRITELOCK);

   if (!(fp = fopen(idesc, "r")))
   {
      FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);
      return (FALSE);
   }
   else
   {
      fseek(fp, sizeof(Header), SEEK_SET);
      fread(body, size - sizeof(Header), 1, fp);
      fclose(fp);
   }

   FreeArea(LAST, LPswd, FILELOCK | WRITELOCK);
   body[size - sizeof(Header)] = 0;

   if (Exists("DLGConfig:batch/Transfer.batch"))
   {
      char                exestr[256];

      UnderScore(RStruct.Name);
      ASPrintf(NULL, exestr, "Execute DLGConfig:batch/Transfer.batch %s %s/%s", RStruct.Name, ifilepath, Header.Filename);
      DeScore(RStruct.Name);
      Execute(exestr, 0, 0);
   }

   /* Raw upload the file */
   Header.Attribute &= ~UNVALIDATED;

   if (zflag)
      Header.Times_Downloaded = 0;

   if (mode)
      MDate(Header.Date);

   for (;;)
   {
      retval = RawUpload(ifilepath, Header.Filename, &Header, body, (zflag) ? toname : NULL, &MsgArea, LPswd, (leavefile && (!zflag)) ? 0 : 1);

      if (retval == -2)
      {
         AFPrintf(&UserDat, sout, SA[217]);
         free(body);

         if (LAST != PVTAREA)
            Read_Area(LAST, "File:Area.bbs");

         return (FALSE);
      }

      if (retval == -1)
      {
         if (finput(0, SA[218]))
         {
            char                comment[128];
            char                path[256];
            char                removecredit;
            long                dummy;
            long                number;

            TwoLines();
            GetPath(altpath, MsgArea.Number, &MsgArea, Header.Filename);
            ASPrintf(NULL, path, "%s%s", altpath, Header.Filename);
            GetComment(path, comment);

            if (MsgArea.Number != PVTAREA)
               sscanf(comment, "FILE:%ld/%ld.fd", &dummy, &number);
            else
               sscanf(comment, "%[~/]/%ld.fd", altpath, &number);

            AFPrintf(&UserDat, sout, SA[167], path);

            if (finput(0,""))
            {
               TwoLines();
               removecredit = finput(0, SA[168]);
               TwoLines();

               if (!KillFile(MsgArea.Number, RStruct.Name, number, LPswd, removecredit, &MsgArea, 0, &UserDat, Ext))
                  AFPrintf(&UserDat, sout, SA[170], Header.Filename);
            }

            TwoLines();
            continue;
         }

         TwoLines();
         free(body);

         if (LAST != PVTAREA)
            Read_Area(LAST, "File:Area.bbs");

         return (FALSE);
      }

      break;
   }

   /* Load back original area data */
   if (LAST != PVTAREA)
      Read_Area(LAST, "File:Area.bbs");
   else
      renumberflag++;

   /* Kill the original file */
   KillFile(LAST, RStruct.Name, (SHORT) filenum, LPswd, 0, &MsgArea, 2, &UserDat, Ext);

   WriteLog(HURLED_FILE, RStruct.Name, Ext, ifile);
   free(body);

   if (mode)
   {
      AFPrintf(&UserDat, sout, SA[219]);
      DeleteFile(vfile);
   }
   else
      AFPrintf(&UserDat, sout, SA[220]);

   return (TRUE);
}
//-

/// NoAbility
void                NoAbility(void)
{
   AFPrintf(&UserDat, sout, SA[221]);
}
//-

/// Check_Write_Access
BOOL                Check_Write_Access(struct Msg_Area *area)
{
   char                filename[128];
   struct Msg_Log      Log;

   if (LEVEL == 255)
      return (TRUE);

   if (area->Flag & AUTO_ACCESS_AREA && LEVEL >= area->llevel && LEVEL <= area->ulevel)
   {
      if ((LEVEL >= area->lwrite && LEVEL <= area->uwrite) ||
          (LEVEL >= area->lsysop && LEVEL <= area->usysop))
         return (TRUE);
   }

   ASPrintf(NULL, filename, "FILE:%d/User.File", area->Number);

   if (LAST != PVTAREA)
      BorrowArea(area->Number, LPswd, "9", 64, FILELOCK | WRITELOCK);

   strcpy(Log.Name, RStruct.Name);
   Upper(Log.Name);

   if (!GetStruct(filename, (char *) &Log, sizeof(Log), 36))
   {
      if (!(Log.dflag & Enter_Priv))
      {
         if ((LEVEL >= area->lwrite && LEVEL <= area->uwrite) || Log.uflag & Enter_Priv || Log.uflag & Sysop_Access)
         {
            FreeArea(area->Number, LPswd, FILELOCK | WRITELOCK);
            return (TRUE);
         }
      }
   }

   FreeArea(area->Number, LPswd, FILELOCK | WRITELOCK);
   return (FALSE);
}
//-

/// RenumberDir
BOOL                RenumberDir(char *dir)
{
   long                Low;
   long                High;
   long                from;
   long                to;
   char                comment[128];
   char                fromname[20];
   char                toname[20];
   struct File_Header  Header;

   CD(dir);
   GetHiLowFPointers((USHORT)PVTAREA, RStruct.Name, &Low, &High, LPswd);

   AFPrintf(&UserDat, sout, SA[222]);

   /* Scan up to first blank fd */
   to = 0;

   do
   {
      to++;
      ASPrintf(NULL, toname, "%ld.fd", to);

      if (to >= High && Exists(toname))
      {
         AFPrintf(&UserDat, sout, SA[155]);
         return (FALSE);
      }
   }
   while (Exists(toname));

   /* Renumber the remaining file descriptions and re-set comments */
   from = to;

   for (;;)
   {
      from++;

      if (from > High)
      {
         if (!PutHiLowFPointers((USHORT)PVTAREA, RStruct.Name, 1L, to - 1L, LPswd))
            AFPrintf(&UserDat, sout, SA[223]);

         AFPrintf(&UserDat, sout, SA[155]);

         if (Log.High_Mess > to - 1)
            Log.High_Mess = to - 1;

         return (TRUE);
      }

      ASPrintf(NULL, fromname, "%ld.fd", from);

      if (Exists(fromname))
      {
         ASPrintf(NULL, toname, "%ld.fd", to);

         if (Exists(toname))
            DeleteFile(toname);
         if (!Rename(fromname, toname))
         {
            AFPrintf(&UserDat, sout, SA[224]);
            return (FALSE);
         }

         if (from == Log.High_Mess)
            Log.High_Mess = to;

         GetFirstStruct(toname, (char *) &Header, sizeof(Header));
         ASPrintf(NULL, comment, "USER:%s/%ld.fd", RStruct.Name, to);
         UnderScore(comment);
         SetComment(Header.Filename, comment);
         to++;
      }
   }
}
//-

/// Read_Search_Areas
void                Read_Search_Areas(void)
{
   BPTR fh = NULL;
   ULONG               size = 0;
   char                filename[256];

   ASPrintf(NULL, filename, "USER:%s/GlobalAreas.file", RStruct.Name);
   UnderScore(filename);

   FileSize(filename, &size);
   HighSearchArea = size / 2;

   if (HighSearchArea > 1024)
      HighSearchArea = 1024;

   if ((fh = Open(filename, MODE_OLDFILE)))
   {
      Read(fh, &SearchAreas, size);
      Close(fh);
   }

   return;
}
//-

/// Add_Batch
LONG                Add_Batch(void)
{
   ULONG               size;
   char                altpath[128];
   char                fullname[256];
   struct Batch        FileEntry;

   if (!FileSize(batchfile, &size))
      if ((size / (long) sizeof(FileEntry)) > 253)
      {
         AFPrintf(&UserDat, sout, "Error: Can't tag file.. Maximum of 254 files already tagged\n\n");
         return (-2);
      }

   FileEntry.free = 0;

   if (Header.Attribute & NORATIO)
      FileEntry.free |= 1;

   if (MsgArea.Flag & TEMP_DOWNLOAD)
      FileEntry.free |= TEMP_DOWNLOAD;

   FileEntry.size = Header.Size;

   strcpy(FileEntry.filename, Header.Filename);

   if (LAST == PVTAREA)
      ASPrintf(NULL, FileEntry.path, "USER:%s/", RStruct.Name);
   else
   {
      GetPath(altpath, LAST, &MsgArea, Header.Filename);
      strcpy(FileEntry.path, altpath);
   }

   UnderScore(FileEntry.path);

   ASPrintf(NULL, fullname, "%s%s", FileEntry.path, FileEntry.filename);

   if (Exists(fullname))
      return (AddStruct(batchfile, (char *) &FileEntry, sizeof(FileEntry), 40));

   return (-2);
}
//-

/// List_Batch
BYTE                List_Batch(long *retval)
{
   FILE               *fp;
   char               *buffer;
   long                buffsize;
   USHORT              pos;

   char                temptime[12];
   struct Batch        FileEntry;

   long                downloadtotal = 0;
   long                chargetotal = 0;
   long                totalsize = 0;

   if (FileSize(batchfile, (ULONG *) & buffsize))
   {
      AFPrintf(&UserDat, sout, SA[225]);
      return (-1);
   }

   buffsize = ((buffsize / (long) sizeof(FileEntry)) * 100) + 1024L;

   if (!(buffer = malloc(buffsize)))
   {
      AFPrintf(&UserDat, sout, SA[226]);
      return (-1);
   }

   if (!(fp = fopen(batchfile, "r")))
   {
      free(buffer);
      return (-1);
   }

   buffsize = ASPrintf(&UserDat, buffer, SA[227]);
   SDraw_Line(buffer + buffsize, UserDat.Screen_Width);
   buffsize += UserDat.Screen_Width;

   while (fread(&FileEntry, sizeof(FileEntry), 1, fp))
   {
      long                downloadtime;

      downloadtime = DLTime(FileEntry.size, RStruct.Baud_Rate, 90, Ext);
      TimeString(downloadtime, temptime);
      downloadtotal += downloadtime;

      if (!(FileEntry.free & 1))
         chargetotal += FileEntry.size;

      totalsize += FileEntry.size;

      buffsize += ASPrintf(&UserDat, buffer + buffsize, SA[228], FileEntry.filename, FileEntry.size, temptime, (FileEntry.free & 1) ? SA[229] : SA[230]);
   }

   fclose(fp);

   buffsize += ASPrintf(&UserDat, buffer + buffsize, SA[231]);
   SDraw_Line(buffer + buffsize, UserDat.Screen_Width);
   buffsize += UserDat.Screen_Width;

   if (!(Strnicmp(Ext, "TL", 2)) || RStruct.Baud_Rate == 0)
      downloadtotal = 0;

   TimeString(downloadtotal, temptime);
   ASPrintf(&UserDat, buffer + buffsize, SA[232], SA[233], totalsize, temptime);

   pos = 0;
   DisplayBuffer(sout, buffer, UserDat.Screen_Width, UserDat.Screen_Len, UserDat.More_Flag, UserDat.Ansi_Flag, &pos, 0, NULL, 1, "\003");

   free(buffer);
   *retval = chargetotal;
   OneLine();
}
//-

/// Batch_Remove
BYTE                Batch_Remove(void)
{
   long                junk;
   long                zflag;
   char                flag;
   struct Batch        Entry;

   flag = finput(0, SA[235]);
   TwoLines();

   if (flag)
   {
      if (DeleteFile(batchfile))
         AFPrintf(&UserDat, sout, SA[236]);
      else
         AFPrintf(&UserDat, sout, SA[237]);
      return (0);
   }

   for (;;)
   {
      List_Batch(&junk);
      zflag = DLGInput(NULL, Entry.filename, NULL, 35, 255, 1, SA[238]);
      TwoLines();

      if (!zflag)
         break;

      if (!DeleteStruct(batchfile, (char *) &Entry, sizeof(Entry), 36))
         AFPrintf(&UserDat, sout, SA[239], Entry.filename);
      else
         AFPrintf(&UserDat, sout, SA[240], Entry.filename);
   }

   return (0);
}
//-

/// ChargeForFiles
BYTE                ChargeForFiles(char *batchname)
{
   FILE               *fp;
   char                ramname[24];
   char                filename[128];
   char                descname[128];
   char                lastname[80];
   struct Batch        Entry;

   ASPrintf(NULL, ramname, "T:%s.Batch", Ext);
   lastname[0] = 0;

   AFPrintf(&UserDat, sout, SA[241]);

   while (!GetFirstStruct(ramname, (char *) &Entry, sizeof(Entry)))
   {
      if (!strcmp(lastname, Entry.filename))
         break;

      if (GetStruct(batchname, (char *) &Entry, sizeof(Entry), 40))
      {
         ASPrintf(NULL, filename, "%s%s", Entry.path, Entry.filename);
         UnderScore(filename);
         GetComment(filename, descname);

         if ((fp = fopen(descname, "r+")))
         {
            fread(&Header, sizeof(Header), 1, fp);
            Header.Times_Downloaded++;
            fseek(fp, 0, SEEK_SET);
            fwrite(&Header, sizeof(Header), 1, fp);
            fclose(fp);
            WriteLog(DOWNLOADED_FILE, RStruct.Name, Ext, Header.Filename);
         }

         if (!(Entry.free & 1))
         {
            UserDat.Bytes_Downloaded += Entry.size;
            UserDat.Files_Downloaded++;
         }
      }

      strcpy(lastname, Entry.filename);
      DeleteStruct(ramname, (char *) &Entry, sizeof(Entry), 40);
   }

   AFPrintf(&UserDat, sout, SA[155]);
   return (0);
}
//-

/// Refuse_Download
void                Refuse_Download(long requested, long allowed)
{
   AFPrintf(&UserDat, sout, SA[242], UserDat.Ratio);
   AFPrintf(&UserDat, sout, SA[243], (requested / 1024L) + 1L, allowed / 1024L);
   AFPrintf(&UserDat, sout, SA[244]);

   if (Exists("DLGConfig:Text/RefuseDownload.txt"))
      DispForm("DLGConfig:Text/RefuseDownload.txt", &UserDat, &UserDat, &RStruct, Ext);
}
//-

/// GetFilename
long  GetFilename(long area)
{
   char                filename[256];
   char                path[256];
   char               *p;
   char                altpath[256];
   SHORT               counter;
   SHORT               numericflag = 1;
   long                number = 0;
   long                dummy = 0;

   dummy = DLGInput(NULL, filename, NULL, 36, 255, 1, SA[245]);
   TwoLines();

   if (!dummy)
      return (-1);

   for (counter = 0; filename[counter]; counter++)
      if (isalpha(filename[counter]))
         numericflag = 0;

   GetPath(altpath, area, &MsgArea, (numericflag) ? NULL : filename);

   p = path;

   if (area != PVTAREA)
      p += ASPrintf(NULL, p, "%s", altpath);
   else
      p += ASPrintf(NULL, p, "USER:%s/", RStruct.Name);

   strcpy(p, filename);
   UnderScore(path);

   sscanf(filename, "%ld", &number);
   GetComment(path, filename);

   if (Exists(filename))
   {
      if (area != PVTAREA)
         sscanf(filename, "FILE:%ld/%ld.fd", &dummy, &number);
      else
         sscanf(filename, "%[~/]/%ld.fd", path, &number);

      if (dummy && dummy != area)
         return (0);

      return (number);
   }

   return (number);
}
//-

/// GetFileInfo
BYTE                GetFileInfo(char *name)
{
   char                filename[256];
   char                altpath[256];

   if (LAST == PVTAREA)
   {
      if (!AutoDownload)
      {
         ASPrintf(NULL, filename, "USER:%s/%d.fd", RStruct.Name, GetFilename(LAST));
         UnderScore(filename);

         if (GetFirstStruct(filename, (char *) &Header, sizeof(Header)))
            return (-1);
      }

      ASPrintf(NULL, name, "USER:%s/%s", RStruct.Name, Header.Filename);
      UnderScore(name);
   }
   else
   {
      if (!AutoDownload)
      {
         ASPrintf(NULL, filename, "FILE:%ld/%ld.fd", LAST, GetFilename(LAST));

         if (GetFirstStruct(filename, (char *) &Header, sizeof(Header)))
            return (-1);
      }

      GetPath(altpath, LAST, &MsgArea, Header.Filename);
      ASPrintf(NULL, name, "%s%s", altpath, Header.Filename);
   }

   return (0);
}
//-

/// ReadFile
BYTE                ReadFile(void)
{
   FILE               *fp;
   long                filenum;
   SHORT               index;
   char                tempname[128];
   char                altpath[128];
   char                readfile[128];
   char                buffer[21];

   filenum = Message;

   if (!AutoDownload)
   {
      if (!(filenum = GetFilename(LAST)))
      {
         AFPrintf(&UserDat, sout, SA[176]);
         return (-1);
      }

      if (filenum < 0)
      {
         AFPrintf(&UserDat, sout, SA[163]);
         return (-1);
      }

      TwoLines();
   }

   if (LAST == PVTAREA)
   {
      ASPrintf(NULL, tempname, "USER:%s/%d.fd", RStruct.Name, filenum);
      UnderScore(tempname);
   }
   else
      ASPrintf(NULL, tempname, "FILE:%ld/%ld.fd", LAST, filenum);

   if (!(fp = fopen(tempname, "r+")))
      return (FALSE);

   fread(&Header, sizeof(Header), 1, fp);

   if (LAST == PVTAREA)
   {
      ASPrintf(NULL, readfile, "USER:%s/%s", RStruct.Name, Header.Filename);
      UnderScore(readfile);
   }
   else
   {
      GetPath(altpath, LAST, &MsgArea, Header.Filename);
      ASPrintf(NULL, readfile, "%s%s", altpath, Header.Filename);
   }

   if (GetFirstStruct(readfile, buffer, 20))
   {
      AFPrintf(&UserDat, sout, SA[246]);
      fclose(fp);
      return (-1);
   }

   for (index = 0; index < 20; index++)
      if (buffer[index] < 9 ||
          (buffer[index] == 11) ||
          ((buffer[index] > 13) && (buffer[index] < 32) && (buffer[index] != 27)) ||
          (buffer[index] > 126 && buffer[index] != 141))
      {
         AFPrintf(&UserDat, sout, SA[247]);
         fclose(fp);
         return (-1);
      }

   Header.Times_Downloaded++;
   fseek(fp, 0, SEEK_SET);
   fwrite(&Header, sizeof(Header), 1, fp);
   fclose(fp);

   DispForm(readfile, &UserDat, &UserDat, &RStruct, Ext);
   return (0);
}
//-

/// SelectSIG
BOOL                SelectSIG(void)
{
   UBYTE               tempnumber;

   if (!INSTACK)
      ListSIGS(&UserDat, 1, 1);

   tempnumber = Sig.number;

   Sig.number = iinput(0, 255, 0, SA[248]);
   sigrestoreflag = FALSE;
   TwoLines();

   if (!Sig.number)
   {
      AFPrintf(&UserDat, sout, SA[249]);
      strcpy(areafile, "FILE:Area.bbs");
      numsigareas = MakeSigArray(areafile, &sigarray, 1);
      UserDat.filesig = 0;
      signumber = 0;
      return (TRUE);
   }

   if (GetStruct("DLGCONFIG:SIGS/SIGS.file", (char *) &Sig, sizeof(Sig), 1) || Sig.level > LEVEL)
   {
      AFPrintf(&UserDat, sout, SA[250]);
      Sig.number = tempnumber;
      return (FALSE);
   }

   ASPrintf(NULL, areafile, "DLGCONFIG:SIGS/%s.file", Sig.name);
   numsigareas = MakeSigArray(areafile, &sigarray, 1);
   UserDat.filesig = Sig.number;
   signumber = Sig.number;
   return (TRUE);
}
//-

/// MenuLen
SHORT               MenuLen(void)
{
   if (UserDat.Help_Level == 1 || AutoDownload)
      return (4);
   if (UserDat.Help_Level == 0)
      return (11);
   if (UserDat.Help_Level == 2)
      return (2);
}
//-

/// PvtOK
BOOL                PvtOK(char *to)
{
   if (PvtSendLevel > LEVEL)
      if (GetLevel(to) < PvtSendLevel)
      {
         AFPrintf(&UserDat, sout, SA[251]);
         return (FALSE);
      }

   return (TRUE);
}
//-

/// _CXBRK
void                _CXBRK(void)
{
   Write_Pointers();
   LogOut(&RStruct, &UserDat, Ext, "File");

   if (tempdownloads[0])
      DelDir(tempdownloads, NULL);

   if (sigrestoreflag)
      UserDat.filesig = sigrestore;

   CloseLibrary(DLGBase);

   exit(0);
}
//-

/// HandleBuiltIn
int                 HandleBuiltIn(UBYTE cmd)
{
   long                inpvalue;
   long                tempflag;
   long                filenum;
   long                b;

   SHORT               spos;

   char                log[256];
   char                ramfile[256];
   char                tempchar;

   switch (cmd)
   {
///   Exit/Abort
      case 0:                          /* Exit */
         if (!INSTACK)
            Clr(UserDat.Ansi_Flag);
         Write_Pointers();

         if (tempdownloads[0])
            DelDir(tempdownloads, NULL);

         if (sigrestoreflag)
            UserDat.filesig = sigrestore;

         WriteUser(RStruct.Name, &UserDat);
         WriteRam(&RStruct, Ext);
         break;
//-

///   File_ChangeArea
      case FA:                          /* File_ChangeArea */
         tempflag = 0;
         Write_Pointers();

         for (;;)
         {
            if (tempflag)
            {
               ListAreas(RStruct.Name, &UserDat, 1, signumber);
               b = iinput(0, 9999, 0, SA[253]);
            }
            else
               b = iinput(0, 9999, 0, SA[252]);

            TwoLines();

            if (achangesig)
               if (!Read_Area(b, areafile))
               {
                  tempflag = 1;
                  continue;
               }

            if (b || tempflag)
               break;

            tempflag = 1;
         }

         achangesig = 0;

         if (!b)
         {
            if (Read_Pointers(LAST))
               InsertStack(STK, "\00111");

            break;
         }

         if (!Read_Pointers(b))
         {
            LAST = b;
            New_Area();
         }
         else
         {
            AFPrintf(&UserDat, sout, SA[256], b);

            if (Read_Pointers(LAST))
               InsertStack(STK, "\00111");
         }

         break;
//-

///   File_Comment
      case FC:                          /* File_Comment */

         if (!Menu[FC].status)
            break;

         if (!AutoDownload)
         {
            AFPrintf(&UserDat, sout, SA[257]);
            break;
         }

         if (LAST == PVTAREA)
         {
            AFPrintf(&UserDat, sout, SA[258]);
            break;
         }

         Add_Comment();
         break;
//-

///   File_Download
      case FD:                          /* File_Download */

         if (!Menu[FD].status)
            break;

         if (!(Log.Priv_Flag & DOWNLOAD))
         {
            NoAbility();
            break;
         }

         if ((DownloadFile()) == 2)
         {
            Delay(100);
            AFPrintf(&UserDat, sout, SA[259]);
            TTimeDelay(2, Ext);
            GetChar();
            AFPrintf(&UserDat, sout, SA[260]);
            TTimeDelay((long) (Globals.TimeOut * 12), Ext);
         }

         break;
//-

///   File_Edit
      case FE:                // File_Edit
      
         if (!AutoDownload)
         {
            if (!(filenum = GetFilename(LAST)))
            {
               AFPrintf(&UserDat, sout, SA[176]);
               return (1);
            }

            if (filenum < 0)
            {
               AFPrintf(&UserDat, sout, SA[163]);
               return (1);
            }
         }
         else
         {
            filenum = Message;
         }

         ASPrintf(NULL, ramfile, "DLG:FileMaint -a %ld -f %ld -e -O", LAST, filenum);
         WriteRam(&RStruct, Ext);
         OverlayProgram(ramfile);
         ReadRam(&RStruct, Ext);

         ASPrintf(NULL, ramfile, "FILE:%ld/%ld.fd", LAST, Message);
         GetFirstStruct(ramfile, (char *) &Header, sizeof(Header));
         break;
//-

///   File_EditSig
      case FO:                          /* File_EditSig */

         highestfile = 0;
         AutoDownload = 0;
         shortmenuflag = 0;
         Edit_Signature();
         break;
//-

///   File_GlobalList
      case FEQUAL:                          /* File_GlobalList */

         if (Log.Priv_Flag & Sysop_Access)
            Menu[FK].status = 1;
         else
            Menu[FK].status = 0;

         highestfile = 0;
         AutoDownload = 0;
         shortmenuflag = 0;
         AskListStuff(1);
         break;
//-

///   File_Kill
      case FK:                          /* File_Kill */

         highestfile = 0;

         if (!AutoDownload)
         {
            AFPrintf(&UserDat, sout, SA[261]);
            break;
         }

         AutoDownload = 0;
         shortmenuflag = 0;
         Kill_File();
         break;
//-

///   File_List
      case FF:                          /* File_List */
         if (Log.Priv_Flag & Sysop_Access)
            Menu[FK].status = 1;
         else
            Menu[FK].status = 0;

         highestfile = 0;
         AutoDownload = 0;
         shortmenuflag = 0;
         AskListStuff(0);
         break;
//-

///   File_ListBatch
      case FL:                          /* File_ListBatch */
         highestfile = 0;
         List_Batch(&tempflag);
         break;
//-

///   File_NewScan
      case FN:                      /* File_NewScan */
         highestfile = 0;

         if (!Menu[FN].status)
            break;

         b = LAST;
         Write_Pointers();

         if (!InGlobalScan)
            AFPrintf(&UserDat, sout, SA[262]);

         spos = 17;

         for (;;)
         {
            tempchar = 0;

            if (LastSearchArea >= HighSearchArea)
            {
               AFPrintf(&UserDat, sout, SA[263]);

               if (InGlobalScan)
               {
                  InGlobalScan = FALSE;
                  b = ScanStart;
                  Message = StartMsg;
               }

               tempchar = 1;
               LastSearchArea = 0;
               break;
            }

            LAST = SearchAreas[LastSearchArea];

            if (sigarray && !CheckForSig(LAST, sigarray, numsigareas))
            {
               LastSearchArea++;
               continue;
            }

            if (Read_Pointers(LAST))
            {
               LastSearchArea++;
               continue;
            }

            GetHiLowFPointers(LAST, RStruct.Name, &Low_Message, &High_Message, LPswd);

            if (!InGlobalScan)
            {
               spos += ASPrintf(&UserDat, log, SA[264], LAST);

               if (UserDat.Ansi_Flag & ANSI_COLOR)
                  spos -= 10;

               if (spos >= UserDat.Screen_Width)
               {
                  AFPrintf(&UserDat, sout, "\n                 ");
                  spos = 17 + strlen(log);

                  if (UserDat.Ansi_Flag & ANSI_COLOR)
                     spos -= 10;
               }

               AFPrintf(&UserDat, sout, log);
            }

            if (ReadChar(0) == 3)
            {
               if (LAST != PVTAREA)
                  LeaveArea(LAST, FILELOCK | WRITELOCK);

               AFPrintf(&UserDat, sout, SA[265]);
               tempchar = 1;
               break;
            }

            if ((Log.High_Mess >= High_Message && !InGlobalScan) || High_Message == 0L)
            {
               LastSearchArea++;

               if (LAST != PVTAREA)
                  LeaveArea(LAST, FILELOCK | WRITELOCK);

               continue;
            }

            LastSearchArea++;
            strcpy(Header.From, "");
            Message = Log.High_Mess;

            if (!InGlobalScan)
               TwoLines();

            break;
         }

         if (tempchar)
         {
            InGlobalScan = FALSE;
            LAST = b;
            Read_Pointers(LAST);
            GetHiLowFPointers(LAST, RStruct.Name, &Low_Message, &High_Message, LPswd);
            break;
         }

         Menu[FK].status = 0;
         Menu[FPERIOD].status = 0;
         Menu[FC].status = 0;
         RStruct.area = LAST;
         WriteRam(&RStruct, Ext);

         if (InGlobalScan)
         {
            InsertStack(STK, scanstack);
            break;
         }

         ASPrintf(NULL, ramfile, "FILE:%ld/EnterArea.txt", LAST);
         DispForm(ramfile, &UserDat, &UserDat, &RStruct, Ext);

         AFPrintf(&UserDat, sout, SA[266]);
         AFPrintf(&UserDat, sout, SA[267], LAST, MsgArea.Name);
         AFPrintf(&UserDat, sout, SA[268]);
         AFPrintf(&UserDat, sout, SA[269], (High_Message - Low_Message) + 1);
         AFPrintf(&UserDat, sout, SA[270]);
         AFPrintf(&UserDat, sout, SA[271], High_Message - Log.High_Mess);
         break;
//-

///   File_PvtArea
      case FP:                      /* File_PvtArea */
         Write_Pointers();
         AFPrintf(&UserDat, sout, SA[272]);
         AFPrintf(&UserDat, sout, SA[273]);
         EnterPrivateArea();
         break;
//-

///   File_Read
      case FR:                      /* File_Read */
         if (!Menu[FR].status)
            break;

         ReadFile();
         break;
//-

///   File_RemoveBatch
      case FZ:                      /* File_RemoveBatch */
         highestfile = 0;
         Batch_Remove();
         break;
//-

///   File_SelectSig
      case FS:                      /* File_SelectSig */
         if (!SelectSIG())
            break;

         if (Sig.number && LAST != PVTAREA && !CheckForSig(LAST, sigarray, numsigareas))
         {
            InsertStack(STK, "\0011;");
            achangesig++;
         }

         break;
//-

///   File_Tag
      case FPERIOD:                      /* File_Tag */
         if (!Menu[FPERIOD].status)
            break;

         if (Add_Batch() != -2)
            AFPrintf(&UserDat, sout, SA[274], Header.Filename);

         break;
//-

///   File_Transfer
      case FT:                      /* File_Transfer */
         if (!(Log.Priv_Flag & Hurl_Priv))
         {
            NoAbility();
            break;
         }

         Hurl_File(0);
         break;
//-

///   File_Upload
      case FU:                      // File_Upload
         highestfile = 0;
         
         if (!Menu[FU].status)
            break;
      
         AutoDownload = 0;
         shortmenuflag = 0;
      
         if (!(Log.Priv_Flag & 1))
         {
            NoAbility();
            break;
         }

         if ((UploadFile()) == 2)
            _CXBRK();

         break;
//-

///   File_Validate
      case FV:                      /* File_Validate */
         Hurl_File(1);
         break;
//-

///   File_ViewArchive
      case FI:                      /* File_ViewArchive */

         if (GetFileInfo(ramfile))
         {
            AFPrintf(&UserDat, sout, SA[275]);
            break;
         }

         ASPrintf(NULL, log, "Execute dlgconfig:batch/ViewArchive.batch %s", ramfile);
         Execute(log, 0, 0);
         Pause();
         break;
//-

///   File_ViewNext
      case FNEXT:                      /* File_ViewNext */
         GetHiLowFPointers(LAST, RStruct.Name, &Low_Message, &High_Message, LPswd);

         if (isdigit(STK[0]))
         {
            sscanf(STK, "%6ld", &inpvalue);

            for (b = 0; isdigit(STK[b]); b++) ;

            movmem(STK + b, STK, strlen(STK) - (b - 1));

            if (inpvalue > High_Message)
               inpvalue = High_Message;

            if (inpvalue < Low_Message)
               inpvalue = Low_Message;

            highestfile = 0;
            Message = --inpvalue;
         }

         if (Message == High_Message)
         {
            if (highestfile)
            {
               highestfile = 0;
               AFPrintf(&UserDat, sout, SA[276]);
               InsertStack(STK, "\00110;");
               break;
            }

            AFPrintf(&UserDat, sout, SA[277]);
            highestfile = 1;
            break;
         }

         do
         {
            if (Message < High_Message)
               Message++;
            else
               break;

            if (Message > Log.High_Mess)
               Log.High_Mess = Message;

            AutoDownload = 1;
            shortmenuflag = 1;
         }  while (Read_Message() != 0);

         break;
//-

///   File_Subscribe
      case FSUB:                      /* File_Subscribe */
         {
            char scanfile[256];

            if(!Menu[FSUB].status)
               break;

            ASPrintf(NULL,scanfile,"User:%s/GlobalAreas.File",RStruct.Name);
            UnderScore(scanfile);

            if(AddArea(scanfile,LAST))
            {
               AFPrintf(&UserDat,sout,"Subscribed.\n\n");
               Menu[FSUB].status = 0;
               Menu[FUNSUB].status = 1;
            }
            else
            {
               AFPrintf(&UserDat,sout,"Failed to subscribe.\n\n");
            }
         }

         break;
//-

///   File_Unsubscribe
      case FUNSUB:                      /* File_Unsubscribe */
         {
            char scanfile[256];

            if(!Menu[FUNSUB].status)
               break;

            ASPrintf(NULL,scanfile,"User:%s/GlobalAreas.File",RStruct.Name);
            UnderScore(scanfile);

            if(DelArea(scanfile,LAST))
            {
               AFPrintf(&UserDat,sout,"Unsubscribed.\n\n");
               Menu[FSUB].status = 1;
               Menu[FUNSUB].status = 0;
            }
            else
            {
               AFPrintf(&UserDat,sout,"Failed to unsubscribe.\n\n");
            }
         }

         break;
//-

      default:
         return (FALSE);
         break;
   }

   return (TRUE);
}
//-

/// FileSubstitute
int                 FileSubstitute(char *cstr, char *result)
{
   char               *s;

   s = (char *) DLGSearch((char *) File_Trans, cstr, 21, 21, NUMELEMENTS);

   if (!s)
   {
      strcpy(result, "");
      return (FALSE);
   }

   switch ((char) (((long) s - (long) File_Trans) / 21L) + 1)
   {
      case 1:
      ASPrintf(NULL, result, SA[278], Message);
      break;

      case 2:
      if (UserDat.Last_File_Area != PVTAREA)
      ASPrintf(NULL, result, SA[279], UserDat.Last_File_Area);
      else
      strcpy(result, SA[280]);
      break;

      case 3:
      if (UserDat.Last_File_Area != PVTAREA)
      ASPrintf(NULL, result, SA[281], MsgArea.Name);
      else
      strcpy(result, SA[282]);
      break;

      case 4:
      ASPrintf(NULL, result, SA[283], Low_Message);
      break;

      case 5:
      ASPrintf(NULL, result, SA[284], High_Message);
      break;
      case 6:
      ASPrintf(NULL, result, SA[285], Sig.number);
      break;

      case 7:
      if (Sig.number)
      ASPrintf(NULL, result, SA[286], Sig.shortname);
      else
      strcpy(result, SA[287]);
      break;

      case 8:
      ASPrintf(NULL, result, SA[288], Log.High_Mess);
      break;

      case 9:
      if (!AutoDownload)
      {
         strcpy(result, SA[289]);
         break;
      }
      ASPrintf(NULL, result, SA[290], Header.Filename);
      break;

      case 10:
      if (!AutoDownload)
      {
         strcpy(result, SA[291]);
         break;
      }

      if (UserDat.Last_File_Area != PVTAREA)
      GetPath(result, UserDat.Last_File_Area, &MsgArea, Header.Filename);
      else
      {
         ASPrintf(NULL, result, "USER:%s/", RStruct.Name);
         UnderScore(result);
      }
      break;
      case 11:
      ASPrintf(NULL, result, SA[292], Header.From);
      break;
      case 12:
      ASPrintf(NULL, result, SA[293], Header.From);
      UnderScore(result);
      break;

      default:
      return (FALSE);
   }

   return (TRUE);
}
//-
