/*static char *SCCSID = "@(#)easfile.c	6.13 92/03/18";*/
/*==============================================================*\
 *                                                              *
 * EASFILE.C                                                    *
 *    (C) Copyright IBM Corporation 1992.                       *
 *--------------------------------------------------------------*
 *  This module contains subroutines for eas.c that specifically*
 *  deal with the Open file interface. Most of the routines were*
 *  taken from Charles Petzold's book "Programming the OS/2     *
 *  Presentation Manager" and were slightly modified.           *
 *                                                              *
 *--------------------------------------------------------------*
 *  Procedures in this file:                                    *
 *   OpenFile()        Asks user for new file name and opens it *
 *   OpenFileProc()    Dialog proc that prompts user file name  *
 *   FillDirListBox()  Fills the directory list box             *
 *   FillFileListBox() Fills the file list box                  *
 *                                                              *
\*==============================================================*/
/*--------------------------------------------------------------*\
 *  Include files, macros, defined constants, and externs       *
\*--------------------------------------------------------------*/
#include "eas.h"

extern EADATA ConvTable[EATABLESIZE];

/****************************************************************\
 *                                                              *
 *  Name:    OpenFile(hwnd, usMode)                             *
 *                                                              *
 *  Purpose: This routine handles opening a new file.  It will  *
 *           also query the user for the disposition of the     *
 *           current file if it has been modified before loading*
 *           the new file.                                      *
 *                                                              *
 *  Usage  : This routine is called by MainDlgProc to deal with *
 *           the Open file interface.                           *
 *                                                              *
 *  Method : Routine should be bullet proof as it does its own  *
 *           error checking.  It assumes that hwnd points to the*
 *           correct window with the name listbox in it.        *
 *                                                              *
 *  Returns: TRUE if a file is open upon exit.                  *
 *                                                              *
\****************************************************************/
BOOL OpenFile(HWND hwnd, ULONG usMode)
{
   CHAR szOldFile[CCHMAXPATH];
   HFILE  FileHandle=0;
   ULONG  ulAct=0L;

   strcpy(szOldFile,szFileName);  /* Save name of the currently open file */

   if(usMode != ARGFILE)                /* It isn't the command line file */
   {
      if(!WinDlgBox(HWND_DESKTOP,      /* Get the file name from the user */
                    hwnd,
                    OpenFileProc,
                    '\0',
                    IDD_OPENBOX,
                    NULL))
      {
         strcpy(szFileName,szOldFile); /* They canceled, restore old file */
         return(FILE_ISOPEN);
      }
   }
                             /* Check filename availble or not */
   if( DosOpen(szFileName, &FileHandle, &ulAct, 0L, FILE_NORMAL,
                        FILE_OPEN, OPEN_SHARE_DENYWRITE, NULL) )
   {
      MessageBox(hwnd, IDMSG_ERRORFILEOPEN, "Error !",
                       MB_OK | MB_ERROR, TRUE);
      return(FILE_ISOPEN);
   }
   else                 /* File is existed and availble to use */
      DosClose(FileHandle);

   if(FILE_ISOPEN) /* Free up everything associated with the current file */
   {
      Free_FEAList(pHoldFEA,pDelList);
      FILE_ISOPEN = FALSE;
   }

   if(QueryEAs(szFileName))                         /* We were successful */
   {
      HOLDFEA *pFEA=pHoldFEA;

      FILE_ISOPEN = TRUE;
      FILE_CHANGED = FALSE;

      WinSendDlgItemMsg(hwnd, IDD_WINLBOX, LM_DELETEALL,0L,0L); /* Fill L-box */

      while(pFEA)
      {
         WinSendDlgItemMsg(hwnd, IDD_WINLBOX, LM_INSERTITEM,
                           MPFROM2SHORT(LIT_END,0),
                           MPFROMP(pFEA->szName));
         pFEA = pFEA->next;
      }
   }
   else                                      /* We couldn't query the EAs */
   {
      *szFileName = '\000';
      memset(szEAType, 0, sizeof(szEAType) );
      WinInvalidateRect(hwndMain, NULL, FALSE);
      FILE_ISOPEN = FALSE;
      return (FILE_ISOPEN);
   }
   memset(szEAType, 0, sizeof(szEAType) );
   WinInvalidateRect(hwndMain, NULL, FALSE);
   pDelList = NULL;
   return(TRUE);
}

