/***************************************************************************

 YAM - Yet Another Mailer
 Copyright (C) 1995-2000 by Marcel Beck <mbeck@yam.ch>
 Copyright (C) 2000-2001 by YAM Open Source Team

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 YAM Official Support Site :  http://www.yam.ch
 YAM OpenSource project    :  http://sourceforge.net/projects/yamos/

 $Id: YAM_MAf.c,v 1.9.2.2 2001/06/03 22:42:02 laursen Exp $

***************************************************************************/

#include "YAM.h"
#include "YAM_rexx.h"

/* local protos */
LOCAL void MA_ValidateStatus(struct Folder*);
LOCAL char *MA_IndexFileName(struct Folder*);
LOCAL BOOL MA_DetectUUE(FILE*);
LOCAL void MA_GetRecipients(char*, struct Person**, int*);

/***************************************************************************
 Module: Main - Folder handling
***************************************************************************/

/*** Index Maintenance ***/

/// MA_PromptFolderPassword
//  Asks user for folder password
BOOL MA_PromptFolderPassword(struct Folder *fo, APTR win)
{
   char passwd[SIZE_PASSWORD], prompt[SIZE_LARGE];
   struct User *user = US_GetCurrentUser();

   if (fo->Flags&FOFL_FREEXS) return TRUE;
   if (!Stricmp(fo->Password, user->Password)) return TRUE;
   sprintf(prompt, GetStr(MSG_MA_GetFolderPass), fo->Name);
   do {
      *passwd = 0;
      if (!StringRequest(passwd, SIZE_PASSWORD, GetStr(MSG_Folder), prompt, GetStr(MSG_Okay), NULL, GetStr(MSG_Cancel), TRUE, win)) return FALSE;
   } while (Stricmp(passwd, fo->Password));
   return TRUE;
}

///
/// MA_ValidateStatus
//  Avoids invalid status values
LOCAL void MA_ValidateStatus(struct Folder *folder)
{
   struct Mail *mail;

   for (mail = folder->Messages; mail; mail = mail->Next)
      if (mail->Status == STATUS_NEW)
         if (folder->Type == FT_OUTGOING) MA_SetMailStatus(mail, STATUS_WFS);
         else if (folder->Type == FT_SENT) MA_SetMailStatus(mail, STATUS_SNT);
         else if (C->UpdateNewMail) MA_SetMailStatus(mail, STATUS_UNR);
}

///
/// MA_IndexFileName
//  Returns file name of folder index
LOCAL char *MA_IndexFileName(struct Folder *folder)
{
   static char buffer[SIZE_PATHFILE];
   strcpy(buffer, GetFolderDir(folder));
   AddPart(buffer, ".index", SIZE_PATHFILE);
   return buffer;
}

