/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Microsoft Corporation, 1989                                 */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
#if 0
/**************************************************************************
 *
 * SOURCE FILE NAME = softfont.c
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION = V2.0
 *
 * DATE        01/09/90
 *
 * DESCRIPTION Soft (downloadable) font installation.
 *             All user-interface code must be Ring 3 only, so it should all go in
 *             here.  Other (non-UI) code having to do with downloading soft fonts
 *             is in "DOWNLOAD.C", in the 'CONFORMING' segment.
 *             SFDialog    -- Soft Font installation Dialog procedure
 *
 * FUNCTIONS
 *
 *
 *                 SFMsgBox
 *                 SetPointer
 *                 ParseHeader
 *                 rwASCIIblock
 *                 rwBINARYblock
 *                 ParseSegment
 *                  SeekStr
 *                 FindFullName
 *                 FindFontName
 *                 FullNamePFB
 *                 InsertPFB
 *                 DeleteEntry
 *                 CheckForDup
 *                 InsertPFA
 *                 NoFonts
 *                 EnableButton
 *                 ListInstalledFonts
 *                 InitSFDialog
 *                 CheckFontDir
 *                 OpenSource
 *                 PfbToPfa
 *                  AddPFA
 *                 AddPFM
 *                 AddFonts
 *                 DeleteFonts
 *                 FreeListBox
 *                 ExitSFDialog
 *                 SFDialog
 *
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
 *   extern PBYTE prdg_AllocMem(SHORT);
 *   extern NPBYTE prdg_FreeMem(PBYTE);
 *   extern PBYTE  GlobalAllocMem(SHORT);
 *   extern NPBYTE GlobalFreeMem(NPBYTE,SHORT);
 *   extern SHORT AfmToPfm(PSZ,PSZ);
 *   extern ULONG PostMsgBox(HMODULE,SHORT,SHORT,SHORT);
 *   extern SHORT CopyStr(PSZ,PSZ);
 *   extern BOOL szIsEqual(PSZ,PSZ);
 *   extern PSZ SeekChar(CHAR,PSZ);
 *   extern SHORT FullNamePFA(PSZ,PSZ);
 *   extern SHORT LoadFontDir(VOID);
 *
*/
#define  INCL_DOSERRORS                /* for DOS errors */
#define  INCL_DOSFILEMGR               /* for DosFindFirst */
#define  INCL_DOSMISC                  /* for DosError */
#define  INCL_WIN                      /* for Win functions */
#define  INCL_HELP                     /* for Help functions */
#define  INCL_WINHELP                  
#define  INCL_DOSNLS
#include <os2.h>
#include <os2p.h>
#include "inc\config.h"                /* dialog stuff */
#include "inc\softfont.h"              /* downloadable font stuff */
#include "inc\pspagtun.h"             /* V2.174057  Page Tuning */


/*
** Globals in DATAR3
*/
static CHAR buf[MXS];                  /* general purpose character buffer  */
static CHAR buf1[BLOCKSIZE],buf2[(BLOCKSIZE *2)+(BLOCKSIZE/16)];
CHAR szInstalledFontDir[BUF_SIZE];

/*
** External Function Prototypes
*/
extern PBYTE prdg_AllocMem(SHORT); /* memory.c */
extern NPBYTE prdg_FreeMem(PBYTE); /* memory.c */
extern PBYTE  GlobalAllocMem(SHORT); /* memory.c */
extern NPBYTE GlobalFreeMem(NPBYTE,SHORT); /* memory.c */
extern SHORT AfmToPfm(PSZ,PSZ); /* afmtopfm.c */
extern ULONG PostMsgBox(HMODULE,SHORT,SHORT,SHORT);
extern SHORT CopyStr(PSZ,PSZ); /* download.c */
extern BOOL _System szIsEqual(PSZ,PSZ);
extern PSZ SeekChar(CHAR,PSZ); /* download.c */
extern SHORT FullNamePFA(PSZ,PSZ); /* download.c */
extern SHORT LoadFontDir(VOID); /* download.c */
extern HMODULE pscript_module;

/* Internal Subroutines */

/***************************************************************************
 *
 * FUNCTION NAME = SFMsgBox
 *
 * DESCRIPTION   = Put up a message box.  Uses 'PostMsgBox'.
 *
 * INPUT         = (usMsgId,usStyle)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (SHORT)PostMsgBox(pscript_module, 0,
 *                  usMsgId, usStyle)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

SHORT SFMsgBox( SHORT usMsgId, SHORT usStyle )
{
  return (SHORT) PostMsgBox( pscript_module, 0, usMsgId, usStyle );
}

/***************************************************************************
 *
 * FUNCTION NAME = SetPointer
 *
 * DESCRIPTION   = Set the system pointer to the specified system style.
 *
 * INPUT         = sPtr
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID SetPointer( SHORT sPtr )
{
  WinSetPointer( HWND_DESKTOP, WinQuerySysPointer( HWND_DESKTOP, sPtr, FALSE ));
  return;
}

/***************************************************************************
 *
 * FUNCTION NAME = ParseHeader
 *
 * DESCRIPTION   = Read in header.  Return TRUE if it's valid and not EOF.
 *
 * INPUT         = (hPFB,pHdr)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL ParseHeader(  HFILE hPFB,  PBHEAD pHdr )
{
  ULONG cbRead;

  return (!DosRead( hPFB, (PVOID)pHdr, (ULONG)sizeof(BHEAD), &cbRead) &&
          cbRead == sizeof(BHEAD) && pHdr->bCheck == CHECK_BYTE && pHdr->bType !=
          EOF_TYPE);
}


/***************************************************************************
 *
 * FUNCTION NAME = rwASCIIblock
 *
 * DESCRIPTION   = Read in an ASCII block, convert CRs to CR/LFs, and write
 *                 it out.
 *
 * INPUT         = (hPFB,hPFA,bsize)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID rwASCIIblock( HFILE hPFB, HFILE hPFA, ULONG bsize )
{
  NPCHAR p1, p2;
  SHORT  i, j;
  ULONG cBytes;

  DosRead( hPFB, (PVOID)buf1, bsize, &bsize );
  j = bsize;
  p1 = (NPCHAR)buf1;
  p2 = (NPCHAR)buf2;

  for (i = 0; i < bsize; i++)
  {
    if (CR == (*p2++ = *p1++))         /* copy buf1 to buf2, inserting LF */
    {                                  /* after every CR. */
      *(p2++) = LF;
      ++j;
    }
  }
  DosWrite( hPFA, (PVOID)buf2, j, &cBytes );
}

