/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public License
 * Version 1.0 (the "NPL"); you may not use this file except in
 * compliance with the NPL.  You may obtain a copy of the NPL at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the NPL is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
 * for the specific language governing rights and limitations under the
 * NPL.
 *
 * The Initial Developer of this code under the NPL is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
 * Reserved.
 */

#include "stdafx.h"

#include "rosetta.h"
#include "res\appicon.h"
#include "dialog.h"
#include "mainfrm.h"
#include "custom.h"
#include "shcut.h"
#include "edt.h"
#include "prmon.h"
#include "fegui.h"
#include "prefapi.h"
#include <io.h>
#include "secrng.h"
#include "mailmisc.h"
#include "ipframe.h"
#include "mnprefs.h"
#include "secnav.h"
#include "edprops.h"

//xpstrsw header is for resource switcher that will hold the proper instance handle for each stringloaded
#include "xpstrsw.h"

#ifndef _AFXDLL
#define new DEBUG_NEW  // MSVC Debugging new...goes to regular new in release mode
#endif
#ifdef __BORLANDC__
	#define _lseek lseek
#endif
       
MODULE_PRIVATE char * XP_CacheFileName();

static HPALETTE ghPalette = NULL;
static CMapWordToPtr gBitmapMap;
static HFONT ghFont = NULL;

// Load a string, stored as RCDATA, from the resource file. The
// caller must free the pointer that is returned
char *
wfe_LoadResourceString (LPCSTR lpszName)
{
	HRSRC	hrsrc;
	HGLOBAL	hRes;
	LPSTR	lpszString;

	hrsrc = ::FindResource(AfxGetResourceHandle(), lpszName, RT_RCDATA);

	if (!hrsrc) {
		TRACE1("wfe_LoadResourceString cannot find resource: %s\n", lpszName);
		return NULL;
	}

	hRes = ::LoadResource(AfxGetResourceHandle(), hrsrc);

	if (!hRes) {
		TRACE1("wfe_LoadResourceString cannot load resource: %s\n", lpszName);
		return NULL;		
	}

	lpszString = (LPSTR)::LockResource(hRes);

	if (!lpszString) {
		TRACE1("wfe_LoadResourceString cannot lock resource: %s\n", lpszName);
		::FreeResource(hRes);
		return NULL;
	}

	// Return a copy of the string
	lpszString = XP_STRDUP(lpszString);

#ifndef XP_WIN32	
	::UnlockResource(hRes);
#endif
	::FreeResource(hRes);
	return lpszString;
}

#define MAXSTRINGLEN 8192 
// Load a string from resource table
//Added pSwitcher to allow us to dictate which HINSTANCE to load the string from.  if NULL, we use AfxGetResourceHandle
//mjudge 10-30-97
char * szLoadString( UINT iID , ResourceSwitcher *pSwitcher/*=NULL*/)
{
    // These strings MUST be static so they don't live on the stack.  Since we
    // will be returning a pointer to one of these strings, we want the info
    // to be there once we exit this function
    // This implements a circular buffer: its size depends on how many times the
    // szLoadString function will be called in a single function call.  For
    // example, if you do this:
    //
    //   MessageBox ( NULL, 
    //                szLoadString(IDS_ERROR1), 
    //                szLoadString(IDS_MSGBOXTITLE), 
    //                MB_OK );
    //
    // We need at least 2 strings here.  We should be safe with four.

    static int iWhichString = 0;
    static char *szLoadedStrings[4] = { NULL, NULL, NULL, NULL };

	if ( !szLoadedStrings[iWhichString] ) {
		szLoadedStrings[iWhichString] = new char[MAXSTRINGLEN];
	}

    // This implements a circular buffer using the four strings. This means that
    // the pointer you get back from szLoadString will have the correct string in
    // it until szLoadString has been called four more times.

	char *szLoadedString = szLoadedStrings[iWhichString];
    iWhichString = (iWhichString + 1) % 4;

    szLoadedString[0] = 0;  // Init the string to emptyville.

	// This allows loading of strings greater than 255 characters. If the
	// first character of the string is an exclamation point, this means to
	// tack on the string with a value of ID+1.  This continues until
	// the next string does not exist or the first character is not an
	// exclamation point

	// These are just normal local variables used for looping and return values
	// and string magic
	char szLoadBuffer[256];

	BOOL bKeepLoading;
	HINSTANCE hResourceHandle;
	if (NULL== pSwitcher)
		hResourceHandle=AfxGetResourceHandle();
	else
		hResourceHandle=pSwitcher->GetResourceHandle();
	do {
		bKeepLoading = FALSE;
		if (LoadString ( hResourceHandle, iID, szLoadBuffer, sizeof(szLoadBuffer))) {


			if ('!' == *szLoadBuffer) {
				// Continuation char found. Keep the loop going
				bKeepLoading = TRUE;
				// Assume next entry in string table is in numerical order
				iID++;
				strcat ( szLoadedString, szLoadBuffer + 1 );
			} else {
				strcat ( szLoadedString, szLoadBuffer );
			}
		}
	} while (bKeepLoading);

	return szLoadedString;
}

#ifdef XP_WIN16
#define INVALID_HANDLE_VALUE NULL 

//  16 Bit FindFirstFile, second parameter void *b must be of type struct
//   _find_t *.  Return value if successful will just be this same
//   structure, otherwise INVALID_HANDLE_VALUE.

PRIVATE char *cp_filesystems = "\\*.*";

//  See _dos_findfirst on how to read the structure _find_t members.
void * 
FindFirstFile(const char * a, void * b) 
{
  //  First off, our void * coming in is actually a dirStruct.
  auto dirStruct *dSp = (dirStruct *)b;
  
  //  See if the dir we're looking at is a root of a file system; string indicates this.
  //  If so, we have to hack a way to provide drive letters and such in the listing.
  if(XP_STRCMP(a, cp_filesystems) == 0) {
    dSp->c_checkdrive = 'A';
  }
  else  {
    //  +2 because +1 means to return false in find next.
    dSp->c_checkdrive = 'Z' + 2;
  }
  
  //  If we're going after the root, then we have to loop through all the drives until we find one....  Ugh.
  //  The way to tell if we're currently looking for file systems, is if c_checkdrive is a valid drive letter.
  if(dSp->c_checkdrive == 'A')  {
    //  Save the drive we're on currently.
    auto int i_current = _getdrive();
    
    while(dSp->c_checkdrive <= 'Z') {
      //  If we can change to a drive, then it is valid.
      //  I would think that there is a better way to do this, but all the examples that I've seen do this
      //    exact thing.
      if(_chdrive(dSp->c_checkdrive - 'A' + 1) == 0)  {
        break;
      }
      
      //  Drive we checked wasn't valid.  Go on to the next one.
      dSp->c_checkdrive++;
    }
    
    //  Restore the original drive.
    _chdrive(i_current);
    
    //  If we found a valid drive, we need to dup it's name in the findfirst stuff to pass it back in the name field.
    //  Also, increment on to the next drive.
    //  Members of the _find_t data structure aren't set up correctly....  They don't seem to be referenced anywhere,
    //    so I'm not going to bother.
    if(dSp->c_checkdrive <= 'Z')  {
      dSp->file_data.name[0] = dSp->c_checkdrive;
      dSp->file_data.name[1] = '|';
      dSp->file_data.name[2] = '\0';
      
      dSp->c_checkdrive++;
      
      //  Just return b, as it is the void dSp, and we will soon be seeing it again in findnext....
      return(b);
    }
    
    //  If we found no valid drives, then we need to return an invalid state.
    return(INVALID_HANDLE_VALUE);
  }

  //  Specify what type of files you'd like to find.  See _dos_findfirst.
  auto unsigned u_finding = _A_NORMAL | _A_RDONLY | _A_ARCH | _A_SUBDIR;
  
  if(_dos_findfirst(a, u_finding, &(dSp->file_data)) == 0)  {
    //  Success, just return the structure containing the info.
    //  b should not be altered!  Only read information from the
    //  structure.

    return(b);
  }
  
  return(INVALID_HANDLE_VALUE);
}

int 
FindNextFile(void * a, void * b)
{
  //  a and b are actually the same.
  //  Check to see if we are still searching drives from findfirst.
  auto dirStruct *dSp = (dirStruct *)a;
  
  if(dSp->c_checkdrive <= 'Z')  {
    //  Save the drive we're on currently.
    auto int i_current = _getdrive();
    
    while(dSp->c_checkdrive <= 'Z') {
      //  If we can change to a drive, then it is valid.
      if(_chdrive(dSp->c_checkdrive - 'A' + 1) == 0)  {
        break;
      }
      
      //  Drive we checked wasn't valid.  Go on to the next one.
      dSp->c_checkdrive++;
    }
    
    //  Restore the original drive.
    _chdrive(i_current);
    
    //  If we found a valid drive, we need to dup it's name in the findfirst stuff to pass it back in the name field.
    //  Also, increment on to the next drive.
    //  Members of the _find_t data structure aren't set up correctly....  They don't seem to be referenced anywhere,
    //    so I'm not going to bother.
    if(dSp->c_checkdrive <= 'Z')  {
      dSp->file_data.name[0] = dSp->c_checkdrive;
      dSp->file_data.name[1] = '|';
      dSp->file_data.name[2] = '\0';
      
      dSp->c_checkdrive++;
      
      //  Just return as findnext
      return(TRUE);
    }
  }
  
  if(dSp->c_checkdrive == 'Z' + 1)  {
    //  Special case where we will stop looking for file systems to list.  Return as though we failed.
    return(FALSE);
  }

  //  Just call _dos_findnext with a, since a and b are actually the
  //  same.  Return true if successful.
  if(_dos_findnext(&(dSp->file_data)) == 0) {
    return(TRUE);
  }
  return(FALSE);
} 

void 
FindClose(void * a)
{
  //  Do nothing.  It's up to the caller to get rid of *a since we
  //  created nothing.
}

#endif

//
// Return a string the same as the In string but with all of the \n's replaced
//  with \r\n's 
//
MODULE_PRIVATE char * 
FE_Windowsify(const char * In)
{
    char *Out;
    char *o, *i; 
    int32 len;

    if(!In)
        return NULL;

    // if every character is a \n then new string is twice as long
    len = (int32) XP_STRLEN(In) * 2 + 1;
    Out = (char *) XP_ALLOC(len);
    if(!Out)
        return NULL;

  // Move the characters over one by one.  If the current character is
  //  a \n replace add a \r before moving the \n over
    for(i = (char *) In, o = Out; i && *i; *o++ = *i++)
       if(*i == '\n')
            *o++ = '\r';

    // Make sure our new string is NULL terminated
    *o = '\0';
    return(Out);
}

// middle cuts string into a string of iNum length.  If bModifyString is
// FALSE (the default), a copy is made which the caller must free
PUBLIC char * fe_MiddleCutString(char *pString ,int iNum, BOOL bModifyString)
{
	ASSERT(pString);
	if (!pString)
		return NULL;

	// If the caller wants us to allocate a new string, just dup the string
	// that was passed in since the result can't be any longer
	if (!bModifyString) {
		pString = strdup(pString);

		if (!pString) {
			TRACE0("fe_MiddleCutString: strdup failed!\n");
			return NULL;
		}
	}

	// Make sure the length to cut to is something sensible
	ASSERT(iNum > 3);
	if (iNum <= 3)
		return pString;  // don't bother...

	// We need to call i18n function for multibyte charset (e.g. Japanese SJIS)
	//
	int16 csid = CIntlWin::GetSystemLocaleCsid();
	if (csid & MULTIBYTE) {
		INTL_MidTruncateString (csid, pString, pString, iNum);
		return pString;
	}

	// See if there is any work to do
	int	nLen = strlen(pString);

	if (nLen > iNum) {
		int	nLeftChars = (iNum - 3) / 2;
		int	nRightChars = iNum - 3 - nLeftChars;

		// Insert the ellipsis
		pString[nLeftChars] = '.';
		pString[nLeftChars + 1] = '.';
		pString[nLeftChars + 2] = '.';

		// Use the right "nRightChars" characters
		strcpy(pString + nLeftChars + 3, pString + nLen - nRightChars);
	}

	return pString;
}

/* puts up a FE security dialog
 *
 * Should return TRUE if the url should continue to
 * be loaded
 * Should return FALSE if the url should be aborted
 */
PUBLIC Bool  
FE_SecurityDialog(MWContext * context, int message, XP_Bool *prefs_toggle)
{

    if (theApp.m_bKioskMode)
        return TRUE;

    if(context) {
		CDialogSecurity box(message, prefs_toggle, ABSTRACTCX(context)->GetDialogOwner());
	return(box.DoModal());
    } else {
        CDialogSecurity box(message, prefs_toggle, NULL);
	return(box.DoModal());
    }
}

// Save the cipher preference to the preferences file
// XXX - jsw - remove me
extern "C" void
FE_SetCipherPrefs(MWContext *context, char *cipher)
{
}

// Retrieve the cipger preferences. The caller is expected to free
// the returned string
// XXX - jsw - remove me
extern "C" char *
FE_GetCipherPrefs(void)
{
	return NULL;
}

//  Return some spanked out full path on the mac.
//  For windows, we just return what was passed in.
//  We must provide it in a seperate buffer, otherwise they might change
//      the original and change also what they believe to be saved.
extern "C"  char *WH_FilePlatformName(const char *pName)    {

    if(pName)   {
        return XP_STRDUP(pName);
    }
    
    return NULL;
}

/* char ch;				// Byte, not Character, to be located
 * const char* cpStr;	// Null-terminated string
 * uint16 iCSID;		// file system id or win_csid
 * jliu@09/08/97
 */
char* intl_strrchr( char* cpStr, char ch, uint16 iCSID )
{
	if( cpStr == NULL || *cpStr == NULL )
		return NULL;

	if( ( iCSID & MULTIBYTE ) == 0  || ( ch & 0x80 ) != 0 )
		return strrchr( cpStr, ch );

	char* cpLastChar = NULL;

	while( *cpStr != NULL ){
		if( *cpStr == ch )
			cpLastChar = cpStr++;
		else if( ( *cpStr & 0x80 ) == 0 )
			cpStr++;
		else
			cpStr = INTL_NextChar( iCSID, cpStr );
	}

	return cpLastChar;
}

/* const char* cpStr;	// Null-terminated string
 * uint16 iCSID;		// file system id or win_csid
 * jliu@09/08/97
 */
BOOL intl_IsEndWithBS( char* cpStr, uint16 iCSID )
{
	if( cpStr == NULL || *cpStr == NULL )
		return FALSE;

	int len = strlen( cpStr );	// how many bytes in cpStr
	if( cpStr[len-1] != '\\' )
		return FALSE;

	if( ( iCSID & MULTIBYTE ) == 0 )
		return TRUE;

	char* cpLastChar = NULL;
	while( *cpStr != NULL ){
		cpLastChar = cpStr;
		cpStr = INTL_NextChar( iCSID, cpStr );
	}

	return *cpLastChar == '\\';
}

extern "C" char *
FE_GetProgramDirectory(char *buffer, int length)
{
	::GetModuleFileName(theApp.m_hInstance, buffer, length);

	//	Find the trailing slash.
	//  char *pSlash = ::strrchr(buffer, '\\');
	char* pSlash = intl_strrchr( buffer, '\\', CIntlWin::GetSystemLocaleCsid() );
	if(pSlash)	{
		*(pSlash+1) = '\0';
	}
	else	{
		buffer[0] = '\0';
	}
    return (buffer);
}


char*
XP_TempDirName(void)
{
    char *tmp = theApp.m_pTempDir;
    if (!tmp)
        return XP_STRDUP(".");
    return XP_STRDUP(tmp);
}

