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

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

#include <Link/Area.h>
#include <link/File.h>
#include <link/io.h>
#include <link/util.h>

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

#include <pragmas/dlg.h>

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


#define INSTACK RStruct.Command_Stack[0]
#define STK     RStruct.Command_Stack
#define HOT     UserDat.Hot_Keys

void  main(int, char **);
int   HandleBuiltIn(UBYTE );

void  GlobalEdit(struct Msg_Area *);
BYTE  Edit_File(struct Msg_Area *);
BYTE  EditBody(char *, struct File_Header *, long);
BYTE  ExtractBody(char *, char *, char *, long, char );
BYTE  WriteHeader(char *, struct File_Header *, long);
void  DisplayDesc(char *, struct Msg_Area *, struct File_Header *);
void  DisplayHeader(struct File_Header *);
BYTE  CheckArea(struct Msg_Area *);
long  SelectArea(struct Msg_Area *);
BYTE  Batch_Upload(char , long);
void  Add_Directory(char *);
BYTE  AmiNet_Upload(long area);

BOOL  FreshenAreas(long);
int   SortQF(struct QuickFile *, struct QuickFile *);

BOOL  ListFiles(struct Msg_Area *);
int   QFByNumber(struct QuickFile *, struct QuickFile *);

long  GetFilename(long);
void _CXBRK(void);


char                 Ext[4];
struct USER_DATA     UserDat;
struct Ram_File      RStruct;
struct Msg_Area      Area;
struct SearchCookie *sc = NULL;
struct SearchCookie *sc2 = NULL;

/// Edit menu
struct ShortMenu EditMenu[7] =
{
   {'S',"From",1},
   {'F',"Filename",1},
   {'D',"Date",1},
   {'#',"Downloads",1},
   {'K',"Size",1},
   {'A',"Attributes",1},
   {'B',"Edit Body",1}
};
//-

/// Main menu
struct NewShortMenu Menu[10] =
{
   {"Abort",1},            // 0
   {"FILEM_AmiNet",1},     // 1
   {"FILEM_BatchUp",1},    // 2
   {"FILEM_ChangeArea",1}, // 3
   {"FILEM_EditFile",1},   // 4
   {"FILEM_Exit",1},       // 5
   {"FILEM_Freshen",1},    // 6
   {"FILEM_GlobalEdit",1}, // 7
   {"FILEM_ListFiles",1},  // 8
   {"FILEM_TurboUp",1}     // 9
};
//-

BPTR  rh = NULL;

char  Overlay      =  FALSE;
char  EditFlag     =  FALSE;
char *body         =  NULL;
long  GlobalArea   =    0;
long  GlobalFile   =    0;

char  LPswd   [10];
char  MenuName[13] = "FILEM_MAIN";
char  exitflag     =  FALSE;


BPTR                 sout;
struct Library      *DLGBase;
struct LangStruct   *ls;
char               **SA;

/// main
void main(int argc,char *argv[])
{
   char *s;
   char *stack = NULL;

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

/// Parse args
   while(--argc>0)
   {
      s = *++argv;

      if (*s++ == '-')
      {
         while(*s)
         {
            switch(*s++)
            {
               case 'a':
               case 'A':  if (!--argc)  break;
               GlobalArea = atoi(*++argv);
               break;
               
               case 'E':
               case 'e':  EditFlag = TRUE;
               break;

               case 'F':
               case 'f':  if (!--argc)  break;
               GlobalFile = atoi(*++argv);
               break;
               case 'o':
               case 'O':  Overlay = TRUE;
               break;

               case 's':
               case 'S':  if (!--argc)  break;
               stack = *++argv;
               break;

               case 'm':
               case 'M':  if (!--argc)  break;
               strncpy(MenuName,*++argv,12);
               MenuName[12] = 0;
               break;
            }
         }
      }
   }
//-

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

   if (!ReadUser(&RStruct,&UserDat,Ext))  _CXBRK();
   if (stack)                             InsertStack(STK, stack);

   ASPrintf(&UserDat, LPswd, "%sFMAINT", Ext);

   if (UserDat.Last_File_Area == PVTAREA  &&  !EditFlag)
      GetFirstStruct("FILE:Area.bbs", (char *)&Area, sizeof(Area));
   else
   {
      Area.Number = (EditFlag)?GlobalArea:UserDat.Last_File_Area;
      CheckArea(&Area);
   }

   if (EditFlag)
   {
      Edit_File(&Area);
      _CXBRK();
   }

   while(!exitflag)
   {
      Chk_Abort();

      if (MenuInput(MenuName,Ext,"FILEM",Menu,10,HandleBuiltIn,&UserDat,&RStruct,UserDat.Help_Level,NULL)==MENUNOTFOUND)
      _CXBRK();
   }

   _CXBRK();
}
//-