/***************************************************************************
 *
 * FUNCTION NAME = rwBINARYblock
 *
 * DESCRIPTION   = Read in a binary block, convert each byte into an ASCII
 *                 representation of hex, add a few CR/LFs for readability,
 *                 and write it out.
 *
 * INPUT         = (hPFB,hPFA,bsize)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID rwBINARYblock( HFILE hPFB, HFILE hPFA, ULONG lbsize )
{
  #define  BinaryToHex(c) (UCHAR)((c) < 10 ? '0' + (c) : 'a' + (c) - 10)

  NPCHAR p1, p2;
  UCHAR  LowNibble, HighNibble;
  ULONG  cBytes;
  SHORT  i;
  SHORT  bsize;       /* local short variable for long input */

  DosRead( hPFB, (PVOID)buf1, bsize, &lbsize );
  p1 = (NPCHAR) buf1;
  p2 = (NPCHAR) buf2;
  bsize = (SHORT) lbsize;

  for (i = 0; i < bsize; i++)
  {
    HighNibble = *p1 >> 4;             /* Most significant four bits        */
    LowNibble = *p1++&0xF;             /* Least significant four bits       */
    *p2++ = BinaryToHex( HighNibble );
    *p2++ = BinaryToHex( LowNibble );

    /*
    ** emit a CR/LF every 64 bytes for readability
    */
    if (i%32 == 31)
    {
      *p2++ = 0xD;
      *p2++ = 0xA;
    }
  }

  /*
  ** adjust buffer size to account for carriage returns
  */
  i = bsize << 1;
  i += (i / 64) * 2;

  /*
  ** add a final carriage return in the case of a partial block
  */
  if (i < sizeof(buf2))
  {
    *p2++ = 0xD;
    *p2 = 0xA;
    i += 2;
  }
  DosWrite( hPFA, (PVOID)buf2, (ULONG)i, &cBytes );
}

/***************************************************************************
 *
 * FUNCTION NAME = ParseSegment
 *
 * DESCRIPTION   = Convert PFB segment to PFA format.
 *
 * INPUT         = (hPFB,hPFA,pHdr)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID ParseSegment( HFILE hPFB, HFILE hPFA, PBHEAD pHdr )
{
  SHORT i, nblocks, rblocks;

  /*
  ** set the number of blocks and the remainder
  */
  nblocks = (int) (pHdr->ulLength / (ULONG) BLOCKSIZE);
  rblocks = (int) (pHdr->ulLength % (ULONG) BLOCKSIZE);

  for (i = 0; i < nblocks; i++)
  {
    if (pHdr->bType == BINARY_TYPE)
    {
      rwBINARYblock( hPFB, hPFA, BLOCKSIZE );
    }
    else
    {
      rwASCIIblock( hPFB, hPFA, BLOCKSIZE );
    }
  }

  if (pHdr->bType == BINARY_TYPE)
  {
    rwBINARYblock( hPFB, hPFA, (ULONG)rblocks );
  }
  else
  {
    rwASCIIblock( hPFB, hPFA, (ULONG)rblocks );
  }
}

/***************************************************************************
 *
 * FUNCTION NAME =  SeekStr
 *
 * DESCRIPTION   =  Search for a string in a long string.
 *
 * INPUT         = pszTarget,pszBuf
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (*pszBuf != '\0')?pFound:(PVOID)0
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PSZ SeekStr( PSZ pszTarget, PSZ pszBuf )
{
  PSZ pT,pFound;

  while (*pszBuf != '\0')
  {
    pFound = pszBuf;                   /* save where we start */
    pT = pszTarget;

    while (*pszBuf++ == *pT)           /* if equal, check the next one */
    {
      pT++;
    }

    if (*pT == '\0')
    {
      break;
    }
  }
  return (*pszBuf != '\0') ? pFound : (PVOID)0;
}

/***************************************************************************
 *
 * FUNCTION NAME = FindFullName
 *
 * DESCRIPTION   = Search for a string of the format
 *
 *                      /FullName (Helvetica Light)
 *
 *                 extract the name, copy it to the return buffer and
 *                 return its length.  If not found, return 0.
 *
 * INPUT         = pszFile, pName
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = cRet
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

SHORT FindFullName( PSZ pszFile, PSZ pName )
{
  PBYTE pStart,pEnd;
  SHORT cRet;

  cRet = 0;

  if (pStart = SeekStr( FULL_NAME, pszFile ))
  {
    pStart = 1 + SeekChar('(', pStart+9 );

    while (*pStart == ' ')             /* eat leading spaces */
    {
      pStart++;
    }
    pEnd = SeekChar(')', (PSZ)pStart );

    while (*(pEnd-1) == ' ')           /* eat trailing spaces */
    {
      pEnd--;
    }
    *pEnd = '\0';
    cRet = CopyStr((PSZ)pName, (PSZ)pStart );
    *pEnd = ')';                    /* mustn't leave a null in our buffer. */
  }
  return  cRet;
}

/***************************************************************************
 *
 * FUNCTION NAME = FindFontName
 *
 * DESCRIPTION   = Search for a string of the format
 *
 *                      /FontName /Helvetica-Light
 *
 *                 extract the name, copy it to the return buffer and
 *                 return its length.  If not found, return 0.
 *
 * INPUT         = pszFile, pName
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = cRet
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

SHORT FindFontName( PSZ pszFile, PSZ pName )
{
  PBYTE pStart, pEnd;
  SHORT cRet;

  cRet = 0;

  if (pStart = SeekStr( FONT_NAME, pszFile ))
  {
    pStart = 1 + SeekChar('/', pStart+9 );
    *(pEnd = SeekChar( ' ', (PSZ)pStart)) = '\0';
    cRet = CopyStr((PSZ)pName, (PSZ)pStart );
    *pEnd = ' ';                    /* mustn't leave a null in our buffer. */
  }
  return  cRet;
}