// Windows _tempnam() lets the TMP environment variable override things sent in
//  so it look like we're going to have to make a temp name by hand
//
// The user should *NOT* free the returned string.  It is stored in static space
//  and so is not valid across multiple calls to this function
//
// The names generated look like
//   c:\netscape\cache\m0.moz
//   c:\netscape\cache\m1.moz
// up to...
//   c:\netscape\cache\m9999999.moz
// after that if fails
//
PUBLIC char *
xp_TempFileName(int type, const char * request_prefix, const char * extension,
				char* file_buf)
{
  const char * directory = NULL; 
  char * ext = NULL;           // file extension if any
  char * prefix = NULL;        // file prefix if any
  XP_Bool bDirSlash = FALSE;
  
  XP_StatStruct statinfo;
  int status;     

  //
  // based on the type of request determine what directory we should be
  //   looking into
  //  
  switch(type) {
    case xpCache:
        directory = theApp.m_pCacheDir;
        ext = ".MOZ";
        prefix = CACHE_PREFIX;
        break;
#ifdef MOZ_MAIL_NEWS        
	case xpSNewsRC:
	case xpNewsRC:
    case xpNewsgroups:
    case xpSNewsgroups:
    case xpTemporaryNewsRC:
        directory = g_MsgPrefs.m_csNewsDir;
        ext = (char *)extension;
        prefix = (char *)request_prefix;
        break;
	case xpMailFolderSummary:
	case xpMailFolder:
		directory = g_MsgPrefs.m_csMailDir;
        ext = (char *)extension;
        prefix = (char *)request_prefix;
		break;
	case xpAddrBook:
		//changed jonm-- to support multi-profile
		//directory = theApp.m_pInstallDir->GetCharValue();
		directory = (const char *)theApp.m_UserDirectory;
		if ((request_prefix == 0) || (XP_STRLEN (request_prefix) == 0))
			prefix = "abook";
		ext = ".nab";
		break;
#endif // MOZ_MAIL_NEWS
	case xpCacheFAT:
		directory = theApp.m_pCacheDir;
		prefix = "fat";
		ext = "db";
		break;
	case xpJPEGFile:
        directory = theApp.m_pTempDir;
		ext = ".jpg";
        prefix = (char *)request_prefix;
		break;
	case xpPKCS12File:
		directory = theApp.m_pTempDir;
		ext = ".p12";
		prefix = (char *)request_prefix;
		break;
    case xpURL:
      {
         if (request_prefix)
         {
            if ( XP_STRRCHR(request_prefix, '/') )
            {
               const char *end;
               XP_StatStruct st;

               directory = (char *)request_prefix;
               end = directory + XP_STRLEN(directory) - 1;
               if ( *end == '/' || *end == '\\' ) {
                 bDirSlash = TRUE;
               }
               if (XP_Stat (directory, &st, xpURL))
                  XP_MakeDirectoryR (directory, xpURL);
               ext = (char *)extension;
               prefix = (char *)"su";
               break;
            }
        }
        // otherwise, fall through
      }
    case xpTemporary:
    default:
        directory = theApp.m_pTempDir;
        ext = (char *)extension;
        prefix = (char *)request_prefix;
        break;
    }

  if(!directory)
    return(NULL);

  if(!prefix)
    prefix = "X";

  if(!ext)
    ext = ".TMP";

  //  We need to base our temporary file names on time, and not on sequential
  //    addition because of the cache not being updated when the user
  //    crashes and files that have been deleted are over written with
  //    other files; bad data.
  //  The 52 valid DOS file name characters are
  //    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_^$~!#%&-{}@`'()
  //  We will only be using the first 32 of the choices.
  //
  //  Time name format will be M+++++++.MOZ
  //    Where M is the single letter prefix (can be longer....)
  //    Where +++++++ is the 7 character time representation (a full 8.3
  //      file name will be made).
  //    Where .MOZ is the file extension to be used.
  //
  //  In the event that the time requested is the same time as the last call
  //    to this function, then the current time is incremented by one,
  //    as is the last time called to facilitate unique file names.
  //  In the event that the invented file name already exists (can't
  //    really happen statistically unless the clock is messed up or we
  //    manually incremented the time), then the times are incremented
  //    until an open name can be found.
  //
  //  time_t (the time) has 32 bits, or 4,294,967,296 combinations.
  //  We will map the 32 bits into the 7 possible characters as follows:
  //    Starting with the lsb, sets of 5 bits (32 values) will be mapped
  //      over to the appropriate file name character, and then
  //      incremented to an approprate file name character.
  //    The left over 2 bits will be mapped into the seventh file name
  //      character.
  //
  
  int i_letter, i_timechars, i_numtries = 0;
  char ca_time[8];
  time_t this_call = (time_t)0;
  
  //  We have to base the length of our time string on the length
  //    of the incoming prefix....
  //
  i_timechars = 8 - strlen(prefix);
  
  //  Infinite loop until the conditions are satisfied.
  //  There is no danger, unless every possible file name is used.
  //
  while(1)  {
    //    We used to use the time to generate this.
    //    Now, we use some crypto to avoid bug #47027
    RNG_GenerateGlobalRandomBytes((void *)&this_call, sizeof(this_call));

    //  Convert the time into a 7 character string.
    //  Strip only the signifigant 5 bits.
    //  We'll want to reverse the string to make it look coherent
    //    in a directory of file names.
    //
    for(i_letter = 0; i_letter < i_timechars; i_letter++) {
      ca_time[i_letter] = (char)((this_call >> (i_letter * 5)) & 0x1F);
      
      //  Convert any numbers to their equivalent ascii code
      //
      if(ca_time[i_letter] <= 9)  {
        ca_time[i_letter] += '0';
      }
      //  Convert the character to it's equivalent ascii code
      //
      else  {
        ca_time[i_letter] += 'A' - 10;
      }
    }
    
    //  End the created time string.
    //
    ca_time[i_letter] = '\0';
    
    //  Reverse the time string.
    //
    _strrev(ca_time);
    
    //  Create the fully qualified path and file name.
    //
    if (bDirSlash)
      sprintf(file_buf, "%s%s%s%s", directory, prefix, ca_time, ext);
    else
      sprintf(file_buf, "%s\\%s%s%s", directory, prefix, ca_time, ext);

    //  Determine if the file exists, and mark that we've tried yet
    //    another file name (mark to be used later).
    //  
	//  Use the system call instead of XP_Stat since we already
	//  know the name and we don't want recursion
	//
	status = _stat(file_buf, &statinfo);
    i_numtries++;
    
    //  If it does not exists, we are successful, return the name.
    //
    if(status == -1)  {
      /* don't generate a directory as part of the 
       * cache temp names.  When the cache file name
       * is passed into the other XP_File functions
       * we will append the cache directory to the name
       * to get the complete path.
       * This will allow the cache to be moved around
       * and for netscape to be used to generate external
       * cache FAT's.  :lou
       */
      if(type == xpCache )
          sprintf(file_buf, "%s%s%s", prefix, ca_time, ext);

//      TRACE("Temp file name is %s\n", file_buf);
      return(file_buf);
    }
    
    //  If there is no room for additional characters in the time,
    //    we'll have to return NULL here, or we go infinite.
    //    This is a one case scenario where the requested prefix is
    //    actually 8 letters long.
    //  Infinite loops could occur with a 7, 6, 5, etc character prefixes
    //    if available files are all eaten up (rare to impossible), in
    //    which case, we should check at some arbitrary frequency of
    //    tries before we give up instead of attempting to Vulcanize
    //    this code.  Live long and prosper.
    //
    if(i_timechars == 0)  {
      break;
    }
    else if(i_numtries == 0x00FF) {
      break;
    }
  }
  
  //  Requested name is thought to be impossible to generate.
  //
  TRACE("No more temp file names....\n");
  return(NULL);
  
}

PUBLIC char *
WH_TempFileName(int type, const char * request_prefix, const char * extension)
{
	static char file_buf[_MAX_PATH];		/* protected by _pr_TempName_lock */
	char* result;
#ifdef NSPR
	XP_ASSERT(_pr_TempName_lock);
	PR_EnterMonitor(_pr_TempName_lock);
#endif
	result = XP_STRDUP(xp_TempFileName(type, request_prefix, extension, file_buf));
#ifdef NSPR
	PR_ExitMonitor(_pr_TempName_lock);
#endif
	return result;
}

//
// Return a string that is equal to the NetName string but with the
//  cross-platform characters changed back into DOS characters
// The caller is responsible for XP_FREE()ing the return string
//
MODULE_PRIVATE char * 
XP_NetToDosFileName(const char * NetName)
{
    char *p, *newName;

    if(!NetName)
        return NULL;
        
    //  If the name is only '/' or begins '//' keep the
	//    whole name else strip the leading '/'
	BOOL bChopSlash = FALSE;

    if(NetName[0] == '/')
        bChopSlash = TRUE;

	// save just / as a path
	if(NetName[0] == '/' && NetName[1] == '\0')
		bChopSlash = FALSE;

	// spanky Win9X path name
	if(NetName[0] == '/' && NetName[1] == '/')
		bChopSlash = FALSE;

    if(bChopSlash)
        newName = XP_STRDUP(&(NetName[1]));
    else
        newName = XP_STRDUP(NetName);

    if(!newName)
        return NULL;

	if( newName[1] == '|' )
		newName[1] = ':';

    for(p = newName; *p; p++){
		if( *p == '/' )
			*p = '\\';
	}

    return(newName);

}

/* implement an lseek using _lseek that
 * writes zero's when extending a file
 * beyond the end.
 * This function attemps to override
 * the standard lseek.
 */
extern "C" long wfe_lseek(int fd, long offset, int origin)
{
 	long cur_pos;
	long end_pos;
	long seek_pos;

	if(origin == SEEK_CUR)
      {	
      	if(offset < 1)							  
	    	return(_lseek(fd, offset, SEEK_CUR));

		cur_pos = _lseek(fd, 0, SEEK_CUR);

		if(cur_pos < 0)
			return(cur_pos);
	  }
										 
	end_pos = _lseek(fd, 0, SEEK_END);
	if(end_pos < 0)
		return(end_pos);

	if(origin == SEEK_SET)
		seek_pos = offset;
	else if(origin == SEEK_CUR)
		seek_pos = cur_pos + offset;
	else if(origin == SEEK_END)
		seek_pos = end_pos + offset;
 	else
	  {
	  	assert(0);
		return(-1);
	  }

 	/* the seek position desired is before the
	 * end of the file.  We don't need
	 * to do anything special except the seek.
	 */
 	if(seek_pos <= end_pos)
 		return(_lseek(fd, seek_pos, SEEK_SET));
 		
 	/* the seek position is beyond the end of the
 	 * file.  Write zero's to the end.
 	 *
	 * we are already at the end of the file so
	 * we just need to "write()" zeros for the
	 * difference between seek_pos-end_pos and
	 * then seek to the position to finish
	 * the call
 	 */
 	{ 
 	 	char buffer[1024];
	   	long len = seek_pos-end_pos;
	   	memset(&buffer, 0, 1024);
	   	while(len > 0)
	      {
	        write(fd, &buffer, CASTINT((1024 > len ? len : 1024)));
		    len -= 1024L;
		  }
		return(_lseek(fd, seek_pos, SEEK_SET));
  	}		

 }