///
/// MA_LoadIndex
//  Loads a folder index from disk
int MA_LoadIndex(struct Folder *folder, BOOL full)
{
   FILE *fh;
   int indexloaded = 0;
   char buf[SIZE_LARGE];

// KPrintF("Loading index for folder %s\n", folder->Name);
   if (fh = fopen(MA_IndexFileName(folder), "r"))
   {
      struct FIndex fi;
      BOOL corrupt = FALSE;

      Busy(GetStr(MSG_BusyLoadingIndex), folder->Name, 0, 0);
      fread(&fi, sizeof(struct FIndex), 1, fh);
      if (fi.ID == MAKE_ID('Y','I','N','3'))
      {
         folder->Total  = fi.Total;
         folder->New    = fi.New;
         folder->Unread = fi.Unread;
         folder->Size   = fi.Size;
         indexloaded++;

         if (full)
         {
            ClearMailList(folder, TRUE);
            for (;;)
            {
               struct Mail mail;
               struct ComprMail cmail;
               clear(&mail, sizeof(struct Mail));               
               if (fread(&cmail, sizeof(struct ComprMail), 1, fh) != 1) break;
               if (cmail.MoreBytes > SIZE_LARGE)
               {
/*
fpos_t pos;
printf("WARNING: Index of folder '%s' CORRUPTED near mailfile '%s' (MoreBytes: 0x%x) - aborting!\n", folder->Name, cmail.MailFile, cmail.MoreBytes);
if (!fgetpos(fh, &pos)) printf("File position: %ld\n", pos);
*/

                  corrupt = TRUE;
                  break;
               }

               fread(buf, 1, cmail.MoreBytes, fh);
               strcpy(mail.Subject, GetNextLine(buf));
               strcpy(mail.From.Address, GetNextLine(NULL));
               strcpy(mail.From.RealName, GetNextLine(NULL));
               strcpy(mail.To.Address, GetNextLine(NULL));
               strcpy(mail.To.RealName, GetNextLine(NULL));
               strcpy(mail.ReplyTo.Address, GetNextLine(NULL));
               strcpy(mail.ReplyTo.RealName, GetNextLine(NULL));
               mail.Folder = folder;
               mail.Flags = (cmail.Flags&0x7ff);
               strcpy(mail.MailFile, cmail.MailFile);
               mail.Date = cmail.Date;
               mail.Status = cmail.Status;
               mail.Importance = cmail.Importance;
               mail.cMsgID = cmail.cMsgID;
               mail.cIRTMsgID = cmail.cIRTMsgID;
               mail.Size = cmail.Size;
               AddMailToList(&mail, folder);
            }
            indexloaded++;
            folder->Flags &= ~FOFL_MODIFY;
         }
      }
      BusyEnd;
      fclose(fh);

      if (corrupt) {
         MA_ScanMailBox(folder);
         MA_SaveIndex(folder);
//printf("Rescanned!\n");
      }
   }
   return indexloaded;
}

///
/// MA_SaveIndex
//  Saves a folder index to disk
BOOL MA_SaveIndex(struct Folder *folder)
{
   struct Mail *mail;
   FILE *fh;
   struct ComprMail cmail;
   char buf[SIZE_LARGE];
   struct FIndex fi;

   if (!(fh = fopen(MA_IndexFileName(folder), "w"))) return FALSE;
   Busy(GetStr(MSG_BusySavingIndex), folder->Name, 0, 0);
   fi.ID = MAKE_ID('Y','I','N','3');
   fi.Total = folder->Total; fi.New = folder->New; fi.Unread = folder->Unread; fi.Size = folder->Size;
   fwrite(&fi, sizeof(struct FIndex), 1, fh);
   for (mail = folder->Messages; mail; mail = mail->Next)
   {
      clear(&cmail, sizeof(struct ComprMail));
      sprintf(buf, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
         mail->Subject,
         mail->From.Address, mail->From.RealName,
         mail->To.Address, mail->To.RealName,
         mail->ReplyTo.Address, mail->ReplyTo.RealName);
      cmail.Flags = mail->Flags;
      strcpy(cmail.MailFile, mail->MailFile);
      cmail.Date = mail->Date;
      cmail.Status = mail->Status;
      cmail.Importance = mail->Importance;
      cmail.cMsgID = mail->cMsgID;
      cmail.cIRTMsgID = mail->cIRTMsgID;
      cmail.Size = mail->Size;
      cmail.MoreBytes = strlen(buf);
      fwrite(&cmail, sizeof(struct ComprMail), 1, fh);
      fwrite(buf, 1, cmail.MoreBytes, fh);
   }
   fclose(fh);
   folder->Flags &= ~FOFL_MODIFY;
   BusyEnd;
   return TRUE;
}

///
/// MA_GetIndex
//  Opens/unlocks a folder
BOOL MA_GetIndex(struct Folder *folder)
{
   if (!folder) return FALSE;
   if (folder->Type == FT_SEPARATOR) return FALSE;
   if (folder->LoadedMode != 2)
   {
      if (*folder->Password && (folder->XPKType&1))
         if (!MA_PromptFolderPassword(folder, G->MA->GUI.WI)) return FALSE;
      if (!MA_LoadIndex(folder, TRUE))
      {
         MA_ScanMailBox(folder);
         MA_SaveIndex(folder);
      }
      MA_ValidateStatus(folder);
      folder->LoadedMode = 2;
   }
   return TRUE;
}