/// Handlebuiltin
int HandleBuiltIn(UBYTE cmd)
{
   switch(cmd)
   {
      case 0:                                     /* Abort */
         WriteRam(&RStruct, Ext);
         exitflag = TRUE;
         break;

      case 1:                                     /* FILEM_AmiNet */
         AmiNet_Upload(Area.Number);
         break;

      case 2:                                     /* FILEM_BatchUp */
         Batch_Upload(0, Area.Number);
         break;

      case 3:                                     /* FILEM_ChangeArea */
         SelectArea(&Area);
         break;

      case 4:                                     /* FILEM_EditFile */
         Edit_File(&Area);
         break;

      case 5:                                     /* FILEM_Exit */
         _CXBRK();
         break;

      case 6:                                     /* FILEM_Freshen */
         FreshenAreas(Area.Number);
         break;

      case 7:                                     /* FILEM_GlobalEdit */
         GlobalEdit(&Area);
         break;

      case 8:                                     /* FILEM_ListFiles */
         ListFiles(&Area);
         break;

      case 9:                                     /* FILEM_TurboUp */
         Batch_Upload(1, Area.Number);
         break;

      default: *STK = 0;
         break;
   }

   return(FALSE);
}
//-

/// GlobalEdit
void GlobalEdit(struct Msg_Area *area)
{
   struct File_Header Header;
   char               filename[80];
   SHORT              attribute = 0;
   int                fp;

   long               a;
   long               Low_Message;
   long               High_Message;


   if (finput(1, SA[407]))  attribute |= NORATIO;
   AFPrintf(NULL,sout,"\n\n");

   GetHiLowFPointers(area->Number, NULL, &Low_Message, &High_Message, LPswd);

   for(a = 1; a <= High_Message ; a++)
   {
      BorrowArea(area->Number,LPswd,"",64,FILELOCK|WRITELOCK);

      ASPrintf(NULL, filename, "FILE:%ld/%ld.fd", area->Number, a);

      if (GetFirstStruct(filename, (char *)&Header, sizeof(Header))==-1)
      {
         FreeArea(area->Number,LPswd,FILELOCK|WRITELOCK);
         continue;
      }

      AFPrintf(&UserDat,sout,SA[408],Header.Filename);

      if ((fp=open(filename,O_RDWR))==EOF)
      {
         FreeArea(area->Number,LPswd,FILELOCK|WRITELOCK);  
         AFPrintf(&UserDat,sout,SA[409]);
         continue;
      }

      Header.Attribute = attribute;
      write(fp,&Header,sizeof(Header));
      close(fp);

      FreeArea(area->Number,LPswd,FILELOCK|WRITELOCK);
      AFPrintf(&UserDat,sout,SA[410]);
   }

   AFPrintf(NULL,sout,"\n");
   return;
}
//-