//
// Returns the absolute name of a file 
// 
// The result of this function can be used with the standard
// open/fopen ansi file functions
// The caller is responsible for XP_FREE()ing the string -*myName
//
PUBLIC char * 
xp_FileName(const char * name, XP_FileType type, char* *myName)
{
	uint16 iFileSystemCSID = CIntlWin::GetSystemLocaleCsid();	// this file system csid, not win_csid
	char * newName = NULL;
    char * netLibName = NULL;
    BOOL   bNeedToRegister = FALSE;   // == do we need to register a new 
                                      //   newshost->file name mapping
	char * prefStr = NULL;
    CString csHostName;
    CString csHost;
    struct _stat sInfo;
    int iDot;
    int iColon;

	CString fileName;
	char* tempName = NULL;

	switch(type) {
	case xpCacheFAT:
		newName = (char *) XP_ALLOC(_MAX_PATH);
		sprintf(newName, "%s\\fat.db", (const char *)theApp.m_pCacheDir);
		break;
	case xpExtCacheIndex:
		newName = (char *) XP_ALLOC(_MAX_PATH);
		sprintf(newName, "%s\\extcache.fat", (const char *)theApp.m_pCacheDir);
		break;

    // larubbio
    case xpSARCacheIndex:
        newName = (char *) XP_ALLOC(_MAX_PATH);
        sprintf(newName, "%s\\archive.fat", theApp.m_pSARCacheDir);
        break;

	case xpHTTPCookie:
		newName = (char *) XP_ALLOC(_MAX_PATH);
		//sprintf(newName, "%s\\cookies.txt", theApp.m_pInstallDir->GetCharValue());
		// changed -- jonm to support multi-profile
		sprintf(newName, "%s\\cookies.txt", (const char *)theApp.m_UserDirectory);
		break;

#if defined(CookieManagement)
	case xpHTTPCookiePermission:
		newName = (char *) XP_ALLOC(_MAX_PATH);
                //sprintf(newName, "%s\\cookperm.txt", theApp.m_pInstallDir->GetCharValue());
		// changed -- jonm to support multi-profile
                sprintf(newName, "%s\\cookperm.txt", (const char *)theApp.m_UserDirectory);
		break;
#endif

#if defined(SingleSignon)
	case xpHTTPSingleSignon:
		newName = (char *) XP_ALLOC(_MAX_PATH);
                //sprintf(newName, "%s\\signons.txt", theApp.m_pInstallDir->GetCharValue());
		// changed -- jonm to support multi-profile
                sprintf(newName, "%s\\signons.txt", (const char *)theApp.m_UserDirectory);
		break;
#endif

#ifdef MOZ_MAIL_NEWS      
	case xpSNewsRC:
	case xpNewsRC:
        // see if we are asking about the default news host
        // else look up in netlib
        if ( !name || !strlen(name) )
            name = g_MsgPrefs.m_csNewsHost;

        netLibName = NET_MapNewsrcHostToFilename((char *)name, 
                                                 (type == xpSNewsRC),
                                                 FALSE);
        
        // if we found something in our map just skip the rest of this stuff
        if(netLibName && *netLibName) {
            newName = XP_STRDUP(netLibName);
            break;
        }

        // whatever name we eventually end up with we will need to register it
        //   before we leave the function
        bNeedToRegister = TRUE;

        // If we are on the default host see if there is a newsrc file in the
        //   news directory.  If so, that is what we want
        if(!stricmp(name, g_MsgPrefs.m_csNewsHost)) {
            csHostName = g_MsgPrefs.m_csNewsDir;
            csHostName += "\\newsrc";
            if(_stat((const char *) csHostName, &sInfo) == 0) {
                newName = XP_STRDUP((const char *) csHostName);
                break;
            }
        }
                        
        // See if we are going to be able to build a file name based 
        //   on the hostname
        csHostName = g_MsgPrefs.m_csNewsDir;
        csHostName += '\\';

        // build up '<hostname>.rc' so we can tell how long its going to be
        //   we will use that as the default name to try
		if(type == xpSNewsRC)
			csHost += 's';
        csHost += name;

        // if we have a news host news.foo.com we just want to use the "news"
        //   part
        iDot = csHost.Find('.');
        if(iDot != -1)
            csHost = csHost.Left(iDot);

#ifdef XP_WIN16
        if(csHost.GetLength() > 8)
            csHost = csHost.Left(8);
#endif

		iColon = csHost.Find(':');
		if (iColon != -1) {
			// Windows file system seems to do horrid things if you have
			// a filename with a colon in it.
			csHost = csHost.Left(iColon);
		}

        csHost += ".rc";

        // csHost is now of the form <hostname>.rc and is in 8.3 format
        //   if we are on a Win16 box

        csHostName += csHost;

        // looks like a file with that name already exists -- panic
        if(_stat((const char *) csHostName, &sInfo) != -1) {
            
            char host[5];

            // else generate a new file in news directory
            strncpy(host, name, 4);
            host[4] = '\0';

            newName = WH_TempFileName(type, host, ".rc");
            if(!newName)
                return(NULL);

        } else {

            newName = XP_STRDUP((const char *) csHostName);

        }

 		break;
	case xpNewsrcFileMap:
        // return name of FAT file in news directory
		newName = (char *) XP_ALLOC(_MAX_PATH);
		sprintf(newName, "%s\\fat", (const char *)g_MsgPrefs.m_csNewsDir);
		break;
	case xpNewsgroups:
	case xpSNewsgroups:
        // look up in netlib
        if ( !name || !strlen(name) )
            name = g_MsgPrefs.m_csNewsHost;

        netLibName = NET_MapNewsrcHostToFilename((char *)name, 
                                                 (type == xpSNewsgroups),
                                                 TRUE);

        if(!netLibName) {

            csHostName = g_MsgPrefs.m_csNewsDir;
            csHostName += '\\';

			if(type == xpSNewsgroups)
				csHost += 's';
            csHost += name;

            // see if we can just use "<hostname>.rcg"
            // it might be news.foo.com so just take "news"
            int iDot = csHost.Find('.');
            if(iDot != -1)
                csHost = csHost.Left(iDot);

#ifdef XP_WIN16
            if(csHost.GetLength() > 8)
                csHost = csHost.Left(8);
#endif

			iColon = csHost.Find(':');
			if (iColon != -1) {
				// Windows file system seems to do horrid things if you have
				// a filename with a colon in it.
				csHost = csHost.Left(iColon);
			}

            csHost += ".rcg";

            // csHost is now of the form <hostname>.rcg

            csHostName += csHost;

            // looks like a file with that name already exists -- panic
            if(_stat((const char *) csHostName, &sInfo) != -1) {
                
                char host[5];

                // else generate a new file in news directory
                strncpy(host, name, 4);
                host[4] = '\0';

                newName = WH_TempFileName(type, host, ".rcg");
                if(!newName)
                    return(NULL);

            } else {

                newName = XP_STRDUP((const char *) csHostName);

            }

            if ( !name || !strlen(name))
                NET_RegisterNewsrcFile(newName,(char *)(const char *)g_MsgPrefs.m_csNewsHost,
                    (type == xpSNewsgroups), TRUE );
            else
                NET_RegisterNewsrcFile(newName,(char*)name,(type == xpSNewsgroups), TRUE );

        } else {

            newName = XP_STRDUP(netLibName);

        }
        break;
	case xpMimeTypes:
		name = NULL;
		break;
#endif // MOZ_MAIL_NEWS
	case xpGlobalHistory:
		newName = (char *) XP_ALLOC(_MAX_PATH);
		// changed -- jonm to support multi-profile
		sprintf(newName, "%s\\%s.hst", (const char *)theApp.m_UserDirectory, XP_AppName);
		break;
    case xpGlobalHistoryList:
        newName = (char *) XP_ALLOC(_MAX_PATH);
        sprintf( newName, "%s\\ns_hstry.htm" );
        break;
	case xpKeyChain:
		name = NULL;
		break;

      /* larubbio */
      case xpSARCache:
        if(!name) {
                      return NULL;
              }
              newName = (char *) XP_ALLOC(_MAX_PATH);
              sprintf(newName, "%s\\%s", theApp.m_pSARCacheDir, name);
              break;

	case xpCache:
        if(!name) {
            tempName = WH_TempFileName(xpCache, NULL, NULL);
			if (!tempName) return NULL;
			name = tempName;
		}
        newName = (char *) XP_ALLOC(_MAX_PATH);
        if ((strchr(name,'|')  || strchr(name,':')))  { // Local File URL if find a |
            if(name[0] == '/')
            	strcpy(newName,name+1); // skip past extra slash
			else
				strcpy(newName,name); // absolute path is valid
        } else {
        	sprintf(newName, "%s\\%s", (const char *)theApp.m_pCacheDir, name);
		}
        break;
    case xpBookmarks:
	case xpHotlist: 
		if (!name || !strlen(name)) 
			name = theApp.m_pBookmarkFile;
		break;
	case xpSocksConfig:
		prefStr = NULL;
		PREF_CopyCharPref("browser.socksfile_location",&prefStr);
		name = prefStr;
		break;		
	case xpCertDB:
        newName = (char *) XP_ALLOC(_MAX_PATH);
        if ( name ) {
			sprintf(newName, "%s\\cert%s.db", (const char *)theApp.m_UserDirectory, name);
        } else {
			sprintf(newName, "%s\\cert.db", (const char *)theApp.m_UserDirectory);
        }
		break;
	case xpCertDBNameIDX:
        newName = (char *) XP_ALLOC(_MAX_PATH);
		sprintf(newName, "%s\\certni.db", (const char *)theApp.m_UserDirectory);
		break;
	case xpKeyDB:
        newName = (char *) XP_ALLOC(_MAX_PATH);
	if ( name ) {
	  sprintf(newName, "%s\\key%s.db", (const char *)theApp.m_UserDirectory, name);
	} else {
	  sprintf(newName, "%s\\key.db", (const char *)theApp.m_UserDirectory);
	}
		break;
	case xpSecModuleDB:
        newName = (char *) XP_ALLOC(_MAX_PATH);
		sprintf(newName, "%s\\secmod.db", (const char *)theApp.m_UserDirectory);
		break;
	case xpSignedAppletDB:
        newName = (char *) XP_ALLOC(_MAX_PATH);
	if ( name ) {
	  sprintf(newName, "%s\\signed%s.db", (const char *)theApp.m_UserDirectory, name);
	} else {
	  sprintf(newName, "%s\\signed.db", (const char *)theApp.m_UserDirectory);
	}
		break;
#ifdef MOZ_MAIL_NEWS      
	case xpAddrBook:
		{
#ifdef XP_WIN16
        if(!name || !strlen(name) )
            newName = WH_TempName(type, NULL);
#else
            newName = (char *) XP_ALLOC(_MAX_PATH);
            strcpy(newName, name);

            // strip off the extension
            char * pEnd = max(strrchr(newName, '\\'), strrchr(newName, '/'));
            if(!pEnd)
				pEnd = newName;

            pEnd = strchr(pEnd, '.');
			if(pEnd)
				*pEnd = '\0';
            strcat(newName, ".nab");
#endif
		}		
        break;
		case xpAddrBookNew:
		{
			newName = (char *) XP_ALLOC(_MAX_PATH);
			sprintf(newName, "%s\\%s", (const char *)theApp.m_UserDirectory, name);
			break;
		}		
        break;
		case xpVCardFile:
		{
            newName = (char *) XP_ALLOC(_MAX_PATH);
            strcpy(newName, name);

            // strip off the extension
            char * pEnd = max(strrchr(newName, '\\'), strrchr(newName, '/'));
            if(!pEnd)
				pEnd = newName;

            pEnd = strchr(pEnd, '.');
			if(pEnd)
				*pEnd = '\0';
            strcat(newName, ".vcf");
		}		
        break;
	case xpLDIFFile:
		{
            newName = (char *) XP_ALLOC(_MAX_PATH);
            strcpy(newName, name);

            // strip off the extension
            char * pEnd = max(strrchr(newName, '\\'), strrchr(newName, '/'));
            if(!pEnd)
				pEnd = newName;

            pEnd = strchr(pEnd, '.');
			if(pEnd)
				*pEnd = '\0';
#ifdef XP_WIN16
			strcat(newName, ".ldi");
#else
            strcat(newName, ".ldif");
#endif
		}		
        break;
	case xpTemporaryNewsRC:
        {
            CString csHostName = g_MsgPrefs.m_csNewsDir;
            csHostName += "\\news.tmp";
            newName = XP_STRDUP((const char *) csHostName);
        }
        break;
#endif // MOZ_MAIL_NEWS        
    case xpPKCS12File:
		{
            newName = (char *) XP_ALLOC(_MAX_PATH);
            strcpy(newName, name);

            // strip off the extension
            char * pEnd = max(strrchr(newName, '\\'), strrchr(newName, '/'));
            if(!pEnd)
				pEnd = newName;

            pEnd = strchr(pEnd, '.');
			if(pEnd)
				*pEnd = '\0';
            strcat(newName, ".p12");
		}		
		break;	
    case xpTemporary:
        if(!name || !strlen(name) )
            newName = WH_TempName(type, NULL);
        break;
#ifdef MOZ_MAIL_NEWS        
    case xpMailFolder:
		if(!name)
		    name = g_MsgPrefs.m_csMailDir;
        break;
	case xpMailFolderSummary:
        {
            newName = (char *) XP_ALLOC(_MAX_PATH);
            strcpy(newName, name);

            // strip off the extension
            char * pEnd = max(strrchr(newName, '\\'), strrchr(newName, '/'));
            if(!pEnd)
                pEnd = newName;

#ifdef XP_WIN16	// backend won't allow '.' in win16 folder names, but just to be safe.
            pEnd = strchr(pEnd, '.');
            if(pEnd)
                *pEnd = '\0';
#endif
            strcat(newName, ".snm");
        }
		break;
	case xpMailSort:
        newName = (char *) XP_ALLOC(_MAX_PATH);
		// if name is not null or empty, it's probably the host name for the imap server.
		// This will need to be extended to support per publc folder filters
		if (name && strlen(name) > 0)
			sprintf(newName, "%s\\ImapMail\\%s\\rules.dat", (const char *)theApp.m_UserDirectory, name);
		else
			sprintf(newName, "%s\\rules.dat", (const char *)g_MsgPrefs.m_csMailDir);
		break;
	case xpNewsSort:
		newName = (char *) XP_ALLOC(_MAX_PATH);
	    sprintf(newName, "%s\\%s", (const char *)g_MsgPrefs.m_csNewsDir, name);
		break;
	case xpMailFilterLog:
		newName = (char *) XP_ALLOC(_MAX_PATH);
		sprintf(newName, "%s\\mailfilt.log", (const char *)g_MsgPrefs.m_csMailDir);
		break;
	case xpNewsFilterLog:
		newName = (char *) XP_ALLOC(_MAX_PATH);
		sprintf(newName, "%s\\newsfilt.log", (const char *)g_MsgPrefs.m_csNewsDir);
		break;
	case xpMailPopState:
        newName = (char *) XP_ALLOC(_MAX_PATH);
        sprintf(newName, "%s\\popstate.dat", (const char *)g_MsgPrefs.m_csMailDir);
		break;
	case xpMailSubdirectory:
        {
            newName = (char *) XP_ALLOC(_MAX_PATH);
            strcpy(newName, name);

            // strip off the trailing slash if any
            char * pEnd = max(strrchr(newName, '\\'), strrchr(newName, '/'));
            if(!pEnd)
                pEnd = newName;

            strcat(newName, ".sbd");
        }
		break;
#endif // MOZ_MAIL_NEWS      
    // name of global cross-platform registry
    case xpRegistry:
        // eventually need to support arbitrary names; this is the default
        newName = (char *) XP_ALLOC(_MAX_PATH);
        if ( newName != NULL ) {
            GetWindowsDirectory(newName, _MAX_PATH);
            int namelen = strlen(newName);
            //if ( newName[namelen-1] == '\\' )
            if( intl_IsEndWithBS( newName, iFileSystemCSID ) )
                namelen--;
            strcpy(newName+namelen, "\\nsreg.dat");
        }
        break;
	// name of news group database 
#ifdef MOZ_MAIL_NEWS   
	case xpXoverCache:
		newName = (char *) XP_ALLOC(_MAX_PATH);
	    sprintf(newName, "%s\\%s", (const char *)g_MsgPrefs.m_csNewsDir, name);
	    break;
#endif // MOZ_MAIL_NEWS
	case xpProxyConfig:
        newName = (char *) XP_ALLOC(_MAX_PATH);
        //sprintf(newName, "%s\\proxy.cfg", theApp.m_pInstallDir->GetCharValue());
		sprintf(newName, "%s\\proxy.cfg", (const char *)theApp.m_UserDirectory);
		break;

    // add any cases where no modification is necessary here 	
    // The name is fine all by itself, no need to modify it 
	case xpFileToPost:
	case xpExtCache:
    case xpURL:
        // name is OK as it is
		break;
#ifdef MOZ_MAIL_NEWS      
	case xpNewsHostDatabase:
		newName = (char *) XP_ALLOC(_MAX_PATH);
		sprintf(newName, "%s\\news.db", (const char *)g_MsgPrefs.m_csNewsDir);
		break;

	case xpImapRootDirectory:
		newName = PR_smprintf ("%s\\ImapMail", (const char *)theApp.m_UserDirectory);
		break;
	case xpImapServerDirectory:
		{
			int len = 0;
			char *tempImapServerDir = XP_STRDUP(name);
			char *imapServerDir = tempImapServerDir;
#ifdef XP_WIN16
			// first, truncate it to 8 characters
			if ((len = XP_STRLEN(imapServerDir)) > 8) {
				imapServerDir = imapServerDir + len - 8;
			}

			// Now, replace all illegal characters with '_'
			const char *illegalChars = "\"/\\[]:;=,|?<>*$. ";
			for (char *possibleillegal = imapServerDir; *possibleillegal; )
				if (XP_STRCHR(illegalChars, *possibleillegal) || ((unsigned char)*possibleillegal < 31) )
					*possibleillegal++ = '_';
				else
					possibleillegal = INTL_NextChar( iFileSystemCSID, possibleillegal );
#endif
			newName = PR_smprintf ("%s\\ImapMail\\%s", (const char *)theApp.m_UserDirectory, imapServerDir);
			if (tempImapServerDir) XP_FREE(tempImapServerDir);
		}
	break;

	case xpJSMailFilters:
		newName = PR_smprintf("%s\\filters.js", (const char *)g_MsgPrefs.m_csMailDir);
		break;
#endif // MOZ_MAIL_NEWS
	case xpJSHTMLFilters:
		newName = PR_smprintf("%s\\hook.js", (const char *)theApp.m_UserDirectory);
		break;
	case xpFolderCache:
		newName = PR_smprintf ("%s\\summary.dat", (const char *)theApp.m_UserDirectory);
		break;

	case xpCryptoPolicy:
		newName = (char *) XP_ALLOC(_MAX_PATH);
		FE_GetProgramDirectory(newName, _MAX_PATH);
		strcat(newName, "moz40p3");
		break;
	
	case xpJSCookieFilters:
		newName = PR_smprintf("%s\\cookies.js", (const char *)theApp.m_UserDirectory);
		break;


#ifdef MOZ_LOC_INDEP
	case xpLIClientDB:
		newName = (char *) XP_ALLOC(_MAX_PATH);
		sprintf(newName, "%s\\locindep.dat", (const char *)theApp.m_UserDirectory);
		break;

	case xpLIPrefs:
		newName = (char *) XP_ALLOC(_MAX_PATH);
		sprintf(newName, "%s\\liprefs.js", (const char *)theApp.m_UserDirectory);
		break;
#endif /* MOZ_LOC_INDEP */

	default:
		ASSERT(0);  /* all types should be covered */
        break;
	}

#ifdef MOZ_MAIL_NEWS    
    // make sure we have the correct newsrc file registered for next time
	if((type == xpSNewsRC || type == xpNewsRC) && bNeedToRegister)
        NET_RegisterNewsrcFile(newName, (char *)name, (type == xpSNewsRC), FALSE );
#endif

    // determine what file we are supposed to load and make sure it looks
    //   like a DOS pathname and not some unixy punk name
	if(newName) {
		*myName = XP_NetToDosFileName((const char*)newName);
		XP_FREE(newName); 
	} else {
		*myName = XP_NetToDosFileName((const char*)name);
	}

	if (tempName) XP_FREE(tempName);

	if (prefStr) XP_FREE(prefStr);        
	
	// whee, we're done
	return(*myName);
}   

//
// Open a file with the given name
// If a special file type is provided we might need to get the name
//  out of the preferences list
//
PUBLIC XP_File 
XP_FileOpen(const char * name, XP_FileType type, const XP_FilePerm perm)
{
	XP_File fp;
	char *filename = WH_FileName(name, type);

	if(!filename || !(*filename))
		return(NULL);
		
     //  THIS MUST BE DONE FIRST TO PLUG WIN OS SECURITY HOLE.
     //  Do not allow UNC pathnames if the command line stated so.
     if(xpURL == type && FALSE == theApp.m_bUNC) {
         //  Make sure we have enough buffer to check.
         if(filename && filename[0] && filename[1]) {
             if(
                 ('\\' == filename[0] && '\\' == filename[1]) ||
                 ('/' == filename[0] && '/' == filename[1]) ||
                 ('\\' == filename[0] && '/' == filename[1]) ||
                 ('/' == filename[0] && '\\' == filename[1])
             ) {
                 //  Presumed UNC format (or likely to not open in the first place).
                 //  Denied.
                 XP_FREE(filename);
                 return(NULL);
             }
         }
     }

#ifdef DEBUG_nobody
	TRACE("Opening a file type (%d) permissions: %s (%s)\n", type, perm, filename);
#endif

#ifdef XP_WIN32
	if (type == xpURL) {
		HANDLE	hFile;
		DWORD	dwType;

		// Check if we're trying to open a device. We don't allow this
		hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
			OPEN_EXISTING, 0, NULL);

		if (hFile != INVALID_HANDLE_VALUE) {
			dwType = GetFileType(hFile);
			CloseHandle(hFile);
	
			if (dwType != FILE_TYPE_DISK) {
				XP_FREE(filename);
				return NULL;
			}
		}
	}