///
/// MA_ExpireIndex
//  Invalidates a folder index
void MA_ExpireIndex(struct Folder *folder)
{
   if (!(folder->Flags&FOFL_MODIFY)) DeleteFile(MA_IndexFileName(folder));
   folder->Flags |= FOFL_MODIFY;
}

///
/// MA_UpdateIndexes
//  Updates indices of all folders
void MA_UpdateIndexes(BOOL initial)
{
   int i;
   struct Folder **flist;

   if (flist = FO_CreateList())
   {
      for (i = 1; i <= (int)*flist; i++) if (flist[i]->Type != FT_SEPARATOR)
         if (initial)
         {
            long dirdate = getft(GetFolderDir(flist[i]));
            long inddate = getft(MA_IndexFileName(flist[i]));
            if (dirdate > inddate+30 && inddate != -1)
            {
               DeleteFile(MA_IndexFileName(flist[i]));
               MA_GetIndex(flist[i]);
            }
         }
         else
         {
            if (flist[i]->LoadedMode == 2 && (flist[i]->Flags&FOFL_MODIFY)) MA_SaveIndex(flist[i]);
         }
      free(flist);
   }
}

///
/// MA_FlushIndexes
//  Removes loaded folder indices from memory and closes folders
void MA_FlushIndexes(BOOL all)
{
   int i;
   struct Folder *fo, **flist, *actfo = FO_GetCurrentFolder();

   if (flist = FO_CreateList())
   {
      for (i = 1; i <= (int)*flist; i++)
      {
         fo = flist[i];
         if ((fo->Type == FT_SENT || fo->Type == FT_CUSTOM || fo->Type == FT_CUSTOMSENT) && fo != actfo  && fo->LoadedMode == 2 && (all || (fo->Flags&FOFL_FREEXS)))
         {
            if (fo->Flags&FOFL_MODIFY) MA_SaveIndex(fo);
            ClearMailList(fo, FALSE);
            fo->LoadedMode = 1;
            fo->Flags &= ~FOFL_FREEXS;
         }
      }
      free(flist);
      DoMethod(G->MA->GUI.LV_FOLDERS, MUIM_NList_Redraw, MUIV_NList_Redraw_All);
   }
}

void SAVEDS MA_FlushIndexFunc(void)
{
   MA_FlushIndexes(TRUE);
}
MakeHook(MA_FlushIndexHook, MA_FlushIndexFunc);
///

/*** Private functions ***/
/// MA_ChangeFolder
//  Changes to another folder
void MA_ChangeFolder(struct Folder *folder)
{
   static struct Folder *lastfolder = NULL;
   struct Folder *actfolder = FO_GetCurrentFolder();
   BOOL folderopen = TRUE;
   int i, pos = 0;

   if (actfolder != folder || actfolder != lastfolder)
   {
      struct MA_GUIData *gui = &G->MA->GUI;
      set(gui->NL_MAILS, MUIA_ShortHelp, NULL);
      if (lastfolder) lastfolder->LastActive = GetMUI(gui->NL_MAILS, MUIA_NList_Active);
      if (folder) nnset(gui->NL_FOLDERS, MUIA_NList_Active, FO_GetFolderPosition(folder));
      else folder = actfolder;
      if (folder->Type == FT_SEPARATOR) folderopen = FALSE;
      else if (!MA_GetIndex(folder)) folderopen = FALSE;
      if (folderopen)
      {
         MA_SetSortFlag();
         DisplayMailList(folder, gui->NL_MAILS);
         DisplayStatistics(folder);

         if (C->JumpToNewMsg)
         {
            // jump to first or last unread mail in folder,
            // depending on sort order

            int incr;

            if (folder->Sort[0] < 0 || folder->Sort[1] < 0)
            {
               get(gui->NL_MAILS, MUIA_NList_Entries, &i);
               i--;
               incr = -1;
            }
            else
            {
               i = 0;
               incr = 1;
            }

            while (1)
            {
               struct Mail *mail;
               DoMethod(gui->NL_MAILS, MUIM_NList_GetEntry, i, &mail);
               if (!mail) break;
               if (mail->Status == STATUS_NEW || mail->Status == STATUS_UNR)
               {
                  pos = i;
                  break;
               }

               i += incr;
            }
         }

         set(gui->NL_MAILS, MUIA_NList_Active, pos);
      }
      set(gui->LV_MAILS, MUIA_Disabled, !folderopen);
      lastfolder = folder;
   }
}