/***************************************************************************
 *
 * FUNCTION NAME = FullNamePFB
 *
 * DESCRIPTION   = Get FullName from .PFB file.  Return length, not
 *                 counting terminating null.
 *
 * INPUT         = pszFile, pName
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = sRet
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

SHORT FullNamePFB( PSZ pszFile, PSZ pName )
{
  HFILE hFilePFB;
  ULONG usAction,cbRead;
  PBYTE pBuf;
  BHEAD Header;
  SHORT sRet;

  sRet = 0;

  if (!DosOpen( pszFile, (PHFILE)&hFilePFB, &usAction, 0L, 0L,
     FILE_OPEN, OPEN_READ_FLAGS, 0L))
  {
    /*
    ** A valid ascii seg?
    */
    if (ParseHeader(hFilePFB, (PVOID)&Header) && Header.bType == ASCII_TYPE)
    {
      cbRead = Header.ulLength;
      pBuf = prdg_AllocMem( cbRead + 1 );  /* room for null */
      *(pBuf+cbRead) = '\0';           /* null-termination insurance */
      DosRead( hFilePFB, (PVOID)pBuf, cbRead, &cbRead );
      sRet = FindFullName( pBuf, pName );
      prdg_FreeMem( pBuf );
    }
    DosClose( hFilePFB );
  }
  return  sRet;
}

/***************************************************************************
 *
 * FUNCTION NAME = InsertPFB
 *
 * DESCRIPTION   = Make a SoftFont entry in a listbox.  Also creates the
 *                 associated SFTFNT data structure and saves the pointer in
 *                 the listbox as well.  Returns the pointer.
 *
 * INPUT         = (hLB,pszFile)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = pFont
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PVOID InsertPFB( HWND hLB,  PSZ pszFile )
  /* PSZ pszFile;                          file name, with path */
{
  CHAR    szName[BUF_SIZE];
  PSFTFNT pFont;
  SHORT   i;                             /* index */

  FullNamePFB( pszFile, (PSZ)szName );
  i = (SHORT) WinSendMsg( hLB, LM_INSERTITEM, MPFROMSHORT(LIT_SORTASCENDING),
                         (PSZ)szName );
  pFont = (PSFTFNT) GlobalAllocMem( sizeof (SFTFNT) );
  CopyStr( (PSZ) pFont->szFullName, (PSZ)szName );
  WinSendMsg( hLB, LM_SETITEMHANDLE, MPFROMSHORT(i), (PSFTFNT)pFont );
  return  pFont;
}

/***************************************************************************
 *
 * FUNCTION NAME = DeleteEntry
 *
 * DESCRIPTION   = Delete a Listbox entry and free the memory block its
 *                 handle points to.
 *
 * INPUT         = hLB, i
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID DeleteEntry( HWND hLB, SHORT i )
{
  GlobalFreeMem( (NPBYTE) WinSendMsg( hLB, LM_QUERYITEMHANDLE,
                 MPFROMSHORT(i), 0L), 0 );
  WinSendMsg( hLB, LM_DELETEITEM, MPFROMSHORT(i), 0L );
}

/***************************************************************************
 *
 * FUNCTION NAME = CheckForDup
 *
 * DESCRIPTION   = See if a listbox entry matches the given target.  If it
 *                 does, delete it and return TRUE.
 *
 * INPUT         = hLB, i, pszName
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = bRet
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL CheckForDup( HWND hLB, SHORT i, PSZ pszName )
{
  CHAR szDup[BUF_SIZE];
  BOOL bRet;

  WinSendMsg( hLB, LM_QUERYITEMTEXT, MPFROM2SHORT( i, sizeof(szDup)), szDup );

  if (bRet = szIsEqual( pszName, szDup ))
  {
    DeleteEntry(hLB, i );
  }
  return  bRet;
}

/***************************************************************************
 *
 * FUNCTION NAME = InsertPFA
 *
 * DESCRIPTION   = Make a SoftFont entry in a listbox.  Also creates the
 *                 associated SFTFNT data structure and saves the pointer in
 *                 the listbox as well.  Returns the pointer.
 *
 * INPUT         = hLB, pszFile
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = pFont
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PVOID InsertPFA( HWND hLB, PSZ pszFile )
{
  CHAR    szName[BUF_SIZE];
  PSFTFNT pFont;
  SHORT   i;                             /* index */

  FullNamePFA( pszFile, (PSZ)szName );
  i = (SHORT)WinSendMsg( hLB, LM_INSERTITEM, MPFROMSHORT(LIT_SORTASCENDING),
     (PSZ) szName );
  pFont = (PSFTFNT) GlobalAllocMem(sizeof(SFTFNT) );
  CopyStr((PSZ) pFont->szFullName, (PSZ) szName );
  CopyStr((PSZ) pFont->szFilePF, (PSZ) pszFile );
  WinSendMsg( hLB, LM_SETITEMHANDLE, MPFROMSHORT(i), (PSFTFNT) pFont );

  /*
  ** Check for duplicate entries.  It is necessary to check both
  ** the next and previous entries, since there is no telling how
  ** future versions of PMWIN will insert duplicates.
  */
  if (!CheckForDup(hLB, i+1, (PSZ) szName) && i > 0)
  {
    CheckForDup( hLB, i-1, (PSZ) szName );
  }
  return  pFont;
}

/***************************************************************************
 *
 * FUNCTION NAME = NoFonts
 *
 * DESCRIPTION   = Put the "No Downloadable Fonts" message in a list box.
 *
 * INPUT         = hLB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID NoFonts( HWND hLB )
{
  SHORT i;
  CHAR  szName[64];                     /* leave room for translation */

  WinLoadMessage( (HAB)0, pscript_module, IDM_NoFonts, sizeof(szName),
                  (PSZ) szName );
  WinEnableWindowUpdate( hLB, FALSE );   /* disable list box */
  WinSendMsg( hLB, LM_DELETEALL, 0L, 0L ); /* clear list box */
                                                /* add item */
  i = (SHORT)WinSendMsg( hLB, LM_INSERTITEM, MPFROMSHORT(LIT_END), (PSZ) szName);
  WinSendMsg( hLB, LM_SETITEMHANDLE, MPFROMSHORT(i), 0L );
                                                /* set handle = 0 */
  WinEnableWindowUpdate( hLB, TRUE );    /* enable list box */
}