/// Edit_File
BYTE Edit_File(struct Msg_Area *area)
{
   int   zflag;
   long  number;

   char  inp[3];

   char changed = 0;
   char qfile     [24];
   char filename  [80];
   char tempstring[80];
   char source    [80];
   char dest      [80];
   char path      [80];
   struct File_Header Header;
   struct QuickFile   QF;

   if (EditFlag)
      number = GlobalFile;
   else
      number = GetFilename(area->Number);

   if(number == 0)
   {
      AFPrintf(NULL,sout,"\n\n");
      return(0);
   }

   BorrowArea(area->Number,LPswd,"",64,FILELOCK|WRITELOCK);

   ASPrintf(NULL,filename,"FILE:%ld/%ld.fd",area->Number,number);

   if (GetFirstStruct(filename,(char *)&Header,sizeof(Header))==-1)
   {
      AFPrintf(&UserDat,sout,SA[411],filename);
      FreeArea(area->Number,LPswd,FILELOCK|WRITELOCK);
      return(-1);
   }

   FreeArea(area->Number,LPswd,FILELOCK|WRITELOCK);

   for(;;)
   {
      if (!INSTACK)
      {
         DisplayDesc(filename,area,&Header);
         menu(EditMenu,7,0);
         AFPrintf(NULL,sout,"\n");
      }

      DLGInput(NULL,inp,NULL,1,127,1, SA[412]);
      Clr(UserDat.Ansi_Flag);

      switch(inp[0])
      {
         case 'A':
            zflag = finput(Header.Attribute&NORATIO, SA[413]);
            AFPrintf(NULL,sout,"\n\n");

            if (zflag)
               Header.Attribute |= NORATIO;
            else
               Header.Attribute &= ~NORATIO;

            changed++;
            break;

         case 'K':
            AFPrintf(&UserDat,sout,SA[414]);
            GetPath(path, area->Number, NULL, Header.Filename);
            ASPrintf(NULL,source,"%s%s",path,Header.Filename);
            FileSize(source, (ULONG *)&Header.Size);
            AFPrintf(&UserDat,sout,SA[415],Header.Size);
            changed++;
            ASPrintf(NULL,qfile,"FILE:%d/File.dat",area->Number);
            strcpy(QF.filename,Header.Filename);

            if (GetStruct(qfile,(char *)&QF,sizeof(QF),36)!=-1)
            {
               QF.size = Header.Size;
               AddStruct(qfile,(char *)&QF,sizeof(QF),36);
            }
            else
            {
               AFPrintf(&UserDat,sout,SA[416]);
               Pause();
            }

            break;

         case '#':
            Header.Times_Downloaded=iinput(0,32000,Header.Times_Downloaded, SA[417]);
            AFPrintf(NULL,sout,"\n\n");
            changed++;
            break;

         case 'D':
            zflag = DLGInput(NULL,tempstring,Header.Date,19,254,0, SA[418]);
            AFPrintf(NULL,sout,"\n\n");

            if (zflag)
            {
               strcpy(Header.Date,tempstring);
               changed++;

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

               if (GetStruct(qfile,(char *)&QF,sizeof(QF),36)!=-1)
               {
                  StringToDate(Header.Date,&(QF.date));
                  AddStruct(qfile,(char *)&QF,sizeof(QF),36);
               }
               else
               {
                  AFPrintf(&UserDat,sout,SA[416]);
                  Pause();
               }
            }

            break;
         
         case 'F':
            zflag = DLGInput(NULL,tempstring,Header.Filename,35,35,1, SA[419]);
            AFPrintf(NULL,sout,"\n\n");
            ScreenPath(tempstring);

            if (!zflag || !strcmp(tempstring,Header.Filename))  break;

            BorrowArea(area->Number,LPswd,"",64,FILELOCK|WRITELOCK);
            GetPath(path,area->Number,NULL,Header.Filename);
            ASPrintf(NULL,source,"%s%s",path,Header.Filename);
            ASPrintf(NULL,dest,"%s%s",path,tempstring);

            if (!Rename(source,dest))
            {
               AFPrintf(&UserDat,sout,SA[420],source,dest);
               FreeArea(area->Number,LPswd,FILELOCK|WRITELOCK);
               break;
            }

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

            if (GetStruct(qfile,(char *)&QF,sizeof(QF),36)!=-1)
            {
               DeleteStruct(qfile,(char *)&QF,sizeof(QF),36);
               strcpy(QF.filename,tempstring);
               AddStruct(qfile,(char *)&QF,sizeof(QF),36);
            }
            else
            {
               AFPrintf(&UserDat,sout,SA[416]);
            }

         
            FreeArea(area->Number,LPswd,FILELOCK|WRITELOCK);
            strcpy(Header.Filename,tempstring);

            changed++;
            WriteHeader(filename,&Header,area->Number);
            break;

         case 0:
            if (changed)
               WriteHeader(filename,&Header,area->Number);

            return(0);
            break;

         case '?':
            if (UserDat.Help_Level==0)  break;
            menu(EditMenu,6,0);
            AFPrintf(NULL,sout,"\n");
            break;

         case 'S':
            Capitalize(Header.From);
            zflag = DLGInput(NULL,tempstring,Header.From,36,254,3, SA[421]);
            Upper(tempstring);
            AFPrintf(NULL,sout,"\n\n");

            if (zflag)
            {
               strcpy(Header.From,tempstring);
               changed++;
            }

            break;

         case 'B':
            EditBody(filename,&Header,area->Number);
            break;
      }
   }
}
//-

