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.
 
 
 
 
 
 

3400 lines
89 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"
#ifdef FEATURE_IAPI
extern HTList *protocols;
static DWORD g_DdeInst = 0; // DDE instance
static HSZ hszMosaic = 0; // "MOSAIC" 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 struct TRANSACTIONMAPSTRUCT *pTransactionMap; // structure used to map incoming/outgoing transactions
static WORD ProtocolHelperID = 1; // unique protocol helper ID to be passed in response to RegisterProtocol
static char *pFileContent; // Used for Verity hack - holds content of local file
static struct VERSIONSTRUCT *pVersionList; // version list
static DDENOTIFYSTRUCT *pDNS = NULL;
//**************************************
// DNS functions
//**************************************
void AddDNS(DDENOTIFYSTRUCT *dns)
{
dns->next = pDNS;
dns->prev = NULL;
if (pDNS)
pDNS->prev = dns;
pDNS = dns;
}
void RemoveDNS(DDENOTIFYSTRUCT *dns)
{
if (dns->prev)
dns->prev->next = dns->next;
if (dns->next)
dns->next->prev = dns->prev;
if (pDNS == dns)
pDNS = dns->next;
if (dns->pURL)
GTR_FREE(dns->pURL);
if (dns->pOriginalProtocol)
GTR_FREE(dns->pOriginalProtocol);
GTR_FREE(dns);
}
//**************************************
// 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;
if (!bInsideQuote)
bIgnoreBlanks = TRUE;
*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++;
bIgnoreBlanks = FALSE;
}
}
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(char *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)
{
struct Viewer_Info *pvi;
int count;
int i;
char *pAtom;
count = Hash_Count(gPrefs.pHashViewers);
for (i = 0; i < count; i++)
{
Hash_GetIndexedEntry(gPrefs.pHashViewers, i, NULL, NULL, (void **) &pvi);
if (pvi)
{
pAtom = HTAtom_name(pvi->atomMIMEType);
if (pAtom && _stricmp(pAtom, pMime) == 0)
return TRUE;
}
}
return FALSE;
}
static struct Mwin *TW_FromTransactionID(long transID)
{
struct Mwin *tw = Mlist;
// Return the tw structure which matches the transaction ID
while (tw)
{
if (tw->transID == transID)
break;
tw = tw->next;
}
return tw;
}
static struct Mwin *TW_FromWindowID(long windowID)
{
struct Mwin *tw = Mlist;
// Return the tw structure which matches the transaction ID
if (windowID == 0xFFFFFFFF)
tw = TW_FindTopmostWindow();
else
{
while (tw)
{
if (tw->serialID == windowID)
break;
tw = tw->next;
}
}
return tw;
}
static struct TRANSACTIONMAPSTRUCT *TMS_FromTransactionID(long transID)
{
struct TRANSACTIONMAPSTRUCT *p;
for (p = pTransactionMap; p; p = p->next)
{
if (p->incoming_transID == transID)
return p;
}
return NULL;
}
BOOL TMS_Remove(struct TRANSACTIONMAPSTRUCT *ptms)
{
struct TRANSACTIONMAPSTRUCT *pprev, *pcurrent;
pcurrent = pTransactionMap;
pprev = NULL;
while (pcurrent != ptms)
{
pprev = pcurrent;
pcurrent = ptms->next;
}
if (!pcurrent)
return FALSE;
if (pprev)
pprev->next = pcurrent->next;
else
pTransactionMap = pcurrent->next;
GTR_FREE(pcurrent);
return TRUE;
}
static char *GetArgumentsFromFile(char *filename)
{
FILE *fp;
long filesize;
char *pTemp, *p1, *p2;
fp = fopen(filename, "rb"); // read as binary to avoid text translation
if (!fp)
return NULL;
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
pTemp = GTR_MALLOC(filesize + 1);
if (!pTemp)
{
fclose(fp);
return NULL;
}
fseek(fp, 0, SEEK_SET);
fread(pTemp, 1, filesize, fp);
pTemp[filesize] = '\0';
fclose(fp);
if (pFileContent)
GTR_FREE(pFileContent);
pFileContent = GTR_MALLOC(filesize + 1);
if (!pFileContent)
{
GTR_FREE(pFileContent);
return NULL;
}
// The receipient must delete the file
remove(filename);
// Now copy pTemp into pFileContent, stripping all CR and LF characters
for (p1 = pTemp, p2 = pFileContent; *p1; p1++)
{
if (*p1 != '\r' && *p1 != '\n')
*p2++ = *p1;
}
*p2 = '\0';
return pFileContent;
}
static HSZ CreateArgument(char *pApp, char *pBuffer)
{
struct VERSIONSTRUCT *pVersion;
char path[_MAX_PATH + 1], filename[_MAX_PATH + 1];
FILE *fp;
HSZ hszItem;
/*
Look for this application in the version list. If found, use the 1.0 hack (caret preceds a
file name containing the arguments). If not, use the old method, even though there is a risk
of arguments getting cut off.
*/
for (pVersion = pVersionList; pVersion; pVersion = pVersion->next)
{
if (_stricmp(pVersion->szApp, pApp) == 0)
break;
}
/* Do not create a file unless necessary */
if ((!pVersion) || (pVersion->major < 1) || (strlen(pBuffer) < 256))
hszItem = DdeCreateStringHandle(g_DdeInst, pBuffer, CP_WINANSI);
else
{
/* Get a temporary file name */
path[0] = 0;
PREF_GetTempPath(_MAX_PATH, path);
GetTempFileName(path, "A", 0, filename);
/* Write the arguments in the temp file */
fp = fopen(filename, "wb");
fwrite(pBuffer, 1, strlen(pBuffer), fp);
fclose(fp);
/* Create a file name spec (caret and filename) */
/* Borrow the path buffer */
sprintf(path, "^%s", filename);
hszItem = DdeCreateStringHandle(g_DdeInst, path, CP_WINANSI);
}
return hszItem;
}
//************************************************
// Dispatch function
//************************************************
HDDEDATA EXPENTRY DdeCallBack(WORD wType,
WORD wFmt,
HCONV hConv,
HSZ hsz1,
HSZ hsz2,
HDDEDATA hDDEData,
DWORD dwData1,
DWORD dwData2)
{
char szTopic[64];
char szItem[2048];
DDEHANDLECALLBACK pCallback;
int index;
char *pItem;
// 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:
case XTYP_POKE:
// 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)
return 0;
DdeQueryString(g_DdeInst, hsz2, szItem, sizeof(szItem), CP_WINANSI);
if (szItem[0] == '^')
pItem = GetArgumentsFromFile(&szItem[1]);
else
pItem = szItem;
if (!pItem)
return 0;
else
return ((*pCallback)(pItem));
case XTYP_CONNECT:
return (HDDEDATA) (hszMosaic == hsz2);
case XTYP_ADVSTART:
case XTYP_ADVREQ:
case XTYP_ADVSTOP:
case XTYP_WILDCONNECT:
return DDE_FNOTPROCESSED;
default:
return (HDDEDATA) NULL;
}
}
//************************************************
// OpenURL functions
//************************************************
static HDDEDATA DDE_Handle_OpenURLResult(char *pItem)
{
char *pTransID, *pWindowID;
long lTransID, lWindowID;
struct TRANSACTIONMAPSTRUCT *ptms;
char szTemp[50];
HSZ hszService, hszTopic, hszItem;
HCONV hConv;
HDDEDATA hReturn;
DDENOTIFYSTRUCT *dns;
pTransID = GetNextArgument(pItem, &lTransID, FALSE);
if (!pTransID)
return 0;
pWindowID = GetNextArgument(NULL, &lWindowID, FALSE);
if (!pWindowID)
return 0;
// Look for the matching transaction in the transaction map.
// We need to pass the result to the original requester,
// translating the transaction ID as necessary.
ptms = TMS_FromTransactionID(lTransID);
if (!ptms)
return 0;
for (dns = pDNS; dns; dns = dns->next)
{
if (dns->lTransID == ptms->outgoing_transID)
break;
}
if (!dns)
return 0;
hszService = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hszTopic = DdeCreateStringHandle(g_DdeInst, dns->szReturnTopic, CP_WINANSI);
hConv = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
sprintf(szTemp, "%ld,%ld", ptms->outgoing_transID, lWindowID);
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);
// Remove the structure from the transaction map list
TMS_Remove(ptms);
RemoveDNS(dns);
return 0;
}
static HDDEDATA DDE_Handle_OpenURL(char *pItem)
{
char *pURL, *pFile, *pWindowID, *pFlags, *pFormData, *pMIMEType, *pProgressApp, *pResultApp;
long lWindowID, lFlags;
BOOL bNoDocCache, bNoImageCache, bBackground, bInvalidProtocol;
HDDEDATA result;
long retval = SDI_SUPER_ACK;
DDENOTIFYSTRUCT *dns, *dns2;
struct Mwin *tw;
struct TRANSACTIONMAPSTRUCT *tms;
HTList *cur;
HTProtocol *p;
char *pProtocol;
XX_DMsg(DBG_SDI, ("OpenURL received: %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 = "";
}
// If result application does not exist, progress cannot be sent.
// In this case, set progress app to an empty value.
if (pResultApp[0] == '\0')
pProgressApp = "";
XX_DMsg(DBG_SDI, ("OpenURL filtered: %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;
AddDNS(dns);
if (pProgressApp[0] || pResultApp[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;
}
else
tms = NULL;
// If the protocol is not supported by Mosaic but is supported by a helper,
// start a windowless tw and pass the URL along.
pProtocol = GTR_strdup(pURL);
strtok(pProtocol, ":");
cur = protocols;
bInvalidProtocol = TRUE;
while ((p = (HTProtocol *) HTList_nextObject(cur)))
{
if (strcmp(p->name, pProtocol) == 0)
{
bInvalidProtocol = FALSE;
if (p->load == DDE_Custom_Protocol_Handler)
{
// We found the protocol
break;
}
}
}
if (bInvalidProtocol)
{
RemoveDNS(dns);
retval = SDI_INVALID_PROTOCOL;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &retval, sizeof(retval),
0, hszReturn, CF_TEXT, 0);
return result;
}
if (p)
{
if (tms)
{
for (dns2 = pDNS; dns2; dns2 = dns2->next)
{
if ((dns2->pProtocol) &&
(_stricmp(pProtocol, dns2->pProtocol) == 0))
{
strcpy(tms->incoming_app, dns2->szResultApp);
break;
}
}
}
// The URL contained a custom registered protocol. We need to issue an
// OpenURL here so that we can send back the result right away. If
// progress app is specified, change the progress to come to Mosaic so
// that it can be rerouted to the requester.
retval = SDI_Issue_OpenURL(pURL, pFile, &lWindowID, lFlags, pFormData,
pMIMEType, "MOSAIC", (pResultApp[0] ? "MOSAIC" : ""));
// The return value from SDI_Issue_OpenURL is really contained in lWindowID.
if (tms)
tms->incoming_transID = lWindowID;
// If the OpenURL requester did not specify to receive the OpenURLResult, then
// just super-ack it. Otherwise, send the transaction ID (unique to Mosaic -
// we provide the mapping)
if (pResultApp[0])
{
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &TransactionID, sizeof(TransactionID),
0, hszReturn, CF_TEXT, 0);
// Do not delete dns because we need it later to send OpenURLResult
}
else
{
retval = SDI_SUPER_ACK;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &retval, sizeof(retval),
0, hszReturn, CF_TEXT, 0);
}
// Delete dns here because there is no OpenURLResult
if (retval == SDI_SUPER_ACK)
{
RemoveDNS(dns);
if (tms)
TMS_Remove(tms);
}
TransactionID++;
GTR_FREE(pProtocol);
return (result);
}
GTR_FREE(pProtocol);
// 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.
if (pFile[0])
{
tw = NewMwin(GWINDOWLESS);
tw->transID = TransactionID;
// tw->szProgressApp is already NULLed
strncpy(tw->szProgressApp, pProgressApp, sizeof(tw->szProgressApp) - 1);
GTR_DoSDI(tw, pURL, NULL, pFile, TRUE);
if (pResultApp[0])
retval = TransactionID;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &retval, sizeof(retval),
0, hszReturn, CF_TEXT, 0);
TransactionID++;
return result;
}
switch(lWindowID)
{
case 0:
//
// Open a new Window and put the URL there. Return a transaction ID for now
// since the operation is asynchronous.
XX_DMsg(DBG_SDI, ("OpenURL: Creating a new window\n"));
dns->bCreateNewWindow = TRUE;
if (pFormData[0])
GTR_NewWindow(pURL, NULL, TransactionID, bNoDocCache, bNoImageCache, pFormData, pProgressApp);
else
GTR_NewWindow(pURL, NULL, TransactionID, bNoDocCache, bNoImageCache, NULL, pProgressApp);
if (pResultApp[0])
retval = TransactionID;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &retval, sizeof(retval),
0, hszReturn, CF_TEXT, 0);
TransactionID++;
return result;
case 0xFFFFFFFF:
//
// Use the most recently active window and put the URL there.
dns->bCreateNewWindow = FALSE;
tw = TW_FromWindowID(lWindowID);
if (!tw)
return 0;
XX_DMsg(DBG_SDI, ("OpenURL: Using most recently active window %d\n", tw->serialID));
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, TRUE, TRUE, bNoDocCache, bNoImageCache, pFormData, NULL);
else
TW_LoadDocument(tw, pURL, TRUE, FALSE, bNoDocCache, bNoImageCache, NULL, NULL);
if (pResultApp[0])
retval = TransactionID;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &retval, sizeof(retval),
0, hszReturn, CF_TEXT, 0);
TransactionID++;
return result;
default:
//
// Check if the specified window exists and use the window
dns->bCreateNewWindow = FALSE;
tw = TW_FromWindowID(lWindowID);
if (tw)
{
XX_DMsg(DBG_SDI, ("OpenURL: Using window %d\n", tw->serialID));
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, TRUE, TRUE, bNoDocCache, bNoImageCache, pFormData, NULL);
else
TW_LoadDocument(tw, pURL, TRUE, FALSE, bNoDocCache, bNoImageCache, NULL, NULL);
retval = tw->transID;
TransactionID++;
}
else
retval = 0;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &retval, sizeof(retval),
0, hszReturn, CF_TEXT, 0);
return result;
}
}
static HDDEDATA DDE_Handle_GetHTTPHead(char *pItem)
{
char *pURL, *pResultApp;
HDDEDATA result;
long retval = SDI_SUPER_ACK;
DDENOTIFYSTRUCT *dns;
struct Mwin *tw;
char *pProtocol;
XX_DMsg(DBG_SDI, ("GetHTTPHead received: %s\n", pItem));
pURL = GetNextArgument(pItem, NULL, TRUE);
if (!pURL)
return 0;
pResultApp = GetNextArgument(NULL, NULL, TRUE);
if (!pResultApp)
return 0;
XX_DMsg(DBG_SDI, ("GetHTTPHead filtered: %s,%s\n",
pURL, pResultApp));
dns = (DDENOTIFYSTRUCT *) GTR_MALLOC(sizeof(DDENOTIFYSTRUCT));
if (!dns)
return 0;
memset(dns, 0, sizeof(DDENOTIFYSTRUCT));
strncpy(dns->szResultApp, pResultApp, sizeof(dns->szResultApp) - 1);
strcpy(dns->szReturnTopic, "WWW_GetHTTPHeadResult");
dns->lTransID = TransactionID;
// The protocol MUST be http. We process this using a windowless tw.
pProtocol = GTR_strdup(pURL);
strtok(pProtocol, ":");
if (0 != strcmp("http", pProtocol))
{
GTR_FREE(dns);
GTR_FREE(pProtocol);
retval = SDI_INVALID_PROTOCOL;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &retval, sizeof(retval),
0, hszReturn, CF_TEXT, 0);
return result;
}
GTR_FREE(pProtocol);
tw = NewMwin(GWINDOWLESS);
tw->transID = TransactionID;
GTR_DoHTTPHead(tw, pURL);
if (pResultApp[0])
retval = TransactionID;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &retval, sizeof(retval),
0, hszReturn, CF_TEXT, 0);
TransactionID++;
AddDNS(dns);
return result;
}
void SDI_Issue_BeginProgress(char *pProgress, long lTransID, char *pMessage, BOOL bInternalUse)
{
struct TRANSACTIONMAPSTRUCT *tms;
HSZ hszTopic, hszService, hszItem;
HDDEDATA hResult;
HCONV hConv;
char *p, *p1;
tms = pTransactionMap;
while (tms)
{
if ((strcmp(tms->outgoing_app, pProgress) == 0) &&
(tms->outgoing_transID == lTransID))
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_BeginProgress", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, pProgress, CP_WINANSI);
hConv = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
XX_DMsg(DBG_SDI, ("Issuing BeginProgress to %s.\n", pProgress));
p1 = MakeQuotedString(pMessage);
p = GTR_MALLOC(strlen(p1) + 50 + 1);
sprintf(p, "%ld,%s", tms->outgoing_transID, p1);
hszItem = CreateArgument(pProgress, p);
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 SDI_Issue_SetProgressRange(char *pProgress, long lTransID, long lRange, BOOL bInternalUse)
{
struct TRANSACTIONMAPSTRUCT *tms;
HSZ hszTopic, hszService, hszItem;
HDDEDATA hResult;
HCONV hConv;
char szTemp[50];
tms = pTransactionMap;
while (tms)
{
if ((strcmp(tms->outgoing_app, pProgress) == 0) &&
(tms->outgoing_transID == lTransID))
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_SetProgressRange", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, pProgress, CP_WINANSI);
hConv = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
XX_DMsg(DBG_SDI, ("Issuing SetProgressRange to %s.\n", pProgress));
sprintf(szTemp, "%ld,%ld", tms->outgoing_transID, lRange);
hszItem = CreateArgument(pProgress, szTemp);
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 SDI_Issue_MakingProgress(struct Mwin *tw, char *pProgressApp, long lTransID,
char *pMessage, long lProgress, BOOL bInternalUse)
{
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 */
/* Do this only for internally generated progress messages */
if (bInternalUse)
{
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, pProgressApp) == 0) &&
(tms->outgoing_transID == lTransID))
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_MakingProgress", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, pProgressApp, CP_WINANSI);
hConv = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
XX_DMsg(DBG_SDI, ("Issuing MakingProgress to %s.\n", pProgressApp));
p1 = MakeQuotedString(pMessage);
p = GTR_MALLOC(strlen(p1) + 100 + 1);
sprintf(p, "%ld,%s,%ld", tms->outgoing_transID, p1, lProgress);
hszItem = CreateArgument(pProgressApp, p);
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 && tw)
{
XX_DMsg(DBG_SDI, ("MakingProgress: Client aborted the process.\n"));
SDI_Issue_EndProgress(tms->outgoing_app, tms->outgoing_transID, bInternalUse);
Async_TerminateByWindow(tw);
}
}
DdeDisconnect(hConv);
}
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
return;
}
tms = tms->next;
}
}
void SDI_Issue_EndProgress(char *pProgress, long lTransID, BOOL bInternalUse)
{
struct TRANSACTIONMAPSTRUCT *tms;
HSZ hszTopic, hszService, hszItem;
HDDEDATA hResult;
HCONV hConv;
char *p;
tms = pTransactionMap;
while (tms)
{
if ((strcmp(tms->outgoing_app, pProgress) == 0) &&
(lTransID == tms->outgoing_transID))
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_EndProgress", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, pProgress, CP_WINANSI);
hConv = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
XX_DMsg(DBG_SDI, ("Issuing EndProgress to %s.\n", pProgress));
p = GTR_MALLOC(50 + 1);
sprintf(p, "%ld", tms->outgoing_transID);
hszItem = CreateArgument(pProgress, p);
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;
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)
pResultApp = "";
// 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);
AddDNS(dns);
// Create a window if its ID is zero
if (lWindowID == 0)
{
dns->bCreateNewWindow = TRUE;
tw = NewMwin(GHTML);
if (!tw)
{
ERR_ReportError(NULL, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
return 0;
}
if (!GDOC_NewWindow(tw))
{
CloseMwin(tw);
return 0;
}
}
else
{
tw = TW_FromWindowID(lWindowID);
if (!tw)
return 0;
}
// If the MIME type is suppoted by an SDI viewer, set the error
// code in tw->lErrorCode now so that when the result is issued,
// it will return the correct return code (-1 = improper type to
// handle in a Mosaic window)
for (dns = pDNS; dns; dns = dns->next)
{
if (dns->mime_type == HTAtom_for(pMIME))
{
tw->lErrorOccurred = SDI_INVALID_MIME;
break;
}
}
// Open document asynchronously
tw->transID = TransactionID;
tw->bSuppressError = TRUE;
tw->SDI_MimeType = HTAtom_for(pMIME);
if (tw->SDI_url)
GTR_FREE(tw->SDI_url);
tw->SDI_url = GTR_strdup(pURL);
OpenLocalDocument(tw->win, pFileSpec);
TransactionID++;
if (pResultApp[0])
transID = tw->transID;
else
transID = SDI_SUPER_ACK;
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, ("SDI: Activating window %s\n", pItem));
pWindowID = GetNextArgument(pItem, &lWindowID, FALSE);
if (!pWindowID)
return 0;
pFlags = GetNextArgument(NULL, &lFlags, FALSE);
if (!pFlags)
return 0;
tw = TW_FromWindowID(lWindowID);
if (tw)
{
TW_RestoreWindow(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;
// count the number of open windows
while (tw && (tw->wintype == GHTML))
{
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 && (tw->wintype == GHTML))
{
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;
pWindowID = GetNextArgument(pItem, &lWindowID, FALSE);
if (!pWindowID)
return 0;
tw = TW_FromWindowID(lWindowID);
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) + 1, 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;
pMain = GetNextArgument(pItem, NULL, TRUE);
if (!pMain)
return 0;
pRelative = GetNextArgument(NULL, NULL, TRUE);
if (!pRelative)
return 0;
pURL = HTParse(pRelative, pMain, PARSE_ALL);
pReturn = MakeQuotedString(pURL);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) pReturn, strlen(pReturn) + 1, 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.
PostMessage(wg.hWndHidden, WM_CLOSE, 0, 0);
return 0;
}
//************************************************
// RegisterURLEcho
//************************************************
static HDDEDATA DDE_Handle_RegisterURLEcho(char *pItem)
{
char *pApplication;
DDENOTIFYSTRUCT *dns;
long ret;
HDDEDATA result;
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
// Make sure that this application has not already been
// registered for URL echo
for (dns = pDNS; dns; dns = dns->next)
{
if ((_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");
AddDNS(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;
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
// Look for the matching item and remove it
for (dns = pDNS; dns; dns = dns->next)
{
if ((_stricmp(dns->szReturnTopic, "WWW_URLEcho") == 0) &&
(_stricmp(dns->szResultApp, pApplication) == 0))
{
RemoveDNS(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;
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
pWindowID = GetNextArgument(NULL, &lWindowID, FALSE);
if (!pWindowID)
return 0;
// Make sure the window exists
tw = TW_FromWindowID(lWindowID);
if (!tw)
return 0;
// Make sure that this application has not already been
// registered for Window close
for (dns = pDNS; dns; dns = dns->next)
{
if ((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");
AddDNS(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;
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 (dns = pDNS; dns; dns = dns->next)
{
if ((dns->lWindowID == lWindowID) &&
(_stricmp(dns->szReturnTopic, "WWW_WindowClose") == 0) &&
(_stricmp(dns->szResultApp, pApplication) == 0))
{
RemoveDNS(dns);
return 0;
}
}
return 0;
}
//************************************************
// RegisterProtocol
//************************************************
static HDDEDATA DDE_Handle_RegisterProtocol(char *pItem)
{
char *pApplication, *pProtocol;
DDENOTIFYSTRUCT *dns;
HTList *cur;
HTProtocol *p;
HDDEDATA result;
LONG ret;
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 (dns = pDNS; dns; dns = dns->next)
{
if (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);
AddDNS(dns);
ret = MAKELONG(0, ProtocolHelperID);
if (ProtocolHelperID == 0x7FFF)
ProtocolHelperID = 1;
else
ProtocolHelperID++;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &ret, sizeof(ret), 0,
hszReturn, CF_TEXT, 0);
return result;
}
//************************************************
// UnRegisterProtocol
//************************************************
static HDDEDATA DDE_Handle_UnRegisterProtocol(char *pItem)
{
char *pApplication, *pProtocol;
DDENOTIFYSTRUCT *dns;
HTList *cur;
HTProtocol *p;
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
pProtocol = GetNextArgument(NULL, NULL, TRUE);
if (!pProtocol)
return 0;
// Remove the notification structure
for (dns = pDNS; dns; dns = dns->next)
{
if ((strcmp(dns->pProtocol, pProtocol) == 0) &&
(_stricmp(dns->szResultApp, pApplication) == 0))
{
// 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));
}
break;
}
}
RemoveDNS(dns);
return 0;
}
}
return 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 (dns = pDNS; dns; dns = dns->next)
{
if (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);
AddDNS(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 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 (dns = pDNS; dns; dns = dns->next)
{
if (dns->mime_type == HTAtom_for(pMIME))
{
RemoveDNS(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
}
//************************************************
// RegisterAppClose
//************************************************
static HDDEDATA DDE_Handle_RegisterAppClose(char *pItem)
{
char *pApplication;
DDENOTIFYSTRUCT *dns;
HDDEDATA result;
BOOL ret;
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
// Make sure that this application has not already been
// registered for app close
for (dns = pDNS; dns; dns = dns->next)
{
if ((_stricmp(dns->szReturnTopic, "WWW_AppClose") == 0) &&
(_stricmp(dns->szResultApp, pApplication) == 0))
{
return 0;
}
}
// Add the request
dns = (DDENOTIFYSTRUCT *) GTR_MALLOC(sizeof(DDENOTIFYSTRUCT));
memset(dns, 0, sizeof(DDENOTIFYSTRUCT));
strcpy(dns->szResultApp, pApplication);
strcpy(dns->szReturnTopic, "WWW_AppClose");
AddDNS(dns);
// Return success
ret = TRUE;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &ret, sizeof(ret), 0, hszReturn, CF_TEXT, 0);
return result;
}
//************************************************
// UnRegisterAppClose
//************************************************
static HDDEDATA DDE_Handle_UnRegisterAppClose(char *pItem)
{
char *pApplication;
DDENOTIFYSTRUCT *dns;
pApplication = GetNextArgument(pItem, NULL, TRUE);
if (!pApplication)
return 0;
// Look for the matching item and remove it
for (dns = pDNS; dns; dns = dns->next)
{
if ((_stricmp(dns->szReturnTopic, "WWW_AppClose") == 0) &&
(_stricmp(dns->szResultApp, pApplication) == 0))
{
RemoveDNS(dns);
return 0;
}
}
return 0;
}
//************************************************
// QueryVersion
//************************************************
static HDDEDATA DDE_Handle_QueryVersion(char *pItem)
{
char *pApp, *pVersion, *p1;
long majorVersion, minorVersion;
int length;
HDDEDATA result;
struct VERSIONSTRUCT *pVersionItem;
XX_DMsg(DBG_SDI, ("QueryVersion received: %s\n", pItem));
pVersion = GetNextArgument(pItem, (long *) &majorVersion, FALSE);
if (!pVersion)
return 0;
pVersion = GetNextArgument(NULL, (long *) &minorVersion, FALSE);
if (!pVersion)
return 0;
// To remain compatible with version 0.9, allow NULL application names.
// Keep track of the version information only if the application name exists.
pApp = GetNextArgument(NULL, NULL, TRUE);
if (pApp)
{
// Add the information in the version structure list or modify
// an existing entry
for (pVersionItem = pVersionList; pVersionItem; pVersionItem = pVersionItem->next)
{
if (strncmp(pApp, pVersionItem->szApp, sizeof(pVersionItem->szApp) - 1) == 0)
break;
}
if (!pVersionItem)
{
pVersionItem = GTR_MALLOC(sizeof(struct VERSIONSTRUCT));
pVersionItem->next = pVersionList;
pVersionList = pVersionItem;
}
strncpy(pVersionItem->szApp, pApp, sizeof(pVersionItem->szApp) - 1);
pVersionItem->szApp[sizeof(pVersionItem->szApp) - 1] = '\0';
pVersionItem->major = majorVersion;
pVersionItem->minor = minorVersion;
}
// 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);
// Version negotiation
if (majorVersion < 1)
{
minorVersion = 9; // version 0.9 is the minimum we can support
}
else if (majorVersion == 1)
{
minorVersion = 0; // version 1.0 is the maximum we can support
}
else
{
majorVersion = 1;
minorVersion = 0; // version 1.0 is the maximum we can support
}
p1 = MakeQuotedString(vv_UserAgentString);
sprintf(pVersion, "%d,%d,%s", majorVersion, minorVersion, p1);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) pVersion, strlen(pVersion) + 1, 0, hszReturn, CF_TEXT, 0);
GTR_FREE(p1);
GTR_FREE(pVersion);
return result;
}
//************************************************
// CancelTransaction
//************************************************
static HDDEDATA DDE_Handle_CancelTransaction(char *pItem)
{
char *pTransID;
long lTransID;
struct Mwin *tw;
HDDEDATA result;
BOOL bCancel = FALSE;
DDENOTIFYSTRUCT *dns;
struct TRANSACTIONMAPSTRUCT *ptms;
char szTemp[50];
HSZ hszService, hszTopic, hszItem;
HCONV hConv;
HDDEDATA hReturn;
//pApplication = GetNextArgument(pItem, NULL, TRUE);
//if (!pApplication)
// return 0;
pTransID = GetNextArgument(pItem, &lTransID, FALSE);
if (!pTransID)
return 0;
// If the transaction is in the transaction map, we need to
// pass this information to another application.
// Can't use TMS_FromTransactionID here because we need to check
// for the outgoing ID instead of incoming ID.
for (ptms = pTransactionMap; ptms; ptms = ptms->next)
{
if (ptms->outgoing_transID == lTransID)
break;
}
if (ptms)
{
hszService = DdeCreateStringHandle(g_DdeInst, ptms->incoming_app, CP_WINANSI);
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_CancelTransaction", CP_WINANSI);
hConv = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
sprintf(szTemp, "%ld", ptms->incoming_transID);
hszItem = DdeCreateStringHandle(g_DdeInst, szTemp, CP_WINANSI);
hReturn = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT,
XTYP_REQUEST, DDE_TIMEOUT, NULL);
DdeDisconnect(hConv);
DdeFreeStringHandle(g_DdeInst, hszItem);
if (hReturn)
DdeGetData(hReturn, (LPBYTE) &bCancel, sizeof(bCancel), 0);
}
DdeFreeStringHandle(g_DdeInst, hszService);
DdeFreeStringHandle(g_DdeInst, hszTopic);
if (bCancel)
{
// If a transaction gets canceled through CancelTransaction,
// then no OpenURLResult will be issued. So, we need to
// remove the tms structure from the transaction map list.
TMS_Remove(ptms);
}
// We can simply pass the same result that we received to the
// requester.
return (hReturn);
}
// Look for a match in the transaction list
for (dns = pDNS; dns; dns = dns->next)
{
if (dns->lTransID == lTransID)
//(_stricmp(dns->szResultApp, pApplication) == 0))
{
// Found. Now cancel the transaction.
tw = Mlist;
while (tw)
{
if (tw->transID == lTransID)
{
Async_TerminateByWindow(tw);
// Return TRUE
bCancel = TRUE;
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bCancel,
sizeof(bCancel), 0, hszReturn, CF_TEXT, 0);
return (result);
}
tw = tw->next;
}
}
}
// Return FALSE
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bCancel,
sizeof(bCancel), 0, hszReturn, CF_TEXT, 0);
return (result);
}
//************************************************
// DDE_Handle_BeginProgress
//************************************************
static HDDEDATA DDE_Handle_BeginProgress(char *pItem)
{
char *pTransID, *pMessage;
long lTransID;
struct Mwin *tw;
BOOL bReturn = TRUE;
HDDEDATA result;
struct TRANSACTIONMAPSTRUCT *ptms;
pTransID = GetNextArgument(pItem, &lTransID, FALSE);
if (!pTransID)
return 0;
pMessage = GetNextArgument(NULL, NULL, TRUE);
if (!pMessage)
return 0;
// Check the given transaction ID for a match within the transaction map.
// If there is a match then we are supposed to pass the progress message
// over to the requester.
ptms = TMS_FromTransactionID(lTransID);
if (ptms)
{
if (strcmp(ptms->incoming_app, ptms->outgoing_app) != 0)
{
SDI_Issue_BeginProgress(ptms->outgoing_app, ptms->outgoing_transID, pMessage, FALSE);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bReturn,
sizeof(bReturn), 0, hszReturn, CF_TEXT, 0);
return (result);
}
tw = TW_FromTransactionID(ptms->outgoing_transID);
}
else
tw = TW_FindTopmostWindow();
WAIT_Push(tw, waitNoInteract, pMessage);
WAIT_SetRange(tw, 0, 100, 100);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bReturn,
sizeof(bReturn), 0, hszReturn, CF_TEXT, 0);
return (result);
}
static HDDEDATA DDE_Handle_SetProgressRange(char *pItem)
{
char *pTransID, *pMax;
long lTransID, lMax;
BOOL bReturn = TRUE;
HDDEDATA result;
struct Mwin *tw;
struct TRANSACTIONMAPSTRUCT *ptms;
pTransID = GetNextArgument(pItem, &lTransID, FALSE);
if (!pTransID)
return 0;
pMax = GetNextArgument(NULL, &lMax, FALSE);
if (!pMax)
return 0;
// Check the given transaction ID for a match within the transaction map.
// If there is a match then we are supposed to pass the progress message
// over to the requester.
ptms = TMS_FromTransactionID(lTransID);
if (ptms)
{
if (strcmp(ptms->incoming_app, ptms->outgoing_app) != 0)
{
SDI_Issue_SetProgressRange(ptms->outgoing_app, ptms->outgoing_transID, lMax, FALSE);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bReturn,
sizeof(bReturn), 0, hszReturn, CF_TEXT, 0);
return (result);
}
tw = TW_FromTransactionID(ptms->outgoing_transID);
}
else
tw = TW_FindTopmostWindow();
WAIT_SetRange(tw, 0, 100, lMax);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bReturn,
sizeof(bReturn), 0, hszReturn, CF_TEXT, 0);
return (result);
}
static HDDEDATA DDE_Handle_MakingProgress(char *pItem)
{
char *pTransID, *pMessage, *pCurrent;
long lTransID, lCurrent;
BOOL bReturn = FALSE;
HDDEDATA result;
struct Mwin *tw;
struct TRANSACTIONMAPSTRUCT *ptms;
pTransID = GetNextArgument(pItem, &lTransID, FALSE);
if (!pTransID)
return 0;
pMessage = GetNextArgument(NULL, NULL, TRUE);
if (!pMessage)
return 0;
pCurrent = GetNextArgument(NULL, &lCurrent, FALSE);
if (!pCurrent)
return 0;
// Check the given transaction ID for a match within the transaction map.
// If there is a match then we are supposed to pass the progress message
// over to the requester.
ptms = TMS_FromTransactionID(lTransID);
if (ptms)
{
if (strcmp(ptms->incoming_app, ptms->outgoing_app) != 0)
{
SDI_Issue_MakingProgress(NULL, ptms->outgoing_app, ptms->outgoing_transID, pMessage, lCurrent, FALSE);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bReturn,
sizeof(bReturn), 0, hszReturn, CF_TEXT, 0);
return (result);
}
tw = TW_FromTransactionID(ptms->outgoing_transID);
}
else
tw = TW_FindTopmostWindow();
// Scale the current value down to 100% - we accept it only this way
if (tw->awi)
{
BHBar_SetStatusField(tw, pMessage);
lCurrent = 100 * lCurrent / tw->awi->nScalingDenominator;
UpdateThermometer(tw, (int) lCurrent);
}
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bReturn,
sizeof(bReturn), 0, hszReturn, CF_TEXT, 0);
return (result);
}
static HDDEDATA DDE_Handle_EndProgress(char *pItem)
{
char *pTransID;
long lTransID;
struct Mwin *tw;
BOOL bReturn = TRUE;
HDDEDATA result;
struct TRANSACTIONMAPSTRUCT *ptms;
pTransID = GetNextArgument(pItem, &lTransID, FALSE);
if (!pTransID)
return 0;
// Check the given transaction ID for a match within the transaction map.
// If there is a match then we are supposed to pass the progress message
// over to the requester.
ptms = TMS_FromTransactionID(lTransID);
if (ptms)
{
if (strcmp(ptms->incoming_app, ptms->outgoing_app) != 0)
{
SDI_Issue_EndProgress(ptms->outgoing_app, ptms->outgoing_transID, FALSE);
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bReturn,
sizeof(bReturn), 0, hszReturn, CF_TEXT, 0);
return (result);
}
tw = TW_FromTransactionID(ptms->outgoing_transID);
}
else
tw = TW_FindTopmostWindow();
WAIT_Pop(tw);
BHBar_SetStatusField(tw, "");
result = DdeCreateDataHandle(g_DdeInst, (LPBYTE) &bReturn,
sizeof(bReturn), 0, hszReturn, CF_TEXT, 0);
return (result);
}
//************************************************
//
// DDE ISSUE
//
//************************************************
BOOL SDI_Issue_ViewDocCache(struct Mwin *tw, HTFormat mime_type)
{
char *p, *p1;
char szWindowID[50];
DDENOTIFYSTRUCT *dns;
HSZ hszTopic, hszService, hszItem;
HCONV hConv;
BOOL result;
HDDEDATA hResult;
XX_DMsg(DBG_SDI, ("Inside ViewDocCache\n"));
sprintf(szWindowID, "%ld", tw->serialID);
p1 = MakeQuotedString(tw->request->destination->szActualURL);
p = GTR_MALLOC(strlen(p1) + strlen(szWindowID) + 10);
if (!p)
return TRUE; // abort
sprintf(p, "%s,%s", p1, szWindowID);
// Now find the app for the given MIME type
for (dns = pDNS; dns; dns = dns->next)
{
if (dns->mime_type == mime_type)
break;
}
if (!dns)
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 = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
hszItem = CreateArgument(dns->szResultApp, p);
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 SDI_Issue_QueryViewer(struct Mwin *tw, HTFormat mime_type, char *pFilename, int nLength)
{
char *p, *p1, *p2, *pStripped;
DDENOTIFYSTRUCT *dns;
HSZ hszTopic, hszService, hszItem;
HCONV hConv;
HDDEDATA hResult;
BOOL ret;
char *pReturnedFileName;
XX_DMsg(DBG_SDI, ("Inside QueryViewer\n"));
p1 = MakeQuotedString(tw->request->destination->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
}
sprintf(p, "%s,%s", p1, p2);
// Now find the app for the given MIME type
for (dns = pDNS; dns; dns = dns->next)
{
if (dns->mime_type == mime_type)
break;
}
if (!dns)
{
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 = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
hszItem = CreateArgument(dns->szResultApp, p);
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
{
pReturnedFileName = GTR_MALLOC(nLength + 1);
memset(pReturnedFileName, 0, nLength + 1);
DdeGetData(hResult, pReturnedFileName, nLength + 1, 0);
XX_DMsg(DBG_SDI, ("QueryViewer result: %s\n", pReturnedFileName));
if (pReturnedFileName[0] == '\0')
{
GTR_FREE(pReturnedFileName);
return FALSE;
}
strcpy(pFilename, pReturnedFileName);
GTR_FREE(pReturnedFileName);
// 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 SDI_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];
DDENOTIFYSTRUCT *dns;
XX_DMsg(DBG_SDI, ("Inside ViewDocFile\n"));
// Find the MIME type
for (dns = pDNS; dns; dns = dns->next)
{
if (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 = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
sprintf(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);
if (pTemp)
{
sprintf(pTemp, "%s,%s,%s,%s", p3, p1, p2, szWindowID);
hszItem = CreateArgument(dns->szResultApp, pTemp);
// 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);
}
else
{
ERR_ReportError(NULL, SID_ERR_OUT_OF_MEMORY, NULL, 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);
}
//*****************************************
// SDI_Issue_Result
//
// Issue results of OpenURL and ShowFile.
// For ShowFile, update the URL as well.
//*****************************************
void SDI_Issue_Result(long transID, long windowID, BOOL success)
{
DDENOTIFYSTRUCT *dns;
BOOL bFound = FALSE;
char szTemp[50];
HCONV hConv;
HSZ hszService, hszTopic, hszItem;
HDDEDATA hReturn;
struct Mwin *tw;
struct TRANSACTIONMAPSTRUCT *tms;
// Send the result of the last OpenURL to the application which issued OpenURL.
for (dns = pDNS; dns; dns = dns->next)
{
if (dns->lTransID == transID)
break;
}
if (!dns)
return;
// Find the matching tw
tw = TW_FromTransactionID(transID);
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);
}
}
if (dns->szResultApp[0])
{
hszService = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hszTopic = DdeCreateStringHandle(g_DdeInst, dns->szReturnTopic, CP_WINANSI);
hConv = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
switch(tw->lErrorOccurred)
{
case SDI_INVALID_URL:
case SDI_CANNOT_SAVE_FILE:
case SDI_INVALID_MIME:
sprintf(szTemp, "%ld,%ld", transID, tw->lErrorOccurred);
break;
default:
sprintf(szTemp, "%ld,%ld", transID, windowID);
break;
}
hszItem = CreateArgument(dns->szResultApp, szTemp);
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);
}
RemoveDNS(dns);
tms = TMS_FromTransactionID(transID);
if (tms)
TMS_Remove(tms);
// Clear the tw structure since it gets reused
tw->transID = 0;
tw->lErrorOccurred = 0;
// Remove the tw if it's type is GWINDOWLESS
if (tw->wintype == GWINDOWLESS)
Plan_close(tw);
}
//*****************************************
// SDI_Issue_HTTPHeadResult
//
// Issue results of GetHTTPHead.
//*****************************************
void SDI_Issue_HTTPHeadResult(long transID, long windowID, BOOL success, char *pHeadData)
{
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 (dns = pDNS; dns; dns = dns->next)
{
if (dns->lTransID == transID)
break;
}
if (!dns) // This should not happen
return;
// Find the matching tw
tw = TW_FromTransactionID(transID);
if (!tw)
return;
if (dns->szResultApp[0])
{
hszService = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hszTopic = DdeCreateStringHandle(g_DdeInst, dns->szReturnTopic, CP_WINANSI);
hConv = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
sprintf(szTemp, "%ld,%ld", transID, windowID);
hszItem = CreateArgument(dns->szResultApp, szTemp);
hReturn = DdeClientTransaction(pHeadData, strlen(pHeadData), hConv, hszItem, CF_TEXT,
XTYP_POKE, DDE_TIMEOUT, NULL);
DdeDisconnect(hConv);
DdeFreeStringHandle(g_DdeInst, hszItem);
}
DdeFreeStringHandle(g_DdeInst, hszService);
DdeFreeStringHandle(g_DdeInst, hszTopic);
}
RemoveDNS(dns);
// Clear the tw structure since it gets reused
tw->transID = 0;
tw->lErrorOccurred = 0;
// Remove the tw if it's type is GWINDOWLESS (it ALWAYS should be, for this case)
if (tw->wintype == GWINDOWLESS)
Plan_close(tw);
}
//*****************************************
// SDI_Issue_URLEcho
//
// Issue URLEcho
//*****************************************
void SDI_Issue_URLEcho(struct Mwin *tw)
{
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 (dns = pDNS; dns; dns = dns->next)
{
if (_stricmp(dns->szReturnTopic, "WWW_URLEcho") == 0)
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_URLEcho", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hConv = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
p1 = MakeQuotedString(tw->w3doc->szActualURL);
p2 = MakeQuotedString(HTAtom_name(tw->mimeType));
p3 = MakeQuotedString(NULL);
p = GTR_MALLOC(strlen(p1) + strlen(p2) + strlen(p3) + 50);
sprintf(p, "%s,%s,%d,%s", p1, p2, tw->serialID, p3);
hszItem = CreateArgument(dns->szResultApp, p);
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);
}
}
}
//*****************************************
// SDI_Issue_WindowClose
//
// Issue Window close
//*****************************************
void SDI_Issue_WindowClose(struct Mwin *tw)
{
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 (dns = pDNS; dns; dns = dns->next)
{
if ((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 = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
sprintf(szTemp, "%ld,%d", dns->lWindowID, (int) wg.bShuttingDown);
hszItem = CreateArgument(dns->szResultApp, szTemp);
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);
}
}
}
//*****************************************
// SDI_Issue_AppClose
//
// Issue app close
//*****************************************
void SDI_Issue_AppClose()
{
DDENOTIFYSTRUCT *dns;
BOOL bFound = FALSE;
HCONV hConv;
HSZ hszService, hszTopic;
HDDEDATA hReturn;
// Go through the list and issue to all registered apps
for (dns = pDNS; dns; dns = dns->next)
{
if ((_stricmp(dns->szReturnTopic, "WWW_AppClose") == 0))
{
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_AppClose", CP_WINANSI);
hszService = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hConv = DdeConnect(g_DdeInst, hszService, hszTopic, NULL);
if (hConv)
{
hReturn = DdeClientTransaction(NULL, 0, hConv, hszMosaic, CF_TEXT,
XTYP_POKE, DDE_TIMEOUT, NULL);
DdeDisconnect(hConv);
}
DdeFreeStringHandle(g_DdeInst, hszTopic);
DdeFreeStringHandle(g_DdeInst, hszService);
}
}
}
//*****************************************
// RegisterNow suite
//*****************************************
BOOL SDI_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
sprintf(szBuffer, "\"MOSAIC\",%ld", TransactionID);
hszApp = DdeCreateStringHandle(g_DdeInst, pApplication, CP_WINANSI);
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_RegisterNow", CP_WINANSI);
hszItem = CreateArgument(pApplication, szBuffer);
hConv = DdeConnect(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
//************************************************
BOOL GTR_HasHelperRegistered(HTFormat format)
{
int i;
DDENOTIFYSTRUCT *dns;
BOOL result = FALSE;
struct Viewer_Info *pCurrent;
for (dns = pDNS; dns; dns = dns->next)
{
if (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);
if (i != -1)
{
if (pCurrent->bTemporaryStruct)
Hash_DeleteIndexedEntry(gPrefs.pHashViewers, i);
else
pCurrent->szCurrentViewerServiceName[0] = '\0';
}
RemoveDNS(dns);
}
break;
}
}
return result;
}
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 = DdeConnect(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, struct Mwin *tw)
{
int result;
long lWindowID;
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;
}
lWindowID = tw->serialID;
result = SDI_Issue_OpenURL(request->destination->szRequestedURL, NULL, &lWindowID,
0, request->szPostData, request->szPostData ? "" : "application/x-www-form-urlencoded",
"MOSAIC", "MOSAIC");
return result;
}
int SDI_Issue_OpenURL(char *pURL, char *pFilespec, long *lWindowID, long lFlags,
char *pFormData, char *pMime, char *pProgressApp, char *pReturnApp)
{
char *p0, *p1, *p2, *p3, *p4, *p5;
int size = 0;
char szWindowID[50], szFlags[50];
char *pBuffer, *pProtocolFromURL;
DDENOTIFYSTRUCT *dns;
HDDEDATA hResult;
HSZ hszApp, hszItem, hszTopic;
HCONV hConv;
int ret = NO;
// 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 (dns = pDNS; dns; dns = dns->next)
{
if ((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);
p5 = MakeQuotedString(pReturnApp);
sprintf(szWindowID, "%ld", *lWindowID);
sprintf(szFlags, "%ld", lFlags);
pBuffer = GTR_MALLOC(strlen(p0) + strlen(p1) + strlen(p2) + strlen(p3) + strlen(p4) + strlen(p5) +
strlen(szWindowID) + strlen(szFlags) + 10);
sprintf(pBuffer, "%s,%s,%s,%s,%s,%s,%s,%s", p0, p1, szWindowID, szFlags, p2, p3, p4, p5);
hszApp = DdeCreateStringHandle(g_DdeInst, dns->szResultApp, CP_WINANSI);
hszTopic = DdeCreateStringHandle(g_DdeInst, "WWW_OpenURL", CP_WINANSI);
hszItem = CreateArgument(dns->szResultApp, pBuffer);
hConv = DdeConnect(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(p5);
GTR_FREE(pProtocolFromURL);
return ret;
}
//************************************************
// Initialization and Termination functions
//************************************************
BOOL InitDDE(void)
{
DWORD flags;
flags = APPCLASS_STANDARD;
if (DdeInitialize((LPDWORD) &g_DdeInst, (PFNCALLBACK) DdeCallBack, flags, 0L))
return FALSE;
hszMosaic = DdeCreateStringHandle(g_DdeInst, "MOSAIC", CP_WINANSI);
hszReturn = DdeCreateStringHandle(g_DdeInst, "Return", CP_WINANSI);
if (!DdeNameService(g_DdeInst, hszMosaic, 0, DNS_REGISTER))
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_GetHTTPHead", NULL, DDE_Handle_GetHTTPHead);
Hash_Add(pTopicHash, "WWW_OpenURLResult", NULL, DDE_Handle_OpenURLResult);
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);
Hash_Add(pTopicHash, "WWW_RegisterViewer", NULL, DDE_Handle_RegisterViewer);
Hash_Add(pTopicHash, "WWW_UnRegisterViewer", NULL, DDE_Handle_UnRegisterViewer);
Hash_Add(pTopicHash, "WWW_RegisterAppClose", NULL, DDE_Handle_RegisterAppClose);
Hash_Add(pTopicHash, "WWW_UnRegisterAppClose", NULL, DDE_Handle_UnRegisterAppClose);
Hash_Add(pTopicHash, "WWW_QueryVersion", NULL, DDE_Handle_QueryVersion);
Hash_Add(pTopicHash, "WWW_CancelTransaction", NULL, DDE_Handle_CancelTransaction);
Hash_Add(pTopicHash, "WWW_BeginProgress", NULL, DDE_Handle_BeginProgress);
Hash_Add(pTopicHash, "WWW_SetProgressRange", NULL, DDE_Handle_SetProgressRange);
Hash_Add(pTopicHash, "WWW_MakingProgress", NULL, DDE_Handle_MakingProgress);
Hash_Add(pTopicHash, "WWW_EndProgress", NULL, DDE_Handle_EndProgress);
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;
// Verity hack buffer
pFileContent = NULL;
// Version list
pVersionList = NULL;
return TRUE;
}
void TerminateDDE(void)
{
DDENOTIFYSTRUCT *dns, *dnsnext;
struct VERSIONSTRUCT *pCur, *pNext;
DdeNameService(g_DdeInst, hszMosaic, 0, DNS_UNREGISTER);
if (hszMosaic)
DdeFreeStringHandle(g_DdeInst, hszMosaic);
if (hszReturn)
DdeFreeStringHandle(g_DdeInst, hszReturn);
Hash_Destroy(pTopicHash);
Hash_Destroy(pServerHash);
if (g_DdeInst)
DdeUninitialize(g_DdeInst);
if (pArgumentBuffer)
GTR_FREE(pArgumentBuffer);
if (pArgReturnBuffer)
GTR_FREE(pArgReturnBuffer);
dns = pDNS;
while (dns)
{
dnsnext = dns->next;
RemoveDNS(dns);
dns = dnsnext;
}
// Verity hack clean up
if (pFileContent)
GTR_FREE(pFileContent);
// Version list clean up
pCur = pVersionList;
while (pCur)
{
pNext = pCur->next;
GTR_FREE(pCur);
pCur = pNext;
}
}
#endif /* FEATURE_IAPI */