/***************************************************************************
 *
 * FUNCTION NAME = EnableButton
 *
 * DESCRIPTION   = The listbox has been touched.  Query it, and enable the
 *                 button iff there is a valid item selected.
 *
 * INPUT         = hDB, idLB, idButton
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID EnableButton( HWND hDB, SHORT idLB, SHORT idButton )
{
  HWND  hLB;
  SHORT i;

  hLB = WinWindowFromID( hDB, idLB );
  i = (SHORT)WinSendMsg( hLB, LM_QUERYSELECTION, MPFROMSHORT(LIT_FIRST), 0L );
  WinEnableWindow(WinWindowFromID( hDB, idButton ), (i != LIT_NONE) && (0L !=
     WinSendMsg( hLB, LM_QUERYITEMHANDLE, MPFROMSHORT(i), 0L)) );
}

/***************************************************************************
 *
 * FUNCTION NAME = ListInstalledFonts
 *
 * DESCRIPTION   = Fill in right list box with listing of installed fonts
 *                 directory.
 *
 * INPUT         = hDB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID ListInstalledFonts( HWND hDB )
{
  HWND        hLB;                      /* Installed fonts list box handle */
  HDIR        hdirPFM,hdirPFA;          /* Installed directory handles */
  FILEFINDBUF findbuf;
  CHAR        szFile[BUF_SIZE];         /* for file names, including path */
  SHORT       usEnd;
  ULONG       usCount;
  PSFTFNT     pFont;                    /* pointer to font structure */
  SHORT       i;                        /* general-purpose index */

  hdirPFM = HDIR_CREATE;               /* initialize */
  usCount = 1;
  hLB = WinWindowFromID( hDB, SF_LB_INSTALLED );
  i = CopyStr( (PSZ) szFile, (PSZ) szInstalledFontDir );
  usEnd = i;                           /* remember end point */
  i += CopyStr( (PSZ) &szFile[i], ALL_PFM );

  switch (DosFindFirst( (PSZ) szFile, (PHDIR)&hdirPFM, FILE_NORMAL,
                        (PFILEFINDBUF)&findbuf, sizeof(FILEFINDBUF), &usCount, 0L))
  {
  case 0:                           /* DOS_OK */
       break;

  /*
  ** dir is made latter when the use gets a chance to enter it
  */
  /*  case ERROR_PATH_NOT_FOUND:       */         /* directory doesn't exist  */
  /*      DosMkDir( INSTALLED_DIR, 0L );   */      /* so create it */
                                                /* and FALL THROUGH */
  default:                         /* all other errors */
      NoFonts( hLB );                    /* clear list box */
      return ;                         /* and leave */
      break;
  }


  /*
  ** There's at least one font file. List all of them.
  */
  WinEnableWindowUpdate( hLB, FALSE );   /* disable list box */
  WinSendMsg( hLB, LM_DELETEALL, 0L, 0L ); /* clear list box */
  hdirPFA = HDIR_SYSTEM;

  do                                   /* for every .PFM file ... */
  {
    /*
    ** Find corresponding .PFA file...
    */
    i = CopyStr( (PSZ) &szFile[usEnd], (PSZ) findbuf.achName );
    szFile[usEnd+i-1] = 'A';

    if (!DosFindFirst( (PSZ) szFile, (PHDIR)&hdirPFA, FILE_NORMAL,
       &findbuf, sizeof(FILEFINDBUF), &usCount, 0L))
    {
      /*
      ** add filename to path
      */
      CopyStr( (PSZ) &szFile[usEnd], (PSZ) findbuf.achName );

      pFont = (PSFTFNT) InsertPFA(hLB, (PSZ) szFile );
    }
  }

  while (!DosFindNext(hdirPFM, &findbuf, sizeof(FILEFINDBUF), &usCount) );
  DosFindClose(hdirPFM );

  if (0 == WinSendMsg( hLB, LM_QUERYITEMCOUNT, 0L, 0L))
  {
    NoFonts( hLB );                      /* clear list box */
  }
  WinEnableWindowUpdate( hLB, TRUE );    /* enable list box */
  return ;
}

/***************************************************************************
 *
 * FUNCTION NAME = InitSFDialog
 *
 * DESCRIPTION   = Initialize Soft Font Installation dialog.
 *
 * INPUT         = (hDB)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL InitSFDialog( HWND hDB )
{
  HHELP    hHelp;
  HMODULE  hMod;
  CHAR     szBuf[128];
  register usLen;

  /*
  ** disable the "Add" and "Delete" buttons
  */
  WinEnableWindow(WinWindowFromID( hDB, SF_ADD), FALSE );
  WinEnableWindow(WinWindowFromID( hDB, SF_ERASE), FALSE );

  /*
  ** initialize source entry and installed fonts list box
  */
  WinSendDlgItemMsg( hDB, ID_FONT_SOURCE, EM_SETTEXTLIMIT, MPFROMSHORT(BUF_SIZE),
                     0L );
  WinSetDlgItemText( hDB, ID_FONT_SOURCE, DEFAULT_FONT_SOURCE );

  /*
  ** Get the installed font dir
  */
  usLen = LoadFontDir()-1;             /* want index to last char; */
  szInstalledFontDir[usLen] = '\0';    /* Temp remove back slash */

  /*
  ** Make sure user doesn't get too carried away - allow room for font name too
  */
  WinSendDlgItemMsg( hDB, ID_INST_FONT_DIR, EM_SETTEXTLIMIT, MPFROMSHORT
                     (BUF_SIZE - FILE_NAME_SIZE), 0L );
  WinSetDlgItemText( hDB, ID_INST_FONT_DIR, (PSZ) szInstalledFontDir );

  /*
  ** Tack on a trailing backslash;
  */
  szInstalledFontDir[usLen] = '\\';    /* Put back back slash */
  ListInstalledFonts(hDB );

  /*
  ** initialize high level help by calling HlpInit which is
  ** defined in pmtkt.dll.
  */
  WinLoadMessage( (HAB)0, (HMODULE)(hMod = pscript_module), IDM_SFInstaller,
                  sizeof(szBuf), (PSZ) szBuf );

  #ifdef   DCR1476
    if (hHelp = (HHELP)HlpInit((HAB)0L, hMod, hDB, (PSZ) szBuf, NULL, 0L))
    {
      HlpRegisterContext((HHELP)hHelp, hMod, IDH_CONTEXT );
    }
    WinSetWindowULong(hDB, 0, hHelp );
  #endif

  /*
  ** leave focus on 'ok' button
  */
  WinSetFocus( HWND_DESKTOP, WinWindowFromID( hDB, DID_OK) );
  return  TRUE;                        /* TRUE => yes, I changed the focus */
}