/// EditBody
BYTE EditBody(char *filename,struct File_Header *header,long area)
{
   int   zflag;

   char  ramfile   [80];
   char  buffer    [255];
   char  qfile     [24];
   char  headerfile[36];
   char  tempstack [42];

   SHORT rp;
   SHORT fp;

   long  charsread;

   struct QuickFile   QF;
   struct File_Header tempheader;

   /* Figure out the name of the T: files */
   ASPrintf(NULL, ramfile,    "T:%s.fd",      Ext);
   ASPrintf(NULL, headerfile, "T:%s.fheader", Ext);
   DeleteFile(ramfile);

   /* If keeping old description, copy body to the ram file */
   zflag = finput(0, SA[422]);
   AFPrintf(NULL,sout,"\n\n");

   ExtractBody(filename,headerfile,ramfile,area,zflag);

   /* Call the editor */
   if (CallEditor(NULL,headerfile,ramfile,FILE_DESC,&UserDat,&RStruct,Ext))
   {
      Clr(UserDat.Ansi_Flag);
      DeleteFile(ramfile);
      DeleteFile(headerfile);
      return(-1);       
   }

   if (GetFirstStruct(headerfile,(char *)&tempheader,sizeof(tempheader))!=-1)
   {
      if (Stricmp(header->Filename,tempheader.Filename))
      {
         ASPrintf(NULL,tempstack,"F;%s",tempheader.Filename);
         InsertStack(STK,tempstack);
      }
   }

   DeleteFile(headerfile);
   Clr(UserDat.Ansi_Flag);

   /* Open description in ram or return if none exists */
   if ((rp=open(ramfile,O_RDONLY))==EOF)  return(-1);

   /* Delete the original file description */
   BorrowArea(area,LPswd,"",64,FILELOCK|WRITELOCK);
   DeleteFile(filename);

   if ((fp=open(filename,O_CREAT+O_RDWR))==EOF)
   {
      AFPrintf(&UserDat,sout,SA[423],filename);
      close(rp);
      FreeArea(area,LPswd,FILELOCK|WRITELOCK);
      return(-1);
   }

   /* Write the header and description to the .fd file */
   write(fp,header,sizeof(struct File_Header));

   while((charsread=read(rp,buffer,254))==254)
   write(fp,buffer,254);
   write(fp,buffer,charsread);
   close(fp);

   ASPrintf(NULL,qfile,"FILE:%d/File.dat",area);
   strcpy(QF.filename,header->Filename);

   if (GetStruct(qfile,(char *)&QF,sizeof(QF),36)!=-1)
   {
      lseek(rp, 0, 0);
      charsread = read(rp,&QF.desc,58);
      QF.desc[charsread] = 0;
      AddStruct(qfile,(char *)&QF,sizeof(QF),36);
   }
   else
   {
      AFPrintf(&UserDat,sout,SA[416]);
      Pause();
   }

   close(rp);
   DeleteFile(ramfile);

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

/// ExtractBody
BYTE ExtractBody(char *filename,char *headerfile,char *ramfile, long area,char flag)
{
   SHORT fp;
   SHORT rp;

   long  charsread;
   char  buffer[255];
   struct File_Header Header;

   DeleteFile(ramfile);
   BorrowArea(area,LPswd,"",64,FILELOCK|WRITELOCK);

   if ((fp=open(filename,O_RDONLY))==EOF)
   {
      FreeArea(area,LPswd,FILELOCK|WRITELOCK);
      return(-1);
   }

   if (!flag)
   {
      if ((rp = open(ramfile,O_CREAT+O_RDWR))==EOF)
      {
         close(fp);
         FreeArea(area,LPswd,FILELOCK|WRITELOCK);
         return(-2);
      }
   }

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

   if (!flag)
   {
      while((charsread = read(fp,buffer,255))==255)
      write(rp, buffer, 255);
      write(rp, buffer, charsread);
      close(rp);
   }

   close(fp);
   FreeArea(area,LPswd,FILELOCK|WRITELOCK);

   DeleteFile(headerfile);
   AddStruct(headerfile,(char *)&Header,sizeof(Header),1);
   return(0);
}
//-

/// WriteHeader
BYTE WriteHeader(char *filename,struct File_Header *header, long area)
{
   SHORT fp;

   BorrowArea(area,LPswd,"",64,FILELOCK|WRITELOCK);

   if ((fp=open(filename,O_RDWR))==EOF)
   {
      FreeArea(area,LPswd,FILELOCK|WRITELOCK);
      return(-1);
   }

   write(fp,header,sizeof(struct File_Header));
   close(fp);
   FreeArea(area,LPswd,FILELOCK|WRITELOCK);
}
//-

/// DisplayDesc
void DisplayDesc(char *filename,struct Msg_Area *area, struct File_Header *Header)
{
   USHORT pos=6;

   DisplayHeader(Header);
   Display_Msg(area->Number,NULL,LPswd,MSG_FILEAREA,filename,UserDat.Screen_Width,UserDat.Screen_Len,UserDat.More_Flag,&pos,100L,UserDat.Ansi_Flag,"\x03");
   AFPrintf(NULL,sout,"\n");
}
//-

/// DisplayHeader
void DisplayHeader(struct File_Header *Header)
{
   Capitalize(Header->From);
   AFPrintf(&UserDat,sout,SA[424],Header->From);
   Upper(Header->From);

   AFPrintf(&UserDat,sout,SA[425],Header->Filename);

   if (Header->Attribute & NORATIO)
      AFPrintf(&UserDat,sout,SA[426]);
   else
      AFPrintf(&UserDat,sout,SA[427]);

   AFPrintf(&UserDat,sout,SA[428], Header->Size, Header->Date);
   AFPrintf(&UserDat,sout,SA[429], Header->Times_Downloaded);
   AFPrintf(&UserDat,sout,"%a6\n\n");
}
//-

/// CheckArea
BYTE CheckArea(struct Msg_Area *area)
{
   BYTE retval = -1;

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

   BorrowArea(area->Number, LPswd, "", 64, FILELOCK|WRITELOCK);

   if (ReadArea(area->Number, area, 1))  retval = 0;

   FreeArea(area->Number,LPswd,FILELOCK|WRITELOCK);
   LeaveArea(area->Number,FILELOCK|WRITELOCK);

   return(retval);
}
//-

/// SelectArea
long SelectArea(struct Msg_Area *area)
{
   long zflag;
   long temp;

   temp  = area->Number;
   zflag = iinput(1,32000,0, SA[430]);
   AFPrintf(NULL,sout,"\n\n");

   if (!INSTACK && !zflag)
   {
      ListAreas(NULL,&UserDat,1,0);
      zflag = iinput(1,32000,0, SA[431]);
      AFPrintf(NULL,sout,"\n\n");
   }

   area->Number = zflag;
   if (CheckArea(area)!=-1)  return(area->Number);

   AFPrintf(&UserDat,sout,SA[432]);
   TwoLines();

   area->Number = temp;
   CheckArea(area);
   return(area->Number);
}
//-

/// Batch_Upload
BYTE Batch_Upload(char mode, long area)
{
   char  ramfile   [128];
   char  headerfile[128];
   char  FilePath  [128];

   char *body      = NULL;
   long  bsize     =  0;
   char  desc[256];

   char  filenotes = FALSE;
   char  movefiles;

   struct File_Header   Header;
   struct Msg_Area      Area;

   /* Make sure area exists */
   Area.Number = area;

   if (CheckArea(&Area) == -1)  return(FALSE);

   Header.Attribute        = 0; 
   Header.Times_Downloaded = 0;
   UserDat.Last_File_Area   = area;


   /* As for the uploader of the file and store it in Header.From */
   if (!DLGInput(NULL,Header.From,RStruct.Name,35,254,3, SA[433]))
   {
      AFPrintf(&UserDat,sout,SA[434]);
      return(-1);
   }

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


   /* Ask if FREE and set the header attribute bit accordingly */
   if (!finput(0, SA[435]))
      Header.Attribute  = 0;
   else
      Header.Attribute |= NORATIO;
      AFPrintf(NULL,sout,"\n\n");


   /* Ask if the files are to be moved, and if so, set the movefiles flag */
   movefiles = finput(1, SA[436]);
   AFPrintf(NULL,sout,"\n\n");


   /* if called in turbo mode, ask for a description */
   if (mode)
   {
      DLGInput(NULL, desc, NULL, 254, 254, 0, SA[437]);
      AFPrintf(NULL,sout,"\n\n");

      body = desc;

      if (!strlen(desc))
      {
         AFPrintf(&UserDat,sout,SA[438]);
         filenotes++;
      }
   }


   /* Ask for path to source files */
   {
      long  temp;

      DLGInput(NULL,FilePath,NULL,40,40,0, SA[439]);
      AFPrintf(NULL,sout,"\n\n");
      temp = strlen(FilePath);
      if (!temp)  return(FALSE);

      temp--;
      if (FilePath[temp]=='/')  FilePath[temp]='\0';
      if (!Exists(FilePath))    return(FALSE);
   }


   /* Calculate header and bodyfile names */
   ASPrintf(NULL, ramfile,    "T:%s.body",   Ext);
   ASPrintf(NULL, headerfile, "T:%s.header", Ext);


   /* start our directory scan loop */
   sc = SearchStart(FilePath, "*");

   for(;;)
   {
      char *scanfile;

      /* Check for a ctrl C */
      Chk_Abort();

      /* get next file, and break out of main loop if there are no more */
      if (!(scanfile = SearchNext(sc)))  break;
      strcpy(Header.Filename, scanfile);
      Upper(Header.Filename);

      /* Get Description */
      if (filenotes)
      {
         char  source[128];
         char *s;

         /* build the filepath */
         s = stpcpy(source, FilePath);
         if (*(s-1) != '/'  &&  *(s-1) != ':')  s = stpcpy(s, "/");
         stpcpy(s, scanfile);

         /* get the comment */
         GetComment(source, body);
         strcat(body, "\n");
      }

      if (!mode)
      {
         ULONG size;

         AFPrintf(&UserDat, sout, SA[440], scanfile);
         Pause();

         DeleteFile(ramfile);
         DeleteFile(headerfile);
         AddStruct(headerfile,(char *)&Header,sizeof(Header),1);

         if (CallEditor(NULL,headerfile,ramfile,FILE_DESC,&UserDat,&RStruct,Ext)) break;
         if (FileSize(ramfile, &size) == -1)                                     break;
         if (!size)                                                              break;

         /* allocate body to the size of the description plus 1 for the null */
         if (bsize < size)
         {
            if (bsize)  free(body);

            if (!(body = malloc(size+1)))
            {
               AFPrintf(&UserDat,sout,SA[441]);
               continue;
            }
            bsize = size + 1;
         }

         /* Load the ramfile into body */
         if (GetFirstStruct(ramfile, body, size)==-1)  continue;
         body[size] = 0;

         /* in case the header has changed while in the editor, load it again */
         GetFirstStruct(headerfile,(char *)&Header,sizeof(Header));
      }

      /* Raw upload the file */
      AFPrintf(&UserDat, sout, SA[442], scanfile);
      for(;;)
      {
         /* set the date in the header to right now */
         MDate(Header.Date);

         if (RawUpload(FilePath,scanfile,&Header,body,NULL,&Area,"FileMaint",movefiles)==-1)
         {
            /* if raw upload fails, prompt the user for a new filename */
            AFPrintf(&UserDat,sout,SA[443],Header.Filename);
            DLGInput(NULL,Header.Filename,NULL,35,35,1, SA[444]);
            AFPrintf(NULL,sout,"\n\n");
            if (!Header.Filename[0])  break;
            continue;
         }

         break;
      }

      if (!Header.Filename[0])
      AFPrintf(&UserDat,sout,SA[445]);
      else
      AFPrintf(&UserDat,sout,SA[446]);
   }

   SearchEnd(sc);
   sc = NULL;

   /* CleanUp */
   DeleteFile(ramfile);
   DeleteFile(headerfile);
   if (bsize)  free(body);

   AFPrintf(NULL,sout,"\n");
}
//-

/// Add_Directory
void Add_Directory(char *name)
{
   BPTR lock;

   if ((lock=CreateDir(name)) != 0)  UnLock(lock);
}
//-

/// FreshenAreas
BOOL FreshenAreas(long area)
{
   long  zflag;
   SHORT fp;
   SHORT filecount = 0;

   long  hi;
   long  low;
   long  counter;

   long  qsize;
   char  qfile[24];
   struct QuickFile *QF;
   struct Msg_Area   Area;

   area = iinput(1,32000,area, SA[447]);
   AFPrintf(NULL,sout,"\n\n");

   if (!area)
   {
      AFPrintf(&UserDat,sout,SA[448]);
      return(FALSE);
   }

   ReadArea(area, &Area, 1);
   ASPrintf(NULL, qfile, "File:%d/File.dat", area);
   GetHiLowFPointers(area, "NONE", &low, &hi, LPswd);

   if (!hi)  return(FALSE);

   qsize = (hi - low + 1) * (long)sizeof(struct QuickFile);

   if (!(QF=(struct QuickFile *)malloc(qsize)))
   {
      AFPrintf(&UserDat,sout,SA[449],qsize);
      return(FALSE);
   }

   for(counter = low; counter <= hi; counter++)
   {
      ULONG fsize;
      long  date;

      struct File_Header Header;
      char  filename[80];
      char  path    [256];
      char  altpath [256];
      char  body    [60];

      ASPrintf(NULL, filename, "FILE:%d/%ld.fd", area, counter);
      BorrowArea(area, LPswd, "", 64, FILELOCK|WRITELOCK);

      if ((fp=open(filename,O_RDWR))==EOF)
      {
         FreeArea(area, LPswd, FILELOCK|WRITELOCK);
         continue;
      }

      if (read(fp, &Header, sizeof(Header)) != sizeof(Header))
      {
         FreeArea(area, LPswd, FILELOCK|WRITELOCK);
         close(fp);
         continue;
      }

      GetPath(path,area,&Area,Header.Filename);
      ASPrintf(NULL,altpath,"%s%s",path,Header.Filename);

      if (FileSize(altpath, &fsize) != -1  &&  fsize != Header.Size)
      {
         Header.Size = fsize;
         lseek(fp, 0, 0);
         write(fp, &Header, sizeof(Header));
      }

      StringToDate(Header.Date, &date);
      (QF+filecount)->date   =  date;
      (QF+filecount)->number = (SHORT)counter;
      (QF+filecount)->size   =  Header.Size;
      strcpy((QF+filecount)->filename,Header.Filename);
      body[read(fp, body, 58)] = 0;
      strcpy((QF+filecount)->desc, body);
      filecount++;

      close(fp);
      FreeArea(area,LPswd,FILELOCK|WRITELOCK);

      AFPrintf(&UserDat,sout,SA[450],altpath,filename);
      if (!SetComment(altpath,filename))
      {
         AFPrintf(&UserDat,sout,SA[451],Header.Filename);
         zflag = finput(1, SA[452]);
         AFPrintf(NULL,sout,"\n\n");    
         if (zflag)
         {
            DeleteFile(filename);
            filecount--;
         }
      }
   }

   AFPrintf(&UserDat,sout,SA[453]);
   qsort(QF,filecount,sizeof(struct QuickFile),SortQF);
   AFPrintf(&UserDat,sout,SA[454]);

   {
      long writesize;

      BorrowArea(area,LPswd,"",64,FILELOCK|WRITELOCK);
      DeleteFile(qfile);

      if ((fp=open(qfile,O_RDWR+O_CREAT))==EOF)
      {
         AFPrintf(&UserDat,sout,SA[455],qfile);
         return(FALSE);
      }

      writesize = filecount * sizeof(struct QuickFile);
      write(fp, QF, writesize);
      close(fp);

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

   free(QF);
   AFPrintf(NULL,sout,"\n");
   return(0);
}
//-

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

/// ListFiles
BOOL ListFiles(struct Msg_Area *Area)
{
   struct QuickFile *QF;
   long   a;
   long   numfiles;
   char   flippybindle = 0;

   if ((numfiles = LoadFiles(Area->Number, (char **)&QF, LPswd)))
   {
      qsort(QF, numfiles, sizeof(struct QuickFile), QFByNumber);
      
      AFPrintf(&UserDat,sout,SA[456],Area->Number,Area->Name);
      Draw_Line(78);

      for(a = 0; a < numfiles; a++)
      {
         if (ReadChar(0)==3)
         {
            AFPrintf(&UserDat,sout,SA[457]);
            break;
         }

         AFPrintf(&UserDat,sout,SA[458],(QF+a)->number,(QF+a)->filename);

         if (flippybindle==2)
         {
            AFPrintf(NULL,sout,"\n");
            flippybindle = 0;
         }
         else
         {
            AFPrintf(NULL,sout,"  ");
            flippybindle++;
         }
      }

      if (flippybindle)  AFPrintf(NULL,sout,"\n");
      Draw_Line(78);

      free(QF);
   }

   return(0);
}
//-

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

/// GetFilename
long GetFilename(long area)
{
   char filename[80];
   char altpath [80];
   char path    [256];

   long number;
   long dummy;

   if(DLGInput(NULL,filename,NULL,36,255,1, SA[459]) == 0) return(0);
   AFPrintf(NULL,sout,"\n\n");

   GetPath(altpath,area,NULL,filename);

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

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

   strcat(path, filename);
   UnderScore(path);

   GetComment(path, filename);

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

   return(number);
}
//-

/// _CXBRK
void _CXBRK(void)
{
   if(rh) Close(rh);

   if(sc)  SearchEnd(sc);
   if(sc2) SearchEnd(sc2);

   if(body) free(body);

   WriteRam(&RStruct,Ext);

   if (!Overlay) ChainProgram("DLG:Menu", Ext);

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

/// AmiNet_Upload
BYTE AmiNet_Upload(long area)
{
   char  ramfile   [128];
   char  headerfile[128];
   char  FilePath  [128];
   char  SearchPath[128];

   char  movefiles;

   long   Success = 0;

   struct File_Header   Header;
   struct Msg_Area      Area;

   ULONG  bsize = 0;

   /* Make sure area exists */
   Area.Number = area;

   if (CheckArea(&Area) == -1)  return(FALSE);

   Header.Attribute        = 0; 
   Header.Times_Downloaded = 0;
   UserDat.Last_File_Area   = area;

   /* Ask for the uploader of the file and store it in Header.From */
   if (!DLGInput(NULL,Header.From,RStruct.Name,35,254,3, SA[433]))
   {
      AFPrintf(&UserDat,sout,SA[434]);
      return(-1);
   }

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


   /* Ask if FREE and set the header attribute bit accordingly */
   if (!finput(0, SA[435]))
      Header.Attribute  = 0;
   else
      Header.Attribute |= NORATIO;
      AFPrintf(NULL,sout,"\n\n");


   /* Ask if the files are to be moved, and if so, set the movefiles flag */
   movefiles = finput(1, SA[436]);
   AFPrintf(NULL,sout,"\n\n");

   /* Ask for path to source files */
   DLGInput(NULL,FilePath,NULL,40,40,0, SA[439]);
   AFPrintf(NULL,sout,"\n\n");
   {
      long temp = 0;

      temp = strlen(FilePath);

      if( !(FilePath[temp-1] == ':') && !(FilePath[temp-1] == '/') )
         strcat(FilePath,"/");

      strcpy(SearchPath,FilePath);
      temp = strlen(SearchPath);
      if(SearchPath[temp-1] != ':')
         SearchPath[temp-1] = 0;
   }

   /* Create header and bodyfile names */
   ASPrintf(NULL, ramfile,    "T:%s.body",   Ext);
   ASPrintf(NULL, headerfile, "T:%s.header", Ext);

   /* start our directory scan loop */
   sc = SearchStart(SearchPath, "*.readme");

   for(;;)
   {
      char *s;
      char *scanfile;
      char *arcfile;
      char  ReadmeName[256];
      char  fragment[256];
      char  TargetName[256];

      /* Check for a ctrl C */
      Chk_Abort();

      /* get next file, and break out of main loop if there are no more */
      if (!(scanfile = SearchNext(sc)))  break;

      ASPrintf(NULL,ReadmeName,"%s%s",FilePath,scanfile);

      if(-1 == (FileSize(ReadmeName,&bsize)))
         continue;

      body = calloc(1,bsize + 1);

      if(body == NULL) continue;

      rh = Open(ReadmeName,MODE_OLDFILE);

      if(!rh)
      {
         free(body);
         body = NULL;
         continue;
      }

      Read(rh,body,bsize);
      Close(rh);
      rh = NULL;

      strcpy(fragment, scanfile);
      s = fragment + strlen(fragment);

      while(s)
      {
         if(*s == '.')
         {
            *s = 0;
            break;
         }

         s--;
      }

      strcat(fragment,".*");

      sc2 = SearchStart(SearchPath,fragment);

      while(arcfile = SearchNext(sc2))
         if(!Stricmp(arcfile, scanfile))
            continue;
         else
            break;

      ASPrintf(NULL,TargetName,"%s%s",FilePath,arcfile);

      Upper(arcfile);
      strcpy(Header.Filename, arcfile);

      SearchEnd(sc2);
      sc2 = NULL;

      /* Raw upload the file */
      AFPrintf(&UserDat, sout, SA[442], Header.Filename);

      for(;;)
      {
         /* set the date in the header to right now */
         MDate(Header.Date);

         Success = RawUpload(FilePath, Header.Filename, &Header, body,
                             NULL, &Area, "FileMaint", movefiles);

         if (Success == -1)
         {
            /* if raw upload fails, prompt the user for a new filename */
            AFPrintf(&UserDat,sout,SA[443],Header.Filename);
            DLGInput(NULL,Header.Filename,NULL,35,35,1, SA[444]);
            AFPrintf(NULL,sout,"\n\n");
            if (!Header.Filename[0])  break;
            continue;
         }

         break;
      }

      if (!Header.Filename[0])
         AFPrintf(&UserDat,sout,SA[445]);
      else
      {
         AFPrintf(&UserDat,sout,SA[446]);
         if(movefiles) DeleteFile(ReadmeName);
      }

      free(body);
      body = NULL;

   }

   SearchEnd(sc);
   sc = NULL;

   /* CleanUp */
   DeleteFile(ramfile);
   DeleteFile(headerfile);

   AFPrintf(NULL,sout,"\n");
}
//-