#endif

#ifdef XP_WIN16
	// Windows uses ANSI codepage, DOS uses OEM codepage, fopen takes OEM codepage
	// That's why we need to do conversion here.
	CString oembuff = filename;
	oembuff.AnsiToOem();
	fp = fopen(oembuff, (char *) perm);

	if (fp && type == xpURL) {
		union _REGS	inregs, outregs;

		// Check if we opened a device. Execute an Interrupt 21h to invoke
		// MS-DOS system call 44h
		inregs.x.ax = 0x4400;	 // MS-DOS function to get device information
		inregs.x.bx = _fileno(fp);
		_int86(0x21, &inregs, &outregs);

		if (outregs.x.dx & 0x80) {
			// It's a device. Don't allow any reading/writing
			fclose(fp);
			XP_FREE(filename);
			return NULL;
		}
	}
#else	
	fp = fopen(filename, (char *) perm);
#endif
	XP_FREE(filename);
	return(fp);
}


//
// Rename tmpname to fname 
//
int XP_FileRename(const char *tmpname, XP_FileType tmptype, const char *fname, XP_FileType ftype)	
{
    char * pOldName = WH_FileName(tmpname, tmptype);
    char * pNewName = WH_FileName(fname, ftype);

    if(!pOldName || !pNewName)
        return(-1);

#ifdef XP_WIN32
	// try using win32 system call. If that fails, do what the old code did.
	if (MoveFileEx(pOldName, pNewName, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
	{
		XP_FREE(pOldName);
		XP_FREE(pNewName);
		return 0;
	}
#endif
    // lets try ANSI first
    int status = rename(pOldName, pNewName);

    // if rename failed try to just copy
    if(status == -1)
    {
        if(WFE_CopyFile(pOldName, pNewName))    
        {
            // we were at least able to copy the file so return the correct
            //   status and get rid of the old file
            status = 0;
            remove(pOldName);
        }
    }

    // clean up
    XP_FREE(pOldName);
    XP_FREE(pNewName);

	return(status);
}

//
// Make a directory with the given name (may need WH_FileName munging first)
//
int XP_MakeDirectory(const char* name, XP_FileType type)	
{
	char * pName = WH_FileName(name, type);
	if(pName) {
	        int dir;
		dir = mkdir(pName);
		XP_FREE(pName);
		return(dir);
	}
	else
		return(-1);
}

//
// Remove a directory with the given name
//
int XP_RemoveDirectory (const char *name, XP_FileType type)
{
	int ret = -1;
	char *pName = WH_FileName (name, type);
	if (pName)	{
		ret = rmdir (pName);
		XP_FREE(pName);
	}
	return ret;
}

/****************************************************************************
*
*	XP_FileTruncate
*
*	PARAMETERS:
*		name	- filename to be truncated
*		length	- desired size (in bytes) for the truncated file
*
*	RETURNS:
*		Non-negative if successful, -1 if an exception occurs
*
*	DESCRIPTION:
*		This function is called to truncate (or extend) a given file.
*
****************************************************************************/

int XP_FileTruncate(const char * name, XP_FileType type, int32 length)
{
	int nRtn = 0;
	
	char * szFileName = WH_FileName(name, type);
	if (szFileName != NULL)
	{
		TRY
		{
			CFile file(szFileName, CFile::modeReadWrite);
			file.SetLength((DWORD)length);
			file.Close();
		}
		CATCH(CFileException, e)
		{
			nRtn = -1;
			
			#ifdef _DEBUG
				afxDump << "File exception: " << e->m_cause << "\n";
			#endif
		}
		END_CATCH
		XP_FREE(szFileName);
	}  /* end if */
	else
	{
		nRtn = -1;
	}  /* end else */

	return(nRtn);
	
} // END OF	FUNCTION XP_FileTruncate()

//
// Mimic unix stat call
// Return -1 on error
//
PUBLIC int 
XP_Stat(const char * name, XP_StatStruct * info, XP_FileType type)
{
    char * filename = WH_FileName(name, type);
    int res;

    if(!info || !filename)
        return(-1);

    //  THIS MUST BE DONE FIRST TO PLUG WIN OS SECURITY HOLE.	
    //  Do not allow UNC pathnames if the command line stated so.
    if(xpURL == type && FALSE == theApp.m_bUNC) {
        //  Make sure we have enough buffer to check.
        if(filename && filename[0] && filename[1]) {
            if(
                ('\\' == filename[0] && '\\' == filename[1]) ||
                ('/' == filename[0] && '/' == filename[1]) ||
                ('\\' == filename[0] && '/' == filename[1]) ||
                ('/' == filename[0] && '\\' == filename[1])
            ) {
                //  Presumed UNC format (or likely to not open in the first place).
                //  Denied.
                XP_FREE(filename);
                return(-1);
            }
        }
    }	
    
    // Strip off final slash on directory names 
    // BUT we will need to make sure we have c:\ NOT c:   
    int len = XP_STRLEN(filename) - 1;
    if(len > 1 && filename[len] == '\\' && filename[len -1] != ':'){
		uint16 iFileSystemCSID = CIntlWin::GetSystemLocaleCsid();	// this file system csid, not win_csid
		if( intl_IsEndWithBS( filename, iFileSystemCSID ) )
			filename[len] = '\0';
	}

#ifdef XP_WIN16        
    //  Also, if we are looking at something like "c:", we won't call stat at 
    //      all, as we never know if they have a diskette in drive A or such 
    //      and don't want to stall waiting.
    //  Be very strict on what we let into this statement, though.
    if(len == 1 && filename[len] == ':')  {
      //  Set the stat info ourselves.  The numbers were generic, taken 
      //    from a _stat call to "c:\"
      //  Is this a hack, or what?
      info->st_atime =
      info->st_ctime =
      info->st_mtime = 315561600L;
      info->st_uid = 0;
      info->st_gid = 0;
      info->st_size = (_off_t) 0;
      info->st_rdev =
      info->st_dev = filename[len - 1] - 'A';
      info->st_mode = 16895;
      info->st_nlink = 1;
      res = 0;
    }
    else  {
	  // Windows uses ANSI codepage, DOS uses OEM codepage, _stat takes OEM codepage
	  // That's why we need to do conversion here.
	  CString oembuff = filename;
	  oembuff.AnsiToOem();
      res = _stat(oembuff, info);
	}
#else // XP_WIN16
      //  Normal file or directory.
      res = _stat(filename, info);
#endif
    XP_FREE(filename);
    return(res);
}
                             
                             
PUBLIC XP_Dir 
XP_OpenDir(const char * name, XP_FileType type)
{
    XP_Dir dir;
    char * filename = WH_FileName(name, type);
	uint16 iFileSystemCSID = CIntlWin::GetSystemLocaleCsid();	// this file system csid, not win_csid
    CString foo;
											  
    if(!filename)
        return NULL;

    //  THIS MUST BE DONE FIRST TO PLUG WIN OS SECURITY HOLE.	
    //  Do not allow UNC pathnames if the command line stated so.
    if(xpURL == type && FALSE == theApp.m_bUNC) {
        //  Make sure we have enough buffer to check.
        if(filename && filename[0] && filename[1]) {
            if(
                ('\\' == filename[0] && '\\' == filename[1]) ||
                ('/' == filename[0] && '/' == filename[1]) ||
                ('\\' == filename[0] && '/' == filename[1]) ||
                ('/' == filename[0] && '\\' == filename[1])
            ) {
                //  Presumed UNC format (or likely to not open in the first place).
                //  Denied.
                XP_FREE(filename);
                return(NULL);
            }
        }
    }	
    
	dir = (XP_Dir) new DIR;

    // For directory names we need \*.* at the end, if and only if there is an actual name specified.
    foo += filename;
    //if(filename[XP_STRLEN(filename) - 1] != '\\')
	if( !intl_IsEndWithBS( filename, iFileSystemCSID ) )
        foo += '\\';
    foo += "*.*";

    dir->directoryPtr = FindFirstFile((const char *) foo, &(dir->data));
    XP_FREE(filename);
    if(dir->directoryPtr == INVALID_HANDLE_VALUE) {
        delete dir;
        return(NULL);
    } else {
        return(dir);
    }
}


//
// HACK:- use a static location cuz unix does it that way even
//  though it makes for non-reentrant code
//
PUBLIC XP_DirEntryStruct * 
XP_ReadDir(XP_Dir dir)
{                                         
    static XP_DirEntryStruct dirEntry;

    if(dir && dir->directoryPtr) {
#ifdef XP_WIN16
        XP_STRCPY(dirEntry.d_name, dir->data.file_data.name);
#else
        XP_STRCPY(dirEntry.d_name, dir->data.cFileName);
#endif
        if(FindNextFile(dir->directoryPtr, &(dir->data)) == FALSE) {
            FindClose(dir->directoryPtr);
            dir->directoryPtr = NULL;
        }
        return(&dirEntry);
    } else {
        return(NULL);
    }
}


//
// Close the directory
//
PUBLIC void 
XP_CloseDir(XP_Dir dir)
{
	if (dir)
	{
		if (dir->directoryPtr)
			FindClose (dir->directoryPtr);
		delete dir;
	}
} 

//
// Return 0 on success, -1 on failure.  Silly unix weenies
//
PUBLIC int 
XP_FileRemove(const char * name, XP_FileType type)
{		   
	char *filename = WH_FileName(name, type);

	if(!filename)
		return(-1);

#ifdef MOZ_MAIL_NEWS	
	if(type == xpNewsRC || type == xpNewsgroups)
        NET_UnregisterNewsHost( name, FALSE);
    else if(type == xpSNewsRC || type == xpSNewsgroups)
        NET_UnregisterNewsHost(name, TRUE);
#endif // MOZ_MAIL_NEWS

	int status = remove(filename);
	XP_FREE(filename);
	return(status);
}

BOOL XP_RemoveDirectoryRecursive(const char *name, XP_FileType type)
{
	XP_DirEntryStruct *entry;
	XP_StatStruct     statbuf;
	BOOL		  ret = TRUE;
	CString 	  dot    = ".";
	CString 	  dotdot = "..";
	int 	 	  status;

	XP_Dir dir = XP_OpenDir(name, type);  
	if (!dir) return FALSE;

	// Go through the directory entries and delete appropriately
	while ((entry = XP_ReadDir(dir)))
	{
		CString child;
		child = name;
		child += "\\";
		child += entry->d_name;
		if (!(status = XP_Stat(child, &statbuf, type)))
			if (entry->d_name == dot || entry->d_name == dotdot)
			{
				// Do nothing, rmdir will clean these up
			}
			else if ((statbuf.st_mode & _S_IFMT) == _S_IFDIR) // _S_ISDIR() isn't on Win16
			{
				// Recursive call to clean out subdirectory 
				if (!XP_RemoveDirectoryRecursive(child, type))
					ret = FALSE;
			}
			else
			{
				// Everything that's not a directory is a file!
				if (XP_FileRemove(child, type) != 0)
					ret = FALSE;
			}
	}

	// OK, remove the top-level directory if we can
	if (XP_RemoveDirectory(name, type) != 0)
		ret = FALSE;
	
	XP_CloseDir(dir);

	return ret;
}


//  Should be self-explanitory --- return TRUE on success FALSE on failure
BOOL 
WFE_MoveFile(const char *cpSrc, const char *cpTarg)  
{
#ifdef XP_WIN32
	return MoveFile(cpSrc, cpTarg);  // overwrite existing target file
#else
    // lets try ANSI first
    int status = rename(cpSrc, cpTarg);

    // if rename failed try to just copy
    if(status !=0)
    {
        if(WFE_CopyFile(cpSrc, cpTarg))    
        {
            // we were at least able to copy the file so return the correct
            //   status and get rid of the old file
            status = 0;
            remove(cpSrc);
			return TRUE;
        }
		else return FALSE;
    }
	else return TRUE;
#endif
}

//  Should be self-explanitory --- return TRUE on success FALSE on failure
BOOL 
WFE_CopyFile(const char *cpSrc, const char *cpTarg)  
{
#ifdef XP_WIN32
	return CopyFile(cpSrc, cpTarg, FALSE);  // overwrite existing target file
#else
  CFile cfSource;
  CFile cfTarget;
  
  TRY {
	Bool fail;
	/* Open returns 0 on failure */
    fail = cfSource.Open(cpSrc, CFile::modeRead | CFile::shareExclusive);
	if (fail == 0)
		return (FALSE);
    fail = cfTarget.Open(cpTarg, CFile::modeWrite | CFile::modeCreate | CFile::shareExclusive);
	if (fail == 0)
		return (FALSE);
  }
  CATCH(CFileException, e)  {
    //  Couldn't do it, just return.
    return(FALSE);
  }
  END_CATCH
  
  //  Copy the thing.
  char *pBuffer = new char[8192];
  UINT uAmount;
  
  do  {
    uAmount = 8192;
    TRY {
      uAmount = cfSource.Read((void *)pBuffer, uAmount);
      cfTarget.Write((void *)pBuffer, uAmount);
    }
    CATCH(CFileException, e)  {
      //  don't know why we failed, but assume we're done.
      //  perhaps end of file.
      break;
    }
    END_CATCH
  }
  while(uAmount != 0);
  
  //  Clean up the buffer.
  //  Files close up automagically.
  delete []pBuffer;
  return(TRUE);
#endif
}

/* copy the file specified by the first argument
 * over the newsrc file.  The second argument specifies
 * the hostname for this newsrc or "" if it is the default
 * host.
 *
 * The first filename argument was generated by a call to WH_TempName
 * with an enum of "xpTemporaryNewsRC" 
 *
 * Should return TRUE on success or FALSE on failure.
 */
extern "C" Bool XP_File_CopyOverNewsRC(const char *newfile, 
                                       const char *news_hostname,
                                       Bool        is_secure)  
{
#ifdef MOZ_MAIL_NEWS
    char *pRCName = NET_MapNewsrcHostToFilename((char *)news_hostname, 
                                                is_secure,
                                                FALSE);

    //  Is the current rc valid?
    if(pRCName == NULL) {
        return(FALSE);
    }

    //  Are we getting a valid filename?
    if(newfile == NULL) {
        return(FALSE);
    }

    //  Does the new one exist?
    CFileStatus rStatus;
    if(CFile::GetStatus(newfile, rStatus) == 0) {
        return(FALSE);
    }

    //  Does the old one exist?
    //  If so, we should remove it.
    if(CFile::GetStatus(pRCName, rStatus) != 0) {
        //  Attempt to remove.
        TRY {
            CFile::Remove(pRCName);
        }
        CATCH(CFileException, e)  {
            return(FALSE);
        }
        END_CATCH     
    }

    TRY {
        //  Attempt a speedy rename.
        CFile::Rename(newfile, pRCName);
    }
    CATCH(CFileException, e)  {
        //  Rename didn't work, attempt to copy, as fast as possible.
        if(FALSE == WFE_CopyFile(newfile, pRCName)) {
            //  Uh, like we lost the newsrc file permanently here!!!!!!!!!!
            ASSERT(0);
            return(FALSE);
        }

        //  Should remove the temp file now, as it is expected to go away.
        TRY {
            CFile::Remove(newfile);
        }
        CATCH(CFileException, e)  {
            //  Leave it lying around, not much we can do.
            return(TRUE);
        }
        END_CATCH
    }
    END_CATCH
#endif // MOZ_MAIL_NEWS
    return(TRUE);
}

extern "C" XP_Bool XP_FileNameContainsBadChars (const char *name)
{
#ifdef XP_WIN16
	char *badChars = "\\/:*?\"<>| ,+";
#else
	char *badChars = "\\/:*?\"<>|";
#endif
	XP_ASSERT( name != NULL );
	uint len = XP_STRLEN(badChars);
	if( len < 1 )
		return FALSE;

	uint16 iFileSystemCSID = CIntlWin::GetSystemLocaleCsid();	// this file system csid, not win_csid
	while( *name != NULL ){
		for (uint j = 0; j < len; j++)
			if (*name == badChars[j])
				return TRUE;
		name = INTL_NextChar( iFileSystemCSID, (char*)name );
	}
	return FALSE;
}

// Print a trace message to the console
//
#ifdef DEBUG
PUBLIC void 
FE_Trace(const char * msg)
{
    /* This used to be just TRACE(msg), but that's a mistake -- 
     * if msg happens to have a '%' in it, TRACE will
     * interpret the '%' as the beginning of an argument to be
     * printf'd and look up the stack and try to
     * interpret random data as the argument. At a minimum this
     * leads to corrupt trace info. Usually it causes bus errors.
     */
    TRACE("%s", msg);
}
#endif

PUBLIC void 
FE_ConnectToRemoteHost(MWContext * context, int url_type, char *
    hostname, char * port, char * username) 
{
    LPSTR   lpszCommand;
    UINT    iRet;

    ASSERT(url_type == FE_TN3270_URL_TYPE ||
           url_type == FE_TELNET_URL_TYPE ||
           url_type == FE_RLOGIN_URL_TYPE);

#ifdef _WIN32
	BOOL checkRegistry = TRUE;
	CInternetShortcut InternetShortcut;
    if (InternetShortcut.ShellSupport() && !theApp.m_bParseTelnetURLs)
	{
      SHELLEXECUTEINFO    sei;
	  
      // Build the command string
      if (port)
        lpszCommand = PR_smprintf("%s://%s:%s", url_type == FE_TN3270_URL_TYPE ?
            "tn3270" : "telnet", hostname, port);
      else
        lpszCommand = PR_smprintf("%s://%s", url_type == FE_TN3270_URL_TYPE ?
            "tn3270" : "telnet", hostname);

      // Use ShellExecuteEx to launch
      sei.cbSize = sizeof(sei);
      sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS;
      sei.hwnd = NULL;
      sei.lpVerb = NULL;  // default to Open
      sei.lpFile = lpszCommand;
      sei.lpParameters = NULL;
      sei.lpDirectory = NULL;
      sei.nShow = SW_SHOW;
      ShellExecuteEx(&sei);
      iRet = (UINT)sei.hInstApp;
	  
      XP_FREE(lpszCommand);

	  checkRegistry = iRet < 32;
	}
	
	if (checkRegistry)
	{
#endif // _WIN32
    char    szBuf[_MAX_PATH];
	LONG	lResult;
	LONG	cbData;
	HKEY	hKey;

	// Build the shell\open key for the file type class
	PR_snprintf(szBuf, sizeof(szBuf), "%s\\shell\\open",
        url_type == FE_TN3270_URL_TYPE ? "tn3270" : "telnet");
	
    // Open the key
    lResult = RegOpenKey(HKEY_CLASSES_ROOT, szBuf, &hKey);
	if (lResult != ERROR_SUCCESS) {
        // Nothing registered for the file type class
        FE_Alert(context, szLoadString(IDS_NO_VIEWER_CONFIGD));
        return;
    }

    // Get the Open command string
    cbData = sizeof(szBuf);
	lResult = RegQueryValue(hKey, "command", szBuf, &cbData);
	RegCloseKey(hKey);

    if (lResult == ERROR_SUCCESS) {
        LPSTR   lpszApp = szBuf;
        LPSTR   lpszArg;

        // Strip off any command line options
        lpszArg = strstr(lpszApp, "%1");
        if ( !lpszArg ) {
            // Look for "%l", instead.
            lpszArg = strstr(lpszApp, "%l");
        }
        if (lpszArg)
            *lpszArg = '\0';  // null terminate the string here

        // Build the WinExec command line
        if (port)
            lpszCommand = PR_smprintf("%s %s %s", lpszApp, hostname, port);
        else
            lpszCommand = PR_smprintf("%s %s", lpszApp, hostname);
    
        // Run it
        iRet = (UINT)WinExec(lpszCommand, SW_SHOW);
        XP_FREE(lpszCommand);
    
        // If the error is file not found or path not found report it here; otherwise
        // report it below
        if (iRet == 2 || iRet == 3) {
            LPSTR   lpszMsg;
    
            lpszMsg = PR_smprintf(szLoadString(IDS_UNABLE_FIND_APP), lpszApp);
            if (lpszMsg) {
                FE_Alert(context, lpszMsg);
                XP_FREE(lpszMsg);
            }
    
            return;
        }
    }
#ifdef _WIN32
	}
#endif // _WIN32

    // See if it worked
    if (iRet < 32) {
        LPSTR   lpszMsg;

        lpszMsg = PR_smprintf(szLoadString(IDS_UNABLE_TO_LAUNCH_APP), iRet);
        if (lpszMsg) {
            FE_Alert(context, lpszMsg);
            XP_FREE(lpszMsg);
        }

    } else {
        FE_Progress(context, szLoadString(IDS_SPAWNING_APP));

        if (username) {
            LPSTR   lpszMsg;

            lpszMsg = PR_smprintf(szLoadString(IDS_LOGIN_AS), username);
            if (lpszMsg) {
                FE_Alert(context, lpszMsg);
                XP_FREE(lpszMsg);
            }
        }
    }
}


PUBLIC void *FE_AboutData (const char *which, char **data_ret, int32 *length_ret, char **content_type_ret)
{
  char *loc = (char*)strchr (which, '?');
  char *which2;
  char *tmp;
  
  if (loc)
    *loc++ = 0;

    BOOL bHandled = FALSE;
    if(FALSE == bHandled) {
        char *pCompare = strdup(which);
        if(pCompare) {
            char *pReplace = strchr(pCompare, '.');
            if(pReplace) {
                *pReplace = '_';
            }
            HINSTANCE hInst = AfxGetResourceHandle();
            if(hInst) {
                HRSRC hFound = FindResource(hInst, pCompare, RT_RCDATA);
                free(pCompare);
                pCompare = NULL;
                if(hFound) {
                    HGLOBAL hRes = LoadResource(hInst, hFound);
                    hFound = NULL;
                    if(hRes) {
                        char *pBytes = (char *)LockResource(hRes);
                        if(pBytes) {
                            //  Check for identifying bin2rc string.
                            if(!strcmp(pBytes, "bin2rc generated resource")) {
                                pBytes += 26; // length + 1

                                //  Next is a content-type.
                                //  The mime type should be something we recognize.
                                //  Assign in a constant string only.
                                if(!stricmp(pBytes, IMAGE_GIF))   {
                                    *content_type_ret = IMAGE_GIF;
                                }
                                else if(!stricmp(pBytes, IMAGE_JPG))    {
                                    *content_type_ret = IMAGE_JPG;
                                }
                                pBytes += strlen(pBytes) + 1;  // length + 1

                                //  Next is the size of the data if we are willing.
                                if(*content_type_ret)   {
                                    *length_ret =  strtol(pBytes, NULL, 10);
                                }
                                pBytes += strlen(pBytes) + 1; // length + 1

                                //  Next is the data if any.
                                if(*length_ret)  {
                                    *data_ret = (char *)malloc(*length_ret);
                                    if(*data_ret) {
                                        memcpy(*data_ret, pBytes, *length_ret);
                                        bHandled = TRUE;
                                    }
                                    else    {
                                        //  Unable to alloc.
                                        //  Clear out.
                                        *content_type_ret = NULL;
                                        *length_ret = 0;
                                    }
                                }
                            }
                            pBytes = NULL;
                        }
                        UnlockResource(hRes);
                        FreeResource(hRes);
                        hRes = NULL;
                    }
                }
            }
        }
    }

    if(FALSE == bHandled)    {
      which2 = strdup (which);
      for (tmp = which2; *tmp; tmp++)
	      *tmp += 69;

        char *a = NULL;
        if (!strcmp (which2, ""))   { 				// about:
            CString csVersion, csBuildNumber;
		    char *tmpversionBuf;

			csVersion = XP_AppVersion;
			csVersion = csVersion.Left(csVersion.Find("]") + 1);
		    tmpversionBuf = (char *)XP_ALLOC(15);
		    //Loading from netscape.exe instead of resdll.dll since the string has been moved #109455
		    LoadString(::AfxGetInstanceHandle(), IDS_APP_BUILD_NUMBER, tmpversionBuf, 15);
			csBuildNumber = tmpversionBuf;
		    if (tmpversionBuf) XP_FREE(tmpversionBuf);
			csVersion+=csBuildNumber;

            char *pSSLVersion = NULL;
			char *pSSLString = NULL;
			HG83722

            char *pSp = szLoadString(IDS_ABOUT_0);
            /* Null pointer check */
            if (pSp && pSSLString ) 
			{
				a = (char *)malloc(strlen(pSp) + strlen(pSSLString) + strlen(csVersion) * 2 + 48);
                sprintf(a, pSp, (const char *)csVersion, (const char *)csVersion, pSSLString);
            }
        
            /* Free string space if allocated */
			if (pSSLString) free(pSSLString);
			if (pSSLVersion) free(pSSLVersion);
        }
        else if (!strcmp (which, "mailintro"))
          a = strdup(szLoadString(IDS_MAIL_0)); 
        else if (!strcmp (which, "license"))
	      a = wfe_LoadResourceString("license");      
        else if (!strcmp (which, "mozilla"))
          a = strdup (szLoadString(IDS_MOZILLA_0));
        else if (!strcmp (which2, "\250\264\265\276\267\256\254\255\271"))
          a = strdup(szLoadString(IDS_COPYRIGHT_0));
        else if (!strcmp (which2, "\247\261\246\263\260"))
          a = strdup ("");                                           
#ifdef EDITOR
        else if (!strcmp (which, "editfilenew"))
          a = strdup (EDT_GetEmptyDocumentString());
#endif // EDITOR
	    else if (!strcmp(which, "plugins"))
	      a = wfe_LoadResourceString("aboutplg");      
        else
          a = strdup(which);

    
        if (a)
        {
        //          for (tmp = a; *tmp; tmp++) *tmp -= 69;
          *data_ret = a;
          *length_ret = strlen (*data_ret);
          *content_type_ret = TEXT_MDL; 
      
          if(!strcmp (which, "license"))
            *content_type_ret = TEXT_PLAIN;

#ifdef DEBUG
          //    Produce some hard to debug situations here manually.
          if(!stricmp(which, "WM_ENDSESSION"))   {
              //    Shutdown of the system case.
              FEU_FrameBroadcast(TRUE, WM_QUERYENDSESSION, 1, 0);
              FEU_FrameBroadcast(FALSE, WM_ENDSESSION, 1, 0);
          }
          else if(!stricmp(which, "debug")) {
            DebugBreak();
          }
          else if(!stricmp(which, "PostQuitMessage"))   {
            PostQuitMessage(0);
          }
#endif
        }
        else
        {
          *data_ret = 0;
          *length_ret = 0;
          *content_type_ret = 0;
        }
        free (which2);
    }

    return(*data_ret);
}

/*****/

PUBLIC void FE_FreeAboutData(void *data, const char *which2)
{
    if(data)   {
        free(data);
        data = NULL;
    }
}

char *XP_PlatformPartialPathToXPPartialPath (const char *platformName)
{
	return XP_STRDUP(platformName);
}


char *XP_PlatformFileToURL (const char *platformName)
{
	CString csXPName;
	WFE_ConvertFile2Url (csXPName, platformName);
	return XP_STRDUP(csXPName);
}
void WFE_ConvertFile2Url(CString& csUrl, const char *pLocalFileName)
{
	uint16 iFileSystemCSID = CIntlWin::GetSystemLocaleCsid();	// this file system csid, not win_csid
	//	First empty the returning url, in case it has something in it.
	csUrl.Empty();

	//	If there's nothing to convert, return now.
	if(pLocalFileName == NULL || *pLocalFileName == '\0')	{
		return;
	}

	//	A CString we can muck with.
	CString csLocal = pLocalFileName;

    if (csLocal.GetLength() > 4) {        

        if ( !strnicmp(&pLocalFileName[strlen(pLocalFileName)-4],".lnk",4)) {
            char szName[_MAX_PATH];
            HRESULT hRes = ::ResolveShortCut(NULL, pLocalFileName, szName);
            if (SUCCEEDED(hRes)) {
                csLocal = szName;
            }
        }
        else if (!strnicmp(&pLocalFileName[strlen(pLocalFileName)-4],".url",4)) {
            CInternetShortcut InternetShortcut;
  		    if (InternetShortcut.ShellSupport()) {
	    	    // got a valid .URL internet shortcut file
                char szNew[_MAX_PATH];
			    CInternetShortcut Shortcut (pLocalFileName);
			    Shortcut.GetURL(szNew,sizeof(szNew));
                csUrl = szNew;
                return;
    	    }
        }
    }


	//	Convert $ROOT to the directory of the executable.
	if(csLocal.Left(5) == "$ROOT")	{
		char aPath[_MAX_PATH];
		::GetModuleFileName(theApp.m_hInstance, aPath, _MAX_PATH);

		//	Find the trailing slash.
		char *pSlash = intl_strrchr(aPath, '\\', iFileSystemCSID);
		if(pSlash)	{
			*pSlash = '\0';
		}
		else	{
			aPath[0] = '\0';
		}

		csLocal = aPath + csLocal.Right(csLocal.GetLength() - 5);
	}
	
	//	Convert local file paths which have a drive letter to an appropriate URL.
	//	This means we must always have a fully qualified file path in order to convert
	//		these correctly.
	const char* src = csLocal.GetBuffer( csLocal.GetLength() ) + 2;
	const char* end = src + csLocal.GetLength() - 2;
	if(csLocal.GetLength() >= 2 && csLocal[1] == ':')	{
		csUrl += "file:///";
		csUrl += csLocal[0];
		csUrl += '|';
#ifdef BUG93660_4_05_FIX
		for(int iTraverse = 2; iTraverse < csLocal.GetLength();
			iTraverse++)	
		{
			if(csLocal[iTraverse] == '\\')
			{
				// bug 93660 -- double byte file name gets truncated
				// We don't want to replace the backslash with
				// forwardslash in case of the double byte file name
				// iTraverse starts with 2; iTraverse - 1 will not go
				// negative 
				if (CIntlWin::GetSystemLocaleCsid() & MULTIBYTE &&
					INTL_IsLeadByte(CIntlWin::GetSystemLocaleCsid(), 
									csLocal[iTraverse-1]))
				{
					csUrl += csLocal[iTraverse];
				}
				else
				{
					csUrl += '/';
				}
			}
			else
			{
				csUrl += csLocal[iTraverse];
			}
		}
#endif
	}
	//	Convert microsoft network paths.
	else if(csLocal.Left(2) == "\\\\" || csLocal.Left(2) == "//")	{
		csUrl += "file:////";
	}
	else	{
		//	This was a normal URL.
		//	Don't corrupt it.
		csUrl = pLocalFileName;
		src = end = NULL;
	}

	if( src != NULL ){
		while( src < end ){
  			if( *src == '\\'){
  				csUrl += '/';
				src++;

  			} else {
				const char* next = INTL_NextChar( iFileSystemCSID, (char*)src );
				ASSERT( next <= end );
				while( src < next )
					csUrl += *src++;
  			}
		}
 		csLocal.ReleaseBuffer();
	}




    // This seems to be missing cases such as "..\foo"
    // Replace all "\" with "/" Note: only do this for the file: protocol or if there is no
	// specified protocol type; this way we won't munge things like mocha: and mailbox:
	int	nUrlType = NET_URL_Type(csUrl);

	if (nUrlType == FILE_TYPE_URL || nUrlType == 0) {
 		char* src = csUrl.GetBuffer( csUrl.GetLength() );
 		while( *src != NULL ){
 			if( *src == '\\' )
 				*src++ = '/';
 			else
 				src = INTL_NextChar( iFileSystemCSID, src );
		}
 		csUrl.ReleaseBuffer();
	}

    //	Check for a file url with an extra slash.
	//	This is special case code to make sure an arbitrary number
	//		of slashes sends the file URL as a microsoft network
	//		path.
	//	Go recursive, minus one slash.
	if(csUrl.Left(10) == "file://///")	{
		CString csLeft = csUrl.Left(9);
		CString csRight = csUrl.Right(csUrl.GetLength() - 10);
		WFE_ConvertFile2Url(csUrl, (const char *)(csLeft + csRight));
	}
}

extern CString WFE_EscapeURL(const char* url)
{
	CString urlStr(url);
	CString encoded;
	int l = urlStr.GetLength();
	for (int i = 0; i < l; i++)
	{
		char c = urlStr[i];
		if (c == ' ')
			encoded += "%20";
		else encoded += c;
	}

	return encoded;
}

extern void FE_SetRefreshURLTimer(MWContext *pContext, uint32 ulSeconds, char *pRefreshUrl) {
//	Purpose:    Set a delayed load timer for a window for a particular URL.
//	Arguments:  pContext    The context that we're in.  We are only interested on wether or not there appears to be a Frame/hence document.
//              ulSeconds   The number of seconds that will pass before we attempt the reload.
//	Returns:    void
//	Comments:
//	Revision History:
//      02-17-95    created GAB
//		07-22-95	modified to use new context.
//      05-03-96    modified to use new API outside of idle loop.
//

    //  Only do this if it is a window context from the back end.
    if(ABSTRACTCX(pContext) && ABSTRACTCX(pContext)->IsWindowContext()) {
        FEU_ClientPull(pContext, ulSeconds * 1000, NET_CreateURLStruct(pRefreshUrl, NET_NORMAL_RELOAD), FO_CACHE_AND_PRESENT, FALSE);
    }
}

#if defined XP_WIN16 && defined DEBUG
void AfxDebugBreak()	{
	_asm { int 3 };
}
#endif

extern "C" void XP_Assert(int stuff)	{
    ASSERT(stuff);
}

extern "C" void fe__assert(void *, void *, unsigned)	{
#ifdef DEBUG
	TRACE("lowest level Assertion failure!\n");
	AfxDebugBreak(); 
#endif
}
extern "C" void fe_abort(void)	{
#ifdef DEBUG
	TRACE("lowest level Abortion called!\n");
	AfxDebugBreak();
#endif
}

extern "C" void XP_AssertAtLine( char *pFileName, int iLine ){
#ifdef DEBUG
#ifdef XP_WIN32
    if( AfxAssertFailedLine( pFileName, iLine) )
#endif
    {
        AfxDebugBreak();
    }
#endif
}

// Draws a 3D button exactly as Windows95 style
void WFE_DrawWindowsButtonRect(HDC hDC, LPRECT lpRect, BOOL bPushed)
{
    
    HPEN penHighlight = ::CreatePen(PS_SOLID, 1, bPushed ? sysInfo.m_clrBtnShadow : sysInfo.m_clrBtnHilite);
    HPEN penShadow = ::CreatePen(PS_SOLID, 1, bPushed ? sysInfo.m_clrBtnHilite : sysInfo.m_clrBtnShadow);
    HPEN penBlack = ::CreatePen(PS_SOLID, 1, RGB(0,0,0));

    // Top and left
    HPEN penOld = (HPEN)::SelectObject(hDC, bPushed ? penBlack : penHighlight);
    ::MoveToEx(hDC, lpRect->left, lpRect->bottom, NULL);
    ::LineTo(hDC, lpRect->left, lpRect->top);
    ::LineTo(hDC, lpRect->right+1, lpRect->top);

    // Bottom and right
    ::SelectObject(hDC, bPushed ? penHighlight : penBlack);
    ::MoveToEx(hDC, lpRect->left+1, lpRect->bottom, NULL);
    ::LineTo(hDC, lpRect->right, lpRect->bottom);
    ::LineTo(hDC, lpRect->right, lpRect->top);

    // Shadow color line inside to black line
    ::SelectObject(hDC, penShadow);
   ::MoveToEx(hDC, lpRect->left+1, lpRect->bottom-1, NULL);
    if( bPushed )
    {
        ::LineTo(hDC, lpRect->left+1, lpRect->top-1);
        ::LineTo(hDC, lpRect->right-1, lpRect->top-1);
    } else {
        ::LineTo(hDC, lpRect->right-1, lpRect->bottom-1);
        ::LineTo(hDC, lpRect->right-1, lpRect->top+1);
    }

    // Cleanup
    ::SelectObject(hDC, penOld);
    ::DeleteObject(penShadow);
    ::DeleteObject(penHighlight);
    ::DeleteObject(penBlack);

}

//============================================================= DrawHighlight
// Draw the highlight around the area
 void WFE_DrawHighlight( HDC hDC, LPRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight )
{
	HPEN hpenTopLeft = ::CreatePen( PS_SOLID, 0, clrTopLeft );
	HPEN hpenBottomRight = ::CreatePen( PS_SOLID, 0, clrBottomRight );
	HPEN hpenOld = (HPEN) ::SelectObject( hDC, hpenTopLeft );

	::MoveToEx( hDC, lpRect->left, lpRect->bottom, NULL );
	::LineTo( hDC, lpRect->left, lpRect->top );
	::LineTo( hDC, lpRect->right - 1, lpRect->top );

	::SelectObject( hDC, hpenBottomRight );
	::LineTo( hDC, lpRect->right - 1, lpRect->bottom - 1);
	::LineTo( hDC, lpRect->left, lpRect->bottom - 1);

	::SelectObject( hDC, hpenOld );

	VERIFY(::DeleteObject( hpenTopLeft ));
	VERIFY(::DeleteObject( hpenBottomRight ));
}


//============================================================ DrawRaisedRect
void WFE_DrawRaisedRect( HDC hDC, LPRECT lpRect )
{
	RECT rcTmp = *lpRect;
	::InflateRect( &rcTmp, -1, -1 );
#ifdef _WIN32
	WFE_DrawHighlight( hDC, &rcTmp, 
				   GetSysColor( COLOR_3DLIGHT ), 
				   GetSysColor( COLOR_3DSHADOW ) );
	WFE_DrawHighlight( hDC, lpRect, 
				   GetSysColor( COLOR_3DHILIGHT ), 
				   GetSysColor( COLOR_3DDKSHADOW ) );
#else
	WFE_DrawHighlight( hDC, lpRect, 
				   GetSysColor( COLOR_BTNHIGHLIGHT ), 
				   GetSysColor( COLOR_BTNSHADOW ) );
	WFE_DrawHighlight( hDC, &rcTmp, 
				   GetSysColor( COLOR_BTNHIGHLIGHT ), 
				   GetSysColor( COLOR_BTNSHADOW ) );
#endif
}


//=========================================================== DrawLoweredRect
void WFE_DrawLoweredRect( HDC hDC, LPRECT lpRect )
{
	RECT rcTmp = *lpRect;
	::InflateRect( &rcTmp, -1, -1 );
#ifdef _WIN32
	WFE_DrawHighlight( hDC, &rcTmp, 
				   GetSysColor( COLOR_3DSHADOW ), 
				   GetSysColor( COLOR_3DLIGHT ) );
	WFE_DrawHighlight( hDC, lpRect, 
				   GetSysColor( COLOR_3DDKSHADOW ), 
				   GetSysColor( COLOR_3DHILIGHT) );
#else
	WFE_DrawHighlight( hDC, &rcTmp, 
				   GetSysColor( COLOR_BTNSHADOW ), 
				   GetSysColor( COLOR_BTNHIGHLIGHT ) );
	WFE_DrawHighlight( hDC, lpRect, 
				   GetSysColor( COLOR_BTNSHADOW ), 
				   GetSysColor( COLOR_BTNHIGHLIGHT ) );
#endif
}

void WFE_Draw3DButtonRect( HDC hDC, LPRECT lpRect, BOOL bPushed )
{
	if ( bPushed ) {
		WFE_DrawLoweredRect( hDC, lpRect );
	} else {
		WFE_DrawRaisedRect( hDC, lpRect );
	}
}

void WFE_MakeTransparentBitmap( HDC hDC, HBITMAP hBitmap )
{
	BITMAP bm;
	COLORREF cColor;
	HBITMAP bmAndBack, bmAndObject, bmAndMem;
	HGDIOBJ bmBackOld, bmObjectOld, bmMemOld;
	HDC hdcTemp, hdcMem, hdcBack, hdcObject;

	VERIFY( ::GetObject( hBitmap, sizeof(BITMAP), (LPSTR)&bm ) );

	// Create some DCs to hold temporary data.
	hdcTemp   = CreateCompatibleDC(hDC);
	hdcBack   = CreateCompatibleDC(hDC);
	hdcObject = CreateCompatibleDC(hDC);
	hdcMem    = CreateCompatibleDC(hDC);

	SelectObject( hdcTemp, hBitmap );

	// Monochrome DC
	bmAndBack   = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);

	// Monochrome DC
	bmAndObject = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);

	bmAndMem    = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight);

	// Each DC must select a bitmap object to store pixel data.
	bmBackOld   = ::SelectObject(hdcBack, bmAndBack);
	bmObjectOld = ::SelectObject(hdcObject, bmAndObject);
	bmMemOld    = ::SelectObject(hdcMem, bmAndMem);

	// Set the background color of the source DC to the color
	// contained in the parts of the bitmap that should be transparent
	cColor = SetBkColor(hdcTemp, RGB_TRANSPARENT );

	// Create the object mask for the bitmap by performing a BitBlt
	// from the source bitmap to a monochrome bitmap.
	BitBlt(hdcObject, 0, 0, bm.bmWidth, bm.bmHeight, hdcTemp, 0, 0, SRCCOPY);

	// Set the background color of the source DC back to the original
	// color.
	SetBkColor(hdcTemp, cColor);

	// Create the inverse of the object mask.
	BitBlt(hdcBack, 0, 0, bm.bmWidth, bm.bmHeight, hdcObject, 0, 0, NOTSRCCOPY);

	// Fill the background of the mem DC with the system background color.
	FillRect( hdcMem, CRect( 0, 0, bm.bmWidth, bm.bmHeight ), CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) ) );

	// Mask out the places where the bitmap will be placed.
	BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcObject, 0, 0, SRCAND);

	// Mask out the transparent colored pixels on the bitmap.
	BitBlt(hdcTemp, 0, 0, bm.bmWidth, bm.bmHeight, hdcBack, 0, 0, SRCAND);

	// XOR the bitmap with the background on the destination DC.
	BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcTemp, 0, 0, SRCPAINT);

	// Copy the results back to the source bitmap.
	BitBlt(hdcTemp, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);

	// Delete the memory bitmaps.
	VERIFY(DeleteObject(SelectObject(hdcBack, bmBackOld)));
	VERIFY(DeleteObject(SelectObject(hdcObject, bmObjectOld)));
	VERIFY(DeleteObject(SelectObject(hdcMem, bmMemOld)));

	// Delete the memory DCs.
	VERIFY(DeleteDC(hdcMem));
	VERIFY(DeleteDC(hdcBack));
	VERIFY(DeleteDC(hdcObject));
	VERIFY(DeleteDC(hdcTemp));
}