/***************************************************************************
 *
 * FUNCTION NAME = CheckFontDir
 *
 * DESCRIPTION   = Makes sure the font directory specified by user is OK.
 *                 If not will put message to reenter. The path/subdir must
 *                 exist.
 *
 * INPUT         = hDB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE if OK
 *
 * RETURN-ERROR  = FALSE if path is bad
 *
 **************************************************************************/

BOOL CheckFontDir( HWND hDB )
{
  register SHORT usDirLen;
  register SHORT usRC;
  SHORT          usCount = 1;
  BOOL           fListFonts;
  CHAR           szDirPath[BUF_SIZE];
  COUNTRYCODE    cc;
  FILESTATUS     sFS;

  /*
  ** Get the font dir path from the dialog
  */
  usDirLen = WinQueryDlgItemText( hDB, ID_INST_FONT_DIR, BUF_SIZE-
                                  FILE_NAME_SIZE, (PSZ) szDirPath );

  /*
  ** Remove any trailing back slash use may have supplied
  */
  if (usDirLen && (szDirPath[usDirLen-1] == '\\'))
  {
    szDirPath[--usDirLen] = '\0';
  }

  /*
  ** See if path exists
  */
  if ((usRC = DosQueryPathInfo((PSZ) szDirPath, FIL_STANDARD, (PVOID)&sFS, sizeof
     (sFS))) == NO_ERROR)
  {
    /*
    ** Name exists - make sure it's a directory
    */
    if (!(sFS.attrFile&FILE_DIRECTORY))
    {
      usRC = 1;                      /* Not a directory - set to some error */
    }
  }

  if (usRC)
  {
    /*
    **     directory so hilite the entry field
    */
    SFMsgBox( IDM_BadDirectory, MB_OK|MB_ICONHAND|MB_MOVEABLE );
    WinSetFocus( HWND_DESKTOP, WinWindowFromID( hDB, ID_INST_FONT_DIR) );

    /*
    ** Indicate problem
    */
    usRC = FALSE;
  }
  else
  {
    /*
    **         Make field read only  (activate this code if needed
    **       WinSendDlgItemMsg(  hDB, ID_INST_FONT_DIR, EM_SETREADONLY,
    **                          MPFROMSHORT( TRUE ), 0L  );
    ** Uppercase the path
    */
    cc.country = 0;
    cc.codepage = 0;
    DosCaseMap( usDirLen, (PCOUNTRYCODE)&cc, (PCHAR)szDirPath );

    /*
    ** Tack on a back slash for global path
    */
    szDirPath[usDirLen++] = '\\';
    szDirPath[usDirLen] = '\0';

    /*
    ** Store new path in ini
    */
    PrfWriteProfileString( HINI_SYSTEMPROFILE, FONT_DIR_APP, FONT_DIR_KEY, (PSZ)
                           szDirPath );

    /*
    ** If the name is different from global value must reload fonts
    */
    fListFonts = strcmp( szInstalledFontDir, szDirPath );

    /*
    ** Copy name to global value
    */
    CopyStr( (PSZ) szInstalledFontDir, (PSZ) szDirPath );

    /*
    ** Re-display the font list if path changed
    */
    if (fListFonts)
    {
      ListInstalledFonts( hDB );
    }
    usRC = TRUE;
  }
  return (usRC );
}

/***************************************************************************
 *
 * FUNCTION NAME = OpenSource
 *
 * DESCRIPTION   = Fill in left list box with listing of source directory.
 *
 * INPUT         = (hDB)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID OpenSource( HWND hDB )
{
  HWND        hLB;                    /* window handle for Source list box */
  HDIR        hdir;                   /* source directory handle */
  FILEFINDBUF findbuf;
  PSZ         pszFile, pEnd;
  ULONG       usCount;
  PSFTFNT     pFont;
  SHORT       sErr;
  SHORT       pszFileSize;

  /*
  ** This may take a while, so put up the hourglass
  */
  SetPointer( SPTR_WAIT );
  hLB = WinWindowFromID( hDB, SF_LB_SOURCE );

  /*
  ** find out from where we're supposed to read the fonts.  Leave room
  ** to add the file spec to directory name.
  */
  usCount = (ULONG) WinQueryDlgItemTextLength( hDB, ID_FONT_SOURCE );
  pszFile = GlobalAllocMem( usCount + 16 );
  pszFileSize = usCount+16;
  pEnd = pszFile+WinQueryDlgItemText( hDB, ID_FONT_SOURCE, usCount+2, pszFile );

  if (*(pEnd-1) != '\\')               /* If no ending '\', add it */
  {
    /*
    ** Note: Copy doesn't require a terminating '\0'
    */
    *pEnd++ = '\\';
  }

  CopyStr( pEnd, ALL_PFB );
  DosError( HARDERROR_DISABLE );