void SAVEDS MA_ChangeFolderFunc(void)
{
   struct Folder *folder = FO_GetCurrentFolder();
   if (folder) MA_ChangeFolder(folder);
}
MakeHook(MA_ChangeFolderHook, MA_ChangeFolderFunc);
///

/*** Mail header scanning ***/
/// MA_NewMailFile
//  Returns an unique name for a new mail file
char *MA_NewMailFile(struct Folder *folder, char *mailfile, int daynumber)
{
   static char buffer[SIZE_PATHFILE];
   char mfile[SIZE_MFILE];
   struct Mail *mail;
   int cnt, mcnt = 0;
   
   if (!mailfile) mailfile = mfile;
   if (!daynumber) { struct DateStamp ds; DateStamp(&ds); daynumber = ds.ds_Days; }
   MA_GetIndex(folder);
   for (mail = folder->Messages; mail; mail = mail->Next)
      if (atoi(mail->MailFile) == daynumber)
         if ((cnt = atoi(&(mail->MailFile)[6])) > mcnt) mcnt = cnt;
   do {
      sprintf(mailfile, "%05d.%03d", daynumber, ++mcnt);
      strcpy(buffer, GetFolderDir(folder));
      AddPart(buffer, mailfile, SIZE_PATHFILE);
   } while (access(buffer,F_OK) == 0);
   return buffer;
}

///
/// MA_DetectUUE
//  Checks if message contains an uuencoded file
LOCAL BOOL MA_DetectUUE(FILE *fh)
{
   char *buffer;
   BOOL found = FALSE;
   int i;

   buffer = calloc(SIZE_LINE,1);
   for (i = 0; GetLine(fh, buffer, SIZE_LINE) && !found && i < 30; i++)
      if (!strncmp(buffer, "begin ", 6) && isdigit((int)buffer[6])) found = TRUE;
   free(buffer);
   return found;
}

///
/// MA_ReadHeader
//  Reads header lines of a message into memory
struct Data2D Header = { 0, 0, NULL };

BOOL MA_ReadHeader(FILE *fh)
{
   char *buffer, *ptr, *head;
   BOOL success = FALSE;
   char prevcharset[SIZE_DEFAULT];

   buffer = calloc(SIZE_LINE,1);
   head   = calloc(SIZE_LINE,1);
   FreeData2D(&Header);
   while (GetLine(fh, buffer, SIZE_LARGE))
   {
      if (!buffer[0]) { success = TRUE; break; }
      clear(head, SIZE_LINE);
      strcpy(prevcharset, "us-ascii");
      RE_ProcessHeader(prevcharset, buffer, TRUE, head);
      if ((buffer[0] == ' ' || buffer[0] == '\t') && Header.Used)
      {
         for (ptr = head; *ptr && ISpace(*ptr); ptr++);
         ptr = StrBufCat(Header.Data[Header.Used-1], ptr);
      }
      else                      
         ptr = StrBufCpy(AllocData2D(&Header, SIZE_DEFAULT), head);
      Header.Data[Header.Used-1] = ptr;
   }
   free(buffer); free(head);
   return success;
}  

///
/// MA_FreeEMailStruct
//  Frees an extended email structure
void MA_FreeEMailStruct(struct ExtendedMail *email)
{
   if (email->SenderInfo) FreeStrBuf(email->SenderInfo);
   if (email->Headers ) FreeStrBuf(email->Headers );
   if (email->NoSTo)    free(email->STo);
   if (email->NoCC )    free(email->CC );
   if (email->NoBCC)    free(email->BCC);
   clear(email, sizeof(struct ExtendedMail));
}

