Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3314 lines
76 KiB

/*
Enhanced NCSA Mosaic from Spyglass
"Guitar"
Copyright 1994 Spyglass, Inc.
All Rights Reserved
Author(s):
Jim Seidman [email protected]
Albert Lee [email protected]
*/
#include "all.h"
#include <iexpdde.h>
#include "contmenu.h"
#include "htmlutil.h"
#include "http_spm.h"
#include "wc_html.h"
#include "w32cmd.h"
#ifdef FEATURE_IAPI
#include "w32dde.h"
#endif
#ifdef FEATURE_IAPI
extern HTList *protocols;
static DWORD g_DdeInst = 0; // DDE instance
static HSZ hszMosaic = 0; // "IEXPLORE" string
static HSZ hszReturn = 0; // "Return" string
static struct hash_table *pTopicHash; // hash table to keep track of topics
static struct hash_table *pServerHash = NULL; // hash table to keep track of currently active servers
static char *pArgumentBuffer; // temporary argument buffer needed for parsing arguments
static int nArgumentBufferLength; // argument buffer length for pArgumentBuffer
static char *pArgReturnBuffer; // argument return buffer
static char *pCurrentArgPos; // current position within argument buffer
static long TransactionID = 1; // unique transaction ID
static HTList *pTransList; // transaction list
static struct TRANSACTIONMAPSTRUCT *pTransactionMap; // structure used to map incoming/outgoing transactions
#pragma data_seg(DATA_SEG_READ_ONLY)
/* HTTP protocol prefix for host */
PRIVATE_DATA CCHAR s_cszHTTPProtocol[] = "http://";
/* name of topic used to issue method invocation response */
PRIVATE_DATA CCHAR s_cszResponseTopic[] = IEXP_DDE_TOPIC_INVOKE_METHOD_RESPONSE;
#pragma data_seg()
#ifdef DEBUG
/*
** IsContained()
**
** Determines whether or not the given jelly data is contained within the given
** jar data.
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL IsContained(PCVOID pcvJar, UINT ucbJarLen, PCVOID pcvJelly,
UINT ucbJellyLen)
{
BOOL bResult = FALSE;
ASSERT(IS_VALID_READ_BUFFER_PTR(pcvJar, CVOID, ucbJarLen));
ASSERT(IS_VALID_READ_BUFFER_PTR(pcvJelly, CVOID, ucbJellyLen));
if (EVAL(pcvJelly >= pcvJar))
{
UINT ucbJellyOffset;
ucbJellyOffset = (PCBYTE)pcvJelly - (PCBYTE)pcvJar;
if (EVAL(ucbJellyOffset <= ucbJarLen) &&
EVAL(ucbJellyLen <= ucbJarLen - ucbJellyOffset))
bResult = TRUE;
}
return(bResult);
}
PRIVATE_CODE BOOL IsValidHSZ(HSZ hsz)
{
return(EVAL(hsz != NULL));
}
PRIVATE_CODE BOOL IsValidHDDEDATA(HDDEDATA hdd)
{
return(EVAL(hdd != NULL));
}
PRIVATE_CODE BOOL IsValidPCWWW_INVOKEMETHODDATA(PCWWW_INVOKEMETHODDATA pcimd)
{
return(IS_VALID_READ_PTR(pcimd, CWWW_INVOKEMETHODDATA) &&
IS_VALID_READ_BUFFER_PTR(pcimd, CBYTE, pcimd->dwcbLen) &&
IS_VALID_STRING_PTR(IMD_HOST_PTR(pcimd), CSTR) &&
EVAL(IsContained(pcimd, pcimd->dwcbLen, IMD_HOST_PTR(pcimd), lstrlen(IMD_HOST_PTR(pcimd)) + 1)) &&
IS_VALID_READ_BUFFER_PTR(IMD_METHOD_PTR(pcimd), CBYTE, pcimd->dwcbMethodLen) &&
EVAL(IsContained(pcimd, pcimd->dwcbLen, IMD_METHOD_PTR(pcimd), pcimd->dwcbMethodLen)));
}
PRIVATE_CODE BOOL IsValidWWWInvokeMethodResult(WWW_INVOKEMETHODRESULT imr)
{
BOOL bResult;
switch (imr)
{
case IMR_OK:
case IMR_ABORT:
case IMR_ERROR:
bResult = TRUE;
break;
default:
bResult = FALSE;
ERROR_OUT(("IsValidWWWInvokeMethodResult(): Invalid WWW_INVOKEMETHODRESULT %d.",
imr));
break;
}
return(bResult);
}
PRIVATE_CODE BOOL IsValidPCWWW_RESPONSEDATA(PCWWW_RESPONSEDATA pcrd)
{
return(IS_VALID_READ_PTR(pcrd, CWWW_RESPONSEDATA) &&
IS_VALID_READ_BUFFER_PTR(pcrd, CBYTE, pcrd->dwcbLen) &&
EVAL(IsValidWWWInvokeMethodResult(pcrd->imr)) &&
IS_VALID_READ_BUFFER_PTR(RD_RESPONSE_PTR(pcrd), CBYTE, pcrd->dwcbResponseLen) &&
EVAL(IsContained(pcrd, pcrd->dwcbLen, RD_RESPONSE_PTR(pcrd), pcrd->dwcbResponseLen)));
}
#endif /* DEBUG */
PRIVATE_CODE BOOL CopyDDEString(HSZ hsz, PSTR *ppsz)
{
BOOL bResult;
DWORD dwcbLen;
ASSERT(IS_VALID_HANDLE(hsz, SZ));
ASSERT(IS_VALID_WRITE_PTR(ppsz, PSTR));
/* Get string length. (+ 1) for null terminator. */
dwcbLen = DdeQueryString(g_DdeInst, hsz, NULL, 0, CP_WINANSI) + 1;
bResult = AllocateMemory(dwcbLen, ppsz);
if (bResult)
{
/* Retrieve DDE data. */
EVAL(DdeQueryString(g_DdeInst, hsz, *ppsz, dwcbLen, CP_WINANSI) + 1
== dwcbLen);
TRACE_OUT(("CopyDDEString(): Copied DDE string \"%s\".",
*ppsz));
}
else
*ppsz = NULL;
ASSERT((bResult &&
IS_VALID_STRING_PTR(*ppsz, STR)) ||
(! bResult &&
EVAL(! *ppsz)));
return(bResult);
}
/*
** CopyDDEData()
**
** Copies data from a DDE data handle in to the local heap.
**
** Arguments:
**
** Returns:
**
** Side Effects: none
**
** N.b., *pdwcbLen is returned >= the length of the actual data.
*/
PRIVATE_CODE BOOL CopyDDEData(HDDEDATA hdd, PBYTE *ppbyteDDEData,
PDWORD pdwcbLen)
{
BOOL bResult;
ASSERT(IS_VALID_HANDLE(hdd, DDEDATA));
ASSERT(IS_VALID_WRITE_PTR(ppbyteDDEData, PBYTE));
ASSERT(IS_VALID_WRITE_PTR(pdwcbLen, DWORD));
/* Get data length. */
*pdwcbLen = DdeGetData(hdd, NULL, 0, 0);
bResult = AllocateMemory(*pdwcbLen, ppbyteDDEData);
if (bResult)
{
TRACE_OUT(("CopyDDEData(): Allocated %lu byte data buffer to hold DDE data.",
*pdwcbLen));
/* Retrieve DDE data. */
EVAL(DdeGetData(hdd, *ppbyteDDEData, *pdwcbLen, 0) == *pdwcbLen);
}
else
{
*ppbyteDDEData = NULL;
*pdwcbLen = 0;
}
ASSERT((bResult &&
IS_VALID_WRITE_BUFFER_PTR(*ppbyteDDEData, BYTE, *pdwcbLen)) ||
(! bResult &&
EVAL(! *ppbyteDDEData) &&
EVAL(! *pdwcbLen)));
return(bResult);
}
typedef struct _my_pvt_connect_struct
{
HANDLE hConnectThread;
DWORD idInst;
HSZ hszService, hszTopic;
PCONVCONTEXT pCC;
HCONV retval;
}PVTCONN;
/*
*
*
*/
DWORD WINAPI ConnectThreadProc(PVTCONN cw)
{
XX_DMsg(DBG_SDI, ("ConnectThreadProc(0x%x, 0x%x, 0x%x, 0x%x)\n",
cw.idInst,cw.hszService,cw.hszTopic,cw.pCC));
cw.retval=DdeConnect(cw.idInst, cw.hszService, cw.hszTopic, cw.pCC);
XX_DMsg(DBG_SDI, ("ConnectThreadProc returned %x\n", cw.retval));
SetEvent(cw.hConnectThread);
return(cw.retval);
}
/*
** MyDdeConnect()
**
** Inline wrapper for DdeConnect() to verify that DdeConnect() is not called
** from a lightweight thread.
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE HCONV MyDdeConnect(DWORD idInst, HSZ hszService, HSZ hszTopic,
PCONVCONTEXT pCC)
{
HCONV retval=0;
DWORD dwWaitFor, dwId;
PVTCONN cw;
cw.idInst = idInst;
cw.hszService = hszService;
cw.hszTopic = hszTopic;
cw.pCC = pCC;
cw.hConnectThread = 0;
cw.retval = 0;
XX_DMsg(DBG_SDI, ("MyDdeConnect(0x%x, 0x%x, 0x%x, 0x%x)\n",idInst,hszService,hszTopic,pCC));
cw.hConnectThread=CreateThread(NULL, 1024, ConnectThreadProc, &cw,
0, &dwId);
ASSERT(cw.hConnectThread);
if (!cw.hConnectThread) return(0);
XX_DMsg(DBG_SDI, (" CreateThread(hConnectThread=0x%x, dwId=0x%x)\n",cw.hConnectThread, dwId));
dwWaitFor = WaitForSingleObject(cw.hConnectThread, 20000);
retval = cw.retval;
if (dwWaitFor == WAIT_FAILED)
{
XX_DMsg(DBG_SDI, ("MyDdeConnect: WaitForSingleObject failed"));
return(0);
}
switch (dwWaitFor)
{
case WAIT_ABANDONED:
XX_DMsg(DBG_SDI, ("MyDdeConnect: WaitForSingleObject abandoned: retval=%x", retval));
break;
case WAIT_OBJECT_0:
XX_DMsg(DBG_SDI, ("MyDdeConnect: WaitForSingleObject signalled: retval=%x", retval));
break;
case WAIT_TIMEOUT:
default:
XX_DMsg(DBG_SDI, ("MyDdeConnect: WaitForSingleObject timed out"));
return(0);
}
XX_DMsg(DBG_SDI, ("MyDdeConnect returns 0x%x\n", retval));
return(retval);
}
#ifdef WINNT
HDDEDATA CALLBACK
DdeCallBack(UINT wType,
UINT wFmt,
HCONV hConv,
HSZ hsz1,
HSZ hsz2,
HDDEDATA hDDEData,
DWORD dwData1,
DWORD dwData2)
#else
HDDEDATA EXPENTRY
DdeCallBack(WORD wType,
WORD wFmt,
HCONV hConv,
HSZ hsz1,
HSZ hsz2,
HDDEDATA hDDEData,
DWORD dwData1,
DWORD dwData2)
#endif
{
char szTopic[64];
char szItem[1000];
DDEHANDLECALLBACK pCallback;
int index;
// The callback function allows the server to communicate
// with the DDEML, and thus, to the client. When the DDEML
// has something to tell the server, it calls the server's
// callback function. When the server has something to tell
// the DDEML (or the client), it does it through the callback
// function.
switch(wType)
{
case XTYP_REGISTER:
DdeQueryString(g_DdeInst, hsz1, szItem, sizeof(szItem), CP_WINANSI);
if (pServerHash)
Hash_Add(pServerHash, szItem, NULL, NULL);
XX_DMsg(DBG_SDI, ("DDE server %s is registering.\n", szItem));
return 0;
case XTYP_UNREGISTER:
DdeQueryString(g_DdeInst, hsz1, szItem, sizeof(szItem), CP_WINANSI);
if (pServerHash)
{
index = Hash_Find(pServerHash, szItem, NULL, NULL);
if (index != -1)
Hash_DeleteIndexedEntry(pServerHash, index);
}
XX_DMsg(DBG_SDI, ("DDE server %s is unregistering.\n", szItem));
return 0;
case XTYP_REQUEST: // XCLASS_DATA
case XTYP_POKE: // XCLASS_FLAGS
// Support topics here. We need to make sure that the topics are legitimate, by
// checking them in the topic hash table.
DdeQueryString(g_DdeInst, hsz1, szTopic, sizeof(szTopic), CP_WINANSI);
if (Hash_Find(pTopicHash, szTopic, NULL, (void **) &pCallback) == -1)
{
XX_DMsg(DBG_SDI, ("DDE topic \"%s\" not found.\n", szTopic));
return 0;
}
DdeQueryString(g_DdeInst, hsz2, szItem, sizeof(szItem), CP_WINANSI);
XX_DMsg(DBG_SDI, ("DDE topic \"%s\" found. item=\"%s\".\n", szTopic, szItem));
return ((*pCallback)(szItem));
case XTYP_EXECUTE: // XCLASS_FLAGS
{
HDDEDATA hddedata = NULL;
PSTR pszTopic;
if (CopyDDEString(hsz1, &pszTopic))
{
if (Hash_Find(pTopicHash, pszTopic, NULL, (void **)&pCallback)
!= -1)
{
DWORD dwcbLen;
PBYTE pbyteData;
if (CopyDDEData(hDDEData, &pbyteData, &dwcbLen))
{
/* Handle requested DDE execution. */
hddedata = (*pCallback)(pbyteData);
FreeMemory(pbyteData);
pbyteData = NULL;
}
else
WARNING_OUT(("DdeCallBack(): Unable to copy DDE data."));
}
else
WARNING_OUT(("DdeCallBack(): Unrecognized DDE execution topic \"%s\".",
szTopic));
FreeMemory(pszTopic);
pszTopic = NULL;
}
XX_DMsg(DBG_SDI, ("DDE (XTYP_EXECUTE) topic \"%s\" return=%x.\n", szTopic, hddedata));
return(hddedata);
}
case XTYP_CONNECT: // XCLASS_BOOL
XX_DMsg(DBG_SDI, ("DDE (XTYP_CONNECT)\n"));
return ((HDDEDATA)(hszMosaic == hsz2));
case XTYP_CONNECT_CONFIRM: // XCLASS_NOTIFICATION
XX_DMsg(DBG_SDI, ("DDE (XTYP_CONNECT_CONFIRM)\n"));
return (HDDEDATA) NULL;
case XTYP_ADVSTART: // XCLASS_BOOL
case XTYP_ADVREQ: // XCLASS_DATA
case XTYP_ADVSTOP: // XCLASS_NOTIFICATION
case XTYP_WILDCONNECT: // XCLASS_DATA
XX_DMsg(DBG_SDI, ("DDE (DDE_FNOTPROCESSED)\n"));
return DDE_FNOTPROCESSED;
default:
XX_DMsg(DBG_SDI, ("DDE (unknown:0x%x)\n", wType));
return (HDDEDATA) NULL;
}
}
//**************************************
// Support functions
//**************************************
static char *GetNextArgument(char *pString, long *pValue, BOOL bString)
{
static char *pNew, *pEnd;
char *pCurrent;
BOOL bIgnoreBlanks, bInsideQuote;
// Parses the given string and returns a pointer to the next argument, or NULL if error.
// pString = beginning of the string to start parsing, or NULL to continue parsing
// a previously passed string
// pValue = pointer to a long integer. This argument will be ignored if bString is
// TRUE. If a non-numeric argument was encountered when bString is FALSE,
// *pValue will be 0, but the return pointer from the function will be NULL.
// bString = specifies if the argument should be wrapped around by double quotes.
// If this value is TRUE and there are no double quotes, the function will
// return NULL
//
// RULES:
//
// - string arguments must start and end with double quotes (")
// - numeric arguments must not be in double quotes
// - a double quote should be denoted by \"
// - commas are used between arguments
// - it is acceptable to specify no argument, such as in ,,
// - hexadecimal notation is valid, such as 0x4f89
// - octal notation is valid, such as 076
// - decimal notation is valid, such as 23. Decimal numbers MUST NOT be preceded by a 0.
//
// example: "hello",-1,2,"what"
// 0x1920,,"test",""
if (pString)
{
// initial setup
if (pArgumentBuffer)
GTR_FREE(pArgumentBuffer);
nArgumentBufferLength = strlen(pString) + 1;
pArgumentBuffer = GTR_MALLOC(nArgumentBufferLength);
strcpy(pArgumentBuffer, pString);
pCurrentArgPos = pArgumentBuffer;
if (pArgReturnBuffer)
GTR_FREE(pArgReturnBuffer);
pArgReturnBuffer = GTR_MALLOC(nArgumentBufferLength);
memset(pArgReturnBuffer, 0, nArgumentBufferLength);
pNew = pArgReturnBuffer;
pEnd = pNew;
}
else
{
if (pCurrentArgPos >= pArgumentBuffer + nArgumentBufferLength)
return NULL; // can't go past end of string
pNew = pEnd;
}
// Start composing the argument
pCurrent = pCurrentArgPos;
bIgnoreBlanks = TRUE; // ignore all blanks if this flag is TRUE
bInsideQuote = FALSE; // TRUE if opening double quote has been encountered
while (*pCurrent)
{
if ((*pCurrent == ' ') && bIgnoreBlanks)
pCurrent++;
else if (*pCurrent == '"')
{
bInsideQuote = ! bInsideQuote;
bIgnoreBlanks = ! bInsideQuote;
*pNew++ = *pCurrent++;
}
else if (*pCurrent == ',')
{
if (!bInsideQuote)
break;
else
*pNew++ = *pCurrent++;
}
else if (*pCurrent == '\\' && bInsideQuote)
{
// Check for \" which means to insert a single double quote
if (*(pCurrent + 1) == '"')
{
*pNew++ = '"';
pCurrent += 2;
}
else
*pNew++ = *pCurrent++;
}
else
*pNew++ = *pCurrent++;
}
pCurrentArgPos = pCurrent + 1;
pNew = pEnd;
pEnd = pNew + strlen(pNew) - 1;
if (bString)
{
if (*pNew == '\0')
{
pEnd = pNew + 1;
return "";
}
if ((*pNew != '"') || (*pEnd != '"'))
return NULL;
*pEnd = '\0';
pEnd += 2;
strcpy(pNew, &pNew[1]);
return pNew;
}
else
{
if (*pNew == '\0')
{
*pValue = 0;
pEnd += 2;
return pNew;
}
if ((*pNew == '"') || (*(pEnd - 1) == '"'))
return NULL;
*pValue = strtoul(pNew, NULL, 0);
pEnd += 2;
return pNew;
}
return NULL;
}
char *MakeQuotedString(PCSTR pString)
{
int length;
char *pReturn, *pCurrent;
// This function converts the given string so that its content is wrapped within
// double quotes. Embedded double quotes will be changed to \".
//
// THE CALLER MUST FREE THE MEMORY RETURNED BY THIS FUNCTION.
if (!pString)
{
pReturn = GTR_MALLOC(3);
strcpy(pReturn, "\"\"");
return pReturn;
}
length = 2 * strlen(pString) + 4; // worst case + 1
pReturn = GTR_MALLOC(length);
memset(pReturn, 0, length);
pCurrent = pReturn;
*pCurrent++ = '"';
while (*pString)
{
if (*pString == '"')
{
*pCurrent++ = '\\';
*pCurrent++ = '"';
}
else
*pCurrent++ = *pString;
pString++;
}
*pCurrent = '"';
return pReturn;
}
static BOOL IsMimeSupported(char *pMime)
{
HTList *pList, *pCurrent;
HTPresentation *pPres;
char *pFormat;
// This fuction returns TRUE if the given MIME type is supported.
// First check the default list.
pList = HTList_new();
HTFormatInit(pList);
pCurrent = pList;
while (pCurrent)
{
pPres = (HTPresentation *) pCurrent->object;
if (pPres)
{
pFormat = HTAtom_name(pPres->rep);
if (pFormat && strcmp(pFormat, pMime) == 0)
break;
}
pCurrent = pCurrent->next;
}
HTList_delete(pList);
if (pCurrent)
return TRUE;
return FALSE;
}
//************************************************
// OpenURL functions
//************************************************
static HDDEDATA DDE_Handle_OpenURL(char *pItem)
{
char *pURL, *pFile, *pWindowID, *pFlags, *pFormData, *pMIMEType, *pProgressApp, *pResultApp;
long lWindowID, lFlags;
BOOL bNoDocCache, bNoImageCache, bBackground;
HDDEDATA result;
DDENOTIFYSTRUCT *dns;
struct Mwin *tw;
long transID;
struct TRANSACTIONMAPSTRUCT *tms;
DWORD dwNewWindowFlags;
DWORD dwLoadDocFlags;
XX_DMsg(DBG_SDI, ("DDE_Handle_OpenURL(%s)\n", pItem));
pURL = GetNextArgument(pItem, NULL, TRUE);
if (!pURL)
return 0;
pFile = GetNextArgument(NULL, NULL, TRUE);
if (!pFile)
return 0;
pWindowID = GetNextArgument(NULL, &lWindowID, FALSE);
if (!pWindowID)
return 0;
pFlags = GetNextArgument(NULL, &lFlags, FALSE);
if (!pFlags)
return 0;
pFormData = GetNextArgument(NULL, NULL, TRUE);
if (!pFormData)
return 0;
pMIMEType = GetNextArgument(NULL, NULL, TRUE);
if (!pMIMEType)
return 0;
pProgressApp = GetNextArgument(NULL, NULL, TRUE);
if (!pProgressApp)
return 0;
pResultApp = GetNextArgument(NULL, NULL, TRUE);
if (!pResultApp)
{
// For compatibility with the older OpenURL spec, allow
// this argument to be absent.
pResultApp = "";
}
XX_DMsg(DBG_SDI, ("OpenURL received: %s,%s,%s,%s,%s,%s,%s,%s\n",
pURL, pFile, pWindowID, pFlags, pFormData, pMIMEType, pProgressApp, pResultApp));
bNoDocCache = lFlags & OPENURL_IGNOREDOCCACHE;
bNoImageCache = lFlags & OPENURL_IGNOREIMAGECACHE;
bBackground = lFlags & OPENURL_BACKGROUNDMODE;
dns = (DDENOTIFYSTRUCT *) GTR_MALLOC(sizeof(DDENOTIFYSTRUCT));
memset(dns, 0, sizeof(DDENOTIFYSTRUCT));
strncpy(dns->szResultApp, pResultApp, sizeof(dns->szResultApp) - 1);
strcpy(dns->szReturnTopic, "WWW_OpenURLResult");
dns->lTransID = TransactionID;
// If the progress app name has been given, then keep it in transaction map
if (pProgressApp[0])
{
tms = GTR_MALLOC(sizeof(struct TRANSACTIONMAPSTRUCT));
memset(tms, 0, sizeof(struct TRANSACTIONMAPSTRUCT));
tms->outgoing_transID = TransactionID;
strncpy(tms->outgoing_app, pProgressApp, sizeof(tms->outgoing_app) - 1);
tms->next = pTransactionMap;
pTransactionMap = tms;
}
// If file spec has been given, then this URL must be saved into the file. Since
// we need a tw structure to bring up the error in, we simply use the first tw
// structure we can grab.
// BUGBUG : <FOR daviddi, from cmf> if the tw is busy, this doesn't seem correct to me
// I have made this somewhat better by erroring out if the window has a modal child
// up, and by trying to get a non-busy window first
if (pFile[0])
{
tw = TW_FindTopmostNotBusyWindow();
if (!tw) tw = TW_FindTopmostWindow();
if (!TW_SafeWindow(tw))
return NULL;
tw->request->nosavedlg = TRUE;
tw->request->savefile = pFile;
tw->transID = TransactionID;
GTR_DownLoad(tw, pURL, NULL,0);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &TransactionID, sizeof(TransactionID),
0, hszReturn, CF_TEXT, 0);
TransactionID++;
HTList_addObject(pTransList, dns);
return result;
}
// If form name is given, see if we can support the MIME type
if (pFormData[0] && !IsMimeSupported(pMIMEType))
{
// MIME is not supported - return an error
transID = SDI_INVALID_MIME;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &transID, sizeof(transID),
0, hszReturn, CF_TEXT, 0);
return result;
}
dwNewWindowFlags = TW_LD_FL_RECORD;
dwLoadDocFlags = TW_LD_FL_RECORD;
if (bNoDocCache)
{
SET_FLAG(dwNewWindowFlags, GTR_NW_FL_NO_DOC_CACHE);
SET_FLAG(dwLoadDocFlags, TW_LD_FL_NO_DOC_CACHE);
}
if (bNoImageCache)
{
SET_FLAG(dwNewWindowFlags, GTR_NW_FL_NO_IMAGE_CACHE);
SET_FLAG(dwLoadDocFlags, TW_LD_FL_NO_IMAGE_CACHE);
}
switch(lWindowID)
{
case 0:
//
// Open a new Window and put the URL there. Return a transaction ID for now
// since the operation is asynchronous.
openNewWindow:
dns->bCreateNewWindow = TRUE;
if (pFormData[0])
GTR_NewWindow(pURL, NULL, 0, TransactionID, dwNewWindowFlags, pFormData, pProgressApp);
else
GTR_NewWindow(pURL, NULL, 0, TransactionID, dwNewWindowFlags, NULL, pProgressApp);
if (pResultApp[0] == '\0')
transID = SDI_SUPER_ACK; // no OpenURLResult will be given
else
transID = TransactionID;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &transID, sizeof(transID),
0, hszReturn, CF_TEXT, 0);
TransactionID++;
HTList_addObject(pTransList, dns);
return result;
case 0xFFFFFFFF:
//
// Use the most recently active window and put the URL there.
dns->bCreateNewWindow = FALSE;
tw = TW_FindDDECandidate();
if (!tw)
{
tw = TW_FindTopmostNotBusyWindow();
}
else if (!TW_SafeWindow(tw))
return NULL;
// was : tw = TW_FindTopmostWindow();
if (!tw)
goto openNewWindow;
if (!bBackground)
SetForegroundWindow(tw->hWndFrame);
tw->transID = TransactionID;
tw->bSuppressError = TRUE;
// tw->szProgressApp is already NULLed
strncpy(tw->szProgressApp, pProgressApp, sizeof(tw->szProgressApp) - 1);
if (pFormData[0])
TW_LoadDocument(tw, pURL, dwLoadDocFlags, pFormData, NULL);
else
TW_LoadDocument(tw, pURL, dwLoadDocFlags, NULL, NULL);
// If the return app string is empty, then return SUPERACK
if (pResultApp[0] == '\0')
transID = SDI_SUPER_ACK; // no OpenURLResult will be given
else
transID = tw->transID;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &transID, sizeof(transID),
0, hszReturn, CF_TEXT, 0);
TransactionID++;
HTList_addObject(pTransList, dns);
return result;
default:
//
// Check if the specified window exists and use the window
dns->bCreateNewWindow = FALSE;
tw = Mlist;
while (tw)
{
if (tw->serialID == lWindowID)
break;
tw = tw->next;
}
if (tw)
{
if (!bBackground)
SetForegroundWindow(tw->win);
tw->transID = TransactionID;
tw->bSuppressError = TRUE;
// tw->szProgressApp is already NULLed
strncpy(tw->szProgressApp, pProgressApp, sizeof(tw->szProgressApp) - 1);
if (pFormData[0])
TW_LoadDocument(tw, pURL, dwLoadDocFlags, pFormData, NULL);
else
TW_LoadDocument(tw, pURL, dwLoadDocFlags, NULL, NULL);
transID = tw->transID;
TransactionID++;
HTList_addObject(pTransList, dns);
}
else
transID = 0;
if (pResultApp[0] == '\0')
transID = SDI_SUPER_ACK; // no OpenURL result will be given
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &transID, sizeof(transID),
0, hszReturn, CF_TEXT, 0);
return result;
}
}
void DDE_Issue_BeginProgress(char *pProgress, char *pMessage)
{
struct TRANSACTIONMAPSTRUCT *tms;
HSZ hszTopic, hszService, hszItem;
HDDEDATA hResult;
HCONV hConv;
char *p, *p1;
XX_DMsg(DBG_SDI, ("DDE_Issue_BeginProgress(%s, %s)\n", pProgress, pMessage));
tms = pTransactionMap;
while (tms)
{
if (strcmp(tms->outgoing_app, pProgress) == 0)
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_BeginProgress", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, pProgress, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
p1 = MakeQuotedString(pMessage);
p = GTR_MALLOC(strlen(p1) + 50 + 1);
wsprintf(p, "%ld,%s", tms->outgoing_transID, p1);
hszItem = DdeCreateStringHandle(g_DdeInst, p, CP_WINANSI);
hResult = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT, XTYP_POKE,
DDE_TIMEOUT, NULL);
DdeFreeStringHandle(g_DdeInst, hszItem);
GTR_FREE(p);
GTR_FREE(p1);
DdeDisconnect(hConv);
}
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
return;
}
tms = tms->next;
}
}
void DDE_Issue_SetProgressRange(char *pProgress, long lRange)
{
struct TRANSACTIONMAPSTRUCT *tms;
HSZ hszTopic, hszService, hszItem;
HDDEDATA hResult;
HCONV hConv;
char szTemp[50];
XX_DMsg(DBG_SDI, ("DDE_Issue_SetProgressRange(%s, 0x%x)\n", pProgress, lRange));
tms = pTransactionMap;
while (tms)
{
if (strcmp(tms->outgoing_app, pProgress) == 0)
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_SetProgressRange", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, pProgress, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
wsprintf(szTemp, "%ld,%ld", tms->outgoing_transID, lRange);
hszItem = DdeCreateStringHandle(g_DdeInst, szTemp, CP_WINANSI);
hResult = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT, XTYP_POKE,
DDE_TIMEOUT, NULL);
DdeFreeStringHandle(g_DdeInst, hszItem);
DdeDisconnect(hConv);
}
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
return;
}
tms = tms->next;
}
}
void DDE_Issue_MakingProgress(struct Mwin *tw, char *pMessage, long lProgress)
{
struct TRANSACTIONMAPSTRUCT *tms;
HSZ hszTopic, hszService, hszItem;
HDDEDATA hResult;
char *p, *p1;
BOOL bCancel;
HCONV hConv;
static char szLastMessage[1024]; /* Last message passed */
static long lLastProgress;
/* Only pass the progress message if something has changed */
XX_DMsg(DBG_SDI, ("DDE_Issue_MakingProgress(%s)\n", pMessage));
if ((strcmp(pMessage, szLastMessage) != 0) || (lProgress != lLastProgress))
{
strncpy(szLastMessage, pMessage, sizeof(szLastMessage) - 1);
szLastMessage[sizeof(szLastMessage) - 1] = '\0';
lLastProgress = lProgress;
}
else
return;
tms = pTransactionMap;
while (tms)
{
if (strcmp(tms->outgoing_app, tw->szProgressApp) == 0)
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_MakingProgress", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, tw->szProgressApp, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
p1 = MakeQuotedString(pMessage);
p = GTR_MALLOC(strlen(p1) + 100 + 1);
wsprintf(p, "%ld,%s,%ld", tms->outgoing_transID, p1, lProgress);
hszItem = DdeCreateStringHandle(g_DdeInst, p, CP_WINANSI);
hResult = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT, XTYP_REQUEST,
DDE_TIMEOUT, NULL);
DdeFreeStringHandle(g_DdeInst, hszItem);
GTR_FREE(p);
GTR_FREE(p1);
// If hResult is valid and its value is TRUE, then kill the thread
if (hResult)
{
DdeGetData(hResult, (LPBYTE) &bCancel, sizeof(bCancel), 0);
if (bCancel)
{
DDE_Issue_EndProgress(tms->outgoing_app);
TW_AbortAndRefresh(tw);
}
}
DdeDisconnect(hConv);
}
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
return;
}
tms = tms->next;
}
}
void DDE_Issue_EndProgress(char *pProgress)
{
struct TRANSACTIONMAPSTRUCT *tms;
HSZ hszTopic, hszService, hszItem;
HDDEDATA hResult;
HCONV hConv;
char *p;
tms = pTransactionMap;
XX_DMsg(DBG_SDI, ("DDE_Issue_EndProgress(%s)\n", pProgress));
while (tms)
{
if (strcmp(tms->outgoing_app, pProgress) == 0)
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_EndProgress", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, pProgress, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
p = GTR_MALLOC(50 + 1);
wsprintf(p, "%ld", tms->outgoing_transID);
hszItem = DdeCreateStringHandle(g_DdeInst, p, CP_WINANSI);
hResult = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT, XTYP_POKE,
DDE_TIMEOUT, NULL);
DdeFreeStringHandle(g_DdeInst, hszItem);
GTR_FREE(p);
DdeDisconnect(hConv);
}
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
return;
}
tms = tms->next;
}
}
//************************************************
// ShowFile
//************************************************
static HDDEDATA DDE_Handle_ShowFile(char *pItem)
{
char *pFileSpec, *pMIME, *pWindowID, *pURL, *pResultApp;
long lWindowID, transID;
struct Mwin *tw;
HDDEDATA result;
DDENOTIFYSTRUCT *dns;
XX_DMsg(DBG_SDI, ("DDE_Handle_ShowFile(%s)\n", pItem));
pFileSpec = GetNextArgument(pItem, NULL, TRUE);
if (!pFileSpec)
return 0;
pMIME = GetNextArgument(NULL, NULL, TRUE);
if (!pMIME)
return 0;
pWindowID = GetNextArgument(NULL, &lWindowID, FALSE);
if (!pWindowID)
return 0;
pURL = GetNextArgument(NULL, NULL, TRUE);
if (!pURL)
return 0;
pResultApp = GetNextArgument(NULL, NULL, TRUE);
if (!pResultApp)
return 0;
// Make sure the window exists
if (lWindowID == 0xFFFFFFFF)
{
tw = TW_FindTopmostWindow();
if (!tw)
return 0;
}
else
{
tw = Mlist;
while (tw && lWindowID != tw->serialID)
tw = tw->next;
if (!tw)
return 0;
}
// Check if we support the mime type
if (pMIME[0] && !IsMimeSupported(pMIME))
{
transID = SDI_INVALID_MIME;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &transID, sizeof(transID), 0,
hszReturn, CF_TEXT, 0);
return result;
}
// Create the notify structure
dns = (DDENOTIFYSTRUCT *) GTR_MALLOC(sizeof(DDENOTIFYSTRUCT));
memset(dns, 0, sizeof(DDENOTIFYSTRUCT));
strncpy(dns->szResultApp, pResultApp, sizeof(dns->szResultApp) - 1);
strcpy(dns->szReturnTopic, "WWW_ShowFileResult");
dns->lTransID = TransactionID;
dns->pURL = GTR_strdup(pURL);
HTList_addObject(pTransList, dns);
// Open document asynchronously
tw->transID = TransactionID;
tw->bSuppressError = TRUE;
OpenLocalDocument(tw->win, pFileSpec, FALSE );
TransactionID++;
if (pResultApp[0] == '\0')
transID = SDI_SUPER_ACK;
else
transID = tw->transID;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &transID, sizeof(transID), 0,
hszReturn, CF_TEXT, 0);
return result;
}
//************************************************
// Activate
//************************************************
static HDDEDATA DDE_Handle_Activate(char *pItem)
{
char *pWindowID, *pFlags;
long lWindowID, lFlags;
struct Mwin *tw;
HDDEDATA result;
// Activate the window with the given ID
XX_DMsg(DBG_SDI, ("DDE_Handle_Activate(%s)\n", pItem));
pWindowID = GetNextArgument(pItem, &lWindowID, FALSE);
if (!pWindowID)
return 0;
pFlags = GetNextArgument(NULL, &lFlags, FALSE);
if (!pFlags)
return 0;
tw = Mlist;
if (lWindowID == 0xFFFFFFFF)
tw = TW_FindTopmostWindow();
else
{
while (tw && lWindowID != tw->serialID)
tw = tw->next;
}
if (tw)
{
SetForegroundWindow(tw->hWndFrame);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &tw->serialID, sizeof(tw->serialID), 0,
hszReturn, CF_TEXT, 0);
}
else
{
lWindowID = 0;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &lWindowID, sizeof(lWindowID), 0,
hszReturn, CF_TEXT, 0);
}
return result;
}
//************************************************
// ListWindows
//************************************************
static HDDEDATA DDE_Handle_ListWindows(char *pItem)
{
long *pBuffer, *pEntry;
int count;
struct Mwin *tw;
HDDEDATA result;
tw = Mlist;
count = 0;
XX_DMsg(DBG_SDI, ("DDE_Handle_ListWindows(%s)\n", pItem));
// count the number of open windows
while (tw)
{
count++;
tw = tw->next;
}
// Pack the window IDs in a long array.
pBuffer = GTR_MALLOC((count + 1) * sizeof(long));
pEntry = pBuffer;
tw = Mlist;
pEntry[0] = count; // first 4 bytes = number of items to follow
count = 1;
while (tw)
{
pEntry[count++] = tw->serialID;
tw = tw->next;
}
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) pBuffer, count * sizeof(long), 0,
hszReturn, CF_TEXT, 0);
GTR_FREE(pBuffer);
return result;
}
//************************************************
// GetWindowInfo
//************************************************
static HDDEDATA DDE_Handle_GetWindowInfo(char *pItem)
{
char *pBuffer, *pWindowID, *pAddress, *pTitle;
long lWindowID;
struct Mwin *tw;
HDDEDATA result;
XX_DMsg(DBG_SDI, ("DDE_Handle_GetWindowInfo(%s)\n", pItem));
pWindowID = GetNextArgument(pItem, &lWindowID, FALSE);
if (!pWindowID)
return 0;
if (lWindowID == 0xFFFFFFFF)
{
tw = TW_FindTopmostWindow();
}
else
{
tw = Mlist;
while (tw)
{
if (tw->serialID == lWindowID)
break;
tw = tw->next;
}
}
if (!tw)
return 0;
pAddress = MakeQuotedString(tw->w3doc->szActualURL);
pTitle = MakeQuotedString(tw->w3doc->title);
pBuffer = GTR_MALLOC(strlen(pAddress) + strlen(pTitle) + 10);
memset(pBuffer, 0, strlen(pAddress) + strlen(pTitle) + 10);
strcpy(pBuffer, pAddress);
strcat(pBuffer, ",");
strcat(pBuffer, pTitle);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) pBuffer, strlen(pBuffer), 0, hszReturn, CF_TEXT, 0);
GTR_FREE(pBuffer);
GTR_FREE(pAddress);
GTR_FREE(pTitle);
return result;
}
//************************************************
// ParseAnchor
//************************************************
static HDDEDATA DDE_Handle_ParseAnchor(char *pItem)
{
char *pMain, *pRelative, *pURL, *pReturn;
HDDEDATA result;
XX_DMsg(DBG_SDI, ("DDE_Handle_ParseAnchor(%s)\n", pItem));
pMain = GetNextArgument(pItem, NULL, TRUE);
if (!pMain)
return 0;
pRelative = GetNextArgument(NULL, NULL, TRUE);
if (!pRelative)
return 0;
pURL = HTParse(pMain, pRelative, PARSE_ALL);
pReturn = MakeQuotedString(pURL);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) pReturn, strlen(pReturn), 0, hszReturn, CF_TEXT, 0);
GTR_FREE(pURL);
GTR_FREE(pReturn);
return result;
}
//************************************************
// Exit
//************************************************
static HDDEDATA DDE_Handle_Exit(char *pItem)
{
// Close Mosaic. Return value does not matter.
XX_DMsg(DBG_SDI, ("DDE_Handle_Exit(%s)\n", pItem));
PostMessage(wg.hWndHidden, WM_CLOSE, 0, 0);
return 0;
}
//************************************************
// RegisterURLEcho
//************************************************
static HDDEDATA DDE_Handle_RegisterURLEcho(char *pItem)
{
char *pApplication;
DDENOTIFYSTRUCT *dns;
long ret;
int i;
HDDEDATA result;
XX_DMsg(DBG_SDI, ("DDE_Handle_RegisterURLEcho(%s)\n", pItem));
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
// Make sure that this application has not already been
// registered for URL echo
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(_stricmp(dns->szReturnTopic, "WWW_URLEcho") == 0) &&
(_stricmp(dns->szResultApp, pApplication) == 0))
{
return 0;
}
}
// Add the echo request
dns = (DDENOTIFYSTRUCT *) GTR_MALLOC(sizeof(DDENOTIFYSTRUCT));
memset(dns, 0, sizeof(DDENOTIFYSTRUCT));
strcpy(dns->szResultApp, pApplication);
strcpy(dns->szReturnTopic, "WWW_URLEcho");
HTList_addObject(pTransList, dns);
ret = TRUE;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &ret, sizeof(ret), 0, hszReturn, CF_TEXT, 0);
return result;
}
//************************************************
// UnRegisterURLEcho
//************************************************
static HDDEDATA DDE_Handle_UnRegisterURLEcho(char *pItem)
{
char *pApplication;
DDENOTIFYSTRUCT *dns;
int i;
XX_DMsg(DBG_SDI, ("DDE_Handle_UnRegisterURLEcho(%s)\n", pItem));
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
// Look for the matching item and remove it
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(_stricmp(dns->szReturnTopic, "WWW_URLEcho") == 0) &&
(_stricmp(dns->szResultApp, pApplication) == 0))
{
HTList_removeObject(pTransList, dns);
return 0;
}
}
return 0;
}
//************************************************
// RegisterWindowClose
//************************************************
static HDDEDATA DDE_Handle_RegisterWindowClose(char *pItem)
{
char *pWindowID, *pApplication;
DDENOTIFYSTRUCT *dns;
long lWindowID;
struct Mwin *tw;
HDDEDATA result;
int i;
XX_DMsg(DBG_SDI, ("DDE_Handle_RegisterWindowClose(%s)\n", pItem));
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
pWindowID = GetNextArgument(NULL, &lWindowID, FALSE);
if (!pWindowID)
return 0;
// Make sure the window exists
tw = Mlist;
while (tw)
{
if (tw->serialID != lWindowID)
tw = tw->next;
else
break;
}
if (!tw)
return 0;
// Make sure that this application has not already been
// registered for Window close
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(dns->lWindowID == lWindowID) &&
(_stricmp(dns->szReturnTopic, "WWW_WindowClose") == 0) &&
(_stricmp(dns->szResultApp, pApplication) == 0))
{
return 0;
}
}
// Add the request
dns = (DDENOTIFYSTRUCT *) GTR_MALLOC(sizeof(DDENOTIFYSTRUCT));
memset(dns, 0, sizeof(DDENOTIFYSTRUCT));
dns->lWindowID = lWindowID;
strcpy(dns->szResultApp, pApplication);
strcpy(dns->szReturnTopic, "WWW_WindowClose");
HTList_addObject(pTransList, dns);
// Return the window ID
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &lWindowID, sizeof(lWindowID), 0, hszReturn, CF_TEXT, 0);
return result;
}
//************************************************
// UnRegisterWindowClose
//************************************************
static HDDEDATA DDE_Handle_UnRegisterWindowClose(char *pItem)
{
char *pWindowID, *pApplication;
DDENOTIFYSTRUCT *dns;
long lWindowID;
int i;
XX_DMsg(DBG_SDI, ("DDE_Handle_UnRegisterWindowClose(%s)\n", pItem));
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
pWindowID = GetNextArgument(NULL, &lWindowID, FALSE);
if (!pWindowID)
return 0;
// Look for the matching item and remove it
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(dns->lWindowID == lWindowID) &&
(_stricmp(dns->szReturnTopic, "WWW_WindowClose") == 0) &&
(_stricmp(dns->szResultApp, pApplication) == 0))
{
HTList_removeObject(pTransList, dns);
return 0;
}
}
return 0;
}
//************************************************
// RegisterProtocol
//************************************************
static HDDEDATA DDE_Handle_RegisterProtocol(char *pItem)
{
char *pApplication, *pProtocol;
DDENOTIFYSTRUCT *dns;
BOOL bSuccess = TRUE;
HTList *cur;
HTProtocol *p;
HDDEDATA result;
int i;
XX_DMsg(DBG_SDI, ("DDE_Handle_RegisterProtocol(%s)\n", pItem));
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
pProtocol = GetNextArgument(NULL, NULL, TRUE);
if (!pProtocol)
return 0;
// Make sure this protocol is not already handled by someone
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(strcmp(dns->pProtocol, pProtocol) == 0))
return 0;
}
// Look for an existing protocol
dns = (DDENOTIFYSTRUCT *) GTR_MALLOC(sizeof(DDENOTIFYSTRUCT));
memset(dns, 0, sizeof(DDENOTIFYSTRUCT));
cur = protocols;
while ((p = (HTProtocol *) HTList_nextObject(cur)))
{
if (strcmp(p->name, pProtocol) == 0)
{
// Modify an existing protocol - but save the original one
dns->pOriginalProtocol = GTR_MALLOC(sizeof(HTProtocol));
memcpy(dns->pOriginalProtocol, p, sizeof(HTProtocol));
// The original name is hard-coded so don't attempt to free it!
p->name = GTR_strdup(pProtocol);
p->load = DDE_Custom_Protocol_Handler;
p->load_async = NULL;
break;
}
}
if (!p)
{
// Add to protocol list
p = (HTProtocol *) GTR_MALLOC(sizeof(HTProtocol));
memset(p, 0, sizeof(HTProtocol));
p->name = GTR_strdup(pProtocol);
p->load = DDE_Custom_Protocol_Handler;
HTRegisterProtocol(p);
}
// Add the protocol to notification list
strcpy(dns->szResultApp, pApplication);
strcpy(dns->szReturnTopic, "WWW_OpenURL");
dns->pProtocol = GTR_strdup(pProtocol);
HTList_addObject(pTransList, dns);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bSuccess, sizeof(bSuccess), 0,
hszReturn, CF_TEXT, 0);
return result;
}
//************************************************
// UnRegisterProtocol
//************************************************
static HDDEDATA DDE_Handle_UnRegisterProtocol(char *pItem)
{
char *pApplication, *pProtocol;
DDENOTIFYSTRUCT *dns;
int i;
HTList *cur;
HTProtocol *p;
XX_DMsg(DBG_SDI, ("DDE_Handle_UnRegisterProtocol(%s)\n", pItem));
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
pProtocol = GetNextArgument(NULL, NULL, TRUE);
if (!pProtocol)
return 0;
// Remove the notification structure
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(strcmp(dns->pProtocol, pProtocol) == 0) &&
(_stricmp(dns->szResultApp, pApplication) == 0))
{
GTR_FREE(dns->pProtocol);
HTList_removeObject(pTransList, dns);
// Remove the protocol from the protocol list, if there was
// no original protocol. If there was an original protocol,
// then restore the old values.
cur = protocols;
while ((p = (HTProtocol *) HTList_nextObject(cur)))
{
if (strcmp(p->name, pProtocol) == 0)
{
if (!dns->pOriginalProtocol)
HTUnregisterProtocol(p);
else
{
GTR_FREE(p->name);
memcpy(p, dns->pOriginalProtocol, sizeof(HTProtocol));
GTR_FREE(dns->pOriginalProtocol);
}
break;
}
}
GTR_FREE(dns);
return 0;
}
}
return 0;
}
#if 0
//************************************************
// RegisterViewer
//************************************************
static HDDEDATA DDE_Handle_RegisterViewer(char *pItem)
{
char *pMIME, *pApplication, *pFlags;
struct Viewer_Info *pViewer, *pCurrent;
BOOL ret;
int index;
long lFlags;
HDDEDATA result;
DDENOTIFYSTRUCT *dns;
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
pMIME = GetNextArgument(NULL, NULL, TRUE);
if (!pMIME)
return 0;
pFlags = GetNextArgument(NULL, &lFlags, FALSE);
if (!pFlags)
return 0;
// Force lFlags to always have ViewDocFile (for now)
lFlags |= 4;
XX_DMsg(DBG_SDI, ("RegisterViewer received: %s,%s,%d\n",
pApplication, pMIME, lFlags));
// Check for duplicates before adding to the registered list.
// Do not allow duplicates.
for (index = 0; index < HTList_count(pTransList); index++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, index);
if ((dns) &&
(dns->mime_type == HTAtom_for(pMIME)))
{
XX_DMsg(DBG_SDI, ("RegisterViewer: duplicate found - fail \n"));
return 0;
}
}
index = Hash_Find(gPrefs.pHashViewers, pMIME, NULL, (void **) &pCurrent);
if (index == -1)
{
pViewer = PREF_InitMIMEType(pMIME, pMIME, "", "", "", NULL, NULL);
strcpy(pViewer->szCurrentViewerServiceName, pApplication);
pViewer->bTemporaryStruct = TRUE;
pViewer->lCurrentViewerFlags = lFlags;
XX_DMsg(DBG_SDI, ("RegisterViewer: added to MIME list\n"));
}
else
{
strcpy(pCurrent->szCurrentViewerServiceName, pApplication);
pCurrent->lCurrentViewerFlags = lFlags;
XX_DMsg(DBG_SDI, ("RegisterViewer: modified existing MIME list\n"));
}
// Add the viewer to the transaction list
dns = (DDENOTIFYSTRUCT *) GTR_MALLOC(sizeof(DDENOTIFYSTRUCT));
memset(dns, 0, sizeof(DDENOTIFYSTRUCT));
strncpy(dns->szResultApp, pApplication, sizeof(dns->szResultApp) - 1);
dns->mime_type = HTAtom_for(pMIME);
HTList_addObject(pTransList, dns);
ret = TRUE;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &ret, sizeof(ret), 0, hszReturn, CF_TEXT, 0);
return result;
}
//************************************************
// UnRegisterViewer
//************************************************
static HDDEDATA DDE_Handle_UnRegisterViewer(char *pItem)
{
char *pMIME, *pApplication;
int i, index;
struct Viewer_Info *pCurrent;
DDENOTIFYSTRUCT *dns;
// Remove the viewer from the viewer list.
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
pMIME = GetNextArgument(NULL, NULL, TRUE);
if (!pMIME)
return 0;
XX_DMsg(DBG_SDI, ("UnRegisterViewer received: %s,%s\n",
pApplication, pMIME));
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(dns->mime_type == HTAtom_for(pMIME)))
{
HTList_removeObject(pTransList, dns);
GTR_FREE(dns);
break;
}
}
// Now fix up the preferences
index = Hash_Find(gPrefs.pHashViewers, pMIME, NULL, (void **) &pCurrent);
if (index == -1)
return 0;
// If this is a temporary structure, remove it
if (pCurrent->bTemporaryStruct)
Hash_DeleteIndexedEntry(gPrefs.pHashViewers, index);
else
pCurrent->szCurrentViewerServiceName[0] = '\0';
return 0; // return code is meaningless
}
#endif
//************************************************
// QueryVersion
//************************************************
static HDDEDATA DDE_Handle_QueryVersion(char *pItem)
{
char *pVersion;
long majorVersion, minorVersion;
int length;
HDDEDATA result;
XX_DMsg(DBG_SDI, ("DDE_Handle_QueryVersion(%s)\n", pItem));
pVersion = GetNextArgument(pItem, (long *) &majorVersion, FALSE);
if (!pVersion)
return 0;
pVersion = GetNextArgument(NULL, (long *) &minorVersion, FALSE);
if (!pVersion)
return 0;
// Now return the browser version and user agent
length = strlen(vv_UserAgentString) + 50;
pVersion = GTR_MALLOC(length);
if (!pVersion)
return 0;
memset(pVersion, 0, length);
wsprintf(pVersion, "0,9,\"%s\"", vv_UserAgentString); // version 0.9
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) pVersion, strlen(pVersion), 0, hszReturn, CF_TEXT, 0);
GTR_FREE(pVersion);
return result;
}
//************************************************
// CancelTransaction
//************************************************
static HDDEDATA DDE_Handle_CancelTransaction(char *pItem)
{
char *pTransID;
long lTransID;
struct Mwin *tw;
HDDEDATA result;
BOOL bReturn = FALSE;
int i;
DDENOTIFYSTRUCT *dns;
XX_DMsg(DBG_SDI, ("DDE_Handle_CancelTransaction(%s)\n", pItem));
//pApplication = GetNextArgument(pItem, NULL, TRUE);
//if (!pApplication)
// return 0;
pTransID = GetNextArgument(pItem, &lTransID, FALSE);
if (!pTransID)
return 0;
// Look for a match in the transaction list
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(dns->lTransID == lTransID))
//(_stricmp(dns->szResultApp, pApplication) == 0))
{
// Found. Now cancel the transaction.
tw = Mlist;
while (tw)
{
if (tw->transID == lTransID)
{
TW_AbortAndRefresh(tw);
// Return TRUE
bReturn = TRUE;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bReturn,
sizeof(bReturn), 0, hszReturn, CF_TEXT, 0);
return (result);
}
tw = tw->next;
}
}
}
// Return FALSE
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bReturn,
sizeof(bReturn), 0, hszReturn, CF_TEXT, 0);
return (result);
}
PRIVATE_CODE BOOL CopyMethodData(PWWW_INVOKEMETHODDATA pimd,
PCSTR pcszHTTPHostURL, PBYTE *ppbyteMethod,
PULONG pulcbMethodLen)
{
BOOL bResult;
BOOL bUseProxy;
ASSERT(IS_VALID_STRUCT_PTR(pimd, CWWW_INVOKEMETHODDATA));
ASSERT(IS_VALID_STRING_PTR(pcszHTTPHostURL, CSTR));
ASSERT(IS_VALID_WRITE_PTR(ppbyteMethod, PBYTE));
ASSERT(IS_VALID_WRITE_PTR(pulcbMethodLen, ULONG));
/* Prepend http host URL if running through proxy. */
bUseProxy = Dest_CheckProxy(pcszHTTPHostURL);
*pulcbMethodLen = pimd->dwcbMethodLen;
if (bUseProxy)
*pulcbMethodLen += lstrlen(pcszHTTPHostURL);
/* Copy method invocation data. */
bResult = AllocateMemory(*pulcbMethodLen, ppbyteMethod);
if (bResult)
{
PSTR pszURIStart;
ULONG ulcBefore;
ULONG ulcAfter;
ULONG ulcMiddle;
/*
* Find start of URI after method. Make sure we don't overflow
* pimd->dwcbMethodLen.
*/
for (pszURIStart = IMD_METHOD_PTR(pimd) + strcspn(IMD_METHOD_PTR(pimd),
g_cszWhiteSpace);
(pszURIStart - IMD_METHOD_PTR(pimd) <= pimd->dwcbMethodLen &&
strchr(g_cszWhiteSpace, *pszURIStart));
pszURIStart = CharNext(pszURIStart))
;
ASSERT(IS_SLASH(*pszURIStart));
ASSERT(pszURIStart >= IMD_METHOD_PTR(pimd));
ulcBefore = pszURIStart - IMD_METHOD_PTR(pimd);
ulcAfter = pimd->dwcbMethodLen - ulcBefore;
CopyMemory(*ppbyteMethod, IMD_METHOD_PTR(pimd), ulcBefore);
/* Insert http host URL for proxy if necessary. */
if (bUseProxy)
{
CopyMemory(*ppbyteMethod + ulcBefore, pcszHTTPHostURL,
lstrlen(pcszHTTPHostURL));
ulcMiddle = lstrlen(pcszHTTPHostURL);
}
else
ulcMiddle = 0;
CopyMemory(*ppbyteMethod + ulcBefore + ulcMiddle,
IMD_METHOD_PTR(pimd) + ulcBefore, ulcAfter);
}
else
{
*ppbyteMethod = NULL;
*pulcbMethodLen = 0;
}
ASSERT((bResult &&
IS_VALID_READ_BUFFER_PTR(*ppbyteMethod, BYTE, *pulcbMethodLen)) ||
(! bResult &&
EVAL(! *ppbyteMethod) &&
EVAL(! *pulcbMethodLen)));
return(bResult);
}
PRIVATE_CODE BOOL CreateAsyncMethodInvocationData(PWWW_INVOKEMETHODDATA pimd,
PINVOKEHTTPMETHODDATA *ppihttpmd)
{
BOOL bResult = FALSE;
PINVOKEHTTPMETHODDATA pihtttmd;
ASSERT(IS_VALID_STRUCT_PTR(pimd, CWWW_INVOKEMETHODDATA));
ASSERT(IS_VALID_WRITE_PTR(ppihttpmd, PINVOKEHTTPMETHODDATA));
*ppihttpmd = NULL;
/* Create wrapper structure. */
if (AllocateMemory(sizeof(*pihtttmd), &pihtttmd))
{
PMWIN pmwin;
ZeroMemory(pihtttmd, sizeof(*pihtttmd));
/* Make a new MWin to use for method invocation. */
pmwin = NewMwin(GHTML);
if (pmwin)
{
PSTR pszApp;
/* Copy required strings. */
if (StringCopy(IMD_APP_PTR(pimd), &pszApp))
{
PSTR pszTopic;
if (StringCopy(s_cszResponseTopic, &pszTopic))
{
ULONG ulcbHostLen;
PSTR pszHost;
/* Prepend http:// prefix to host name. */
/* sizeof() includes null terminator. */
ulcbHostLen = sizeof(s_cszHTTPProtocol) +
lstrlen(IMD_HOST_PTR(pimd));
if (AllocateMemory(ulcbHostLen, &pszHost))
{
PBYTE pbyteMethod;
ULONG ulcbMethodLen;
lstrcpy(pszHost, s_cszHTTPProtocol);
lstrcat(pszHost, IMD_HOST_PTR(pimd));
ASSERT(lstrlen(pszHost) + 1 == ulcbHostLen);
if (CopyMethodData(pimd, pszHost, &pbyteMethod,
&ulcbMethodLen))
{
/* Fill in structure fields. */
pihtttmd->pmwin = pmwin;
pihtttmd->pvUser = pimd->pvUser;
pihtttmd->pszApp = pszApp;
pihtttmd->pszTopic = pszTopic;
pihtttmd->pszHost = pszHost;
pihtttmd->pbyteMethod = pbyteMethod;
pihtttmd->ulcbMethodLen = ulcbMethodLen;
*ppihttpmd = pihtttmd;
bResult = TRUE;
}
else
{
FreeMemory(pszHost);
pszHost = NULL;
CREATEASYNCMETHODINVOCATIONDATA_BAIL1:
FreeMemory(pszTopic);
pszTopic = NULL;
CREATEASYNCMETHODINVOCATIONDATA_BAIL2:
FreeMemory(pszApp);
pszApp = NULL;
CREATEASYNCMETHODINVOCATIONDATA_BAIL3:
CloseMwin(pmwin);
pmwin = NULL;
CREATEASYNCMETHODINVOCATIONDATA_BAIL4:
FreeMemory(pihtttmd);
pihtttmd = NULL;
}
}
else
goto CREATEASYNCMETHODINVOCATIONDATA_BAIL1;
}
else
goto CREATEASYNCMETHODINVOCATIONDATA_BAIL2;
}
else
goto CREATEASYNCMETHODINVOCATIONDATA_BAIL3;
}
else
goto CREATEASYNCMETHODINVOCATIONDATA_BAIL4;
}
if (bResult)
TRACE_OUT(("CreateAsyncMethodInvocationData(): Created INVOKEHTTPMETHODDATA."));
else
WARNING_OUT(("CreateAsyncMethodInvocationData(): Failed to create INVOKEHTTPMETHODDATA."));
ASSERT((bResult &&
IS_VALID_STRUCT_PTR(*ppihttpmd, CINVOKEHTTPMETHODDATA)) ||
(! bResult &&
EVAL(! *ppihttpmd)));
return(bResult);
}
PRIVATE_CODE void DestroyAsyncMethodInvocationData(PINVOKEHTTPMETHODDATA pihttpmd)
{
ASSERT(IS_VALID_STRUCT_PTR(pihttpmd, CINVOKEHTTPMETHODDATA));
CloseMwin(pihttpmd->pmwin);
FreeMemory(pihttpmd->pszApp);
FreeMemory(pihttpmd->pszTopic);
FreeMemory(pihttpmd->pszHost);
FreeMemory(pihttpmd->pbyteMethod);
if (pihttpmd->pbyteResponse)
FreeMemory(pihttpmd->pbyteResponse);
FreeMemory(pihttpmd);
return;
}
PRIVATE_CODE BOOL CreateResponseData(PINVOKEHTTPMETHODDATA pihttpmd,
PWWW_RESPONSEDATA *pprd)
{
BOOL bResult = FALSE;
DWORD dwcbLen;
PWWW_RESPONSEDATA prd;
ASSERT(IS_VALID_STRUCT_PTR(pihttpmd, CINVOKEHTTPMETHODDATA));
ASSERT(IS_VALID_WRITE_PTR(pprd, PWWW_RESPONSEDATA));
/* Calculate total length of WWW_RESPONSEDATA structure. */
dwcbLen = sizeof(*prd) + pihttpmd->ulcbResponseLen;
bResult = AllocateMemory(dwcbLen, &prd);
if (bResult)
{
/* Copy hosts's response. */
prd->dwcbLen = dwcbLen;
prd->pvUser = pihttpmd->pvUser;
switch (pihttpmd->nResult)
{
case HT_LOADED:
prd->imr = IMR_OK;
break;
default:
/* BUGBUG: Provide finer IMR_ error differentiation here. */
prd->imr = IMR_ERROR;
break;
}
prd->dwcbResponseOffset = sizeof(*prd);
prd->dwcbResponseLen = pihttpmd->ulcbResponseLen;
CopyMemory(RD_RESPONSE_PTR(prd), pihttpmd->pbyteResponse,
pihttpmd->ulcbResponseLen);
*pprd = prd;
}
else
*pprd = NULL;
if (bResult)
TRACE_OUT(("CreateResponseData(): Created %lu byte WWW_RESPONSEDATA structure.",
dwcbLen));
else
WARNING_OUT(("CreateResponseData(): Failed to create %lu byte WWW_RESPONSEDATA structure.",
dwcbLen));
ASSERT((bResult &&
IS_VALID_STRUCT_PTR(*pprd, CWWW_RESPONSEDATA)) ||
(! bResult &&
EVAL(! *pprd)));
return(bResult);
}
PRIVATE_CODE void DestroyResponseData(PWWW_RESPONSEDATA prd)
{
ASSERT(IS_VALID_STRUCT_PTR(prd, CWWW_RESPONSEDATA));
FreeMemory(prd);
return;
}
PRIVATE_CODE HDDEDATA DDE_InvokeMethod(PWWW_INVOKEMETHODDATA pimd)
{
HDDEDATA hddResult = DDE_FNOTPROCESSED;
PINVOKEHTTPMETHODDATA pihttpmd;
ASSERT(IS_VALID_STRUCT_PTR(pimd, CWWW_INVOKEMETHODDATA));
/* Create method initialization structure. */
if (CreateAsyncMethodInvocationData(pimd, &pihttpmd))
{
/* Invoke method on host via new lightweight thread. */
if (Async_StartThread(&InvokeHTTPMethod_Async, pihttpmd,
pihttpmd->pmwin))
hddResult = (HDDEDATA)DDE_FACK;
else
{
DestroyAsyncMethodInvocationData(pihttpmd);
pihttpmd = NULL;
}
}
if (hddResult == (HDDEDATA)DDE_FACK)
TRACE_OUT(("DDE_InvokeMethod(): Method invocation kicked off successfully."));
else
WARNING_OUT(("DDE_InvokeMethod(): Method invocation failed."));
ASSERT(hddResult == (HDDEDATA)DDE_FACK ||
hddResult == (HDDEDATA)DDE_FBUSY ||
hddResult == (HDDEDATA)DDE_FNOTPROCESSED);
return(hddResult);
}
/*
** DDE_Issue_InvokeMethodResult()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: Frees pihttpmd.
*/
PUBLIC_CODE BOOL DDE_Issue_InvokeMethodResult(PINVOKEHTTPMETHODDATA pihttpmd)
{
BOOL bResult = FALSE;
PWWW_RESPONSEDATA prd;
ASSERT(IS_VALID_STRUCT_PTR(pihttpmd, CINVOKEHTTPMETHODDATA));
/* Create host response structure. */
if (CreateResponseData(pihttpmd, &prd))
{
HSZ hszApp;
/* Post response back to app. */
hszApp = DdeCreateStringHandle(g_DdeInst, pihttpmd->pszApp,
CP_WINANSI);
if (hszApp)
{
HSZ hszTopic;
hszTopic = DdeCreateStringHandle(g_DdeInst, pihttpmd->pszTopic,
CP_WINANSI);
if (hszTopic)
{
HCONV hConv;
hConv = MyDdeConnect(g_DdeInst, hszApp, hszTopic, NULL);
if (hConv)
{
bResult = (DdeClientTransaction((unsigned char *)prd, prd->dwcbLen, hConv,
hszReturn, CF_TEXT,
XTYP_POKE, DDE_TIMEOUT,
NULL) != 0);
EVAL(DdeDisconnect(hConv));
hConv = NULL;
}
EVAL(DdeFreeStringHandle(g_DdeInst, hszTopic));
hszTopic = NULL;
}
EVAL(DdeFreeStringHandle(g_DdeInst, hszApp));
hszApp = NULL;
}
DestroyResponseData(prd);
prd = NULL;
}
DestroyAsyncMethodInvocationData(pihttpmd);
pihttpmd = NULL;
if (bResult)
TRACE_OUT(("DDE_Issue_InvokeMethodResult(): Method invocation result issued successfully."));
else
WARNING_OUT(("DDE_Issue_InvokeMethodResult(): Failed to issue method invocation result."));
return(bResult);
}
//************************************************
//
// DDE ISSUE
//
//************************************************
BOOL DDE_Issue_ViewDocCache(struct Mwin *tw, HTFormat mime_type)
{
char *p, *p1;
char szWindowID[50];
int i;
DDENOTIFYSTRUCT *dns;
HSZ hszTopic, hszService, hszItem;
HCONV hConv;
BOOL result;
HDDEDATA hResult;
XX_DMsg(DBG_SDI, ("Inside ViewDocCache\n"));
wsprintf(szWindowID, "%ld", tw->serialID);
p1 = MakeQuotedString(tw->request->destination->szActualURL);
p = GTR_MALLOC(strlen(p1) + strlen(szWindowID) + 10);
if (!p)
return TRUE; // abort
wsprintf(p, "%s,%s", p1, szWindowID);
// Now find the app for the given MIME type
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(dns->mime_type == mime_type))
{
break;
}
}
if (i == HTList_count(pTransList))
return TRUE; // abort
// Now we found the item - Issue ViewDocCache
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_ViewDocCache", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
hszItem = DdeCreateStringHandle(g_DdeInst, p, CP_WINANSI);
hResult = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT, XTYP_REQUEST,
DDE_TIMEOUT, NULL);
XX_DMsg(DBG_SDI, ("ViewDocCache result: %d\n", hResult));
if (!hResult)
result = FALSE; // document not in cache
else
DdeGetData(hResult, (LPBYTE) &result, sizeof(result), 0);
DdeFreeStringHandle(g_DdeInst, hszItem);
DdeDisconnect(hConv);
}
else
result = FALSE;
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
tw->bSuppressError = TRUE;
return result;
}
BOOL DDE_Issue_QueryViewer(struct Mwin *tw, HTFormat mime_type, char *pFilename, int nLength)
{
char *p, *p1, *p2, *pStripped;
int i;
DDENOTIFYSTRUCT *dns;
HSZ hszTopic, hszService, hszItem;
HCONV hConv;
HDDEDATA hResult;
BOOL ret;
XX_DMsg(DBG_SDI, ("Inside QueryViewer\n"));
p1 = MakeQuotedString(tw->w3doc->szActualURL);
p2 = MakeQuotedString(HTAtom_name(mime_type));
p = GTR_MALLOC(strlen(p1) + strlen(p2) + 10);
if (!p)
{
GTR_FREE(p1);
GTR_FREE(p2);
return FALSE; // abort
}
wsprintf(p, "%s,%s", p1, p2);
// Now find the app for the given MIME type
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(dns->mime_type == mime_type))
{
break;
}
}
if (i == HTList_count(pTransList))
{
GTR_FREE(p1);
GTR_FREE(p2);
return FALSE;
}
// Now we found the item - Issue QueryViewer
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_QueryViewer", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
hszItem = DdeCreateStringHandle(g_DdeInst, p, CP_WINANSI);
hResult = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT, XTYP_REQUEST,
DDE_TIMEOUT, NULL);
if (!hResult)
{
XX_DMsg(DBG_SDI, ("QueryViewer result: 0"));
GTR_FREE(p1);
GTR_FREE(p2);
return FALSE;
}
else
{
memset(pFilename, 0, nLength);
DdeGetData(hResult, pFilename, nLength, 0);
XX_DMsg(DBG_SDI, ("QueryViewer result: %s\n",
pFilename));
// Strip off the enclosing double quotes
pStripped = GetNextArgument(pFilename, NULL, TRUE);
if (pStripped)
{
// If the string is empty, then return FALSE - this means
// that the helper app does not want to override the filename.
if (pStripped[0] == '\0')
{
GTR_FREE(p1);
GTR_FREE(p2);
return FALSE;
}
strcpy(pFilename, pStripped);
}
}
DdeFreeStringHandle(g_DdeInst, hszItem);
DdeDisconnect(hConv);
ret = TRUE;
}
else
ret = FALSE;
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
GTR_FREE(p1);
GTR_FREE(p2);
return ret;
}
void DDE_Issue_ViewDocFile(char *pFilename, char *pURL, char *pMime, long lWindowID)
{
HCONV hConv;
HSZ hszService, hszTopic, hszItem;
char *pTemp, *p1, *p2, *p3;
int length;
HDDEDATA hReturn;
char szWindowID[50];
int i;
DDENOTIFYSTRUCT *dns;
XX_DMsg(DBG_SDI, ("Inside ViewDocFile\n"));
// Find the MIME type
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(dns->mime_type == HTAtom_for(pMime)))
{
break;
}
}
// Pass the file info to viewer
hszService = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_ViewDocFile", CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
wsprintf(szWindowID, "%ld", lWindowID);
p1 = MakeQuotedString(pURL);
p2 = MakeQuotedString(pMime);
p3 = MakeQuotedString(pFilename);
length = strlen(p1) + strlen(p2) + strlen(szWindowID) + strlen(p3) + 10;
pTemp = GTR_MALLOC(length);
wsprintf(pTemp, "%s,%s,%s,%s", p3, p1, p2, szWindowID);
hszItem = DdeCreateStringHandle(g_DdeInst, pTemp, CP_WINANSI);
// Pass the data
XX_DMsg(DBG_SDI, ("ViewDocFile issued: %s,%s,%s,%s\n",
p3, p1, p2, szWindowID));
hReturn = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT,
XTYP_POKE, DDE_TIMEOUT, NULL);
DdeDisconnect(hConv);
DdeFreeStringHandle(g_DdeInst, hszItem);
GTR_FREE(p1);
GTR_FREE(p2);
GTR_FREE(p3);
GTR_FREE(pTemp);
}
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
}
//*****************************************
// DDE_Issue_Result
//
// Issue results of OpenURL and ShowFile.
// For ShowFile, update the URL as well.
//*****************************************
PRIVATE_CODE void DDE_Issue_Result(long transID, long windowID, BOOL success)
{
int i;
DDENOTIFYSTRUCT *dns;
BOOL bFound = FALSE;
char szTemp[50];
HCONV hConv;
HSZ hszService, hszTopic, hszItem;
HDDEDATA hReturn;
struct Mwin *tw;
// Send the result of the last OpenURL to the application which issued OpenURL.
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) && (dns->lTransID == transID))
{
bFound = TRUE;
break;
}
}
if (!bFound)
return;
// Find the matching tw
for (tw = Mlist; tw; tw = tw->next)
{
if (tw->transID == transID)
break;
}
if (!tw)
return;
if (!success)
{
// The specified URL load was a failure.
// Destroy the new window since the URL load failed
if (dns->bCreateNewWindow)
PostMessage(tw->hWndFrame, WM_CLOSE, 0, 0);
}
else
{
// Update the URL if this is from ShowFile
if (strcmp(dns->szReturnTopic, "WWW_ShowFileResult") == 0)
{
GTR_FREE(tw->w3doc->szActualURL);
tw->w3doc->szActualURL = GTR_strdup(dns->pURL);
TBar_UpdateTBar(tw);
}
}
// Clear the tw structure since it gets reused
tw->transID = 0;
hszService = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hszTopic = DdeCreateStringHandle(g_DdeInst, dns->szReturnTopic, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
wsprintf(szTemp, "%ld,%ld", transID, windowID);
hszItem = DdeCreateStringHandle(g_DdeInst, szTemp, CP_WINANSI);
hReturn = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT,
XTYP_POKE, DDE_TIMEOUT, NULL);
DdeDisconnect(hConv);
DdeFreeStringHandle(g_DdeInst, hszItem);
}
DdeFreeStringHandle(g_DdeInst, hszService);
DdeFreeStringHandle(g_DdeInst, hszTopic);
HTList_removeObject(pTransList, dns);
if (dns->pURL)
GTR_FREE(dns->pURL);
GTR_FREE(dns);
}
//*****************************************
// DDE_Issue_URLEcho
//
// Issue URLEcho
//*****************************************
PRIVATE_CODE void DDE_Issue_URLEcho(LONG lSerialID, PCSTR pcszURL,
HTAtom htaMIMEType)
{
int i;
DDENOTIFYSTRUCT *dns;
BOOL bFound = FALSE;
HCONV hConv;
HSZ hszService, hszTopic, hszItem;
HDDEDATA hReturn;
char *p, *p1, *p2, *p3;
// Go through the list and issue URL echo to all registered apps
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(_stricmp(dns->szReturnTopic, "WWW_URLEcho") == 0))
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_URLEcho", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
p1 = MakeQuotedString(pcszURL);
p2 = MakeQuotedString(HTAtom_name(htaMIMEType));
p3 = MakeQuotedString(NULL);
p = GTR_MALLOC(strlen(p1) + strlen(p2) + strlen(p3) + 50);
wsprintf(p, "%s,%s,%d,%s", p1, p2, lSerialID, p3);
hszItem = DdeCreateStringHandle(g_DdeInst, p, CP_WINANSI);
hReturn = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT,
XTYP_POKE, DDE_TIMEOUT, NULL);
DdeDisconnect(hConv);
DdeFreeStringHandle(g_DdeInst, hszItem);
GTR_FREE(p3);
GTR_FREE(p2);
GTR_FREE(p1);
}
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
}
}
}
//*****************************************
// DDE_Issue_WindowClose
//
// Issue Window close
//*****************************************
void DDE_Issue_WindowClose(struct Mwin *tw)
{
int i;
DDENOTIFYSTRUCT *dns;
BOOL bFound = FALSE;
HCONV hConv;
HSZ hszService, hszTopic, hszItem;
HDDEDATA hReturn;
char szTemp[50];
// Go through the list and issue to all registered apps
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(dns->lWindowID == tw->serialID) &&
(_stricmp(dns->szReturnTopic, "WWW_WindowClose") == 0))
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_WindowClose", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
wsprintf(szTemp, "%ld,%d", dns->lWindowID, (int) wg.bShuttingDown);
hszItem = DdeCreateStringHandle(g_DdeInst, szTemp, CP_WINANSI);
hReturn = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT,
XTYP_POKE, DDE_TIMEOUT, NULL);
DdeDisconnect(hConv);
DdeFreeStringHandle(g_DdeInst, hszItem);
}
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
}
}
}
//*****************************************
// RegisterNow suite
//*****************************************
BOOL DDE_Issue_RegisterNow(struct Mwin *tw, char *pApplication)
{
HSZ hszApp, hszItem, hszTopic;
HCONV hConv;
char szBuffer[128];
BOOL bReturn;
long seconds;
HDDEDATA hResult;
// Tell the specified application to register within certain interval.
// Now issue RegisterNow and get the number of seconds required
wsprintf(szBuffer, "\"MOSAIC\",%ld", TransactionID);
hszApp = DdeCreateStringHandle(g_DdeInst, pApplication, CP_WINANSI);
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_RegisterNow", CP_WINANSI);
hszItem = DdeCreateStringHandle(g_DdeInst, szBuffer, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszApp, hszTopic, NULL);
if (hConv)
{
hResult = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT, XTYP_REQUEST,
DDE_TIMEOUT, NULL);
if (!hResult)
bReturn = FALSE;
else
{
bReturn = TRUE;
// Get the requested number of seconds
DdeGetData(hResult, (LPBYTE) &seconds, sizeof(seconds), 0);
}
DdeDisconnect(hConv);
}
DdeFreeStringHandle(g_DdeInst, hszApp);
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszItem);
if (bReturn)
{
// Start a timer for the duration of requested time
tw->transID = TransactionID;
SetTimer(wg.hWndHidden, TransactionID, seconds * 1000, NULL);
TransactionID++;
return TRUE;
}
return FALSE;
}
void DDE_Handle_RegisterDone(char *pItem)
{
long lTransID;
char *pTransID;
struct Mwin *tw;
pTransID = GetNextArgument(pItem, &lTransID, FALSE);
if (!pTransID)
return;
if (KillTimer(wg.hWndHidden, lTransID))
{
/* Existence of timer indicates that the transaction ID is valid */
tw = Mlist;
while (tw)
{
if (tw->transID == lTransID)
{
Async_UnblockByWindow(tw);
return;
}
tw = tw->next;
}
}
}
//************************************************
// Utility functions
//************************************************
#if 0
BOOL GTR_HasHelperRegistered(HTFormat format)
{
int i;
DDENOTIFYSTRUCT *dns;
BOOL result = FALSE;
struct Viewer_Info *pCurrent;
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(dns->mime_type == format))
{
// See if it's still up
result = GTR_IsHelperReady(dns->szResultApp);
// If not up, it means that the helper died without
// unregistering. Clean up for the helper.
if (!result)
{
i = Hash_Find(gPrefs.pHashViewers,
HTAtom_name(format), NULL, (void **) &pCurrent);
HTList_removeObject(pTransList, dns);
if (i != -1)
{
if (pCurrent->bTemporaryStruct)
Hash_DeleteIndexedEntry(gPrefs.pHashViewers, i);
else
pCurrent->szCurrentViewerServiceName[0] = '\0';
}
}
break;
}
}
return result;
}
#endif
BOOL GTR_StartApplication(char *app)
{
return (ExecuteCommand(app) == 0);
}
BOOL GTR_IsHelperReady(char *app)
{
int index;
HSZ hszService, hszTopic;
HCONV hConv;
/* First check the hash to see if the server is up. */
index = Hash_Find(pServerHash, app, NULL, NULL);
if (index != -1)
return TRUE;
/* Now attempt to connect using some bogus topic - this hack
assumes that the helper app will only check the service name during
XTYP_CONNECT */
hszTopic = DdeCreateStringHandle(g_DdeInst, "1", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, app, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
DdeDisconnect(hConv);
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
return (hConv != 0);
}
//************************************************
// Custom protocol handler
// When an app adds a new protocol, this function
// takes care of dispatching OpenURL
//************************************************
int DDE_Custom_Protocol_Handler(HTRequest *request)
{
int result;
long lWindowID = 1;
HTList *cur;
char *pProtocol;
HTProtocol *p;
pProtocol = GTR_strdup(request->destination->szRequestedURL);
strtok(pProtocol, ":");
// Make sure the protocol exists
cur = protocols;
while ((p = (HTProtocol *) HTList_nextObject(cur)))
{
if (strcmp(p->name, pProtocol) == 0)
break;
}
GTR_FREE(pProtocol);
if (!p)
{
// Protocol not found. Return an error.
return -1;
}
result = DDE_Issue_OpenURL(request->destination->szRequestedURL, NULL, &lWindowID,
0, NULL, NULL, NULL);
return result;
}
int DDE_Issue_OpenURL(char *pURL, char *pFilespec, long *lWindowID, long lFlags,
char *pFormData, char *pMime, char *pProgressApp)
{
char *p0, *p1, *p2, *p3, *p4;
int size = 0;
char szWindowID[50], szFlags[50];
char *pBuffer, *pProtocolFromURL;
DDENOTIFYSTRUCT *dns;
HDDEDATA hResult;
HSZ hszApp, hszItem, hszTopic;
HCONV hConv;
int ret = NO, i;
// Get the protocol from URL
pProtocolFromURL = GTR_MALLOC(strlen(pURL) + 1);
strcpy(pProtocolFromURL, pURL);
strtok(pProtocolFromURL, ":");
// Find the application name from the protocol name
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if ((dns) &&
(dns->pProtocol) &&
(strcmp(dns->pProtocol, pProtocolFromURL) == 0))
{
break;
}
}
// Compose the argument string for OpenURL and issue it to the protocol handler.
p0 = MakeQuotedString(pURL);
p1 = MakeQuotedString(pFilespec);
p2 = MakeQuotedString(pFormData);
p3 = MakeQuotedString(pMime);
p4 = MakeQuotedString(pProgressApp);
wsprintf(szWindowID, "%ld", *lWindowID);
wsprintf(szFlags, "%ld", lFlags);
pBuffer = GTR_MALLOC(strlen(p0) + strlen(p1) + strlen(p2) + strlen(p3)
+ strlen(p4) +strlen(szWindowID) + strlen(szFlags) + 10);
wsprintf(pBuffer, "%s,%s,%s,%s,%s,%s,%s", p0, p1, szWindowID, szFlags, p2, p3, p4);
hszApp = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_OpenURL", CP_WINANSI);
hszItem = DdeCreateStringHandle(g_DdeInst, pBuffer, CP_WINANSI);
hConv = MyDdeConnect(g_DdeInst, hszApp, hszTopic, NULL);
if (hConv)
{
hResult = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT, XTYP_REQUEST,
DDE_TIMEOUT, NULL);
if (hResult)
{
DdeGetData(hResult, (LPBYTE) lWindowID, sizeof(*lWindowID), 0);
if (*lWindowID)
ret = 29999; // fake success
}
DdeDisconnect(hConv);
}
DdeFreeStringHandle(g_DdeInst, hszApp);
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszItem);
GTR_FREE(pBuffer);
GTR_FREE(p0);
GTR_FREE(p1);
GTR_FREE(p2);
GTR_FREE(p3);
GTR_FREE(p4);
GTR_FREE(pProtocolFromURL);
return ret;
}
//************************************************
// Initialization and Termination functions
//************************************************
BOOL InitDDE(void)
{
DWORD flags;
flags = APPCLASS_STANDARD;
ASSERT(!g_DdeInst);
if (DdeInitialize((LPDWORD) &g_DdeInst, (PFNCALLBACK) DdeCallBack, flags, 0L) != DMLERR_NO_ERROR)
{
XX_DMsg(DBG_SDI, ("InitDDE failed\n"));
return FALSE;
}
ASSERT(g_DdeInst);
XX_DMsg(DBG_SDI, ("InitDDE, g_DdeInst=0x%x\n", g_DdeInst));
if (!hszMosaic)
hszMosaic = DdeCreateStringHandle(g_DdeInst, IEXP_DDE_SERVICE, CP_WINANSI);
ASSERT(hszMosaic);
if (!hszReturn)
hszReturn = DdeCreateStringHandle(g_DdeInst, IEXP_DDE_ITEM_RETURN, CP_WINANSI);
ASSERT(hszReturn);
if (!DdeNameService(g_DdeInst, hszMosaic, 0, DNS_REGISTER))
{
XX_DMsg(DBG_SDI, ("InitDDE (DdeNameService) failed\n"));
return FALSE;
}
// Create a hash table that contains all of our supported topics.
pTopicHash = Hash_Create();
Hash_Add(pTopicHash, "WWW_OpenURL", NULL, DDE_Handle_OpenURL);
Hash_Add(pTopicHash, "WWW_ShowFile", NULL, DDE_Handle_ShowFile);
Hash_Add(pTopicHash, "WWW_Activate", NULL, DDE_Handle_Activate);
Hash_Add(pTopicHash, "WWW_ListWindows", NULL, DDE_Handle_ListWindows);
Hash_Add(pTopicHash, "WWW_GetWindowInfo", NULL, DDE_Handle_GetWindowInfo);
Hash_Add(pTopicHash, "WWW_ParseAnchor", NULL, DDE_Handle_ParseAnchor);
Hash_Add(pTopicHash, "WWW_Exit", NULL, DDE_Handle_Exit);
Hash_Add(pTopicHash, "WWW_RegisterURLEcho", NULL, DDE_Handle_RegisterURLEcho);
Hash_Add(pTopicHash, "WWW_UnRegisterURLEcho", NULL, DDE_Handle_UnRegisterURLEcho);
Hash_Add(pTopicHash, "WWW_RegisterWindowClose", NULL, DDE_Handle_RegisterWindowClose);
Hash_Add(pTopicHash, "WWW_UnRegisterWindowClose", NULL, DDE_Handle_UnRegisterWindowClose);
Hash_Add(pTopicHash, "WWW_RegisterProtocol", NULL, DDE_Handle_RegisterProtocol);
Hash_Add(pTopicHash, "WWW_UnRegisterProtocol", NULL, DDE_Handle_UnRegisterProtocol);
#if 0
Hash_Add(pTopicHash, "WWW_RegisterViewer", NULL, DDE_Handle_RegisterViewer);
Hash_Add(pTopicHash, "WWW_UnRegisterViewer", NULL, DDE_Handle_UnRegisterViewer);
#endif
Hash_Add(pTopicHash, "WWW_QueryVersion", NULL, DDE_Handle_QueryVersion);
Hash_Add(pTopicHash, "WWW_CancelTransaction", NULL, DDE_Handle_CancelTransaction);
Hash_Add(pTopicHash, IEXP_DDE_TOPIC_INVOKE_METHOD, NULL, DDE_InvokeMethod);
Hash_Add(pTopicHash, "WWW_RegisterDone", NULL, DDE_Handle_RegisterDone);
// Create a server hash table
pServerHash = Hash_Create();
// Prepare the argument buffer
pArgumentBuffer = NULL;
pCurrentArgPos = NULL;
// Prepare transaction list
pTransList = HTList_new(); // note: first item in the list is not used
pTransactionMap = NULL;
return TRUE;
}
void TerminateDDE(void)
{
int i;
DDENOTIFYSTRUCT *dns;
DdeNameService(g_DdeInst, hszMosaic, 0, DNS_UNREGISTER);
if (hszMosaic)
{
DdeFreeStringHandle(g_DdeInst, hszMosaic);
hszMosaic=0;
}
if (hszReturn)
{
DdeFreeStringHandle(g_DdeInst, hszReturn);
hszReturn=0;
}
Hash_Destroy(pTopicHash);
Hash_Destroy(pServerHash);
if (g_DdeInst)
{
DdeUninitialize(g_DdeInst);
g_DdeInst=0;
}
if (pArgumentBuffer)
GTR_FREE(pArgumentBuffer);
if (pArgReturnBuffer)
GTR_FREE(pArgReturnBuffer);
for (i = 0; i < HTList_count(pTransList); i++)
{
dns = (DDENOTIFYSTRUCT *) HTList_objectAt(pTransList, i);
if (dns->pURL)
GTR_FREE(dns->pURL);
if (dns->pProtocol)
GTR_FREE(dns->pProtocol);
GTR_FREE(dns);
}
HTList_delete(pTransList);
}
#endif /* FEATURE_IAPI */