HitDisk:

  hdir = HDIR_CREATE;                  /* initialize */
  usCount = 1;

  switch (sErr = DosFindFirst(pszFile, (PHDIR)&hdir, FILE_NORMAL,
          (PFILEFINDBUF)&findbuf, sizeof(FILEFINDBUF), &usCount, 0L))
  {
  case 0:                           /* DOS_OK */
       break;

  case ERROR_NOT_READY:            /* drive door open, probably */
       if (MBID_RETRY == SFMsgBox(IDM_DriveOpen, MB_RETRYCANCEL|MB_ICONHAND|
           MB_MOVEABLE))
       {
         goto HitDisk;
       }
       else
       {
         NoFonts( hLB );                  /* cancel */
       }
      break;

  /*             */
  /*
  ** Added the following case to provide the SF dialog with access
  ** to the b: drive in a one drive system.  (It's only accessable
  ** through a HARDERROR gate.
  */
  case ERROR_DISK_CHANGE:
       DosError( HARDERROR_ENABLE );
       goto HitDisk;
       break;

  case  ERROR_FILENAME_EXCED_RANGE :
  case  ERROR_PATH_NOT_FOUND :

    SFMsgBox(IDM_BadDirectory, MB_OK|MB_ICONHAND|MB_MOVEABLE );
    WinSetFocus(HWND_DESKTOP, WinWindowFromID( hDB, ID_FONT_SOURCE) );
    break;
  default  :                         /* all other errors */
    NoFonts(hLB );
    break;
  }
  DosError(HARDERROR_ENABLE );

  if (!sErr)                       /* There's at least one good file here. */
  {                                    /* List all of them in listbox. */
    WinSendMsg( hLB, LM_DELETEALL, 0L, 0L ); /* clear list box */

    do
    {                                  /* for every PFB file ... */
      CopyStr( pEnd, (PSZ) findbuf.achName );
                                                    /* add font to list */
      pFont = (PSFTFNT) InsertPFB(hLB, pszFile );
      CopyStr( (PSZ) pFont->szFilePF, (PSZ) findbuf.achName );
    }

    while (!DosFindNext( hdir, (PFILEFINDBUF)&findbuf, sizeof(FILEFINDBUF),
                         &usCount) );
    WinSendDlgItemMsg( hDB, SF_OPEN, BM_SETDEFAULT, 0L, 0L );
  }
  DosFindClose( hdir );
  GlobalFreeMem( pszFile, pszFileSize );
  SetPointer( SPTR_ARROW );
}

/***************************************************************************
 *
 * FUNCTION NAME = PfbToPfa
 *
 * DESCRIPTION   = A PC filter that expands an Adobe IBM PC font file into
 *                 ASCII that can be saved and loaded into any PostScript
 *                 interpreter.  At the front of the file, we stick the
 *                 FullName and FontName as a comment line, like so:
 *                 %Full Name%FontName%
 *
 * INPUT         = pszPFB, pszPFA
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0 on success.
 *
 * RETURN-ERROR  = DOS error codes, if any
 *
 **************************************************************************/

SHORT PfbToPfa( PSZ pszPFB,PSZ pszPFA )
{
  BHEAD Hdr;
  HFILE hPFB,hPFA;
  ULONG ulNewPtr;
  PBYTE pIn;
  ULONG usAct, cbRead;
  SHORT i;
  SHORT sRet;

  if (!(sRet = DosOpen(pszPFB, (PHFILE)&hPFB, &usAct, 0L, 0,
     FILE_OPEN, OPEN_READ_FLAGS, 0L)) && !(sRet = DosOpen(pszPFA, (PHFILE)
     &hPFA, &usAct, (ULONG)BLOCKSIZE, FILE_NORMAL, FILE_TRUNCATE |
     FILE_CREATE, OPEN_WRITE_FLAGS, 0L)))
  {
    buf2[0] = '%';

    if (ParseHeader(hPFB, (PVOID)&Hdr) && Hdr.bType == ASCII_TYPE) /* a valid ascii seg? */
    {
      cbRead = (SHORT) Hdr.ulLength+1;
      pIn = prdg_AllocMem( cbRead + 1 );   /* room for null */
      DosRead( hPFB, (PVOID)pIn, cbRead, &cbRead );
      *(pIn+cbRead) = '\0';            /* null-termination insurance */
      i = 1+FindFullName( pIn, (PSZ) &buf2[1] );
      buf2[i++] = '%';
      i += FindFontName( pIn, (PSZ) &buf2[i] );
      buf2[i++] = '%';
      buf2[i++] = CR;
      buf2[i++] = LF;                  /* end comment with end line */
      prdg_FreeMem( pIn );
    }
    DosSetFilePtr( hPFB, 0L, FILE_BEGIN, &ulNewPtr );

    if (!(sRet = DosWrite(hPFA, (PVOID)buf2, i, &usAct)))
    {
      while (ParseHeader(hPFB, (PVOID)&Hdr)) /* returns 'stuff to do?' */
        ParseSegment(hPFB, hPFA, (PVOID)&Hdr );
    }
    DosClose( hPFB );
    DosClose( hPFA );
  }
  return  sRet;
}

/***************************************************************************
 *
 * FUNCTION NAME =  AddPFA
 *
 * DESCRIPTION   =  Create a PFA file in the target directory from a PFB
 *                  file in the source directory.
 *
 * INPUT         = (pszSrc,pszDst)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = FALSE
 *
 **************************************************************************/