///
/// MA_GetRecipients
//  Extracts recipients from a header field
LOCAL void MA_GetRecipients(char *h, struct Person **per, int *percnt)
{
   int cnt;
   char *p = h, *next;
   for (cnt = 0; *p;)
   {
      cnt++;
      if (p = MyStrChr(p, ',')) p++; else break;
   }
   *percnt = cnt;
   if (cnt)
   {
      *per = calloc(cnt, sizeof(struct Person));
      for (cnt = 0, p = h; *p; cnt++)
      {
         if (next = MyStrChr(p, ',')) *next++ = 0;
         ExtractAddress(p, (struct Person *)((ULONG)*per+cnt*sizeof(struct Person)));
         if (!(p = next)) break;
      }
   }
}

///
/// MA_ExamineMail
//  Parses the header lines of a message and fills email structure
struct ExtendedMail *MA_ExamineMail(struct Folder *folder, char *file, char *statstr, BOOL deep)
{
   static struct ExtendedMail email;
   static struct Person pe;
   struct Mail *mail = (struct Mail *)&email;
   char *p, fullfile[SIZE_PATHFILE];
   int ok, i, j;
   struct DateStamp *foundDate = NULL;
   FILE *fh;

   clear(&email, sizeof(struct ExtendedMail));
   stccpy(mail->MailFile, file, SIZE_MFILE);
   email.DelSend = !C->SaveSent;
   if (fh = fopen(GetMailFile(fullfile, folder, mail), "r"))
   {
      BOOL xpk = FALSE;
      if (fgetc(fh) == 'X') if (fgetc(fh) == 'P') if (fgetc(fh) == 'K') xpk = TRUE;
      if (xpk)
      {
         fclose(fh);
         if (!StartUnpack(GetMailFile(NULL, folder, mail), fullfile, folder)) return NULL;
         fh = fopen(fullfile, "r");
      }
      else rewind(fh);
   }
   if (fh)
   {
      MA_ReadHeader(fh);
      if (MA_DetectUUE(fh)) mail->Flags |= MFLAG_MULTIPART;
      fclose(fh);
      for (ok=i=0; i < Header.Used; i++)
      {
         char *value, *field = Header.Data[i];
         if (value = strchr(field, ':'))
         {
            *value++ = 0;
            if (!stricmp(field, "from"))
            {
               ok |= 1;
               ExtractAddress(value, &pe);
               mail->From =  pe;
            }
            if (!stricmp(field, "reply-to"))
            {
               ok |= 8;
               ExtractAddress(value, &pe);
               mail->ReplyTo = pe;
            }
            if (!stricmp(field, "original-recipient"))
            {
               ExtractAddress(value, &pe);
               email.OriginalRcpt = pe;
            }
            if (!stricmp(field, "disposition-notification-to"))
            {
               ExtractAddress(value, &pe);
               email.ReceiptTo = pe;
               email.ReceiptType = RCPT_TYPE_ALL;
               mail->Flags |= MFLAG_SENDMDN;
            }
            if (!stricmp(field, "return-view-to"))
            {
               ExtractAddress(value, &pe);
               email.ReceiptTo = pe;
               email.ReceiptType = RCPT_TYPE_READ;
            }
            if (!stricmp(field, "return-receipt-to"))
            {
               email.RetRcpt = TRUE;
            }
            if (!stricmp(field, "to") && !(ok & 2))
            {
               ok |= 2;
               if (p = MyStrChr(value, ',')) *p++ = 0;
               ExtractAddress(value, &pe);
               mail->To = pe;
               if (p)
               {
                  mail->Flags |= MFLAG_MULTIRCPT;
                  if (deep && !email.NoSTo) MA_GetRecipients(p, &(email.STo), &(email.NoSTo));
               }
            }
            if (!stricmp(field, "cc"))
            {
               mail->Flags |= MFLAG_MULTIRCPT;
               if (deep && !email.NoCC) MA_GetRecipients(value, &(email.CC), &(email.NoCC));
            }
            if (!stricmp(field, "bcc"))
            {
               mail->Flags |= MFLAG_MULTIRCPT;
               if (deep && !email.NoBCC) MA_GetRecipients(value, &(email.BCC), &(email.NoBCC));
            }
            if (!stricmp(field, "subject"))
            {
               ok |= 4;
               stccpy(mail->Subject, Trim(value), SIZE_SUBJECT);
            }
            if (!stricmp(field, "message-id"))
            {
               mail->cMsgID = CompressMsgID(p = Trim(value));
               stccpy(email.MsgID, p, SIZE_MSGID);
            }
            if (!stricmp(field, "in-reply-to"))
            {
               mail->cIRTMsgID = CompressMsgID(p = Trim(value));
               stccpy(email.IRTMsgID, p, SIZE_MSGID);
            }
            if (!stricmp(field, "date"))
            {
               foundDate = ScanDate(value);
            }
            if (!stricmp(field, "importance"))
            {
               p = Trim(value);
               if (!stricmp(p, "high")) mail->Importance = 1;
               if (!stricmp(p, "low")) mail->Importance = -1;
            }
            if (!stricmp(field, "priority") && !mail->Importance)
            {
               p = Trim(value);
               if (!stricmp(p, "urgent")) mail->Importance = 1;
               if (!stricmp(p, "non-urgent")) mail->Importance = -1;
            }
            if (!stricmp(field, "content-type"))
            {
               p = Trim(value);
               if (!strnicmp(p, "multipart/mixed", 15)) mail->Flags |= MFLAG_MULTIPART;
               if (!strnicmp(p, "multipart/report", 16)) mail->Flags |= MFLAG_REPORT;
               if (!strnicmp(p, "multipart/encrypted", 19)) mail->Flags |= MFLAG_CRYPT;
               if (!strnicmp(p, "multipart/signed", 16)) mail->Flags |= MFLAG_SIGNED;
            }
            if (!stricmp(field, "x-senderinfo"))
            {
               mail->Flags |= MFLAG_SENDERINFO;
               if (deep) email.SenderInfo = StrBufCpy(email.SenderInfo, value);
            }
            if (deep)
            {
               if (!stricmp(field, "x-yam-options"))
               {
                  if (strstr(value, "delsent")) email.DelSend = TRUE;
                  if (p = strstr(value, "sigfile")) email.Signature = p[7]-'0'+1;
                  for (j = SEC_SIGN; j <= SEC_SENDANON; j++) if (strstr(value, SecCodes[j])) email.Security = j;
               }
               if (!strnicmp(field, "x-yam-header-", 13))
               {
                  email.Headers = StrBufCat(StrBufCat(email.Headers, &field[13]), ":");
                  email.Headers = StrBufCat(StrBufCat(email.Headers, value), "\\n");
               }
            }
         }
      }
      FreeData2D(&Header);
      if ((ok & 8) && !mail->ReplyTo.RealName[0] && !stricmp(mail->ReplyTo.Address, mail->From.Address)) strcpy(mail->ReplyTo.RealName, mail->From.RealName);
      mail->Date.ds_Days   = foundDate ? foundDate->ds_Days   : atol(mail->MailFile);
      mail->Date.ds_Minute = foundDate ? foundDate->ds_Minute : 0;
      mail->Date.ds_Tick   = foundDate ? foundDate->ds_Tick   : 0;
      mail->Size = FileSize(fullfile);
      if (statstr)
         for (mail->Status = STATUS_NEW, i = 0; i < STATUS_NEW; i++)
            if (*statstr == *Status[i]) mail->Status = i;
      FinishUnpack(fullfile);
      return &email;
   }
   FinishUnpack(fullfile);
   return NULL;
}