#define RGB_TO_RGBQUAD(r,g,b)   (RGB(b,g,r))
#define CLR_TO_RGBQUAD(clr)     (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)))

HBITMAP WFE_LoadSysColorBitmap( HINSTANCE hInst, LPCSTR lpszResourceName )
{
	struct COLORMAP
	{
		// use DWORD instead of RGBQUAD so we can compare two RGBQUADs easily
		DWORD rgbqFrom;
		int iSysColorTo;
	};
	static const COLORMAP sysColorMap[] =
	{
		// mapping from color in DIB to system color
		{ RGB_TO_RGBQUAD(0x00, 0x00, 0x00),  COLOR_BTNTEXT },       // black
		{ RGB_TO_RGBQUAD(0x80, 0x80, 0x80),  COLOR_BTNSHADOW },     // dark grey
		{ RGB_TO_RGBQUAD(0xC0, 0xC0, 0xC0),  COLOR_BTNFACE },       // bright grey
		{ RGB_TO_RGBQUAD(0xFF, 0xFF, 0xFF),  COLOR_BTNHIGHLIGHT },   // white
		{ RGB_TO_RGBQUAD(0xFF, 0x00, 0xFF),  COLOR_BTNFACE }   // hot pink
	};
	const int nMaps = 5;

	HRSRC hRsrc = ::FindResource(hInst, lpszResourceName, RT_BITMAP);

	HGLOBAL hglb;
	if ((hglb = LoadResource(hInst, hRsrc)) == NULL)
		return NULL;

	LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb);
	if (lpBitmap == NULL)
		return NULL;

	// make copy of BITMAPINFOHEADER so we can modify the color table
	int nColorTableSize = 1 << lpBitmap->biBitCount;
	UINT nSize = CASTUINT(lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD));
	LPBITMAPINFOHEADER lpBitmapInfo = (LPBITMAPINFOHEADER)::malloc(nSize);
	if (lpBitmapInfo == NULL)
		return NULL;
	memcpy(lpBitmapInfo, lpBitmap, nSize);

	// color table is in RGBQUAD DIB format
	DWORD* pColorTable =
		(DWORD*)(((LPBYTE)lpBitmapInfo) + (UINT)lpBitmapInfo->biSize);

	for (int iColor = 0; iColor < nColorTableSize; iColor++)
	{
		// look for matching RGBQUAD color in original
		for (int i = 0; i < nMaps; i++)
		{
			if (pColorTable[iColor] == sysColorMap[i].rgbqFrom)
			{
				pColorTable[iColor] =
					CLR_TO_RGBQUAD(::GetSysColor(sysColorMap[i].iSysColorTo));
				break;
			}
		}
	}

	int nWidth = (int)lpBitmapInfo->biWidth;
	int nHeight = (int)lpBitmapInfo->biHeight;
	HDC hDCScreen = ::GetDC(NULL);
	HBITMAP hbm = ::CreateCompatibleBitmap(hDCScreen, nWidth, nHeight);

	if (hbm != NULL)
	{
		HDC hDCGlyphs = ::CreateCompatibleDC(hDCScreen);
		HBITMAP hbmOld = (HBITMAP)::SelectObject(hDCGlyphs, hbm);

		LPBYTE lpBits;
		lpBits = (LPBYTE)(lpBitmap + 1);
		lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);

		StretchDIBits(hDCGlyphs, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
			lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
		SelectObject(hDCGlyphs, hbmOld);

		::DeleteDC(hDCGlyphs);
	}
	::ReleaseDC(NULL, hDCScreen);

	// free copy of bitmap info struct and resource itself
	::free(lpBitmapInfo);
	::FreeResource(hglb);

	return hbm;
}