BOOL AddPFA( PSZ pszSrc, PSZ pszDst )
{

  while (TRUE)
  {
    if (!PfbToPfa(pszSrc, pszDst))
    {
      return  TRUE;
    }
    else if (MBID_CANCEL == SFMsgBox( IDM_CantFindPFB, MB_RETRYCANCEL | MB_ICONHAND |
             MB_MOVEABLE))
    {
      return  FALSE;
    }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = AddPFM
 *
 * DESCRIPTION   = Create a PFM file in the target directory from an AFM
 *                 file in the source directory.
 *
 * INPUT         = (pszSrc,pszDst)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = !AfmToPfm(pszSrc, pszDst)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL AddPFM( PSZ pszSrc, PSZ pszDst )
{
  ULONG       cCount;               /* # of AFM files to search for */
  HDIR        hDir;
  FILEFINDBUF FindBuf;             /* for AFM file search, room for just 1 */

  hDir = HDIR_SYSTEM;
  cCount = 1;                          /* loop 'til found or user gives up */

  while (DosFindFirst(pszSrc, (PHDIR)&hDir, FILE_NORMAL|FILE_READONLY|
         FILE_HIDDEN|FILE_ARCHIVED, (PVOID)&FindBuf, sizeof(FindBuf),
         &cCount, 0L))
  {

    if (MBID_CANCEL == SFMsgBox(IDM_CantFindAFM, MB_RETRYCANCEL|MB_ICONHAND|
       MB_MOVEABLE))
    {
      return  FALSE;
    }
    else
    {
      cCount = 1;                      /* set up for next search */
    }
  }
                                    /* found the afm, make the pfm */
  return !AfmToPfm( pszSrc, pszDst );
}

/***************************************************************************
 *
 * FUNCTION NAME = AddFonts
 *
 * DESCRIPTION   = Install selected fonts.
 *
 * INPUT         = (hDB)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID AddFonts( HWND hDB )
{
  HWND hSrcLB,                         /* list box handles */
       hDstLB;
  CHAR szSrc[BUF_SIZE],                /* string buffers */
       szDest[BUF_SIZE];
  SHORT i, j,                          /* listbox indices, */
        cSrcEnd,cDstEnd,               /* marks end of directory part of string */
        cSrcRoom,cDstRoom,             /* room remaining in buffer */
        cLength;                       /* file name length */
  PSFTFNT pFont,psfNew;
  HDIR    hDir;
  FILEFINDBUF FindBuf;                 /* for AFM file search, room for just 1 */
  BOOL        fCancel;
  ULONG       cCount;                       /* # of AFM files to search for */

  /*
  ** This may take a while, so put up the hourglass
  */

  SetPointer(SPTR_WAIT );
  hSrcLB = WinWindowFromID( hDB, SF_LB_SOURCE ); /* invest in handles */
  hDstLB = WinWindowFromID( hDB, SF_LB_INSTALLED );

  /*
  ** Get source directory string.
  */
  cSrcEnd = WinQueryDlgItemText( hDB, ID_FONT_SOURCE, (sizeof(szSrc)-10), (PSZ)
                                 szSrc );

  if (szSrc[cSrcEnd-1] != '\\')        /* If no ending '\', add it */
  {
    szSrc[cSrcEnd++] = '\\';           /* Note Copy doesn't require */
                                                /* a terminating '\0' */
  }
  cSrcRoom = sizeof( szSrc ) - cSrcEnd;

  /*
  ** Assemble destination string.
  */
  cDstEnd = CopyStr( (PSZ) szDest, szInstalledFontDir );
  cDstRoom = sizeof(szDest)-cDstEnd;

  /*
  ** Copy PFB files
  */
  for (i = LIT_FIRST; LIT_NONE != (i = (SHORT)WinSendMsg( hSrcLB,
       LM_QUERYSELECTION, MPFROMSHORT(i), 0L) ); )
  {                                    /* for each selection... */
    pFont = WinSendMsg( hSrcLB, LM_QUERYITEMHANDLE, MPFROMSHORT(i), 0L );

    /*
    ** Add file name to source path.
    */
    CopyStr( (PSZ) &szSrc[cSrcEnd], (PSZ) pFont->szFilePF );

    /*
    ** Add file name to destination path.
    */
    cLength = CopyStr( (PSZ) &szDest[cDstEnd], (PSZ) pFont->szFilePF );

    /*
    ** Convert .PFB filename to .PFA filenames
    */
    szDest[cDstEnd+cLength-1] = 'A';

    if (!AddPFA((PSZ) szSrc, (PSZ) szDest)) /* if copy fails, */
    {
      WinSendMsg( hSrcLB, LM_SELECTITEM,  /* deselect so we won't */
         MPFROMSHORT(i),               /* try to get AFM file */
         MPFROMSHORT(FALSE) );
    }
  }

  /*
  ** Look for an .AFM file.  If not found, which is likely,
  ** ask them to insert the disk containing it.
  */
  CopyStr( (PSZ) &szSrc[cSrcEnd], ALL_AFM );
  hDir = HDIR_SYSTEM;
  fCancel = FALSE;
  cCount = 1;

  if (DosFindFirst((PSZ) szSrc, (PHDIR)&hDir, FILE_NORMAL|FILE_READONLY|
     FILE_HIDDEN|FILE_ARCHIVED, (PVOID)&FindBuf, sizeof(FindBuf),
     &cCount, 0L))
  {
    fCancel = (MBID_CANCEL == SFMsgBox( IDM_InsertAFMDisk, MB_OKCANCEL |
                                        MB_ICONEXCLAMATION) );
  }

  /*
  ** if the first entry is the "NoFonts" message, with handle=0L, delete it
  */
  if (0L == WinSendMsg( hDstLB, LM_QUERYITEMHANDLE, 0L, 0L))
  {
    WinSendMsg( hDstLB, LM_DELETEITEM, 0L, 0L );
  }

  /*
  ** Now create PFM files
  */
  for (i = LIT_FIRST; LIT_NONE != (i = (SHORT)WinSendMsg( hSrcLB,
     LM_QUERYSELECTION, MPFROMSHORT(LIT_FIRST), 0L) ); )
  {                                    /* for each selection... */
    pFont = WinSendMsg( hSrcLB, LM_QUERYITEMHANDLE, MPFROMSHORT(i), 0L );

    /*
    ** Add file name to source path
    */
    CopyStr( (PSZ) &szSrc[cSrcEnd], (PSZ) pFont->szFilePF );

    /*
    ** Add file name to destination path. (And save length)
    */
    cLength = CopyStr( (PSZ) &szDest[cDstEnd], (PSZ) pFont->szFilePF );

    /*
    ** Convert .PFB filenames to .PFM and .AFM filenames
    */
    szSrc[cSrcEnd+cLength-1] = szDest[cDstEnd+cLength-1] = 'M';
    szSrc[cSrcEnd+cLength-3] = 'A';

    if (!fCancel && AddPFM((PSZ) szSrc, (PSZ) szDest)) /* create .PFM file */
    {
      szDest[cDstEnd+cLength-1] = 'A';
      pFont = (PSFTFNT) InsertPFA(hDstLB, (PSZ) szDest );
    }
    else
    {
      szDest[cDstEnd+cLength - 1] = 'A'; /* can't create PFM, so */
      DosDelete(szDest );               /* delete PFA file */
    }
    WinSendMsg( hSrcLB, LM_SELECTITEM,  /* unselect in source list */
                MPFROMSHORT(i), MPFROMSHORT(FALSE) );
  }                                    /* 'for' */

  if (0 == WinSendMsg( hDstLB, LM_QUERYITEMCOUNT, 0L, 0L))
  {
    NoFonts(hDstLB );                   /* clear list box */
  }
                                                    /* disable "Add" button */
  WinEnableWindow( WinWindowFromID( hDB, SF_ADD), FALSE );
  SetPointer( SPTR_ARROW );
  return ;
}

/***************************************************************************
 *
 * FUNCTION NAME = DeleteFonts
 *
 * DESCRIPTION   = Delete selected fonts.
 *
 * INPUT         = (hDB)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID DeleteFonts( HWND hDB )
{
  HWND    hLB;                            /* handle of Installed list box */
  CHAR    szFile[BUF_SIZE];
  PSFTFNT pFont;
  SHORT   i, cLength;

  /*
  ** This will only take a second, but put up the hourglass anyway
  */
  SetPointer( SPTR_WAIT );
  hLB = WinWindowFromID( hDB, SF_LB_INSTALLED );
  WinEnableWindowUpdate(hLB, FALSE );   /* belay updates */

  while (LIT_NONE != (i = (SHORT)WinSendMsg( hLB, LM_QUERYSELECTION,
     MPFROMSHORT(LIT_FIRST), 0L)))
  {
    pFont = WinSendMsg( hLB, LM_QUERYITEMHANDLE, MPFROMSHORT(i), 0L );
    cLength = CopyStr( (PSZ) szFile, (PSZ) pFont->szFilePF );
    DosDelete( szFile );                 /* delete PFA file */
    szFile[cLength-1] = 'M';           /* change string to .PFM */
    DosDelete( szFile );                 /* delete PFM file */
    GlobalFreeMem( (PBYTE)pFont, sizeof(SFTFNT) );
    WinSendMsg( hLB, LM_DELETEITEM, MPFROMSHORT(i), 0L );
  }

  if (0 == WinSendMsg( hLB, LM_QUERYITEMCOUNT, 0L, 0L))
  {
    NoFonts(hLB );                      /* if it's empty, label it so */
  }
  WinEnableWindowUpdate( hLB, TRUE );    /* ok, now you can update display */
                                            /* disable "Delete" button */

  WinEnableWindow(WinWindowFromID( hDB, SF_ERASE), FALSE );
  SetPointer( SPTR_ARROW );
}