///
/// MA_ScanMailBox
//  Scans for message files in a folder directory
void MA_ScanMailBox(struct Folder *folder)
{
   struct ExtendedMail *mail;
   struct FileInfoBlock *fib;
   BPTR lock;

   Busy(GetStr(MSG_BusyScanning), folder->Name, 0, 0);
   ClearMailList(folder, TRUE);
   fib = AllocDosObject(DOS_FIB,NULL);
   if (lock = Lock(GetFolderDir(folder), ACCESS_READ))
   {
      Examine(lock, fib);
      while (ExNext(lock,fib) && (IoErr() != ERROR_NO_MORE_ENTRIES))
      {
         DoMethod(G->App,MUIM_Application_InputBuffered);
         if (IsValidMailFile(fib->fib_FileName))
            if (fib->fib_Size)
            {
               if (mail = MA_ExamineMail(folder,fib->fib_FileName,fib->fib_Comment,FALSE))
               {
                  AddMailToList((struct Mail *)mail, folder);
                  MA_FreeEMailStruct(mail);
               }
            }
            else
            {
               char path[SIZE_PATHFILE];
               NameFromLock(lock, path, SIZE_PATHFILE);
               AddPart(path, fib->fib_FileName, SIZE_PATHFILE);
               DeleteFile(path);
            }
      }
      UnLock(lock);
   }
   FreeDosObject(DOS_FIB,fib);
   BusyEnd;
}
///