/****************************************************************\
 *                                                              *
 *  Name:    OpenFileProc(hwnd, msg, mp1, mp2)                  *
 *                                                              *
 *  Purpose: This proc handles the user interface to select a   *
 *           file name. Some elementary checks are done to make *
 *           sure the filename is valid.                        *
 *                                                              *
 *  Usage  : This routine is called by OpenFile to open the file*
 *                                                              *
 *  Method : The interface is NOT foolproof as it is possible to*
 *           continue with a non-existant file name.  Also,     *
 *           users are not currently allowed to view/edit the   *
 *           EAs attached to a directory.                       *
 *                                                              *
 *  Returns: TRUE if selects OK, FALSE if Cancel is selected.   *
 *                                                              *
\****************************************************************/
MRESULT EXPENTRY OpenFileProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
   static CHAR szCurrentPath[CCHMAXPATH]={'.', '\\', '*', '\000'},
                szBuffer[CCHMAXPATH];
   CHAR        szParsedPath[CCHMAXPATH];
   SHORT       sSelect;
   MRESULT sRC;

   switch(msg)
   {
      case WM_INITDLG:
         FixSysMenu(hwnd);
         FillDirListBox(hwnd,szCurrentPath);
         FillFileListBox(hwnd);
         WinSendDlgItemMsg(hwnd, IDD_FILEEDIT,EM_SETTEXTLIMIT,
                                 MPFROM2SHORT(CCHMAXPATH,0),NULL);
         return (MRESULT)0L;

      case WM_CONTROL:                      /* An lbox item is selected */
         if(SHORT1FROMMP(mp1) == IDD_DIRLIST ||
            SHORT1FROMMP(mp1) == IDD_FILELIST)
         {                                        /* Get item->szBuffer */
            sSelect = (USHORT) WinSendDlgItemMsg(hwnd,
                               SHORT1FROMMP(mp1),
                               LM_QUERYSELECTION, 0L, 0L);

            WinSendDlgItemMsg(hwnd, SHORT1FROMMP(mp1),
                              LM_QUERYITEMTEXT,
                              MPFROM2SHORT(sSelect, sizeof(szBuffer)),
                              MPFROMP(szBuffer));
         }

         switch(SHORT1FROMMP(mp1))
         {
            case IDD_DIRLIST:          /* Item was in the directory lbox */
               switch(SHORT2FROMMP(mp1))
               {
                  case LN_ENTER:           /* Go to the select drive/dir */
                     if(*szBuffer == ' ')
                        DosSelectDisk(*(szBuffer+1) - '@');
                     else
                        DosSetCurrentDir(szBuffer);

                     FillDirListBox(hwnd, szCurrentPath);
                     FillFileListBox(hwnd);

                     WinSetDlgItemText(hwnd, IDD_FILEEDIT, "");
                     return (MRESULT)0L;
               }
               break;

            case IDD_FILELIST:             /* Item was in the file lbox */
               switch(SHORT2FROMMP(mp1))
               {
                  case LN_SELECT:          /* Copy name to entry field  */
                     WinSetDlgItemText(hwnd, IDD_FILEEDIT, szBuffer);
                     return (MRESULT)0L;

                  case LN_ENTER:              /* Try to query the file */
                     if(ParseFileName(szFileName, szBuffer) != FILE_VALID)
                        return 0;          /* Some error, don't finish */
                     WinDismissDlg(hwnd, TRUE);
                     return (MRESULT)0L;
               }
               break;
         }
         break;

      case WM_COMMAND:
         switch(LOUSHORT(mp1))
         {
            case DID_OK:       /* Try to query file in the entry field */
               memset(szBuffer, 0, sizeof(szBuffer) );
               WinQueryDlgItemText(hwnd, IDD_FILEEDIT,
                                   sizeof(szBuffer), szBuffer);
                                         /* Check filename availble or not */
               if(*szBuffer == '\000')
               {
                  MessageBox(hwnd, IDMSG_NOFILEOPEN, "Error !",
                                   MB_OK | MB_ERROR, TRUE);
                  return FALSE;
               }
               switch(ParseFileName(szParsedPath, szBuffer))
               {
                  case FILE_INVALID:            /* Can't open the file */
                     WinAlarm(HWND_DESKTOP, WA_ERROR);
                     FillDirListBox(hwnd, szCurrentPath);
                     FillFileListBox(hwnd);
                     return (MRESULT)0L;

                  case FILE_PATH:    /* It was an incomplete path name */
                     strcpy(szCurrentPath,szBuffer);
                     FillDirListBox(hwnd, szCurrentPath);
                     FillFileListBox(hwnd);
                     WinSetDlgItemText(hwnd, IDD_FILEEDIT, "");
                     return (MRESULT)0L;

                  case FILE_VALID:                     /* It was valid */
                     strcpy(szFileName, szParsedPath);
                     WinDismissDlg(hwnd, TRUE);
                     return (MRESULT)0L;
               }
               break;

            case DID_CANCEL:
               WinDismissDlg(hwnd, FALSE);
               return (MRESULT)0L;
         }
         break;

      case WM_CLOSE:
         WinDismissDlg(hwnd, FALSE);
         return (MRESULT)0L;

   }
   sRC = WinDefDlgProc(hwnd, msg, mp1, mp2);
   return sRC;
}