/////////////////////////////////////////////////////////////////////////////
// equivalent to LoadBitmap(), except uses pDC for
// correct color mapping of BMP into pDC's palette.
HBITMAP wfe_LoadBitmap(HINSTANCE hInst, HDC hDC, LPCSTR pszBmName ) 
{
	int iFrames;

	if ((pszBmName == MAKEINTRESOURCE(IDB_ANIM_0)) && (CUST_IsCustomAnimation(&iFrames))) {
		char *pFile=NULL,*pUrl=NULL;
		HBITMAP hCust = NULL;
		CString csProfileFile;

		int iError = PREF_CopyConfigString("toolbar.logo.win_large_file",&pFile);
		ASSERT(iError != PREF_ERROR);

		// we need to first check the profile for the file (for PE) and then resort to the default of the EXE dir
		csProfileFile = theApp.m_UserDirectory;
		csProfileFile += "\\";
		csProfileFile += pFile;
		hCust = WFE_LoadBitmapFromFile(csProfileFile);
		
		if (!hCust)  // try the default place
			hCust = WFE_LoadBitmapFromFile(pFile);	
		if (pFile) XP_FREE(pFile);
		if (hCust) return hCust;
	}

	if ((pszBmName == MAKEINTRESOURCE(IDB_ANIMSMALL_0)) && (CUST_IsCustomAnimation(&iFrames))) {
		char *pFile=NULL,*pUrl=NULL;
		HBITMAP hCust = NULL;
		CString csProfileFile;

		int iError = PREF_CopyConfigString("toolbar.logo.win_small_file",&pFile);
		ASSERT(iError != PREF_ERROR);

		// we need to first check the profile for the file (for PE) and then resort to the default of the EXE dir
		csProfileFile = theApp.m_UserDirectory;
		csProfileFile += "\\";
		csProfileFile += pFile;
		hCust = WFE_LoadBitmapFromFile(csProfileFile);
		
		if (!hCust)  // try the default place
			hCust = WFE_LoadBitmapFromFile(pFile);
		if (pFile) XP_FREE(pFile);
		if (hCust) return hCust;
	}

    // get the resource from the file
    HBITMAP hBmp = (HBITMAP)FindResource(hInst, pszBmName, RT_BITMAP);
    ASSERT(hBmp != NULL);
    if(!hBmp)
        return NULL;
    HGLOBAL hRes = LoadResource(hInst, (HRSRC)hBmp);
    ASSERT(hRes != NULL);
    if(!hRes)
        return NULL;
    LPBITMAPINFO pPackedDib = (LPBITMAPINFO)(LockResource(hRes));
    ASSERT(pPackedDib != NULL);
    if(!pPackedDib)
        return NULL;
        
    // build a DDB header for  pDC

    BITMAPINFOHEADER bmihDDB;
    memcpy(&bmihDDB, pPackedDib, sizeof(BITMAPINFOHEADER));
    bmihDDB.biBitCount = GetDeviceCaps( hDC, BITSPIXEL);
    bmihDDB.biClrUsed = 0;
    bmihDDB.biClrImportant = 0;

    
    // create the DDB
    int iColorTableSize =
        (1 << pPackedDib->bmiHeader.biBitCount) * sizeof(RGBQUAD);
    void* pBits =
        ((char*)pPackedDib) + pPackedDib->bmiHeader.biSize + iColorTableSize;
    HBITMAP hDDB = CreateDIBitmap(hDC,
                                &bmihDDB,
                                CBM_INIT,
                                pBits,
                                pPackedDib,
                                DIB_RGB_COLORS);
    
    // done, clean up
	UnlockResource(hRes);
    BOOL bResult = FreeResource(hRes);
    
    return hDDB;
}

