mirror of https://github.com/lianthony/NT4.0
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.
1650 lines
47 KiB
1650 lines
47 KiB
/*
|
|
Enhanced NCSA Mosaic from Spyglass
|
|
"Guitar"
|
|
|
|
Copyright 1994 Spyglass, Inc.
|
|
All Rights Reserved
|
|
|
|
Author(s):
|
|
Jim Seidman [email protected]
|
|
Eric W. Sink [email protected]
|
|
*/
|
|
|
|
#include "all.h"
|
|
|
|
|
|
static void x_DoLoadDocument(struct Mwin *tw, struct DestInfo *pDest,
|
|
BOOL bRecord, BOOL bPost, BOOL bNoDocCache, BOOL bNoImageCache,
|
|
char * szPostData, CONST char *szReferer);
|
|
int TW_AddToHistory(struct Mwin *tw, char *url, BOOL bPost, char *szPostData);
|
|
|
|
void GTR__DownLoad(struct Mwin *tw, char *url, CONST char *szReferer, CONST char *savefile, BOOL nosavedlg);
|
|
|
|
/* Ensure that an http URL has a slash after the system name. This function is suitable
|
|
for "fixing" both URLs and proxy server specifications */
|
|
static void x_EnforceHostSlash(char *url)
|
|
{
|
|
char * p = url;
|
|
|
|
while (*p && *p!=':')
|
|
{
|
|
if (isupper(*p))
|
|
*p = tolower(*p);
|
|
p++;
|
|
}
|
|
|
|
if (!strncmp(url, "http://", 7))
|
|
{
|
|
if (!strchr(url + 7, '/'))
|
|
strcat(url, "/");
|
|
}
|
|
|
|
#ifdef SHTTP_ACCESS_TYPE
|
|
if (!strncmp(url, "shttp://", 8))
|
|
{
|
|
if (!strchr(url + 8, '/'))
|
|
strcat(url, "/");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/* Find the element index for a local anchor */
|
|
int TW_FindLocalAnchor(struct _www *pdoc, char *name)
|
|
{
|
|
int i;
|
|
int nameLen;
|
|
|
|
nameLen = strlen(name);
|
|
|
|
if (pdoc->elementCount)
|
|
{
|
|
for (i = 0; i >= 0; i = pdoc->aElements[i].next)
|
|
{
|
|
struct _element* pel = &pdoc->aElements[i];
|
|
|
|
if (pel->lFlags & ELEFLAG_NAME)
|
|
{
|
|
if (pel->nameLen == nameLen)
|
|
{
|
|
if (0 == (pdoc->pool.f->Compare) (&pdoc->pool, name, pel->nameOffset, nameLen))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/* This is meant to be a convenient interlude function which both reads in the images
|
|
and then reformats the document if necessary. It doesn't use ppInfo at all. */
|
|
int GDOC_LoadImages_Async(struct Mwin *tw, int nState, void **ppInfo)
|
|
{
|
|
struct Params_GDOC_LoadImages *pparams = NULL;
|
|
|
|
if (ppInfo)
|
|
{
|
|
pparams = *ppInfo;
|
|
}
|
|
|
|
switch (nState)
|
|
{
|
|
case STATE_INIT:
|
|
{
|
|
struct Params_Image_LoadAll *pil;
|
|
|
|
pil = GTR_CALLOC(sizeof(*pil), 1);
|
|
if (pil)
|
|
{
|
|
pil->tw = tw;
|
|
if (pparams)
|
|
{
|
|
pil->bLoad = pparams->bLoad;
|
|
pil->bReload = pparams->bReload;
|
|
}
|
|
else
|
|
{
|
|
pil->bLoad = gPrefs.bAutoLoadImages;
|
|
pil->bReload = FALSE;
|
|
}
|
|
|
|
Async_DoCall(Image_LoadAll_Async, pil);
|
|
return STATE_OTHER;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
}
|
|
|
|
case STATE_OTHER:
|
|
case STATE_ABORT:
|
|
{
|
|
if (W3Doc_CheckForImageLoad(tw->w3doc))
|
|
{
|
|
TW_Reformat(tw);
|
|
/* TODO: Go back to correct place in document */
|
|
}
|
|
TW_UpdateTBar(tw);
|
|
return STATE_DONE;
|
|
}
|
|
}
|
|
XX_Assert((0), ("Function called with illegal state: %d", nState));
|
|
return STATE_DONE;
|
|
}
|
|
|
|
static void x_HandleCurrentDocument(struct Mwin *tw, struct DestInfo *pDest, BOOL bNoImageCache)
|
|
{
|
|
int ndx;
|
|
|
|
#if defined(FEATURE_IAPI)
|
|
tw->transID = 0; /* special ID - Requested URL is already loaded in the window */
|
|
#endif
|
|
|
|
#if 0
|
|
/* TODO: Make this case work */
|
|
if (bNoImageCache)
|
|
{
|
|
Image_NukeImages(tw->w3doc, TRUE);
|
|
if (!g_bAbort)
|
|
Image_LoadAllImages(tw, !gPrefs.bAutoLoadImages);
|
|
}
|
|
#endif
|
|
|
|
W3Doc_CheckAnchorVisitations(tw->w3doc);
|
|
/* TW_InvalidateDocument( tw ); */
|
|
|
|
if (pDest->szActualLocal)
|
|
{
|
|
ndx = TW_FindLocalAnchor(tw->w3doc, pDest->szActualLocal);
|
|
if (ndx < 0)
|
|
ndx = 0;
|
|
#if 0
|
|
/*
|
|
If we wanted to add local anchors to the window history,
|
|
this would be a partial solution. The problem is in going
|
|
back to the same document you're in. If you were at the top,
|
|
then you want to scroll back there. If you come to the document
|
|
from being in a different document, you want to be scrolled where
|
|
you were before.
|
|
*/
|
|
{
|
|
char buf[MAX_URL_STRING+1];
|
|
strcpy(buf, pDest->szActualURL);
|
|
strcat(buf, "#");
|
|
strcat(buf, pDest->szActualLocal);
|
|
TW_AddToHistory(tw, buf, FALSE, NULL);
|
|
}
|
|
#endif
|
|
|
|
TW_ScrollToElement(tw, ndx);
|
|
}
|
|
else
|
|
{
|
|
TW_ScrollToElement(tw, tw->w3doc->iFirstVisibleElement);
|
|
}
|
|
}
|
|
|
|
static void x_HandleCacheHit(struct Mwin *tw, struct DestInfo *pDest, int doc_index, BOOL bNoImageCache, BOOL bRecord, BOOL bPost, char *szPostData)
|
|
{
|
|
struct _www *w3doc;
|
|
int ndx;
|
|
char buf[MAX_URL_STRING * 2];
|
|
|
|
/*
|
|
Move the w3doc to the end of the cache list
|
|
*/
|
|
Hash_GetIndexedEntry(&tw->doc_cache, doc_index, NULL, NULL, (void **) &w3doc);
|
|
Hash_DeleteIndexedEntry(&tw->doc_cache, doc_index);
|
|
MRQ_MakeString(buf, pDest->szActualURL, bPost, szPostData);
|
|
Hash_Add(&tw->doc_cache, buf, NULL, (void *) w3doc);
|
|
W3Doc_DisconnectFromWindow(tw->w3doc, tw);
|
|
|
|
W3Doc_ConnectToWindow(w3doc, tw);
|
|
W3Doc_CheckAnchorVisitations(w3doc);
|
|
|
|
if (bNoImageCache)
|
|
{
|
|
Image_NukeImages(tw->w3doc, TRUE);
|
|
}
|
|
#if defined(FEATURE_IAPI)
|
|
else
|
|
tw->transID = 0; /* special ID - Requested URL is already loaded in the window */
|
|
#endif
|
|
|
|
if (tw->win)
|
|
{
|
|
TW_SetWindowName(tw);
|
|
TW_Reformat(tw);
|
|
#ifdef FEATURE_STATUS_ICONS
|
|
SetStatusIcon(tw, ICON_POS_1, tw->w3doc->security);
|
|
DrawStatusIconPixmaps(tw);
|
|
#endif
|
|
|
|
}
|
|
|
|
if (pDest->szActualLocal)
|
|
{
|
|
ndx = TW_FindLocalAnchor(tw->w3doc, pDest->szActualLocal);
|
|
if (ndx < 0)
|
|
ndx = 0;
|
|
TW_ScrollToElement(tw, ndx);
|
|
}
|
|
else
|
|
{
|
|
#ifndef MAC
|
|
TW_ScrollToElement(tw, w3doc->iFirstVisibleElement);
|
|
#else
|
|
TW_InvalidateDocument(tw); /* The doc is already valid just redraw it */
|
|
#endif
|
|
}
|
|
|
|
if (bRecord)
|
|
{
|
|
TW_AddToHistory(tw, pDest->szActualURL, bPost, szPostData);
|
|
GHist_Add(pDest->szActualURL, tw->w3doc->title, time(NULL));
|
|
}
|
|
|
|
/* TW_InvalidateDocument(tw); */
|
|
|
|
#if 0
|
|
/*
|
|
Let's not automatically load missing images when a document is fetched from
|
|
the RAM document cache.
|
|
*/
|
|
{
|
|
struct Params_GDOC_LoadImages *pparams;
|
|
|
|
pparams = GTR_CALLOC(sizeof(*pparams), 1);
|
|
if (pparams)
|
|
{
|
|
pparams->tw = tw;
|
|
pparams->bLoad = gPrefs.bAutoLoadImages;
|
|
Async_StartThread(GDOC_LoadImages_Async, pparams, tw);
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
}
|
|
}
|
|
#endif /* NOT */
|
|
}
|
|
|
|
struct Params_HandleLoadDocument {
|
|
/* To be filled in by caller */
|
|
struct DestInfo *pDest;
|
|
BOOL bRecord;
|
|
BOOL bPost;
|
|
BOOL bNoDocCache;
|
|
BOOL bNoImageCache;
|
|
char * szPostData; /* This is GTR_FREE'd by this function! */
|
|
CONST char * szReferer;
|
|
|
|
/* Used internally by routine */
|
|
HTRequest * request;
|
|
struct _www * prev_w3doc;
|
|
int status;
|
|
};
|
|
|
|
#define STATE_HLD_TRIEDLOAD (STATE_OTHER)
|
|
#define STATE_HLD_GOTIMAGES (STATE_OTHER+1)
|
|
|
|
/* Handle loading an (ostensibly) new document. This could result in an HTTP redirection to a new
|
|
document which is actually present in the cache, in which case we'll call x_DoLoadDocument()
|
|
recursively. */
|
|
static int x_HandleLoadDocument_Async(struct Mwin *tw, int nState, void **ppInfo)
|
|
{
|
|
struct Params_HandleLoadDocument *pParams;
|
|
char buf[MAX_URL_STRING + 32 + 1];
|
|
static BOOL success;
|
|
|
|
#ifdef _GIBRALTAR
|
|
BOOL bAborted = FALSE;
|
|
#endif // _GIBRALTAR
|
|
|
|
pParams = *ppInfo;
|
|
|
|
switch (nState)
|
|
{
|
|
case STATE_INIT:
|
|
#ifdef USE_MEMMANAGE
|
|
GTR_RestoreCushion();
|
|
#endif
|
|
strcpy(buf, GTR_GetString(SID_INF_ACCESSING_URL));
|
|
GTR_strncat(buf, pParams->pDest->szActualURL, MAX_URL_STRING);
|
|
|
|
#if defined(_DEBUG)
|
|
|
|
OutputDebugString("URL being loaded: ");
|
|
OutputDebugString(pParams->pDest->szActualURL);
|
|
OutputDebugString("\n");
|
|
|
|
#endif // _DEBUG
|
|
|
|
WAIT_Push(tw, waitNoInteract, buf);
|
|
tw->bLoading = TRUE;
|
|
|
|
if (pParams->bPost)
|
|
{
|
|
pParams->request = tw->post_request;
|
|
|
|
XX_Assert((pParams->szPostData),
|
|
("x_HandleLoadDocument: bPost set when szPostData NULL."));
|
|
|
|
pParams->request->szPostData = pParams->szPostData;
|
|
|
|
XX_Assert((strcmp(HTAtom_name(pParams->request->content_type),
|
|
"application/x-www-form-urlencoded")==0),
|
|
("x_handleLoadDocument: request content-type not as expected [%s].",
|
|
HTAtom_name(pParams->request->content_type)));
|
|
|
|
/*
|
|
TODO Why are we not init-ing the members of the request
|
|
struct here?
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
pParams->request = tw->request;
|
|
|
|
|
|
/*
|
|
We need to initialize a few things here to make sure we're not
|
|
getting values left over from previous uses of this request struct.
|
|
|
|
TODO We should not be re-using these request structs. We should
|
|
allocate a new one for each request.
|
|
*/
|
|
pParams->request->content_encoding = 0;
|
|
pParams->request->content_length = 0;
|
|
pParams->request->content_type = 0;
|
|
pParams->request->content_language = 0;
|
|
pParams->request->callback = NULL;
|
|
pParams->request->iFlags = 0;
|
|
pParams->request->output_stream = NULL;
|
|
pParams->request->szLocalFileName = NULL;
|
|
pParams->request->output_format = WWW_PRESENT; /* dpg */
|
|
#ifdef FEATURE_IAPI
|
|
pParams->request->savefile = NULL;
|
|
#endif
|
|
}
|
|
|
|
|
|
pParams->request->destination = pParams->pDest;
|
|
pParams->request->referer = pParams->szReferer;
|
|
|
|
pParams->prev_w3doc = tw->w3doc;
|
|
if (pParams->bRecord)
|
|
{
|
|
pParams->request->iFlags |= HTREQ_RECORD;
|
|
}
|
|
else
|
|
{
|
|
pParams->request->iFlags &= (~HTREQ_RECORD);
|
|
}
|
|
|
|
if (pParams->bNoDocCache)
|
|
{
|
|
pParams->request->iFlags |= HTREQ_RELOAD;
|
|
}
|
|
|
|
/* Call load routines asynchronously. */
|
|
{
|
|
struct Params_LoadAsync *pLoadParams;
|
|
|
|
pLoadParams = GTR_CALLOC(sizeof(*pLoadParams), 1);
|
|
if (pLoadParams)
|
|
{
|
|
pLoadParams->request = pParams->request;
|
|
pLoadParams->pStatus = &pParams->status;
|
|
Async_DoCall(HTLoadSpecial_Async, pLoadParams);
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
}
|
|
return STATE_HLD_TRIEDLOAD;
|
|
|
|
case STATE_HLD_TRIEDLOAD:
|
|
if (pParams->request->szLocalFileName)
|
|
{
|
|
GTR_FREE(pParams->request->szLocalFileName);
|
|
pParams->request->szLocalFileName = NULL;
|
|
}
|
|
|
|
if (pParams->request->referer)
|
|
{
|
|
/*
|
|
This code fixes a memory leak. A consequence is that
|
|
the referer string is not passed to redirects. This
|
|
could be considered correct anyway.
|
|
*/
|
|
GTR_FREE((char *) pParams->request->referer);
|
|
pParams->request->referer = NULL;
|
|
pParams->szReferer = NULL;
|
|
}
|
|
pParams->request->iFlags &= (~HTREQ_RECORD);
|
|
|
|
/* We don't want to do a WAIT_Pop() here because that would bring us back to
|
|
the base state, resetting the globe position. */
|
|
WAIT_Update(tw, waitSameInteract,"");
|
|
|
|
if (pParams->status == HT_REDIRECTION_ON_FLY)
|
|
{
|
|
/*
|
|
Since we never POST on a redirect, we no longer need the
|
|
POST data
|
|
*/
|
|
if (pParams->szPostData)
|
|
{
|
|
GTR_FREE(pParams->szPostData);
|
|
pParams->szPostData = NULL;
|
|
}
|
|
|
|
|
|
/* If we got here, our destination has already been updated to
|
|
reflect the redirection. */
|
|
|
|
/* This isn't useful in the history, but it allows us to properly
|
|
change the link color on redirected links */
|
|
GHist_Add(pParams->pDest->szRequestedURL, GTR_GetString(SID_INF_DOCUMENT_MOVED), time(NULL));
|
|
|
|
/* Call recursively so that we can check the image cache, etc. Note that we
|
|
never set bPost after a redirection. */
|
|
/* TODO: Should we reset bNoDocCache if bPost is true, so that a form request
|
|
can lead us to a cached document? */
|
|
/* NOTE: since we force bPost false, we don't send szPostData to the call. */
|
|
|
|
x_DoLoadDocument(tw, pParams->pDest, pParams->bRecord, FALSE, pParams->bNoDocCache, pParams->bNoImageCache, NULL, pParams->szReferer);
|
|
|
|
/* tw->bLoading won't get reset if we wind up with a cache hit. */
|
|
tw->bLoading = FALSE;
|
|
WAIT_Pop(tw);
|
|
/* Note that this is the one instance in this function where
|
|
we return without destroying the destination. This is
|
|
because we passed it to x_DoLoadDocument, so that function
|
|
will free it. */
|
|
success = TRUE;
|
|
goto finish_up;
|
|
}
|
|
else if (pParams->status == HT_LOADED)
|
|
{
|
|
if (tw->w3doc && (pParams->prev_w3doc != tw->w3doc))
|
|
{
|
|
#if 0
|
|
/*
|
|
This is once again being done in guitar.c when the w3doc is created, so that
|
|
you can hit BACK while the images are downloading, and the right thing will
|
|
happen.
|
|
*/
|
|
/*
|
|
If we got here, then we know we got a new document. Let's
|
|
add it to the Window history
|
|
*/
|
|
if (pParams->bRecord)
|
|
{
|
|
TW_AddToHistory(tw, pParams->pDest->szActualURL, pParams->bPost, pParams->szPostData);
|
|
GHist_Add(pParams->pDest->szActualURL, tw->w3doc->title, time(NULL));
|
|
}
|
|
#endif
|
|
|
|
#ifdef FEATURE_INLINED_IMAGES
|
|
/* check if IsImage and don't nuke it, cuz we just
|
|
** got done bringing it in
|
|
*/
|
|
if (!tw->w3doc->bIsImage &&pParams->bNoImageCache)
|
|
#else
|
|
if (pParams->bNoImageCache)
|
|
#endif
|
|
{
|
|
Image_NukeImages(tw->w3doc, FALSE);
|
|
}
|
|
|
|
if (gPrefs.ReformatHandling > 0)
|
|
{
|
|
FORM_ShowAllChildWindows(tw->w3doc, SW_SHOW);
|
|
}
|
|
}
|
|
|
|
/*
|
|
If we are going to add this to the window history, then we
|
|
have already done so. Therefore, we no longer need the POST
|
|
data.
|
|
*/
|
|
if (pParams->szPostData)
|
|
{
|
|
GTR_FREE(pParams->szPostData);
|
|
pParams->szPostData = NULL;
|
|
}
|
|
|
|
tw->bLoading = FALSE;
|
|
|
|
if (tw->win && tw->w3doc && (pParams->prev_w3doc != tw->w3doc))
|
|
{
|
|
TW_SetWindowName(tw);
|
|
if (gPrefs.ReformatHandling > 0)
|
|
{
|
|
TW_Reformat(tw);
|
|
}
|
|
|
|
/* Load in images for this document */
|
|
{
|
|
struct Params_Image_LoadAll *pil;
|
|
pil = GTR_CALLOC(sizeof(*pil), 1);
|
|
if (pil)
|
|
{
|
|
pil->tw = tw;
|
|
pil->bLoad = gPrefs.bAutoLoadImages;
|
|
pil->bReload = pParams->bNoImageCache;
|
|
Async_DoCall(Image_LoadAll_Async, pil);
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
}
|
|
return STATE_HLD_GOTIMAGES;
|
|
}
|
|
else
|
|
{
|
|
/* Even though the load succeeded we didn't get a new document.
|
|
That means we're done. */
|
|
WAIT_Pop(tw);
|
|
Dest_DestroyDest(pParams->pDest);
|
|
success = FALSE;
|
|
goto finish_up;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pParams->szPostData)
|
|
{
|
|
GTR_FREE(pParams->szPostData);
|
|
pParams->szPostData = NULL;
|
|
}
|
|
|
|
/*
|
|
!bOK : the load failed
|
|
*/
|
|
#if defined(FEATURE_IAPI)
|
|
/* If the request is from an IAPI application, do not show the error box */
|
|
|
|
if (tw->transID == 0)
|
|
#endif
|
|
{
|
|
/*
|
|
We deliberately do not display the errDocLoadFailed if the interlude dialog
|
|
was cancelled.
|
|
*/
|
|
if (!(pParams->request->iFlags & HTREQ_USERCANCEL))
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_DOCUMENT_LOAD_FAILED_S, pParams->pDest->szRequestedURL, NULL);
|
|
}
|
|
}
|
|
|
|
tw->bLoading = FALSE;
|
|
#ifndef _GIBRALTAR
|
|
//
|
|
// Why invalidate the document if the load failed?
|
|
// This will also cause that annoying edit box
|
|
// restoration of the current doc
|
|
//
|
|
TW_InvalidateDocument(tw);
|
|
#endif
|
|
|
|
WAIT_Pop(tw);
|
|
Dest_DestroyDest(pParams->pDest);
|
|
success = FALSE;
|
|
goto finish_up;
|
|
}
|
|
XX_Assert((0), ("Fell through case improperly!"));
|
|
|
|
case STATE_HLD_GOTIMAGES:
|
|
#ifdef DONT_KEEP_CONNECTIONS_ALIVE_BETWEEN_DOCUMENTS
|
|
/* If this block is enabled, connections will be thrown away after all
|
|
inline images in a document have been transferred. - CWilso */
|
|
if (tw->cached_conn.type == CONN_HTTP)
|
|
{
|
|
/*
|
|
We don't allow KeepAlive to span documents, but maybe we should...
|
|
*/
|
|
TW_DisposeConnection(&tw->cached_conn);
|
|
}
|
|
#endif
|
|
if (W3Doc_CheckForImageLoad(tw->w3doc) || (gPrefs.ReformatHandling == 0))
|
|
{
|
|
TW_Reformat(tw);
|
|
/* TODO: Go back to correct place in document */
|
|
}
|
|
if (gPrefs.ReformatHandling == 0)
|
|
{
|
|
/* We prevented this from occuring earlier, so we do it now */
|
|
FORM_ShowAllChildWindows(tw->w3doc, SW_SHOW);
|
|
}
|
|
WAIT_Pop(tw);
|
|
Dest_DestroyDest(pParams->pDest);
|
|
success = TRUE;
|
|
goto finish_up;
|
|
|
|
case STATE_ABORT:
|
|
if (tw->w3doc)
|
|
{
|
|
if (W3Doc_CheckForImageLoad(tw->w3doc))
|
|
{
|
|
TW_Reformat(tw);
|
|
/* TODO: Go back to correct place in document ? */
|
|
}
|
|
FORM_ShowAllChildWindows(tw->w3doc, SW_SHOW);
|
|
}
|
|
WAIT_Pop(tw);
|
|
if (pParams->szPostData)
|
|
{
|
|
GTR_FREE(pParams->szPostData);
|
|
}
|
|
Dest_DestroyDest(pParams->pDest);
|
|
success = TRUE;
|
|
|
|
#ifdef _GIBRALTAR
|
|
//
|
|
// abort == success? I don't know why they did that,
|
|
// but let's not update the edit box in that case
|
|
//
|
|
bAborted = TRUE;
|
|
#endif // _GIBRALTAR
|
|
|
|
goto finish_up;
|
|
|
|
finish_up:
|
|
#ifdef _GIBRALTAR
|
|
//
|
|
// Leave the edit box intact if we failed. Highly annoying
|
|
// to change it back to the currently loaded doc instead.
|
|
//
|
|
if (success && !bAborted)
|
|
{
|
|
TW_UpdateTBar(tw);
|
|
}
|
|
#else
|
|
TW_UpdateTBar(tw);
|
|
#endif
|
|
|
|
#if defined(FEATURE_IAPI)
|
|
/* Free and clear the tw->SDI_url because it may get reused */
|
|
|
|
SDI_Issue_URLEcho(tw);
|
|
|
|
if (tw->SDI_url)
|
|
{
|
|
GTR_FREE(tw->SDI_url);
|
|
tw->SDI_url = NULL;
|
|
}
|
|
|
|
if (tw->transID)
|
|
#ifdef UNIX
|
|
SDI_Issue_Result(tw, success);
|
|
#else
|
|
SDI_Issue_Result(tw->transID, tw->serialID, success);
|
|
#endif
|
|
#endif
|
|
return STATE_DONE;
|
|
}
|
|
XX_Assert((0), ("Function called with illegal state: %d", nState));
|
|
return STATE_DONE;
|
|
}
|
|
|
|
static void x_DoLoadDocument(struct Mwin *tw, struct DestInfo *pDest,
|
|
BOOL bRecord, BOOL bPost, BOOL bNoDocCache, BOOL bNoImageCache,
|
|
char * szPostData, CONST char *szReferer)
|
|
{
|
|
int ndx;
|
|
struct _www *w3doc;
|
|
BOOL bDestroyDest;
|
|
char *szMyReferer;
|
|
|
|
/*
|
|
NOTE THAT THIS SECTION OF CODE IS COMMENTED OUT
|
|
|
|
#ifdef _GIBRALTAR
|
|
|
|
#define CLEAN_URL(str)\
|
|
{\
|
|
char * pch = str;\
|
|
while (pch && (*pch == ' ' || *pch == '\t')) ++pch;\
|
|
if (pch != str)\
|
|
{\
|
|
strcpy(str, pch);\
|
|
}\
|
|
}
|
|
|
|
//
|
|
// Clean up the URL
|
|
//
|
|
CLEAN_URL(url);
|
|
|
|
#endif // _GIBRALTAR
|
|
*/
|
|
|
|
bDestroyDest = TRUE;
|
|
|
|
#ifdef FEATURE_IAPI
|
|
if (tw->SDI_url)
|
|
GTR_FREE(tw->SDI_url);
|
|
tw->SDI_url = GTR_strdup(pDest->szRequestedURL);
|
|
#endif
|
|
|
|
/*
|
|
We make our own copy of the referer, since it could be freed indirectly
|
|
by the cache removal below.
|
|
*/
|
|
if (szReferer)
|
|
{
|
|
szMyReferer = GTR_strdup(szReferer);
|
|
}
|
|
else
|
|
{
|
|
szMyReferer = NULL;
|
|
}
|
|
|
|
w3doc = NULL;
|
|
tw->mimeType = 0;
|
|
if (tw->doc_cache.table) /* Only GHTML currenlty has a document cache */
|
|
{
|
|
char buf[MAX_URL_STRING * 2];
|
|
|
|
MRQ_MakeString(buf, pDest->szActualURL, bPost, szPostData);
|
|
ndx = Hash_Find(&tw->doc_cache, buf, NULL, (void **)&w3doc);
|
|
|
|
#ifdef _GIBRALTAR
|
|
|
|
if ( ndx >= 0
|
|
&& ( bNoDocCache
|
|
|| !w3doc->bIsComplete
|
|
|| (w3doc->expires && (w3doc->expires < time(NULL)))
|
|
)
|
|
)
|
|
#else
|
|
if (ndx >= 0 && (bNoDocCache || !w3doc->bIsComplete))
|
|
#endif // _GIBRALTAR
|
|
|
|
{
|
|
/* Delete this item from the cache */
|
|
if (tw->w3doc == w3doc)
|
|
{
|
|
W3Doc_DisconnectFromWindow(w3doc, tw);
|
|
}
|
|
|
|
if (bNoImageCache)
|
|
{
|
|
Image_NukeImages(w3doc, TRUE);
|
|
}
|
|
|
|
W3Doc_FreeContents(tw, w3doc);
|
|
GTR_FREE(w3doc);
|
|
|
|
/*
|
|
We need to re-do the search here to make sure that the document is still
|
|
in the cache. It is possible that it was removed in the call to
|
|
W3Doc_DisconnectFromWindow().
|
|
*/
|
|
ndx = Hash_Find(&tw->doc_cache, buf, NULL, (void **)&w3doc);
|
|
if (ndx >= 0)
|
|
{
|
|
Hash_DeleteIndexedEntry(&tw->doc_cache, ndx);
|
|
}
|
|
w3doc = NULL;
|
|
}
|
|
}
|
|
|
|
/* See if this is the currently loaded document */
|
|
if (w3doc)
|
|
{
|
|
if (tw->w3doc == w3doc)
|
|
{
|
|
x_HandleCurrentDocument(tw, pDest, bNoImageCache);
|
|
}
|
|
else
|
|
{
|
|
x_HandleCacheHit(tw, pDest, ndx, bNoImageCache, bRecord, bPost, szPostData);
|
|
}
|
|
if (szPostData)
|
|
{
|
|
GTR_FREE((char *) szPostData);
|
|
}
|
|
}
|
|
#ifdef FEATURE_IMAGE_VIEWER
|
|
else if (!bNoDocCache && (Viewer_ShowCachedFile(pDest->szActualURL)))
|
|
{
|
|
/* We used the existing copy on disk */
|
|
if (szPostData)
|
|
{
|
|
GTR_FREE((char *) szPostData);
|
|
}
|
|
#if defined(FEATURE_IAPI)
|
|
/* special ID - Requested URL is already loaded in the window */
|
|
tw->transID = 0;
|
|
#endif
|
|
}
|
|
#endif
|
|
#ifdef FEATURE_SOUND_PLAYER
|
|
else if (!bNoDocCache && (SoundPlayer_ShowCachedFile(pDest->szActualURL)))
|
|
{
|
|
/* We used the existing copy on disk */
|
|
if (szPostData)
|
|
{
|
|
GTR_FREE((char *) szPostData);
|
|
}
|
|
#if defined(FEATURE_IAPI)
|
|
/* special ID - Requested URL is already loaded in the window */
|
|
tw->transID = 0;
|
|
#endif
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/*
|
|
** This is the situation where we actually have to load a document, either because
|
|
** it's not in the cache or because we are forcing a reload.
|
|
*/
|
|
struct Params_HandleLoadDocument *pHLDParams;
|
|
|
|
pHLDParams = GTR_CALLOC(sizeof(*pHLDParams), 1);
|
|
if (pHLDParams)
|
|
{
|
|
pHLDParams->pDest = pDest;
|
|
pHLDParams->bRecord = bRecord;
|
|
pHLDParams->bPost = bPost;
|
|
pHLDParams->bNoDocCache = bNoDocCache;
|
|
pHLDParams->bNoImageCache = bNoImageCache;
|
|
pHLDParams->szPostData = (char *) szPostData;
|
|
pHLDParams->szReferer = szMyReferer;
|
|
|
|
Async_StartThread(x_HandleLoadDocument_Async, pHLDParams, tw);
|
|
|
|
/* The load function will destroy the destination for us when it
|
|
completes. */
|
|
bDestroyDest = FALSE;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
if (bDestroyDest)
|
|
Dest_DestroyDest(pDest);
|
|
}
|
|
|
|
static void x_FigureOutMissingProtocol(char *s)
|
|
{
|
|
char buf[MAX_URL_STRING + 1];
|
|
char *resolvedURL;
|
|
char *p;
|
|
char *q;
|
|
|
|
/* trim trailing whitespace, if any */
|
|
p = s + strlen(s) - 1;
|
|
while ((p >= s) && isspace((unsigned char)*p))
|
|
*p-- = '\0';
|
|
|
|
/* trim leading whitespace, if any */
|
|
for (p = s; *p && isspace((unsigned char)*p); p++) ;
|
|
|
|
if (p > s)
|
|
{
|
|
strcpy(buf, p);
|
|
strcpy(s, buf);
|
|
}
|
|
|
|
p = strchr(s, ':');
|
|
q = strchr(s, '.');
|
|
|
|
if (!p || (q && (q < p)))
|
|
{
|
|
/*
|
|
If there is no colon in the URL, then no protocol was specified.
|
|
Probably, someone typed just a hostname, and we are expected
|
|
to fix it up by prepending the right protocol.
|
|
*/
|
|
|
|
/** make sure that this is NOT an ALIAS **/
|
|
resolvedURL = GetResolvedURL(s, NULL, NULL, NULL);
|
|
|
|
if (resolvedURL && strcmp(s, resolvedURL))
|
|
{
|
|
GTR_FREE(resolvedURL);
|
|
return; /** this is an alias **/
|
|
}
|
|
|
|
if (strstr(s, "ftp"))
|
|
{
|
|
strcpy(buf, "ftp://");
|
|
}
|
|
else if (strstr(s, "gopher"))
|
|
{
|
|
strcpy(buf, "gopher://");
|
|
}
|
|
else
|
|
{
|
|
strcpy(buf, "http://");
|
|
}
|
|
strcat(buf, s);
|
|
|
|
strcpy(s, buf);
|
|
}
|
|
}
|
|
|
|
/* This function will free szPostData when done */
|
|
int TW_LoadDocument(struct Mwin *tw, char *url,
|
|
BOOL bRecord, BOOL bPost, BOOL bNoDocCache, BOOL bNoImageCache,
|
|
char * szPostData, CONST char *szReferer)
|
|
{
|
|
char buf[MAX_URL_STRING + 32 + 1];
|
|
struct DestInfo *pDest;
|
|
|
|
if (!url || !*url)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_NO_URL_SPECIFIED, NULL, NULL);
|
|
if (szPostData)
|
|
{
|
|
GTR_FREE(szPostData);
|
|
}
|
|
TW_UpdateTBar(tw);
|
|
return -1;
|
|
}
|
|
|
|
XX_Assert((strlen(url) <= MAX_URL_STRING), ("TW_LoadDocument received a URL longer than %d characters. Actual length was %d\n", MAX_URL_STRING, strlen(url)));
|
|
|
|
#ifdef WIN32
|
|
/* Add the URL to the URL combobox */
|
|
|
|
GWC_GDOC_AddStringToURLCombobox(tw, url);
|
|
#ifndef _GIBRALTAR
|
|
GWC_GDOC_ResetURLLabel(tw, FALSE);
|
|
#endif
|
|
#endif
|
|
|
|
/* If this is a relative anchor, make a full URL */
|
|
if (*url == '#')
|
|
{
|
|
if (!tw->w3doc)
|
|
{
|
|
/* Shouldn't happen */
|
|
ERR_ReportError(tw, SID_ERR_NO_URL_SPECIFIED, NULL, NULL);
|
|
if (szPostData)
|
|
{
|
|
GTR_FREE(szPostData);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
GTR_strncpy(buf, tw->w3doc->szActualURL, MAX_URL_STRING);
|
|
strcat(buf, url);
|
|
}
|
|
else
|
|
{
|
|
GTR_strncpy(buf, url, MAX_URL_STRING);
|
|
}
|
|
|
|
/* Terminate any other threads currently running on this window. */
|
|
|
|
if (Async_DoThreadsExistByWindow(tw))
|
|
Async_TerminateByWindow(tw);
|
|
|
|
x_FigureOutMissingProtocol(buf);
|
|
|
|
/* If the URL is of the form "http://system", append a slash at the end */
|
|
x_EnforceHostSlash(buf);
|
|
|
|
pDest = Dest_CreateDest(buf);
|
|
if (pDest)
|
|
x_DoLoadDocument(tw, pDest, bRecord, bPost, bNoDocCache, bNoImageCache,
|
|
szPostData, szReferer);
|
|
else
|
|
{
|
|
if (szPostData)
|
|
GTR_FREE(szPostData);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
struct Params_Download {
|
|
char *url; /* Freed by function */
|
|
char *szReferer; /* Freed by function */
|
|
char *savefile; /* Freed by function */
|
|
BOOL nosavedlg;
|
|
|
|
/* Used internally */
|
|
HTRequest *request;
|
|
struct DestInfo *pDest;
|
|
int status;
|
|
};
|
|
|
|
static int x_DownLoad_Async(struct Mwin *tw, int nState, void **ppInfo)
|
|
{
|
|
struct Params_Download *pParams;
|
|
char buf[MAX_URL_STRING + 32 + 1];
|
|
struct Params_LoadAsync *pla;
|
|
static BOOL success;
|
|
|
|
pParams = *ppInfo;
|
|
|
|
switch (nState)
|
|
{
|
|
case STATE_INIT:
|
|
pParams->pDest = Dest_CreateDest(pParams->url);
|
|
if (!pParams->pDest)
|
|
{
|
|
GTR_FREE(pParams->url);
|
|
if (pParams->szReferer)
|
|
GTR_FREE(pParams->szReferer);
|
|
success = FALSE;
|
|
goto finish_up;
|
|
}
|
|
|
|
/* Set up the request structure */
|
|
pParams->request = HTRequest_new();
|
|
HTFormatInit(pParams->request->conversions);
|
|
pParams->request->output_format = WWW_UNKNOWN;
|
|
pParams->request->referer = pParams->szReferer;
|
|
pParams->request->destination = pParams->pDest;
|
|
pParams->request->iFlags |= HTREQ_BINARY;
|
|
pParams->request->savefile = pParams->savefile;
|
|
pParams->request->nosavedlg = pParams->nosavedlg;
|
|
|
|
#ifdef FEATURE_IAPI
|
|
/* Make a copy of the requested URL to use later */
|
|
|
|
tw->SDI_url = GTR_strdup(pParams->url);
|
|
#endif
|
|
|
|
/* This is a user initiated request for download, so
|
|
** dont allow any configur dialog button
|
|
*/
|
|
pParams->request->noconfbutton = 1;
|
|
|
|
strcpy(buf, GTR_GetString(SID_INF_DOWNLOADING));
|
|
GTR_strncat(buf, pParams->pDest->szActualURL, MAX_URL_STRING);
|
|
WAIT_Push(tw, waitNoInteract, buf);
|
|
|
|
pla = GTR_CALLOC(sizeof(*pla), 1);
|
|
if (pla)
|
|
{
|
|
pla->request = pParams->request;
|
|
pla->pStatus = &pParams->status;
|
|
|
|
Async_DoCall(HTLoadDocument_Async, pla);
|
|
return STATE_OTHER;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
case STATE_OTHER:
|
|
WAIT_Pop(tw);
|
|
if (!pParams->status)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_DOCUMENT_LOAD_FAILED_S, pParams->url, NULL);
|
|
}
|
|
Dest_DestroyDest(pParams->pDest);
|
|
HTRequest_delete(pParams->request);
|
|
GTR_FREE(pParams->url);
|
|
if (pParams->szReferer)
|
|
{
|
|
GTR_FREE(pParams->szReferer);
|
|
}
|
|
success = TRUE;
|
|
goto finish_up;
|
|
|
|
case STATE_ABORT:
|
|
WAIT_Pop(tw);
|
|
Dest_DestroyDest(pParams->pDest);
|
|
HTRequest_delete(pParams->request);
|
|
GTR_FREE(pParams->url);
|
|
if (pParams->szReferer)
|
|
{
|
|
GTR_FREE(pParams->szReferer);
|
|
}
|
|
success = TRUE;
|
|
goto finish_up;
|
|
|
|
finish_up:
|
|
TW_UpdateTBar(tw);
|
|
|
|
#if defined(FEATURE_IAPI)
|
|
/* Free and clear the tw->SDI_url because it may get reused */
|
|
|
|
SDI_Issue_URLEcho(tw);
|
|
|
|
if (tw->SDI_url)
|
|
{
|
|
GTR_FREE(tw->SDI_url);
|
|
tw->SDI_url = NULL;
|
|
}
|
|
|
|
if (tw->transID)
|
|
|
|
#ifdef UNIX
|
|
SDI_Issue_Result(tw, success);
|
|
#else
|
|
SDI_Issue_Result(tw->transID, tw->serialID, success);
|
|
#endif
|
|
#endif
|
|
return STATE_DONE;
|
|
}
|
|
XX_Assert((0), ("Function called with illegal state: %d", nState));
|
|
return STATE_DONE;
|
|
}
|
|
|
|
/* Note these functions are not at all related to the similarly named
|
|
** function GTR_DoDownLoad() which is used for HTFile Streams
|
|
**
|
|
** These functions initiate a download from places like SDI OpenURL
|
|
** and Cntl-Mouse.
|
|
**
|
|
*/
|
|
void GTR_DownLoad(struct Mwin *tw, char *url, CONST char *szReferer)
|
|
{
|
|
GTR__DownLoad(tw, url, szReferer, NULL, 0);
|
|
return;
|
|
}
|
|
|
|
void GTR__DownLoad(struct Mwin *tw, char *url, CONST char *szReferer, CONST char *savefile, BOOL nosavedlg)
|
|
{
|
|
char buf[MAX_URL_STRING + 32 + 1];
|
|
struct Params_Download *pdl;
|
|
|
|
if (!url || !*url)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_NO_URL_SPECIFIED, NULL, NULL);
|
|
TW_UpdateTBar(tw);
|
|
return;
|
|
}
|
|
|
|
/* If the URL is of the form "http://system", append a slash at the end */
|
|
GTR_strncpy(buf, url, MAX_URL_STRING);
|
|
x_EnforceHostSlash(buf);
|
|
|
|
pdl = GTR_CALLOC(sizeof(*pdl), 1);
|
|
if (pdl)
|
|
{
|
|
/* Make copies of the URL and referer that we know won't be freed */
|
|
pdl->url = GTR_strdup(buf);
|
|
if (szReferer)
|
|
{
|
|
pdl->szReferer = GTR_strdup(szReferer);
|
|
}
|
|
else
|
|
{
|
|
pdl->szReferer = NULL;
|
|
}
|
|
|
|
if (savefile)
|
|
{
|
|
pdl->savefile = GTR_strdup(savefile);
|
|
}
|
|
pdl->nosavedlg = nosavedlg;
|
|
|
|
Async_StartThread(x_DownLoad_Async, pdl, tw);
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
#ifdef FEATURE_IAPI
|
|
|
|
/* Left this function call cuz is already used cross platform. */
|
|
void GTR_DoSDI(struct Mwin *tw, char *url, CONST char *szReferer, CONST char *savefile, BOOL nosavedlg)
|
|
{
|
|
GTR__DownLoad(tw, url, szReferer, savefile, nosavedlg);
|
|
/* return GTR__DownLoad(tw, url, szReferer, savefile, nosavedlg);*/
|
|
}
|
|
|
|
#ifdef WIN32
|
|
|
|
/*
|
|
This code is currently Win32-only, and experimental. It implements
|
|
support for an SDI verb to retrieve the HTTP headers using the HEAD
|
|
method, for a given URL.
|
|
*/
|
|
struct Params_HTTPHead {
|
|
char *url; /* Freed by function */
|
|
|
|
/* Used internally */
|
|
HTRequest *request;
|
|
struct DestInfo *pDest;
|
|
int status;
|
|
};
|
|
|
|
static int x_HTTPHead_Async(struct Mwin *tw, int nState, void **ppInfo)
|
|
{
|
|
struct Params_HTTPHead *pParams;
|
|
char buf[MAX_URL_STRING + 32 + 1];
|
|
struct Params_LoadAsync *pla;
|
|
static BOOL success;
|
|
|
|
pParams = *ppInfo;
|
|
|
|
switch (nState)
|
|
{
|
|
case STATE_INIT:
|
|
pParams->pDest = Dest_CreateDest(pParams->url);
|
|
if (!pParams->pDest)
|
|
{
|
|
GTR_FREE(pParams->url);
|
|
success = FALSE;
|
|
goto finish_up;
|
|
}
|
|
|
|
/* Set up the request structure */
|
|
pParams->request = HTRequest_new();
|
|
HTFormatInit(pParams->request->conversions);
|
|
pParams->request->output_format = WWW_UNKNOWN;
|
|
pParams->request->referer = NULL;
|
|
pParams->request->destination = pParams->pDest;
|
|
pParams->request->iFlags |= HTREQ_BINARY;
|
|
pParams->request->savefile = NULL;
|
|
pParams->request->nosavedlg = FALSE;
|
|
pParams->request->method = METHOD_HEAD;
|
|
|
|
strcpy(buf, GTR_GetString(SID_INF_RETRIEVING_HTTP_HEAD_INFORMATION));
|
|
GTR_strncat(buf, pParams->pDest->szActualURL, MAX_URL_STRING);
|
|
WAIT_Push(tw, waitNoInteract, buf);
|
|
|
|
pla = GTR_CALLOC(sizeof(*pla), 1);
|
|
if (pla)
|
|
{
|
|
pla->request = pParams->request;
|
|
pla->pStatus = &pParams->status;
|
|
|
|
Async_DoCall(HTLoadDocument_Async, pla);
|
|
return STATE_OTHER;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
case STATE_OTHER:
|
|
WAIT_Pop(tw);
|
|
if (!pParams->status)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_DOCUMENT_LOAD_FAILED_S, pParams->url, NULL);
|
|
}
|
|
|
|
if (tw->transID)
|
|
{
|
|
SDI_Issue_HTTPHeadResult(tw->transID, tw->serialID, success, pParams->request->pHeadData);
|
|
}
|
|
|
|
Dest_DestroyDest(pParams->pDest);
|
|
HTRequest_delete(pParams->request);
|
|
GTR_FREE(pParams->url);
|
|
success = TRUE;
|
|
goto finish_up;
|
|
|
|
case STATE_ABORT:
|
|
WAIT_Pop(tw);
|
|
Dest_DestroyDest(pParams->pDest);
|
|
HTRequest_delete(pParams->request);
|
|
GTR_FREE(pParams->url);
|
|
success = TRUE;
|
|
goto finish_up;
|
|
|
|
finish_up:
|
|
TW_UpdateTBar(tw);
|
|
return STATE_DONE;
|
|
}
|
|
XX_Assert((0), ("Function called with illegal state: %d", nState));
|
|
return STATE_DONE;
|
|
}
|
|
|
|
void GTR_DoHTTPHead(struct Mwin *tw, char *url)
|
|
{
|
|
char buf[MAX_URL_STRING + 32 + 1];
|
|
struct Params_HTTPHead *pdl;
|
|
|
|
if (!url || !*url)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_NO_URL_SPECIFIED, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
/* If the URL is of the form "http://system", append a slash at the end */
|
|
GTR_strncpy(buf, url, MAX_URL_STRING);
|
|
x_EnforceHostSlash(buf);
|
|
|
|
pdl = GTR_CALLOC(sizeof(*pdl), 1);
|
|
if (pdl)
|
|
{
|
|
/* Make copies of the URL that we know won't be freed */
|
|
pdl->url = GTR_strdup(buf);
|
|
|
|
Async_StartThread(x_HTTPHead_Async, pdl, tw);
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
#endif /* WIN32 */
|
|
#endif /* FEATURE_IAPI */
|
|
|
|
struct Params_ViewSource {
|
|
char *url; /* Freed by function */
|
|
|
|
/* Used internally */
|
|
HTRequest *request;
|
|
struct DestInfo *pDest;
|
|
int status;
|
|
struct CharStream *myCharStream;
|
|
};
|
|
|
|
static int x_ViewSource_Async(struct Mwin *tw, int nState, void **ppInfo)
|
|
{
|
|
struct Params_ViewSource *pParams;
|
|
struct Params_LoadAsync *pla;
|
|
static BOOL success;
|
|
|
|
pParams = *ppInfo;
|
|
|
|
switch (nState)
|
|
{
|
|
case STATE_INIT:
|
|
pParams->pDest = Dest_CreateDest(pParams->url);
|
|
if (!pParams->pDest)
|
|
{
|
|
GTR_FREE(pParams->url);
|
|
success = FALSE;
|
|
goto finish_up;
|
|
}
|
|
|
|
/* Set up the request structure */
|
|
pParams->request = HTRequest_new();
|
|
HTFormatInit(pParams->request->conversions);
|
|
pParams->request->output_format = WWW_PRESENT;
|
|
pParams->request->referer = NULL;
|
|
pParams->request->destination = pParams->pDest;
|
|
pParams->request->myCharStream = pParams->myCharStream;
|
|
pParams->request->iFlags |= HTREQ_VIEWSOURCE;
|
|
|
|
pla = GTR_CALLOC(sizeof(*pla), 1);
|
|
if (pla)
|
|
{
|
|
pla->request = pParams->request;
|
|
pla->pStatus = &pParams->status;
|
|
|
|
Async_DoCall(HTLoadDocument_Async, pla);
|
|
return STATE_OTHER;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
case STATE_OTHER:
|
|
if (!pParams->status)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_DOCUMENT_LOAD_FAILED_S, pParams->url, NULL);
|
|
}
|
|
Dest_DestroyDest(pParams->pDest);
|
|
HTRequest_delete(pParams->request);
|
|
GTR_FREE(pParams->url);
|
|
success = TRUE;
|
|
goto finish_up;
|
|
|
|
case STATE_ABORT:
|
|
Dest_DestroyDest(pParams->pDest);
|
|
HTRequest_delete(pParams->request);
|
|
GTR_FREE(pParams->url);
|
|
success = TRUE;
|
|
goto finish_up;
|
|
|
|
finish_up:
|
|
TW_UpdateTBar(tw);
|
|
|
|
return STATE_DONE;
|
|
}
|
|
XX_Assert((0), ("Function called with illegal state: %d", nState));
|
|
return STATE_DONE;
|
|
}
|
|
|
|
#ifndef _GIBRALTAR
|
|
void GTR_ViewSource(struct Mwin *orig_tw)
|
|
{
|
|
struct Mwin *new_tw;
|
|
char buf[MAX_URL_STRING + 32 + 1];
|
|
struct Params_ViewSource *pdl;
|
|
|
|
new_tw = NewMwin(GHTML);
|
|
if (!new_tw)
|
|
{
|
|
ERR_ReportError(orig_tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
if (!GDOC_NewWindow(new_tw))
|
|
{
|
|
CloseMwin(new_tw);
|
|
return;
|
|
}
|
|
|
|
/* If the URL is of the form "http://system", append a slash at the end */
|
|
GTR_strncpy(buf, orig_tw->w3doc->szActualURL, MAX_URL_STRING);
|
|
x_EnforceHostSlash(buf);
|
|
|
|
pdl = GTR_CALLOC(sizeof(*pdl), 1);
|
|
if (pdl)
|
|
{
|
|
/* Make a copy of the URL that we know won't be freed */
|
|
pdl->url = GTR_strdup(buf);
|
|
pdl->myCharStream = orig_tw->w3doc->source;
|
|
Async_StartThread(x_ViewSource_Async, pdl, new_tw);
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(orig_tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
}
|
|
}
|
|
#endif /* _GIBRALTAR */
|
|
|
|
int TW_AddToHistory(struct Mwin *tw, char *url, BOOL bPost, char *szPostData)
|
|
{
|
|
struct MiniRequest *mrq;
|
|
struct MiniRequest *new_mrq;
|
|
|
|
XX_DMsg(DBG_HIST, ("Adding to window history: %s\n", url));
|
|
|
|
/* tw parameter check added [der:11/29/95] */
|
|
if (!tw) return 0;
|
|
|
|
while (tw->history_index--)
|
|
{
|
|
mrq = HTList_removeLastObject(tw->history);
|
|
if (mrq)
|
|
{
|
|
GTR_FREE(mrq->url);
|
|
if (mrq->szPostData)
|
|
{
|
|
XX_Assert((mrq->bPost), ("You can't have POST data without POST!"));
|
|
GTR_FREE(mrq->szPostData);
|
|
}
|
|
GTR_FREE(mrq);
|
|
}
|
|
}
|
|
|
|
mrq = HTList_objectAt(tw->history, 0);
|
|
#ifdef XX_DEBUG
|
|
if (mrq)
|
|
{
|
|
XX_DMsg(DBG_HIST, ("Last item in window history is currently: %s\n", mrq->url));
|
|
}
|
|
#endif /* XX_DEBUG */
|
|
if (!mrq || strcmp(url, mrq->url) || (mrq->bPost != bPost) || (szPostData && strcmp(mrq->szPostData, szPostData)))
|
|
{
|
|
new_mrq = GTR_CALLOC(1, sizeof(*new_mrq));
|
|
if (new_mrq)
|
|
{
|
|
new_mrq->url = GTR_strdup(url);
|
|
new_mrq->bPost = bPost;
|
|
if (szPostData)
|
|
{
|
|
XX_Assert((bPost), ("You can't have POST data without POST!"));
|
|
new_mrq->szPostData = GTR_strdup(szPostData);
|
|
}
|
|
}
|
|
|
|
HTList_addObject(tw->history, new_mrq);
|
|
tw->history_index = HTList_indexOf(tw->history, new_mrq);
|
|
}
|
|
else
|
|
{
|
|
XX_DMsg(DBG_HIST, ("tw->history_index = 0\n"));
|
|
tw->history_index = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void TW_GoBack(struct Mwin *tw)
|
|
{
|
|
struct MiniRequest *mrq;
|
|
|
|
/* tw parameter check added [der:11/29/95] */
|
|
if (tw && HTList_count(tw->history) > (tw->history_index + 1))
|
|
{
|
|
mrq = (struct MiniRequest *) HTList_objectAt(tw->history, ++tw->history_index);
|
|
if (mrq)
|
|
{
|
|
TW_LoadDocument(tw, mrq->url, FALSE, mrq->bPost, FALSE, FALSE, (mrq->szPostData ? GTR_strdup(mrq->szPostData) : NULL), tw->request->referer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XX_DMsg(DBG_WWW, ("Cannot go back\n"));
|
|
}
|
|
}
|
|
|
|
void TW_GoForward(struct Mwin *tw)
|
|
{
|
|
struct MiniRequest *mrq;
|
|
|
|
/* tw parameter check added [der:11/29/95] */
|
|
if (tw && tw->history_index > 0)
|
|
{
|
|
mrq = (struct MiniRequest *) HTList_objectAt(tw->history, --tw->history_index);
|
|
if (mrq)
|
|
{
|
|
TW_LoadDocument(tw, mrq->url, FALSE, mrq->bPost, FALSE, FALSE, (mrq->szPostData ? GTR_strdup(mrq->szPostData) : NULL), tw->request->referer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XX_DMsg(DBG_WWW, ("Cannot go forward\n"));
|
|
}
|
|
}
|
|
|
|
void TW_Reload(struct Mwin *tw)
|
|
{
|
|
struct MiniRequest *mrq;
|
|
|
|
/* tw parameter check added [der:11/29/95] */
|
|
if (!tw) return;
|
|
|
|
mrq = (struct MiniRequest *) HTList_objectAt(tw->history, tw->history_index);
|
|
|
|
if (mrq)
|
|
TW_LoadDocument(tw, mrq->url, FALSE, mrq->bPost, TRUE, TRUE, (mrq->szPostData ? GTR_strdup(mrq->szPostData) : NULL), tw->request->referer);
|
|
}
|
|
|
|
void TW_SetCurrentDocAsHomePage(struct Mwin *tw)
|
|
{
|
|
struct MiniRequest *mrq;
|
|
char *url;
|
|
|
|
/* tw parameter check added [der:11/29/95] */
|
|
if (!tw) return;
|
|
|
|
if (tw->w3doc)
|
|
{
|
|
url = tw->w3doc->szActualURL;
|
|
}
|
|
else
|
|
{
|
|
mrq = (struct MiniRequest *) HTList_objectAt(tw->history, tw->history_index);
|
|
url = mrq->url;
|
|
}
|
|
|
|
strcpy(gPrefs.szHomeURL, url);
|
|
#ifdef UNIX
|
|
SavePreferences(&gPrefs);
|
|
#endif /* UNIX */
|
|
|
|
#ifdef WIN32
|
|
SavePreferences();
|
|
#endif /* WIN32 */
|
|
|
|
#ifdef MAC
|
|
/* TODO What do we call here to save the preferences ?? */
|
|
#endif /* MAC */
|
|
}
|
|
|
|
BOOL TW_CanGoBack(struct Mwin *tw)
|
|
{
|
|
/* tw parameter check added [der:11/29/95] */
|
|
return (tw && HTList_count(tw->history) > (tw->history_index + 1));
|
|
}
|
|
|
|
BOOL TW_CanGoForward(struct Mwin *tw)
|
|
{
|
|
/* tw parameter check added [der:11/29/95] */
|
|
return (tw && tw->history_index > 0);
|
|
}
|
|
|
|
int TW_CountWindowHistory(struct Mwin *tw)
|
|
{
|
|
/* tw parameter check added [der:11/29/95] */
|
|
if (tw)
|
|
return HTList_count(tw->history);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void TW_DestroyWindowHistory(struct Mwin *tw)
|
|
{
|
|
int count;
|
|
int i;
|
|
struct MiniRequest *mrq;
|
|
|
|
/* tw parameter check added [der:11/29/95] */
|
|
if (!tw) return;
|
|
|
|
count = HTList_count(tw->history);
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
mrq = HTList_objectAt(tw->history, i);
|
|
if (mrq)
|
|
{
|
|
GTR_FREE(mrq->url);
|
|
if (mrq->szPostData)
|
|
{
|
|
XX_Assert((mrq->bPost), ("You can't have POST data without POST!"));
|
|
GTR_FREE(mrq->szPostData);
|
|
}
|
|
GTR_FREE(mrq);
|
|
}
|
|
}
|
|
HTList_delete(tw->history);
|
|
}
|
|
|