/****************************************************************\
 *                                                              *
 *  Name:    FillDirListBox(hwnd, pcCurrentPath)                *
 *                                                              *
 *  Purpose: This routine is called by OpenFileProc to fill in  *
 *           the directory list box                             *
 *                                                              *
 *  Usage  : This routine is called by OpenFileProc to fill the *
 *           file list box.                                     *
 *                                                              *
 *  Method : Adequete error checking is NOT done on the return  *
 *           values of the system calls.  Also, it is remotely  *
 *           possible that the calls to add to the list box     *
 *           could fail.                                        *
 *                                                              *
 *  Returns: VOID                                               *
 *                                                              *
\* **************************************************************/
VOID FillDirListBox(HWND hwnd, CHAR *pcCurrentPath)
{
   static CHAR szDrive [] = "  :";
   FILEFINDBUF3 findbuf;
   HDIR        hDir = HDIR_CREATE;
   SHORT       sDrive;
   ULONG       ulCurPathLen, ulDriveMap=0L, ulSearchCount = 1, ulDriveNum=0L;

   memset(&findbuf,0,sizeof(FILEFINDBUF) );

   DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap);
   *pcCurrentPath     = (CHAR) (ulDriveNum + '@');
   *(pcCurrentPath+1) = ':';
   *(pcCurrentPath+2) = '\\';
   ulCurPathLen = CCHMAXPATH;
   DosQueryCurrentDir(0L, pcCurrentPath + 3, &ulCurPathLen);

   WinSetDlgItemText(hwnd, IDD_PATH, pcCurrentPath);
   WinSendDlgItemMsg(hwnd, IDD_DIRLIST, LM_DELETEALL, NULL, NULL);

   for(sDrive = ('A'-'A'); sDrive <= ('Z'-'A'); sDrive++)
   {
      if(ulDriveMap & (1L << sDrive))
      {
         *(szDrive+1) = (CHAR) (sDrive + 'A');

         WinSendDlgItemMsg(hwnd, IDD_DIRLIST, LM_INSERTITEM,
                           MPFROM2SHORT(LIT_END, 0),
                           MPFROMP(szDrive));
      }
   }
   if (DosFindFirst("*", &hDir, FILE_DIRECTORY, &findbuf,
                sizeof(findbuf), &ulSearchCount, FIL_STANDARD))
   {
      DosBeep(500,110);
      return;
   }
   while(ulSearchCount)
   {
      if(findbuf.attrFile & 0x0010 &&
         (findbuf.achName[0] != '.' || findbuf.achName[1]))

         WinSendDlgItemMsg(hwnd, IDD_DIRLIST, LM_INSERTITEM,
                           MPFROM2SHORT(LIT_SORTASCENDING, 0),
                           MPFROMP(findbuf.achName));

      if(DosFindNext(hDir, &findbuf, sizeof(findbuf), &ulSearchCount))
         break;
   }
   return;
}

