pjs/cmd/winfe/fenet.cpp

1200 строки
35 KiB
C++
Executable File

/* -*- 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 "npapi.h"
#include "np.h"
#include "npassoc.h"
#include "edview.h"
#include "prefapi.h"
#include "hiddenfr.h"
#include "extgen.h"
#define ASYNC_DNS
#ifndef _AFXDLL
#define new DEBUG_NEW // MSVC Debugging new...goes to regular new in release mode
#endif
CMapStringToOb DNSCacheMap(sizeof(CDNSObj));
extern char *FE_FindFileExt(char * path);
/* Remove all objects from the dns cache map */
PUBLIC void FE_DeleteDNSList(MWContext * currentContext)
{
POSITION pos;
CString key;
CDNSObj *obj = NULL;
/* Get the starting position. Actually, whether the position returned is actually the start
is irrelevant. */
pos = DNSCacheMap.GetStartPosition();
while (pos)
{
/* GetNextAssoc sets pos to another position in the map. Again, we don't care where
we just want to know that another position exists so we can continue removing objs. */
DNSCacheMap.GetNextAssoc(pos, key, (CObject *&)obj);
/* Only delete from the list if the current context owns the particular lookup. */
if(obj->context == currentContext)
{
/* Only delete the dns object if there are no
more sockets in the sock list */
if (XP_ListCount(obj->m_sock_list) == 0) {
DNSCacheMap.RemoveKey(key);
delete obj;
}
}
}
}
int FE_AsyncDNSLookup(MWContext *context, char * host_port, PRHostEnt ** hoststruct_ptr_ptr, PRFileDesc *socket)
{
// Initialize our DNS objects.
CDNSObj * dns_obj=NULL;
*hoststruct_ptr_ptr = NULL;
// Look up and see if the host is in our cached DNS lookups and if so....
if (DNSCacheMap.Lookup(host_port,(CObject *&)dns_obj)) {
// See if the cached value was an error, and if so, return an error.
// Should we retry the lookup if it was?
if (dns_obj->m_iError != 0 && dns_obj->i_finished != 0) { // DNS error
WSASetLastError(dns_obj->m_iError);
DNSCacheMap.RemoveKey(host_port);
// Only delete the dns object if there are no
// more sockets in the sock list
if (dns_obj && XP_ListCount(dns_obj->m_sock_list) == 0)
delete dns_obj;
return -1;
}
// If this isn't NULL, then we have a good match. Return it as such and clear the context.
else if (dns_obj->m_hostent->h_name != NULL && dns_obj->i_finished != 0) {
*hoststruct_ptr_ptr = (PRHostEnt *)dns_obj->m_hostent;
return 0;
}
// There isn't an error, and there isn't a host name, return that we are waiting for the
// lookup.... This doesn't make clear sense, unless you take into account that the
// hostent structure is empty when another window is also looking this same host up,
// so we return that we are waiting too.
else {
/* see if the socket we are looking up is already in
* the socket list. If it isn't, add it.
* The socket list provides us with a way to
* send events to NET_ProcessNet for each socket
* waiting for a lookup
*/
XP_List * list_ptr = dns_obj->m_sock_list;
PRFileDesc *tmp_sock;
if(list_ptr)
list_ptr = list_ptr->next;
while(list_ptr) {
tmp_sock = (PRFileDesc *) list_ptr->object;
if(tmp_sock == socket)
return MK_WAITING_FOR_LOOKUP;
list_ptr = list_ptr->next;
}
/* socket not in the list, add it */
XP_ListAddObject(dns_obj->m_sock_list, (void *) socket);
return MK_WAITING_FOR_LOOKUP;
}
} else {
// There is no cache entry, begin the async dns lookup.
// Capture the current window handle, we pass this to the async code, for passing
// back a message when the lookup is complete.
// Actually, just pass the application's main window to avoid
// needing a frame window to do DNS lookups.
HWND hWndFrame = AfxGetApp()->m_pMainWnd->m_hWnd;
// Create and initialize our dns object. Allocating hostent struct, host name and port string,
// and error code from the lookup.
dns_obj = new CDNSObj();
dns_obj->m_hostent = (struct hostent *)XP_ALLOC(MAXGETHOSTSTRUCT * sizeof(char));
if(dns_obj->m_hostent) {
memset(dns_obj->m_hostent, 0, MAXGETHOSTSTRUCT * sizeof(char));
}
dns_obj->m_host = XP_STRDUP(host_port);
dns_obj->m_sock_list = XP_ListNew();
dns_obj->context = context;
XP_ListAddObject(dns_obj->m_sock_list, (void *) socket);
// Insert the entry into the cached DNS lookups.
// Also, set the context, and actually begin the DNS lookup.
// Return that we're waiting for it to complete.
if( !(dns_obj->m_handle = WSAAsyncGetHostByName(hWndFrame,
msg_FoundDNS,
dns_obj->m_host,
(char *)dns_obj->m_hostent,
MAXGETHOSTSTRUCT) ) ) {
delete dns_obj;
return -1;
}
DNSCacheMap.SetAt(host_port,dns_obj);
return MK_WAITING_FOR_LOOKUP;
}
}
CDNSObj::CDNSObj()
{
// make sure we're clean.
m_hostent = NULL;
m_host = NULL;
m_handle = NULL;
context = NULL;
m_iError = 0;
i_finished = 0;
m_sock_list = 0;
}
CDNSObj::~CDNSObj()
{
if(m_hostent) {
XP_FREE(m_hostent);
m_hostent = NULL;
}
if(m_host) {
XP_FREE(m_host);
m_host = NULL;
}
if (m_sock_list) {
while (XP_ListRemoveTopObject(m_sock_list))
;
XP_ListDestroy(m_sock_list);
}
}
#ifdef DEBUG
char *
NOT_NULL (const char *x)
{
if(!x) {
TRACE("Panic! -- An assert of NOT_NULL is about to fail\n");
}
ASSERT(x);
return (char *)x;
}
#endif
// converts a URL to a local (8+3) filename
// the return must be freed by caller
char * fe_URLtoLocalName(const char * url, const char *pMimeType)
{
CString *csURL, csExt,csName;
// Determine the extension.
char aExt[_MAX_EXT];
size_t stExt = 0;
DWORD dwFlags = 0;
#ifdef XP_WIN16
dwFlags = EXT_DOT_THREE;
#endif
aExt[0] = '\0';
stExt = EXT_Invent(aExt, sizeof(aExt), dwFlags, url, pMimeType);
csExt = aExt;
int idx;
csURL = new CString(url);
int iQuestionMark = csURL->Find('?');
int iPound = csURL->Find('#');
int iEnd;
if ((iQuestionMark > 0) && (iPound > 0)) // wow both!
*csURL = csURL->Left(min(iQuestionMark,iPound));
else if ((iQuestionMark > 0) || (iPound > 0)) { // 1 or the other
if (iQuestionMark > 0)
iEnd = iQuestionMark;
else if (iPound > 0)
iEnd = iPound;
*csURL = csURL->Left(iEnd);
}
int iDot = csURL->ReverseFind('.');
int iSlash = csURL->ReverseFind('/');
if (iSlash > 0) {
if (iDot < iSlash) {
if( iSlash == csURL->GetLength() -1 ){
// CLM: If here, there was no filename after last slash
// so lets try to make a name from end of URL path
*csURL = csURL->Left(iSlash);
iSlash = csURL->ReverseFind('/');
}
if (iSlash > 0) {
csName = csURL->Right(csURL->GetLength() - iSlash -1);
}
iDot = 0;
}
else csName = csURL->Mid(iSlash+1, iDot-iSlash-1);
}
// Should we really return NULL?
// There will be cases that don't fit, and does this mean that they won't be able to save a file
// locally since a name can't be formulated?
if (csName.IsEmpty()) {
delete(csURL);
return NULL;
}
#ifdef XP_WIN16
csName = csName.Left(8);
#endif
char *name = csName.GetBuffer(0);
// replace extra periods in 8 character name with underscores
for (idx =0 ; idx < csName.GetLength(); idx++) {
if ((name[idx] == '.')||(name[idx] == ':')) name[idx] = '_';
}
csName.ReleaseBuffer(-1);
*csURL = csName + csExt;
char *cp_retval = strdup((const char *)*csURL);
delete csURL;
return(cp_retval);
}
char* FE_URLToLocalName( char *pStr ){
return fe_URLtoLocalName( (const char*)pStr, NULL);
}
#ifdef XP_WIN16
PUBLIC void * WIN16_malloc(unsigned long size)
{
if((size <= 0) || (size > 64000)) {
TRACE("WIN16_malloc() FUN FUN FUN %ld\n", size);
return(NULL);
}
void *Ret = malloc((size_t) size);
if (!Ret)
TRACE("WIN16_malloc() failed to alloc %ld bytes\n", size);
return(Ret);
}
PUBLIC void * WIN16_realloc(void * ptr, unsigned long size)
{
if((size <= 0) || (size > 64000)) {
TRACE("WIN16_realloc() FUN FUN FUN %ld\n", size);
return(NULL);
}
void * Ret = realloc(ptr, (size_t) size);
if (!Ret)
TRACE("WIN16_realloc() failed to realloc %ld bytes\n", size);
return(Ret);
}
PUBLIC void WIN16_bcopy(char * from_ptr, char * to_ptr, unsigned long size)
{
if((!to_ptr) || (size > 64000)) {
TRACE("WIN16_bcopy() FUN FUN FUN %ld\n", size);
return;
}
memmove(to_ptr, from_ptr, (size_t) size);
}
#endif /* XP_WIN16 */
//
// Add a temporary file to the list of files that get deleted on exit
//
void FE_DeleteFileOnExit(const char *pFilename, const char *pURL)
{
// Remember the information in the INI file.
CString csFileName = pFilename;
csFileName.MakeLower();
theApp.WriteProfileString("Temporary File URL Resolution", csFileName, pURL);
}
//
// We are exiting now. Clean up any temp files we have generated
//
void FE_DeleteTempFilesNow()
{
char *pBuffer = new char[8192];
theApp.GetPrivateProfileString("Temporary File URL Resolution", NULL, "", pBuffer, 8192, AfxGetApp()->m_pszProfileName);
// We have a double null terminated list of file names here.
// Go ahead and go through each one, deleteing them all.
char *pTraverse = pBuffer;
int iRemoveResult = 0;
while(*pTraverse != '\0') {
// Remove this file.
iRemoveResult = remove(pTraverse);
ASSERT(!iRemoveResult);
// Go on to the next entry.
while(*pTraverse != '\0') {
pTraverse++;
}
pTraverse++;
}
delete[] pBuffer;
// Clear out the section in the INI file also.
#ifdef XP_WIN16
::WritePrivateProfileString("Temporary File URL Resolution", NULL, NULL, AfxGetApp()->m_pszProfileName);
#else
// To clear them out in the Registry, use RegDeleteKey.
// Create the appropriate key.
HKEY hKey;
DWORD dwDisposition;
char aBuffer[256];
sprintf(aBuffer, "Software\\%s\\%s", "Netscape", "Netscape Navigator");
long lResult = RegCreateKeyEx(HKEY_CURRENT_USER, aBuffer, NULL, NULL, NULL,
KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition);
if(lResult != ERROR_SUCCESS) {
return;
}
RegDeleteKey(hKey, "Temporary File URL Resolution");
RegCloseKey(hKey);
#endif
}
//
// Since netlib is too stubborn to give us a flush cache function do it
// by hand
//
PUBLIC void
FE_FlushCache()
{
int32 prefInt;
NET_SetMemoryCacheSize(0);
PREF_GetIntPref("browser.cache.memory_cache_size",&prefInt);
NET_SetMemoryCacheSize(prefInt * 1024);
}
void CheckLegalFileName(char* full_path)
{
CString temp = full_path;
#ifdef XP_WIN16
static char funnychar[13] = "\\/:*?\"<>| ,+";
#else
static char funnychar[10] = "\\/:*?\"<>|";
#endif
int index;
while ((index = temp.FindOneOf(funnychar)) != -1) {
temp.SetAt(index, '_'); // replace the illegal char with space.
}
strcpy(full_path, temp);
}
int SetCurrentDir(char * pDir)
{
if( pDir ){
#ifdef XP_WIN16
// We need to double "\" characters when setting directory
char dir[2*_MAX_PATH];
char * pSource = pDir;
char * pDest = dir;
while( *pSource ){
*pDest++ = *pSource;
if( *pSource == '\\' ){
*pDest++ = '\\';
}
pSource++;
}
*pDest = '\0';
// This is SLOW ( > 5 sec) on Win95!
return _chdir(dir);
#else
BOOL bRet = SetCurrentDirectory(pDir);
return bRet ? 0 : -1;
#endif // XP_WIN16
}
return -1;
}
//
// Get a save file name from the user
// If caller has an idea for the name it should be passed in initial else
// initial should be NULL
// Return a pointer (to be freed by callee) of full path name else NULL if
// the selection was canceled
// It is up to the user to free the filename
//
//CLM: Why the ?#$% is type passed in as a pointer???
// If pDocumentTitle is not null, then edit box is added to allow user to enter document title for edited documents
MODULE_PRIVATE char *
wfe_GetSaveFileName(HWND m_hWnd, char * prompt, char * initial, int * type, char** ppPageTitle)
{
OPENFILENAME fname;
char * full_path;
char name[2 * _MAX_FNAME];
char filter[256];
char * extension = NULL;
char * pOldExt = NULL;
int index = 1;
Bool bAppendHTML_Ext = FALSE;
BOOL bHtmlOnly = FALSE;
char aIExt[_MAX_EXT];
// We restrict saving type to HTML in the editor
CString htm_filter_used;
// Only pre-4.0 version show the file filter bug
BOOL bBadNT = sysInfo.m_bWinNT && sysInfo.m_dwMajor < 4;
if(type && *type == HTM_ONLY){
bHtmlOnly = TRUE;
if (bBadNT)
htm_filter_used.LoadString(IDS_FILTERNT_HTM);
else
#ifdef XP_WIN16
htm_filter_used.LoadString(IDS_FILTER_HTM16);
#else
htm_filter_used.LoadString(IDS_FILTER_HTM32);
#endif
} else {
if (bBadNT)
// For NT, use same string as 16bit
htm_filter_used.LoadString(IDS_HTM_FILTER16);
else
#ifdef XP_WIN16
htm_filter_used.LoadString(IDS_HTM_FILTER16);
#else
htm_filter_used.LoadString(IDS_HTM_FILTER32);
#endif
}
// Default is to use the filter that includes *.htm/*.html, *.txt, and *.*
strcpy(filter, htm_filter_used);
// try to guess the type
if(initial) {
if( bHtmlOnly || strcasestr(initial, "htm") || strcasestr(initial, "html")) {
/*__EDITOR__*/
// Use ".html" for 32-bit versions
#ifdef XP_WIN16
extension = "htm";
#else
extension = "html";
#endif
if( bHtmlOnly ){
// This will force replacing any existing EXT with value "extension"
bAppendHTML_Ext = TRUE;
}
/*__EDITOR__END*/
index = 1;
} else if(strcasestr(initial, "gif")) {
strcpy(filter, szLoadString(IDS_GIF_FILTER));
extension = "gif";
index = 1;
} else if(strcasestr(initial, "xbm")) {
strcpy(filter, szLoadString(IDS_XBM_FILTER));
extension = "xbm";
index = 1;
} else if(strcasestr(initial, "jpg") || strcasestr(initial, "jpeg")) {
#ifdef XP_WIN16
strcpy(filter, szLoadString(IDS_JPG_FILTER16));
#else
strcpy(filter, szLoadString(IDS_JPG_FILTER32));
#endif
extension = "jpg";
index = 1;
} else if(strcasestr(initial, "txt")) {
strcpy(filter, htm_filter_used); //htm_filter
extension = "txt";
index = 2;
} else if(strcasestr(initial, "p12")) {
extension = "p12";
strcpy(filter, szLoadString(IDS_PKCS12_FILTER));
} else {
extension = aIExt;
aIExt[0] = '\0';
size_t stExt = 0;
DWORD dwFlags = EXT_NO_PERIOD;
#ifdef XP_WIN16
dwFlags |= EXT_DOT_THREE;
#endif
stExt = EXT_Invent(aIExt, sizeof(aIExt), dwFlags, initial, NULL);
if(!stExt) {
extension = NULL;
}
if(extension) {
strcpy(filter, szLoadString(IDS_ALL_FILTER));
} else {
// We have a name but no extension
// Use the list for HTML files, *.txt, or *.*
if ( !type || (*type == 0 || *type == ALL || *type == HTM || *type == HTM_ONLY) ) {
// If HTM was requested type or no type requested, then build
// a better suggested name
bAppendHTML_Ext = TRUE;
}
}
// Show *.htm as initial filter
index = 1;
}
}
if( (!initial && type && (*type == HTM || *type == HTM_ONLY)) || bAppendHTML_Ext ){
bAppendHTML_Ext = TRUE;
// no initial name --- assume HTML if it was requested type
index = 1;
// Use ".html" for 32-bit versions
#ifdef XP_WIN16
extension = "htm";
#else
extension = "html";
#endif
} else if (!initial && type && (*type == P12)) {
extension = "p12";
strcpy(filter, szLoadString(IDS_PKCS12_FILTER));
} else if(!initial) {
extension = "*";
index +=2;
}
// Replace '\n' with '\0' before pass to FileCommon dialog
for (char *p = filter; *p ; p++) {
if (*p == '\n')
*p = '\0';
}
// space for the full path name
full_path = (char *) XP_ALLOC(2 * _MAX_PATH * sizeof(char));
if(!full_path)
return(NULL);
// clear stuff out
name[0] = '\0';
full_path[0] = '\0';
char aDrive[_MAX_DRIVE];
char aPath[_MAX_PATH];
char aFName[_MAX_FNAME];
char aExt[_MAX_EXT];
CString defaultDir;
BOOL bUsingDefault = FALSE;
BOOL bUsingEditorDir = FALSE;
char *fileName = initial;
#ifdef XP_WIN16
char dosFileName[13];
#endif
if(fileName) {
#ifdef XP_WIN16
// convert file name to be 8.3
char *ext = FE_FindFileExt(fileName);
// Fill with 0 to assure proper termination
memset(dosFileName, 0, 13*sizeof(char));
if( ext ){
char *firstDot = strchr(fileName, '.');
if ((firstDot - fileName) > 8)
// chop it to 8 characters
firstDot = fileName+8;
strncpy(dosFileName, fileName, (firstDot-fileName));
strncpy(dosFileName+(firstDot-fileName), ext,
min(strlen(ext), 4));
fileName = dosFileName;
} else if( strlen(fileName) > 8 ){
strncpy(dosFileName, fileName, 8);
fileName = dosFileName;
}
#endif
_splitpath(fileName, aDrive, aPath, aFName, aExt);
XP_STRCPY(full_path, aFName);
if(bAppendHTML_Ext){
// Here's where we build the better suggested name
XP_STRCAT(full_path, ".");
XP_STRCAT(full_path, extension);
}
else {
XP_STRCAT(full_path, aExt);
}
defaultDir += aDrive;
defaultDir += aPath;
}
char currentDir[_MAX_PATH+1];
char * HaveCurrentDir = NULL;
char dir[_MAX_PATH];
if (defaultDir.IsEmpty()) {
int iLen = _MAX_PATH;
if(bHtmlOnly){
PREF_GetCharPref("editor.html_directory",dir,&iLen);
bUsingEditorDir = TRUE;
// Save current directory to restore later
// This is Win16 Compatable (GetCurrentDirectory is available for Win32)
HaveCurrentDir = _getdcwd(0, currentDir, _MAX_PATH);
} else {
PREF_GetCharPref("browser.download_directory",dir,&iLen);
bUsingDefault = TRUE;
}
defaultDir = dir;
}
CheckLegalFileName(full_path);
memset(&fname, 0, sizeof(fname));
fname.lStructSize = sizeof(OPENFILENAME);
fname.hwndOwner = m_hWnd;
fname.lpstrFilter = filter;
fname.lpstrCustomFilter = NULL;
fname.nFilterIndex = index;
fname.lpstrFile = full_path;
fname.nMaxFile = 2 * _MAX_PATH;
fname.lpstrFileTitle = name;
fname.nMaxFileTitle = 2 * _MAX_FNAME;
fname.lpstrInitialDir = defaultDir;
fname.lpstrTitle = prompt;
fname.lpstrDefExt = extension;
fname.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
BOOL bResult = FEU_GetSaveFileName(&fname);
// see if the user selects a file or hits cancel
if(bResult) {
if (bUsingDefault || bUsingEditorDir ) {
char *full_dir = (char *) XP_STRDUP(full_path);
full_dir[fname.nFileOffset] = '\0';
if( bUsingDefault ){
PREF_SetCharPref("browser.download_directory", full_dir);
} else {
PREF_SetCharPref("editor.html_directory", full_dir);
if( HaveCurrentDir ){
SetCurrentDir(currentDir);
}
}
XP_FREE(full_dir);
}
// tell the caller if the user selected to save this as text
// if a source file and we want to save as text pass it back else
// just pass back that we want to save it as source
if(type) {
if(filter == htm_filter_used && fname.nFilterIndex == TXT)
*type = TXT;
else
*type = HTM;
}
// tack the extension on at the end if the name doesn't have one
// the Win9x dialog is not really respecting the DefExt as
// explained in the help files
char * pLastBit = strrchr(full_path, '\\');
if(!pLastBit)
pLastBit = full_path;
else
pLastBit++; // skip over slash
// figure out if the user has put an extension on the path name
char * pNewExt = strrchr(pLastBit, '.');
// Common dialog will act incorrectly if user uses ".shtml".
// We get the following: "fname.shtml.html" so strip off the ".html"
if(pNewExt && !_stricmp(pNewExt, ".html")) {
*pNewExt = '\0';
char * pExt = strrchr(pLastBit, '.');
if(pExt && !_stricmp(pExt, ".shtml")){
// We found the user's ".shtml", so return truncated version
return(full_path);
}
// ".shtml" not found - restore the period
*pNewExt = '.';
}
//
// so we have a new extension that is not equal to the original one
//
// see if it ends .txt if so then the user really wanted to save a text file
// no matter what the selector is set to. Damn Win9x guidelines
if(pNewExt && !_stricmp(pNewExt, ".txt")) {
if(type)
*type = TXT;
return(full_path);
}
return(full_path);
} else {
// user hit cancel
if( full_path) XP_FREE(full_path);
return(NULL);
}
}
// Appends the specified filter description and pattern to the end of szFilterString,
// adding double NULL at the end. szFilterString must be a double NULL terminated
// string upon entry
//
// This routine doesn't add a duplicate to the list of description/patterns that are
// already there
void wfe_AppendToFilterString(char* szFilterString, char* szDescription, char* szPattern)
{
if(!szFilterString || !szDescription || !szPattern)
return;
// Find the end of the existing filter (double NULL terminated). While we're at it,
// check for an existing entry that's an exact match
char* pStr = szFilterString;
BOOL bDescriptionMatches;
while (*pStr != '\0') {
// See if the description matches
bDescriptionMatches = stricmp(pStr, szDescription) == 0;
// Skip over the description and get the filter pattern
pStr = strchr(pStr, '\0') + 1;
// Filter description and pattern really must exist as a pair
ASSERT(*pStr != '\0');
if (*pStr == '\0')
break; // found the double NULL terminator
// If the description matched, then check the filter pattern
if (bDescriptionMatches && stricmp(pStr, szPattern) == 0)
return; // don't add a duplicate string
// Skip over the filter pattern and get the next pair
pStr = strchr(pStr, '\0') + 1;
}
// At this point we're pointing to the second NULL terminator. Add the new
// description to the end
strcpy(pStr, szDescription);
// Append the filter pattern, leaving the NULL terminator at the end of the
// description
pStr += strlen(szDescription) + 1;
strcpy(pStr, szPattern);
// Add a final NULL terminator
pStr += strlen(szPattern) + 1;
*pStr = '\0';
}
// Appends the szFilterAppendString to the end of the szFilterString, adding
// double NULL at the end. szFilterString must be a double NULL terminated string
// upon entry. szFilterAppendString must also be a double NULL terminated string
void wfe_AppendFilterStringToFilterString(char* szFilterString,
char* szFilterAppendString)
{
if((szFilterString == NULL) || (szFilterAppendString == NULL))
return;
// find the end of the existing filter, (double NULL)
// szFilterString MUST be a double NULL term'd string or bad things happen
char* pCharFilterString = szFilterString;
while(!((*pCharFilterString == '\0') && (*(pCharFilterString + 1) == '\0')))
pCharFilterString++;
if(pCharFilterString != szFilterString) // if the string is not empty
pCharFilterString++; // start at the second NULL
// find the size of the szFilterAppendString
char* pCharString = szFilterAppendString;
int iStringSize = 0;
while(!((*pCharString == '\0') && (*(pCharString + 1) == '\0')))
{
pCharString++;
iStringSize++;
}
// append the szFilterAppendString to the filter
memcpy(pCharFilterString, szFilterAppendString, iStringSize);
// double NULL terminate the string
pCharFilterString += iStringSize;
*pCharFilterString = '\0', pCharFilterString++, *pCharFilterString = '\0';
}
static BOOL
IsNullPlugin(NPFileTypeAssoc* pAssociation)
{
// The null plug-in is the default plug-in handler and has the wildcard
// '*' as it's file extent
return pAssociation->extentstring && strcmp(pAssociation->extentstring, "*") == 0;
}
//
// construct a filter string from all the plugins file associations, and
// from the previous filter template
//
//CLM: Modified this to allow restricting filter to just *.HTM;*.HTML
// Use HTM_ONLY (-1) instead of HTM
//
char* wfe_ConstructFilterString(int type)
{
NPFileTypeAssoc* pAssociation = NULL;
if (type != HTM_ONLY){
// get the list of associations for all plugin MIME types
// ONLY if we are not looking for just HTM/HTML files (used for Editor)
pAssociation = NPL_GetFileAssociation(NULL);
}
char filter[256];
int iFilterSize;
// Pre-4.0 NT Common Dialog has a bug: *.htm;*.html shows ".htm" files as ".html"
if ( sysInfo.m_bWinNT && sysInfo.m_dwMajor < 4 ) {
if(type == HTM_ONLY)
strcpy(filter, szLoadString(IDS_FILTERNT_HTM));
else
strcpy(filter, szLoadString(IDS_FILTERNT));
iFilterSize = strlen(filter);
}
else {
if (type == HTM_ONLY)
#ifdef XP_WIN16
strcpy(filter, szLoadString(IDS_FILTER_HTM16));
#else
strcpy(filter, szLoadString(IDS_FILTER_HTM32));
#endif
else if(type == P12)
strcpy(filter, szLoadString(IDS_PKCS12_FILTER));
else
#ifdef XP_WIN16
strcpy(filter, szLoadString(IDS_FILTER16));
#else
strcpy(filter, szLoadString(IDS_FILTER32));
#endif
iFilterSize = strlen(filter);
}
// Replace '\n' with '\0' before pass to CommDialog
for (char *p = filter; *p ; p++)
if (*p == '\n') *p = '\0';
if(pAssociation == NULL)
{
char* pString = NULL;
if(iFilterSize) {
pString = (char *)XP_ALLOC(iFilterSize);
}
if(pString) {
memcpy(pString, filter, iFilterSize);
}
return pString;
}
// Determine how much memory to allocate. The filter string consists of pairs of NULL
// terminated strings. The first string describes the filter and the second string
// specifies the filter pattern
int iAccumulator = 0;
do {
if (pAssociation->fileType && pAssociation->extentlist) {
// Add in space for the filter description
iAccumulator += strlen((const char*)pAssociation->fileType);
// NULL terminator between filter desciption and filter pattern
iAccumulator++;
// Determine the space needed for the filter pattern. There can be multiple
// filter patterns per filter description by separating the filter patterns
// with a semicolon
for (char** ppExtentList = pAssociation->extentlist; *ppExtentList;) {
// The extent list is just the file extension. The filter pattern should
// include a "*."
iAccumulator += strlen("*.") + strlen(*ppExtentList);
// If there's another filter pattern then add a semicolon delimiter
if (*++ppExtentList)
iAccumulator++;
}
// Space for NULL terminating the filter pattern string
iAccumulator++;
}
pAssociation = pAssociation->pNext;
} while(pAssociation);
// Add in room for the basic template (this size includes the final NULL
// terminator)
iAccumulator += iFilterSize;
char* pFilterString = (char *) XP_ALLOC(iAccumulator);
if (pFilterString) {
// Start off with an empty filter string
pFilterString[0] = '\0';
pFilterString[1] = '\0';
// Add the basic template
wfe_AppendFilterStringToFilterString(pFilterString, filter);
pAssociation = NPL_GetFileAssociation(NULL);
// Add the plugin filters
for (pAssociation = NPL_GetFileAssociation(NULL); pAssociation; pAssociation = pAssociation->pNext) {
if (IsNullPlugin(pAssociation))
continue;
if (pAssociation->fileType && pAssociation->extentlist) {
// Build the filter pattern(s). There can be multiple filter patterns for a
// filter description by separating the filter patterns with a semicolon
CString strFilterPattern;
for (char** ppExtentList = pAssociation->extentlist; *ppExtentList;) {
// The extent list is just the file extension. The filter pattern should
// include a "*."
strFilterPattern += "*.";
strFilterPattern += *ppExtentList;
// If there's another filter pattern then add a semicolon delimiter
if (*++ppExtentList)
strFilterPattern += ';';
}
// Add the filter description and filter pattern if it doesn't already exist
// in the list. You can end up with duplicates if there is a plug-in that registers
// more than one MIME type for a given extension, e.g. audio/aiff and audio/x-aiff
wfe_AppendToFilterString(pFilterString, (char*)pAssociation->fileType,
(char*)(const char*)strFilterPattern);
}
}
}
return pFilterString;
}
#ifdef XP_WIN16
PRIVATE void wfe_InplaceToLower(char *pConvert) {
while (pConvert && *pConvert) {
*pConvert = XP_TO_LOWER(*pConvert);
pConvert++;
}
}
#endif
//
// Return the path name of a file the user has picked for a given task
// It is up to the user to free the filename
// The file must exist
// Return NULL if the user cancels
// If pOpenIntoEditor is not null, then radio buttons are added to select window type
// set initial choice and read user's choice from this
MODULE_PRIVATE char *
wfe_GetExistingFileName(HWND m_hWnd, char * prompt, int type, XP_Bool bMustExist, BOOL * pOpenIntoEditor)
{
OPENFILENAME fname;
char * full_path = NULL;
char name[_MAX_FNAME];
char * defaultDir = NULL;
char* filter = wfe_ConstructFilterString(type);
/* initialize the OPENFILENAME struct */
BOOL result;
UINT index = (type == HTM_ONLY) ? 1 : type;
// space for the full path name
full_path = (char *) XP_ALLOC(_MAX_PATH * sizeof(char));
if(!full_path){
XP_FREE(filter);
return(NULL);
}
name[0] = '\0';
full_path[0] = '\0';
char currentDir[_MAX_PATH+1];
char * HaveCurrentDir = NULL;
char dir[_MAX_PATH];
if(type == HTM_ONLY){
int iLen = _MAX_PATH;
PREF_GetCharPref("editor.html_directory",dir,&iLen);
defaultDir = dir;
// Save current directory to restore later
HaveCurrentDir = _getdcwd(0, currentDir, _MAX_PATH);
}
// set up the entries
fname.lStructSize = sizeof(OPENFILENAME);
fname.hwndOwner = m_hWnd;
fname.lpstrFilter = filter;
fname.lpstrCustomFilter = NULL;
fname.nFilterIndex = index;
fname.lpstrFile = full_path;
fname.nMaxFile = _MAX_PATH;
fname.lpstrFileTitle = name;
fname.nMaxFileTitle = _MAX_FNAME;
fname.lpstrInitialDir = defaultDir;
fname.lpstrTitle = prompt;
fname.Flags = OFN_HIDEREADONLY;
fname.lpstrDefExt = NULL;
if(bMustExist)
fname.Flags |= OFN_FILEMUSTEXIST;
result = FEU_GetOpenFileName(&fname);
XP_FREE(filter);
// see if the user selects a file or hits cancel
if(result) {
// On win16 force to lower case.
#ifdef XP_WIN16
wfe_InplaceToLower(full_path);
#endif
if(type == HTM_ONLY){
char *full_dir = (char *) XP_STRDUP(full_path);
full_dir[fname.nFileOffset] = '\0';
PREF_SetCharPref("editor.html_directory",full_dir);
XP_FREE(full_dir);
if( HaveCurrentDir ){
SetCurrentDir(currentDir);
}
}
return(full_path);
} else {
// user hit cancel
if(full_path) XP_FREE(full_path);
return(NULL);
}
}
// CLM: Similar to wfe_GetExistingFileName(),
// but designed to select Image Files: *.jpg, *.gif
//
// Return the path name of a file the user has picked for a given task
// It is up to the user to free the filename
// Return NULL if the user cancels
//
MODULE_PRIVATE char *
wfe_GetExistingImageFileName(HWND m_hWnd, char * prompt, XP_Bool bMustExist)
{
OPENFILENAME fname;
char * full_path;
char name[_MAX_FNAME];
char filter[256];
#ifdef XP_WIN16
strcpy(filter, szLoadString(IDS_IMAGE_FILTER16));
#else
strcpy(filter, szLoadString(IDS_IMAGE_FILTER32));
#endif
// replace '\n' with '\0' before pass to CommonDialog
for (char *p = filter; *p ; p++)
if (*p == '\n') *p = '\0';
/* initialize the OPENFILENAME struct */
// space for the full path name
full_path = (char *) XP_ALLOC(_MAX_PATH * sizeof(char));
if(!full_path)
return(NULL);
name[0] = '\0';
full_path[0] = '\0';
// Save current directory to restore later
char currentDir[_MAX_PATH+1];
char * HaveCurrentDir = _getdcwd(0, currentDir, _MAX_PATH);
char defaultDir[_MAX_PATH];
int iLen = _MAX_PATH;
PREF_GetCharPref("editor.image_directory",defaultDir,&iLen);
// set up the entries
fname.lStructSize = sizeof(OPENFILENAME);
fname.hwndOwner = m_hWnd;
fname.lpstrFilter = filter;
fname.lpstrCustomFilter = NULL;
fname.nFilterIndex = 0;
fname.lpstrFile = full_path;
fname.nMaxFile = _MAX_PATH;
fname.lpstrFileTitle = name;
fname.nMaxFileTitle = _MAX_FNAME;
fname.lpstrInitialDir = defaultDir;
fname.lpstrTitle = prompt;
fname.Flags = OFN_HIDEREADONLY;
fname.lpstrDefExt = NULL;
if(bMustExist)
fname.Flags |= OFN_FILEMUSTEXIST;
// see if the user selects a file or hits cancel
if(FEU_GetOpenFileName(&fname)) {
// On win16 force to lower case.
#ifdef XP_WIN16
wfe_InplaceToLower(full_path);
#endif
char *full_dir = (char *) XP_STRDUP(full_path);
full_dir[fname.nFileOffset] = '\0';
PREF_SetCharPref("editor.image_directory",full_dir);
XP_FREE(full_dir);
if( HaveCurrentDir ){
SetCurrentDir(currentDir);
}
return(full_path);
} else {
// user hit cancel
XP_FREE(full_path);
return(NULL);
}
}
// Just need a stub. Always fail
//
extern "C" int dupsocket(int foo)
{
return(-1);
}
// INTL_ResourceCharSet(void)
//
extern "C" char *INTL_ResourceCharSet(void)
{
return szLoadString(IDS_RESOURCE_CHARSET) ;
}