static int FindColorIndex(LPRGBQUAD pColors, int nNumColors, COLORREF color)
{
	for(int i = 0; i < nNumColors; i++)
	{
		if(pColors[i].rgbRed == GetRValue(color) &&
		   pColors[i].rgbGreen == GetGValue(color) &&
		   pColors[i].rgbBlue == GetBValue(color)) {
				return i;
		}
	}
	return -1;
}

// Loads a bitmap and returns the handle. Retrieves the color of the
// first pixel in the image and replaces that entry in the color table
// with clrBackground
HBITMAP WFE_LoadTransparentBitmap(HINSTANCE hInstance, HDC hDC, COLORREF clrBackground, COLORREF clrTransparent,
								  HPALETTE hPalette, UINT nResID)
{
	// Find the resource
	HRSRC	hrsrc = FindResource(hInstance, MAKEINTRESOURCE(nResID), RT_BITMAP);

	assert(hrsrc);
	if (!hrsrc)
		return NULL;

	// Get a handle for the resource
	HGLOBAL	hglb = LoadResource(hInstance, hrsrc);
	if (!hglb)
		return NULL;

	// Get a pointer to the BITMAPINFOHEADER
	LPBITMAPINFOHEADER	lpbi = (LPBITMAPINFOHEADER)LockResource(hglb);

	// We expect a 4-bpp or 8-bpp image only
	assert(lpbi->biBitCount == 4 || lpbi->biBitCount == 8);
	if (lpbi->biBitCount != 4 && lpbi->biBitCount != 8) {
		UnlockResource(hglb);
		FreeResource(hglb);
		return NULL;
	}

#ifdef XP_WIN32
	// make copy of BITMAPINFOHEADER so we can modify the color table
	int nColorTableSize = 1 << lpbi->biBitCount;
	UINT nSize = CASTUINT(lpbi->biSize + nColorTableSize * sizeof(RGBQUAD));

	LPBITMAPINFOHEADER lpBitmapInfo = (LPBITMAPINFOHEADER)::malloc(nSize);
	if (lpBitmapInfo == NULL)
		return NULL;
	memcpy(lpBitmapInfo, lpbi, nSize);

	// color table is in RGBQUAD DIB format
	LPRGBQUAD pColors =
		(LPRGBQUAD)((LPSTR)lpBitmapInfo + lpBitmapInfo->biSize);

	LPRGBQUAD pOldColors =
		(LPRGBQUAD)((LPSTR)lpbi + lpbi->biSize);

	UINT	nClrUsed = lpbi->biClrUsed == 0 ? 1 << lpbi->biBitCount : (UINT)lpbi->biClrUsed;
	LPBYTE	lpBits = (LPBYTE)(pOldColors + nClrUsed);


#else
	LPRGBQUAD	pColors = (LPRGBQUAD)((LPSTR)lpbi + (WORD)lpbi->biSize);
	UINT	nClrUsed = lpbi->biClrUsed == 0 ? 1 << lpbi->biBitCount : (UINT)lpbi->biClrUsed;
	LPBYTE	lpBits = (LPBYTE)(pColors + nClrUsed);
#endif


	// Munge the color table entry
//	int	nIndex = lpbi->biBitCount == 8 ? *lpBits : *lpBits & 0xF;
	int nIndex = FindColorIndex(pColors, nClrUsed, clrTransparent);

	pColors[nIndex].rgbGreen = GetGValue(clrBackground);
	pColors[nIndex].rgbRed = GetRValue(clrBackground);
	pColors[nIndex].rgbBlue = GetBValue(clrBackground);

	// Create the DDB
	HBITMAP		hBitmap;
	HPALETTE hOldPalette = SelectPalette(hDC, hPalette, FALSE);


#ifdef XP_WIN32
	hBitmap = CreateDIBitmap(hDC, lpBitmapInfo, CBM_INIT, lpBits,
		(LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS);

	::free(lpBitmapInfo);
#else
	hBitmap = CreateDIBitmap(hDC, lpbi, CBM_INIT, lpBits,
		(LPBITMAPINFO)lpbi, DIB_RGB_COLORS);

	//Restore the bitmap in case we want to go through this process again
	pColors[nIndex].rgbRed = GetRValue(clrTransparent);
	pColors[nIndex].rgbGreen = GetGValue(clrTransparent);
	pColors[nIndex].rgbBlue = GetBValue(clrTransparent);
#endif
	// The parent should unselect the palette when they got destroy.
		SelectPalette(hDC, hOldPalette, TRUE);
	// Release the resource
	UnlockResource(hglb);
	FreeResource(hglb);

	return hBitmap;
}

void WFE_InitializeUIPalette(HDC hDC)
{
	IL_IRGB transparentColor;
	transparentColor.index = 0;
	transparentColor.red = 255;
	transparentColor.green = 0;
	transparentColor.blue = 255;
	if(ghPalette == NULL) {
		ghPalette = CDCCX::CreateColorPalette(hDC, transparentColor, 8);

	}
}

BOOL WFE_IsGlobalPalette(HPALETTE hPal)
{

	return (hPal == ghPalette);
}

HPALETTE WFE_GetUIPalette(CWnd* parent)
{
	// for normal case.
	if (!parent)
		return ghPalette;
	else if (parent->IsKindOf(RUNTIME_CLASS(CGenericFrame))) {
		CWinCX* pcxWin = ((CGenericFrame*)parent)->GetMainWinContext();
		if (pcxWin) {
			HPALETTE hPalette = pcxWin->GetPalette();
			if (hPalette) return hPalette;
			else return	ghPalette;
		}
		else return ghPalette;
	}
	else if (parent->IsKindOf(RUNTIME_CLASS(CInPlaceFrame))) {	 // for OLE
		// XXX write me.
		CWinCX *pWinCX = (CWinCX*)FEU_GetLastActiveFrameContext();
		if (pWinCX) {
			HPALETTE hPalette = pWinCX->GetPalette();
			if (hPalette) return hPalette;
			else return	ghPalette;
		}
		else return	ghPalette;

	}
	else // for other case. 
		return ghPalette;
}

void WFE_DestroyUIPalette(void)
{
	if(ghPalette)
		DeleteObject(ghPalette);
}

typedef struct {
	COLORREF clrBackground;
	HBITMAP bitmap;
} BitmapMapEntry;

// if bTransparent is FALSE then clrBackground and clrTransparent are ignored
HBITMAP WFE_LookupLoadAndEnterBitmap(HDC hDC, UINT nID, BOOL bTransparent, HPALETTE hPalette, 
									 COLORREF clrBackground, COLORREF clrTransparent)
{

	HINSTANCE hInst = AfxGetResourceHandle();
	HBITMAP hBitmap;
	BitmapMapEntry *pEntry = NULL;

	if(!gBitmapMap.Lookup(nID, (void*&)pEntry) || pEntry->clrBackground != clrBackground)
	{
		HPALETTE hOldPalette = SelectPalette(hDC, hPalette, FALSE);

		if(bTransparent)
			hBitmap = WFE_LoadTransparentBitmap(hInst, hDC, clrBackground, clrTransparent,
												hPalette, nID);
		else
		{
			hBitmap = wfe_LoadBitmap(hInst, hDC, MAKEINTRESOURCE(nID));
		}
		if(!pEntry)
			pEntry = new BitmapMapEntry;
		pEntry->clrBackground = clrBackground;
		pEntry->bitmap = hBitmap;
		gBitmapMap.SetAt(nID, (void*&)pEntry);
		::SelectPalette(hDC, hOldPalette, TRUE);
	}

	return pEntry->bitmap;
}

void WFE_RemoveBitmapFromMap(UINT nID)
{
	BitmapMapEntry *pEntry = NULL;

	if(gBitmapMap.Lookup(nID, (void*&)pEntry))
	{
		::DeleteObject(pEntry->bitmap);
		delete pEntry;
		gBitmapMap.RemoveKey(nID);
	}
}

void WFE_DestroyBitmapMap(void)
{
	POSITION pos;
	WORD dwKey;
	BitmapMapEntry *pEntry = NULL;

	// also destroy bitmaps;
	pos = gBitmapMap.GetStartPosition();

	while(pos)
	{
		gBitmapMap.GetNextAssoc(pos, dwKey,(void *&)pEntry);
		DeleteObject(pEntry->bitmap);
		delete pEntry;
	}

	gBitmapMap.RemoveAll();


}

HFONT WFE_GetUIFont(HDC hDC)
{
#ifdef XP_WIN32
		if (sysInfo.m_bWin4 == TRUE)
			ghFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
		else 
#endif
		if (sysInfo.m_bDBCS == FALSE)
			ghFont = (HFONT) GetStockObject(ANSI_VAR_FONT);
		else {
			if (ghFont == NULL) {
				LOGFONT lf;
				XP_MEMSET(&lf,0,sizeof(LOGFONT));
				lf.lfPitchAndFamily = FF_SWISS;
				lf.lfCharSet = IntlGetLfCharset(0);
   				lf.lfHeight = -MulDiv(8, GetDeviceCaps(hDC, LOGPIXELSY), 72);
				strcpy(lf.lfFaceName, IntlGetUIPropFaceName(0));
				lf.lfWeight = 400;
				ghFont = theApp.CreateAppFont( lf );
			}
		}
	return ghFont;
}

void WFE_DestroyUIFont(void)
{
}

CFrameWnd *WFE_GetOwnerFrame(CWnd *pWnd)
{
	return pWnd->GetTopLevelFrame();
}

int WFE_FindMenu(CMenu *pMenu, CString& menuItemName)
{
	if (!pMenu)
	    return -1;

	int nCount = pMenu->GetMenuItemCount();
	
	for(int i = 0; i < nCount; i++)
	{
		char lpszMenuString[64];

		pMenu->GetMenuString(i, lpszMenuString, 64, MF_BYPOSITION);

		if(strcmp( lpszMenuString, menuItemName) == 0)
			return i;

	}

	return -1;

}

int WFE_FindMenuItem(CMenu *pMenu, UINT nCommand)
{
	if (!pMenu)
	    return -1;

	int nCount = pMenu->GetMenuItemCount();
	
	for(int i = 0; i < nCount; i++)
	{

		UINT nID = pMenu->GetMenuItemID(i);

		if(nID == nCommand)
			return i;

	}

	return -1;
}

#ifdef FEATURE_LOAD_BITMAP_FILES
#include "loadbmps.i00"
#endif

HBITMAP WFE_LoadBitmapFromFile (const char* szFileName)
{
    HBITMAP hRetval = NULL;
    
#ifdef FEATURE_LOAD_BITMAP_FILES
    hRetval = wfe_loadbitmapfromfile(szFileName);
#else
#ifdef _WIN32
    //  This only works on >= 95 and NT4.
    hRetval = (HBITMAP)LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
#endif
#endif
    
    return(hRetval);
}

void WFE_FillSolidRect(CDC *pDC, CRect crRect, COLORREF rgbFill)	{
#ifdef XP_WIN32
	pDC->FillSolidRect(crRect, rgbFill);
#else
	::SetBkColor(pDC->m_hDC, rgbFill);
	::ExtTextOut(pDC->m_hDC, 0, 0, ETO_OPAQUE, crRect, NULL, 0, NULL);
#endif
}

#define STRING_ELLIPSES _T("...")

int WFE_DrawTextEx( int iCSID, HDC hdc, LPTSTR lpchText, int cchText, LPRECT lprc, UINT dwDTFormat,
					UINT dwMoreFormat )
{
	if (cchText < 0)
		cchText = _tcslen(lpchText);

#ifdef XP_WIN32
	if ((dwMoreFormat == WFE_DT_CROPRIGHT) && sysInfo.m_bWin4) {
		dwDTFormat |= DT_END_ELLIPSIS;
		return CIntlWin::DrawTextEx(iCSID, hdc, (LPTSTR) lpchText, cchText, lprc,
									dwDTFormat, NULL);
	}
#endif

	LPTSTR pString = NULL;
    CSize cs = CIntlWin::GetTextExtent( iCSID, hdc, lpchText, cchText);

    if (cs.cx > (lprc->right - lprc->left) ) {
		int iNumToRemove = 0;
	    int iEllipsesLength = _tcslen(STRING_ELLIPSES);

		pString = new _TCHAR[cchText + iEllipsesLength + 2];
		if (!pString) {
			ASSERT(0);
			return 0;
		}
		_tcscpy(pString,lpchText);
		while ( cs.cx > (lprc->right - lprc->left) ) {
			if (++iNumToRemove >= cchText) {
				delete [] pString;
				return cs.cy;
			}
			switch (dwMoreFormat) {
				case WFE_DT_CROPRIGHT:
					_tcscpy(&pString[cchText - iNumToRemove], STRING_ELLIPSES);
					break;
				case WFE_DT_CROPCENTER:
					{
						int iLeft = (cchText - iNumToRemove) / 2;
						int iRight = iLeft + ((cchText - iNumToRemove)%2);
						_tcscpy(&pString[iLeft], STRING_ELLIPSES);
						_tcscpy(&pString[iLeft+iEllipsesLength],
								&lpchText[cchText-iRight]);
					}
					break;
				case WFE_DT_CROPLEFT:
						_tcscpy(pString, STRING_ELLIPSES);
						_tcscpy(&pString[iEllipsesLength],
								&lpchText[iNumToRemove]);
					break;
			}
			cs = CIntlWin::GetTextExtent( iCSID, hdc, pString, strlen(pString));
		}
		lpchText = pString;
    }

    int res = CIntlWin::DrawText( iCSID, hdc, (LPTSTR) lpchText, -1,  lprc, dwDTFormat );

	if (pString)
    	delete [] pString;
	
	return res;
	
}

#ifdef __BORLANDC__
	#define	_S_IFREG	S_IFREG
#endif

// If pszLocalName is not NULL, we return the full pathname
//   in local platform syntax, even if file is not found.
//   Caller must free this string.
// Returns TRUE if file already exists
//
MODULE_PRIVATE Bool
XP_ConvertUrlToLocalFile( const char * szURL, char **pszLocalName)
{
    BOOL bFileFound = FALSE;
    // Default assumes no file found - no local filename
    if ( pszLocalName ) {
        *pszLocalName = NULL;
    }

    // Must have "file:" URL type and at least 1 character after "///"
    if ( szURL == NULL || !NET_IsLocalFileURL((char*)szURL) || XP_STRLEN(szURL) <= 8 ) {
        return FALSE;
    }

    // Extract file path from URL: e.g. "/c|/foo/file.html"
    char *szPath = NET_ParseURL( szURL, GET_PATH_PART);
    if ( szPath == NULL ) {
        return FALSE;
    }

  	// Get filename - skip over initial "/"
    char *szFileName;
    if (szPath[0] == '/' && szPath[1] == '/') {
      // bug 35222, if url is a shared Windows (NT or Win95) directory using UNC name,
      // don't skip over the first slash, WH_FileName will do the right thing.
      // I have the suspicion that we should never be skipping the first slash, that
      // WH_FileName knows what to do, but I don't want to make a risky change now.
      szFileName = WH_FileName(szPath, xpURL);
    }
    else {
      szFileName = WH_FileName(szPath+1, xpURL);
    }
    XP_FREE(szPath);

    // Test if file exists
    XP_StatStruct statinfo; 
    if ( -1 != XP_Stat(szFileName, &statinfo, xpURL) &&
        statinfo.st_mode & _S_IFREG ) {
        bFileFound = TRUE;
    }

    if ( pszLocalName ) {
        // Pass string to caller
        // (we didn't change it, so there's no need to XP_STRDUP)
        *pszLocalName = szFileName;
    }
    return bFileFound;
}


// Create a backup filename for renaming current file before saving data
//    Input should be be URL file type "file:///..."
//    Caller must free the string with XP_FREE
//
MODULE_PRIVATE char *
XP_BackupFileName( const char * szURL )
{
    char * szFileName;
    // Must have "file:" URL type and at least 1 character after "///"
    if ( szURL == NULL || !NET_IsLocalFileURL((char*)szURL) || XP_STRLEN(szURL) <= 8 ) {
        return NULL;
    }
    // Add extra space for 8+3 temp filename, but subtract for "file:///"
    szFileName = (char *) XP_ALLOC((XP_STRLEN(szURL)+5)*sizeof(char));
    if ( szFileName == NULL ) {
        return NULL;
    }
	// Get filename but ignore "file:///"
    {
	char* filename;
  if (szURL[8] == '/') {
    // bug 35222, if url is a shared Windows (NT or Win95) directory using UNC name,
    // don't skip over the first slash, WH_FileName will do the right thing.
    // I have the suspicion that we should never be skipping the first slash, that
    // WH_FileName knows what to do, but I don't want to make a risky change now.
    filename = WH_FileName(szURL+7, xpURL);
  }
  else {
    filename = WH_FileName(szURL+8, xpURL);
  }
	if (!filename) return NULL;
	XP_STRCPY(szFileName,filename);
	XP_FREE(filename);
    }

#ifdef XP_WIN16
    char * pEnd = szFileName + XP_STRLEN( szFileName );
    while ( *pEnd != '\\' && pEnd != szFileName ) {
        if ( *pEnd == '.' ) {
            // Truncate at current extension
            *pEnd = '\0';
        }
        pEnd--;
    }
#endif
    // Add extension to the filename
    XP_STRCAT( szFileName, ".BAK" );
    return szFileName;
}

// Copy file routine for Editor - ask user permission
//  to overwrite existing file.
// Params may be local file format or "file://" URL format,
//   and assumes full pathnames
BOOL FE_CopyFile(const char *cpSrc, const char *cpTarg)
{
    char * szSrc = NULL;
    char * szTarg = NULL;
    BOOL bFreeSrc = FALSE;
    BOOL bFreeTarg = FALSE;
    BOOL bSrcExists = TRUE;
    BOOL bTargExists = FALSE;
    XP_StatStruct statinfo; 
    CString csMsg;
    BOOL bResult = FALSE;

    if ( NET_IsLocalFileURL((char*)cpSrc) ){
        bSrcExists = XP_ConvertUrlToLocalFile(cpSrc, &szSrc);        
        bFreeSrc = (szSrc != NULL);
    } else {
        // Use supplied name - assume its a file
        szSrc = (char*)cpSrc;
        bSrcExists = (-1 != XP_Stat(cpSrc, &statinfo, xpURL)) &&
                     (statinfo.st_mode & _S_IFREG);
    }

    if ( bSrcExists ){
        if ( NET_IsLocalFileURL((char*)cpTarg) ){
            bTargExists = XP_ConvertUrlToLocalFile(cpTarg, &szTarg);
            bFreeTarg = (szTarg != NULL);
        } else {
            bTargExists = (-1 != XP_Stat(cpTarg, &statinfo, xpURL)) &&
                          (statinfo.st_mode & _S_IFREG);
            // Use supplied name - assume its a file
            szTarg = (char*)cpTarg;
        }
        if ( bTargExists ) {
            AfxFormatString1(csMsg, IDS_WARN_REPLACE_FILE, szTarg);  
            if ( IDYES == MessageBox( NULL, csMsg, szLoadString(IDS_COPY_FILE), 
                                      MB_YESNO | MB_ICONQUESTION) ) {
                bResult = WFE_CopyFile(szSrc, szTarg);
            }
        } else {
            bResult = WFE_CopyFile(szSrc, szTarg);
        }
        if ( !bResult ) {
            AfxFormatString1(csMsg, IDS_ERR_COPY_FILE, szSrc);  
            MessageBox( NULL, csMsg, szLoadString(IDS_COPY_FILE), MB_OK | MB_ICONSTOP);
        }
    }
    else {
        // Can't copy if no source!
        AfxFormatString1(csMsg, IDS_ERR_SRC_NOT_FOUND, szSrc);  
        MessageBox( NULL, csMsg, szLoadString(IDS_COPY_FILE), MB_OK | MB_ICONSTOP);
    }

    if ( bFreeSrc ) {
        XP_FREE(szSrc);
    }
    if ( bFreeTarg ) {
        XP_FREE(szTarg);
    }
    return bResult;
}

// CLM: Some simple functions to aid in COLORREF to LO_Color conversions

// Fill a LoColor structure
void WFE_SetLO_Color( COLORREF crColor, LO_Color *pLoColor )
{
    if ( pLoColor ) {
    	pLoColor->red = GetRValue(crColor);
        pLoColor->green = GetGValue(crColor);
        pLoColor->blue = GetBValue(crColor);
    }
}

// This allocates a new LoColor structure if it
//   does not exist
void WFE_SetLO_ColorPtr( COLORREF crColor, LO_Color **ppLoColor )
{
	if ( ppLoColor == NULL ) {
        return;
    }
	if ( *ppLoColor == NULL ) {
        *ppLoColor = XP_NEW( LO_Color );
    }
	(*ppLoColor)->red = GetRValue(crColor);
    (*ppLoColor)->green = GetGValue(crColor);
    (*ppLoColor)->blue = GetBValue(crColor);
}

// Convert a LO_Color structure or get the default
//  default document colors
COLORREF WFE_LO2COLORREF( LO_Color * pLoColor, int iColorIndex )
{
#ifdef MOZ_NGLAYOUT
  XP_ASSERT(0);
  return 0;
#else
    COLORREF crColor = 0;
    if ( pLoColor ) {
        crColor = RGB( pLoColor->red, pLoColor->green, pLoColor->blue);
    } 
    else {
        crColor = RGB(lo_master_colors[iColorIndex].red,
                      lo_master_colors[iColorIndex].green,
                      lo_master_colors[iColorIndex].blue);
    }
    return crColor;
#endif /* MOZ_NGLAYOUT */
}

// Parse a "#FFEEAA" style color string into colors make a COLORREF
BOOL WFE_ParseColor(char *pRGB, COLORREF * pCRef )
{
#ifdef MOZ_NGLAYOUT
  XP_ASSERT(0);
  return FALSE;
#else
    uint8 red, green, blue;
    BOOL bColorsFound = LO_ParseRGB(pRGB, &red, &green, &blue);
    if ( bColorsFound ) {
        *pCRef = RGB( red, green, blue);
    }
    return bColorsFound;
#endif /* MOZ_NGLAYOUT */
}

// Helper to clear data
void WFE_FreeLO_Color(LO_Color_struct **ppLo)
{
    if ( *ppLo ) {
        XP_FREE( *ppLo );
        *ppLo = NULL;
    }
}

#ifdef EDITOR
// Get current color at caret or within a selection
COLORREF WFE_GetCurrentFontColor(MWContext * pMWContext)
{
    COLORREF crColor = DEFAULT_COLORREF;

    EDT_CharacterData *pCharData = EDT_GetCharacterData(pMWContext);

    if( !pMWContext ){
        return crColor;
    }

    if( pCharData && 0 != (pCharData->mask & TF_FONT_COLOR) ){
        // We are sure about the color
        if( pCharData->pColor ){
            // If we have a LO_Color struct, then use its color
            crColor = WFE_LO2COLORREF( pCharData->pColor, LO_COLOR_FG );
        }
    } else {
        // We are not sure of color
        crColor = MIXED_COLORREF;
    }
    if(pCharData) EDT_FreeCharacterData(pCharData);
    return crColor;
}
#endif // EDITOR

/******************************************************************************/
/* Thread-safe entry points: */

extern PRMonitor* _pr_TempName_lock;

char *
WH_TempName(XP_FileType type, const char * prefix)
{
	static char buf[_MAX_PATH];	/* protected by _pr_TempName_lock */
	char* result;
#ifdef NSPR
	XP_ASSERT(_pr_TempName_lock);
	PR_EnterMonitor(_pr_TempName_lock);
#endif
	result = XP_STRDUP(xp_TempFileName(type, prefix, NULL, buf));
#ifdef NSPR
	PR_ExitMonitor(_pr_TempName_lock);
#endif
	return result;
}

// The caller is responsible for XP_FREE()ing the return string
PUBLIC char *
WH_FileName (const char *name, XP_FileType type)
{
	char* myName;
	char* result;
	/*
	** I'm not sure this lock is really needed by windows, but just
	** to be safe:
	*/
#ifdef NSPR
	//	XP_ASSERT(_pr_TempName_lock);
	//	PR_EnterMonitor(_pr_TempName_lock);
#endif
	result = xp_FileName(name, type, &myName);
#ifdef NSPR
	//	PR_ExitMonitor(_pr_TempName_lock);
#endif
	return myName;
}

int32 FE_LPtoDPoint(MWContext *pContext, int32 logicalPoint)    
{
      int32 iRetval = logicalPoint;

      CAbstractCX *pAbstract = ABSTRACTCX(pContext);
      if(pAbstract && pAbstract->IsDCContext())       {
              CDCCX *pCx = CXDC(pContext);
              HDC hDC = pCx->GetContextDC();
              if(hDC) {
                      POINT tempPoint;
                      tempPoint.x = 1;
                      tempPoint.y = logicalPoint;
                      // it is printing, convert them from device point to logical point for printers
                      if( TRUE == ::LPtoDP(hDC, &tempPoint, 1) )
                              iRetval = tempPoint.y;
              }
      }

      return(iRetval);
}

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

#ifdef XP_WIN16
static UINT PASCAL DirOpenHookProc(
        HWND hDlg,                /* window handle of the dialog box */
        UINT message,             /* type of message                 */
        UINT wParam,            /* message-specific information    */
        LONG lParam)
#else
static BOOL APIENTRY DirOpenHookProc(
        HWND hDlg,                /* window handle of the dialog box */
        UINT message,             /* type of message                 */
        UINT wParam,            /* message-specific information    */
        LONG lParam)
#endif
{
    switch (message)
    {
        case WM_INITDIALOG:
        //We must put something in this field, even though it is hidden.  This is
        //because if this field is empty, or has something like "*.txt" in it,
        //and the user hits OK, the dlg will NOT close.  We'll jam something in
        //there (like "k5bg") so when the user hits OK, the dlg terminates.
        //Note that we'll deal with the "k5bg" during return processing (see below)
            SetDlgItemText(hDlg, edt1, "k5bg");
        break;
    }
    return (FALSE);
}

/////////////////////////////////////////////////////////////////////////////
// CDirDialog		   
CDirDialog::CDirDialog(CWnd* pParent, LPCTSTR pInitDir)
	: CFileDialog(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, NULL, pParent)
{
	m_szIniFile[0] = '\0';

	m_ofn.lStructSize		= sizeof(OPENFILENAME);
	m_ofn.hwndOwner			= pParent->GetSafeHwnd();
	m_ofn.hInstance			= AfxGetResourceHandle();
	m_ofn.lpstrFile			= m_szIniFile;
	m_ofn.nMaxFile			= 132;
	m_ofn.lpstrFilter		= NULL; 
	m_ofn.lpstrCustomFilter = NULL;
	m_ofn.lpstrInitialDir	= pInitDir; 
	m_ofn.lpstrFileTitle	= NULL;
	m_ofn.nMaxFileTitle		= 132;
	m_ofn.lpstrDefExt		= (LPSTR)NULL;
	m_ofn.lpstrDefExt		= "";
#ifdef XP_WIN32
	m_ofn.Flags = OFN_NOCHANGEDIR | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK |OFN_NONETWORKBUTTON |OFN_LONGNAMES; 
	m_ofn.lpfnHook = (LPOFNHOOKPROC)DirOpenHookProc;
#else
	m_ofn.Flags = OFN_NOCHANGEDIR | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK; 
	m_ofn.lpfnHook = &DirOpenHookProc;
#endif
	m_ofn.lpTemplateName = (LPTSTR)MAKEINTRESOURCE(FILEOPENORD);

}

void CDirDialog::DoDataExchange(CDataExchange* pDX)
{
	CFileDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CDirDialog, CFileDialog)
END_MESSAGE_MAP()

void FE_PokeLibSecOnIdle()
{
    long	lVal;
    DWORD	dwVal;
    HWND	hWnd;
	BYTE	buf[20];
	int		nBytes;

	nBytes = RNG_GetNoise(buf, sizeof(buf));
    RNG_RandomUpdate(buf, nBytes);

    dwVal = GetMessagePos();			// mouse position based
    RNG_RandomUpdate(&dwVal, sizeof(dwVal));

    lVal = GetMessageTime();			// time from startup to last message
    RNG_RandomUpdate(&lVal, sizeof(lVal));

    lVal = GetTickCount();			// we are about to go idle so this is probably
    RNG_RandomUpdate(&lVal, sizeof(lVal));	//   different from the one above

    hWnd = GetClipboardOwner(); 		// 2 or 4 bytes
    RNG_RandomUpdate((void *)&hWnd, sizeof(HWND));
}


void WFE_DrawDragRect(CDC* pdc, LPCRECT lpRect, SIZE size,
	LPCRECT lpRectLast, SIZE sizeLast, CBrush* pBrush, CBrush* pBrushLast)
{
#ifdef XP_WIN32
	pdc->DrawDragRect(lpRect, size, lpRectLast, sizeLast, pBrush, pBrushLast);
#endif
}

void FE_GetDocAndWindowPosition(MWContext * context, int32 *pX, int32 *pY, 
    int32 *pWidth, int32 *pHeight )
{
	if(context && ABSTRACTCX(context) &&
        ABSTRACTCX(context)->IsWindowContext() == TRUE)	{
		CPaneCX *pPaneCX = VOID2CX(context->fe.cx, CPaneCX);

        *pX = pPaneCX->GetOriginX(); 
        *pY = pPaneCX->GetOriginY();                             

    	//	When we report the size to layout, we must always take care to subtract
    	//		for the size of the scrollbars if we have dynamic or always on
    	//		scrollers.
    	if(pPaneCX->DynamicScrollBars() == FALSE 
    	        && pPaneCX->IsHScrollBarOn() == FALSE 
    	        && pPaneCX->IsVScrollBarOn() == FALSE)	{
    	    *pWidth = pPaneCX->GetWidth();
    	    *pHeight = pPaneCX->GetHeight();
    	}
    	else	{
    		*pWidth = pPaneCX->GetWidth() - sysInfo.m_iScrollWidth;
    		*pHeight = pPaneCX->GetHeight() - sysInfo.m_iScrollHeight;
    	}
    }
	else	{
		//	No window here....
		ASSERT(0);
		*pX = *pY = *pHeight = *pWidth = 0;
	}
}

/* Convert an HTML SIZE param value (1-7) into POINT-SIZE value */
int16 FE_CalcFontPointSize(MWContext * pMWContext, intn iSize, XP_Bool bFixedWidth)
{
    if( pMWContext /*&& wfe_iFontSizeMode == ED_FONTSIZE_ADVANCED*/ )
    {
	    EncodingInfo *pEncoding = theApp.m_pIntlFont->GetEncodingInfo(pMWContext);
        int iBaseSize = bFixedWidth ? pEncoding->iFixSize : pEncoding->iPropSize;

        CDCCX *pDC = VOID2CX(pMWContext->fe.cx, CDCCX);

        if( pDC && iSize >= MIN_FONT_SIZE && iSize <= MAX_FONT_SIZE )
            return (int16)(pDC->CalcFontPointSize(iSize, iBaseSize));
    }
    return 0;    
}