/***************************************************************************
 *
 * FUNCTION NAME = FreeListBox
 *
 * DESCRIPTION   = Free up all the memory used by a list box.
 *
 *                 Go through the listbox (from bottom to top, for convenience).
 *                 For each entry, get the handle and free the memory.
 *
 * INPUT         = (hLB)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID FreeListBox( HWND hLB )
{
  SHORT i;

  for (i = (SHORT) WinSendMsg( hLB, LM_QUERYITEMCOUNT, 0L, 0L)-1; i >= 0; i--)
  {
    GlobalFreeMem( (NPBYTE)WinSendMsg( hLB, LM_QUERYITEMHANDLE,
                   MPFROMSHORT(i), 0L), sizeof(SFTFNT) );
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = ExitSFDialog
 *
 * DESCRIPTION   = Clean up and exit Soft Font installer dialog.
 *
 * INPUT         = ExitSFDialog(hDB)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID ExitSFDialog( HWND hDB )
{
  FreeListBox( WinWindowFromID( hDB, SF_LB_SOURCE) ); /* free memory */
  FreeListBox( WinWindowFromID( hDB, SF_LB_INSTALLED) );

  /*
  **  DCR 1476    HlpDestroy((HHELP)WinQueryWindowULong( hDB, 0 ) );
  */

  WinDismissDlg( hDB, TRUE );            /* take me outta here! */
}


/*
** Entry Points
*/
/***************************************************************************
 *
 * FUNCTION NAME = SFDialog
 *
 * DESCRIPTION   = Soft Font Installer Dialog Function, of course.
 *
 * INPUT         = (hDB,wMsg,mp1,mp2)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

MRESULT EXPENTRY SFDialog( HWND hDB, SHORT wMsg, MPARAM mp1, MPARAM mp2 )
{
  #define  usID          SHORT1FROMMP(mp1)

  switch (wMsg)
  {

  /*
  **  DCR 1476
  */
  case HM_QUERY_KEYS_HELP:
       return (MRESULT)IDH_KEYS;

  case WM_INITDLG:
       return (MRESULT)InitSFDialog(hDB );
       break;

  case WM_CONTROL:
       switch (usID)
       {
       case SF_LB_SOURCE:
            if (LN_SELECT == SHORT2FROMMP(mp1))
            {
              EnableButton( hDB, SF_LB_SOURCE, SF_ADD );
            }
            break;

       case SF_LB_INSTALLED:
            if (LN_SELECT == SHORT2FROMMP(mp1))
            {
              EnableButton( hDB, SF_LB_INSTALLED, SF_ERASE );
            }
            break;

       case ID_FONT_SOURCE:
            switch (SHORT2FROMMP(mp1))
            {
            case EN_SETFOCUS:
                 WinSendDlgItemMsg( hDB, DID_OK, BM_SETDEFAULT, MPFROMSHORT(FALSE),
                                    0L );
                 WinSendDlgItemMsg( hDB, SF_OPEN, BM_SETDEFAULT, MPFROMSHORT(TRUE),
                                    0L );
                 break;

            case EN_KILLFOCUS:
                 WinSendDlgItemMsg( hDB, SF_OPEN, BM_SETDEFAULT, MPFROMSHORT(FALSE),
                                    0L );
                 WinSendDlgItemMsg( hDB, DID_OK, BM_SETDEFAULT, MPFROMSHORT(TRUE),
                                    0L );
                 break;
            }                            /* switch mp1 */
       }                                /* switch usId */
       return 0L;
       break;

  case WM_COMMAND:
       switch (usID)
       {
       case SF_OPEN:
            if (CheckFontDir(hDB) == TRUE)
            {
              OpenSource( hDB );
            }
            break;

       case SF_ADD:
            if (CheckFontDir(hDB) == TRUE)
            {
              AddFonts( hDB );
            }
            break;

       case SF_ERASE:
            if (CheckFontDir(hDB) == TRUE)
            {
              DeleteFonts( hDB );
            }
            break;

       case DID_OK:
            ExitSFDialog(hDB );
            break;
       }
       break;

  case WM_SYSCOMMAND:
  default :
       return  (MRESULT) WinDefDlgProc( hDB, wMsg, mp1, mp2 );
  }                                    /* switch msg */
  return (MRESULT)TRUE;
}
#endif