/*** Hooks ***/
/// PO_InitFolderList
//  Creates a popup list of all folders
long SAVEDS ASM PO_InitFolderList(REG(a2,Object *pop))
{  
   int i;
   struct Folder **flist;

   DoMethod(pop, MUIM_List_Clear);
   DoMethod(pop, MUIM_List_InsertSingle, GetStr(MSG_MA_Cancel), MUIV_List_Insert_Bottom);
   if (flist = FO_CreateList())
   {
      for (i = 1; i <= (int)*flist; i++) if (flist[i]->Type != FT_SEPARATOR)
         DoMethod(pop, MUIM_List_InsertSingle, flist[i]->Name, MUIV_List_Insert_Bottom);
      free(flist);
   }
   return TRUE;
}
MakeHook(PO_InitFolderListHook, PO_InitFolderList);

///
/// MA_LV_FDspFunc
//  Folder listview display hook
long SAVEDS ASM MA_LV_FDspFunc(REG(a2,char **array), REG(a1,struct Folder *entry))
{
   if (entry)
   {
      static char dispfold[SIZE_DEFAULT], disptot[SIZE_SMALL], dispunr[SIZE_SMALL], dispnew[SIZE_SMALL], dispsiz[SIZE_SMALL];
      strcpy(array[0] = dispfold, entry->Name);
      array[1] = array[2] = array[3] = array[4] = "";
      *dispsiz = 0;
      if (entry->Type == FT_SEPARATOR)
         array[DISPLAY_ARRAY_MAX] = "\033E\033t\033c";
      else
      {
         if (!*dispfold) sprintf(dispfold, "(%s)", FilePart(entry->Path));
         if (entry->XPKType&1) strcat(dispfold, " \033o[0]");
         if (entry->LoadedMode)
         {
            if (entry->New+entry->Unread) array[DISPLAY_ARRAY_MAX] = MUIX_PH;
            sprintf(array[1] = disptot, "%d", entry->Total);
            sprintf(array[2] = dispunr, "%d", entry->Unread);
            sprintf(array[3] = dispnew, "%d", entry->New);
            FormatSize(entry->Size, array[4] = dispsiz);
         }
      }
   }
   else 
   {
      array[0] = GetStr(MSG_Folder);
      array[1] = GetStr(MSG_Total);
      array[2] = GetStr(MSG_Unread);
      array[3] = GetStr(MSG_New);
      array[4] = GetStr(MSG_Size);
   }
   return 0;
}
MakeHook(MA_LV_FDspFuncHook,MA_LV_FDspFunc);

///
/// MA_MakeFOFormat
//  Creates format definition for folder listview
void MA_MakeFOFormat(APTR lv)
{
   int i;
   int defwidth[FOCOLNUM] = { -1,-1,-1,-1,-1 };
   char format[SIZE_LARGE];
   BOOL first = TRUE;
   *format = 0;
   for (i = 0; i < FOCOLNUM; i++) if (C->FolderCols & (1<<i))
   {
      if (first) first = FALSE; else strcat(format, " BAR,");
      sprintf(&format[strlen(format)], "COL=%ld W=%ld", i, defwidth[i]);
      if (i) strcat(format, " P=\033r");
   }
   strcat(format, " BAR");
   set(lv, MUIA_NList_Format, format);
}
///