/****************************************************************\
 *                                                              *
 *  Name:    FillFileListBox(hwnd)                              *
 *                                                              *
 *  Purpose: This routine is called by OpenFileProc to fill in  *
 *           the file list box with files in the current        *
 *           directory.                                         *
 *                                                              *
 *  Usage  : This routine is called by OpenFileProc to fill the *
 *           file list box.                                     *
 *                                                              *
 *  Method : Adequete error checking is NOT done on the return  *
 *           values of the system calls.  Also, it is remotely  *
 *           possible that the calls to add to the list box     *
 *           could fail.                                        *
 *                                                              *
 *  Returns: VOID                                               *
 *                                                              *
\****************************************************************/
VOID FillFileListBox(HWND hwnd)
{
   FILEFINDBUF3 findbuf;
   HDIR        hDir = HDIR_CREATE;
   ULONG       ulSearchCount = 1; /* Read 1 entry at a time */

   memset(&findbuf,0,sizeof(FILEFINDBUF) );
   WinSendDlgItemMsg(hwnd, IDD_FILELIST, LM_DELETEALL, NULL, NULL);

   if (DosFindFirst("*", &hDir, FILE_NORMAL, &findbuf, sizeof(findbuf),
                       &ulSearchCount,FIL_STANDARD))
   {
      DosBeep(700,110);
      return;
   }
   while(ulSearchCount)
   {
      WinSendDlgItemMsg(hwnd, IDD_FILELIST, LM_INSERTITEM,
                        MPFROM2SHORT(LIT_SORTASCENDING, 0),
                        MPFROMP(findbuf.achName));

      if(DosFindNext(hDir, &findbuf, sizeof(findbuf), &ulSearchCount))
         break;
   }
   return;
}

/****************************************************************\
 *                                                              *
 *  Name:    ParseFileName(pcOut, pcIn)                         *
 *                                                              *
 *  Purpose: This routine changes drive and directory as per    *
 *           pcIn string.                                       *
 *                                                              *
 *  Usage:   Note that pcOut is only valid if FILE_VALID is     *
 *           returned. In place of strupr(), a codepage should  *
 *           be fetched and DosCaseMap() should be used to allow*
 *           for extended chars. This routine could use some    *
 *           cleanup work.                                      *
 *                                                              *
 *  Returns: FILE_INVALID if pcIn had invalid drive or no       *
 *                           directory                          *
 *           FILE_PATH    if pcIn was empty or had just a path/ *
 *                           no file name.                      *
 *           FILE_VALID   if pcIn point to good file.           *
 *                                                              *
\****************************************************************/
LONG ParseFileName(CHAR *pcOut, CHAR *pcIn)
{
   CHAR   *pcLastSlash, *pcFileOnly ;
   ULONG  ulDriveMap, ulDirLen = CCHMAXPATH, ulDriveNum=0L;

   strupr(pcIn);   /* Does NOT handle extended chars, should use DosCaseMap */

   if(*pcIn == '\000')              /* If string is empty, return FILE_PATH */

      return FILE_PATH;

                        /* Get drive from input string or use current drive */
   if(*(pcIn+1) == ':')                      /* Yup, they specified a drive */
   {
      if(DosSelectDisk(*pcIn - '@'))            /* Change to selected drive */
         return FILE_INVALID;
      pcIn += 2;
   }
   DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap);      /* Get current drive */
   *pcOut++ = (CHAR) (ulDriveNum + '@');              /* Build drive letter */
   *pcOut++ = ':';
   *pcOut++ = '\\';

   if(*pcIn == '\000')  /* If rest of the string is empty, return FILE_PATH */
      return FILE_PATH;

       /* Search for the last backslash.  If none, it could be a directory. */
   if(!(pcLastSlash = strrchr(pcIn, '\\')))                  /* No slashes? */
   {
      if(!DosSetCurrentDir(pcIn))
         return FILE_PATH;                            /* It was a directory */
                                       /* Get current dir & attach input fn */
      DosQueryCurrentDir(0L, pcOut, &ulDirLen);

      if(*(pcOut+strlen(pcOut)-1) != '\\')
         strcat(pcOut++, "\\");

      strcat(pcOut, pcIn);
      return FILE_VALID;
   }
               /* If the only backslash is at the beginning, change to root */
   if(pcIn == pcLastSlash)
   {
      DosSetCurrentDir("\\");

      if(*(pcIn+1) == '\000')
         return FILE_PATH;

      strcpy(pcOut, pcIn+1);
      return FILE_VALID;
   }
                   /* Attempt to change directory -- Get current dir if OK */
  *pcLastSlash = '\0';

   if(DosSetCurrentDir(pcIn))
      return FILE_INVALID;

   DosQueryCurrentDir(0L, pcOut, &ulDirLen);
                                            /* Append input filename if any */
   pcFileOnly = pcLastSlash+1;

   if(*pcFileOnly == '\000')
      return FILE_PATH;

   if(*(pcOut+strlen(pcOut)-1) != '\\')
      strcat(pcOut++, "\\");

   strcat(pcOut, pcFileOnly);
   return FILE_VALID;
}
