mirror of https://github.com/lianthony/NT4.0
387 lines
8.7 KiB
387 lines
8.7 KiB
/*
|
|
Enhanced NCSA Mosaic from Spyglass
|
|
"Guitar"
|
|
|
|
Copyright 1994 Spyglass, Inc.
|
|
All Rights Reserved
|
|
|
|
Author(s):
|
|
Jim Seidman jim@spyglass.com
|
|
*/
|
|
|
|
/* GuitErrs.c - code to handle buffering of errors */
|
|
/* Author: Jim Seidman */
|
|
|
|
#include "all.h"
|
|
|
|
|
|
#define ERRORBUFLEN 256
|
|
#define MAXERRORS 4
|
|
|
|
struct _HTStream
|
|
{
|
|
HTStreamClass *isa; /* all we need to know */
|
|
};
|
|
|
|
|
|
/* I'm going to be cheap and just use a static array to store these errors. */
|
|
static far struct ErrorRecord
|
|
{
|
|
enum GuitError geErr;
|
|
char buf1[ERRORBUFLEN];
|
|
char buf2[ERRORBUFLEN];
|
|
}
|
|
erRecords[MAXERRORS];
|
|
|
|
/* This can become greater than MAXERRORS to show that we overflowed the array. */
|
|
static int nErrorCount = 0;
|
|
static int bBuffer = FALSE;
|
|
|
|
|
|
/* Messages to show for the different errors. */
|
|
static const int errorIds[] =
|
|
{
|
|
RES_STRING_ERR1,
|
|
RES_STRING_ERR2,
|
|
RES_STRING_ERR3,
|
|
RES_STRING_ERR4,
|
|
RES_STRING_ERR5,
|
|
RES_STRING_ERR6,
|
|
RES_STRING_ERR7,
|
|
RES_STRING_ERR8,
|
|
RES_STRING_ERR9,
|
|
RES_STRING_ERR10,
|
|
RES_STRING_CANNOT_DELETE,
|
|
RES_STRING_NO_DIR,
|
|
RES_STRING_CANT_MOVE_FILE,
|
|
RES_STRING_CANT_SAVE_CACHE,
|
|
RES_STRING_ERR11,
|
|
RES_STRING_ERR12,
|
|
RES_STRING_ERR62,
|
|
RES_STRING_ERR13,
|
|
RES_STRING_ERR14,
|
|
RES_STRING_ERR15,
|
|
RES_STRING_ERR16,
|
|
RES_STRING_ERR17,
|
|
RES_STRING_ERR18,
|
|
RES_STRING_ERR19,
|
|
RES_STRING_ERR20,
|
|
RES_STRING_ERR21,
|
|
RES_STRING_ERR22,
|
|
RES_STRING_ERR23,
|
|
RES_STRING_ERR24,
|
|
RES_STRING_ERR25,
|
|
RES_STRING_ERR26,
|
|
RES_STRING_ERR27,
|
|
RES_STRING_ERR28,
|
|
RES_STRING_ERR29,
|
|
RES_STRING_ERR30,
|
|
RES_STRING_ERR32,
|
|
RES_STRING_ERR33,
|
|
RES_STRING_ERR34,
|
|
RES_STRING_ERR35,
|
|
RES_STRING_ERR36,
|
|
RES_STRING_ERR37,
|
|
RES_STRING_ERR38,
|
|
RES_STRING_ERR39,
|
|
RES_STRING_ERR40,
|
|
RES_STRING_ERR41,
|
|
RES_STRING_ERR42,
|
|
RES_STRING_ERR43,
|
|
RES_STRING_ERR44,
|
|
RES_STRING_ERR45,
|
|
RES_STRING_ERR46,
|
|
RES_STRING_ERR47,
|
|
RES_STRING_ERR48,
|
|
RES_STRING_ERR49,
|
|
RES_STRING_ERR50,
|
|
RES_STRING_ERR51,
|
|
RES_STRING_ERR52,
|
|
RES_STRING_ERR53,
|
|
RES_STRING_ERR54,
|
|
RES_STRING_ERR55,
|
|
RES_STRING_ERR56,
|
|
RES_STRING_ERR57,
|
|
RES_STRING_ERR58,
|
|
RES_STRING_ERR59,
|
|
RES_STRING_ERR60,
|
|
RES_STRING_ERR61,
|
|
RES_STRING_ERR_APP_EXEC_FAILED,
|
|
RES_STRING_ERR_NO_ASSOC,
|
|
RES_STRING_ERR_EXEC_FAILED,
|
|
RES_STRING_NNTP_POST_FAILED,
|
|
RES_STRING_NNTP_UNEXPECTED,
|
|
RES_STRING_NNTP_POST_NOT_ALLOWED,
|
|
RES_STRING_SHTTP_ERROR
|
|
};
|
|
|
|
/* Buffer an error. cbMsgID is resource id for string to pass to ERR_ReportError*/
|
|
void ERR_SimpleError(struct Mwin *tw, enum GuitError geErr, int cbMsgID)
|
|
{
|
|
char szMsg[512];
|
|
|
|
if (LoadString(wg.hInstance, cbMsgID, szMsg, sizeof(szMsg)-1) == 0)
|
|
szMsg[0] = '\0';
|
|
ERR_ReportError(tw,geErr,szMsg,"");
|
|
}
|
|
|
|
|
|
static void ERR_ShowOneError(struct Mwin *param_tw, int cbStringID, const char *p1, const char *p2,
|
|
HTStream *pErrTarget )
|
|
{
|
|
ThreadID tid;
|
|
struct Mwin * tw;
|
|
char buf[256];
|
|
BOOL bGlobe;
|
|
const char *pStrings[2];
|
|
PVOID pMessage;
|
|
#define FORMAT_PARAMS (FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_MAX_WIDTH_MASK)
|
|
|
|
if (param_tw)
|
|
{
|
|
tw = param_tw;
|
|
}
|
|
else
|
|
{
|
|
tid = Async_GetCurrentThread();
|
|
if (tid)
|
|
{
|
|
tw = Async_GetWindowFromThread(tid);
|
|
}
|
|
else
|
|
{
|
|
tw = NULL;
|
|
}
|
|
}
|
|
|
|
if (tw)
|
|
{
|
|
bGlobe = TBar_SetGlobe(tw,FALSE);
|
|
}
|
|
|
|
pStrings[0] = p1;
|
|
pStrings[1] = p2;
|
|
if (LoadString(wg.hInstance, cbStringID, buf, sizeof(buf)-1) &&
|
|
FormatMessage(FORMAT_PARAMS,buf,0,0,(LPSTR)&pMessage,0,pStrings))
|
|
{
|
|
if ( pErrTarget )
|
|
{
|
|
const char cszBar[] = "</B><HR>";
|
|
const char cszBold[] = "<B>";
|
|
|
|
// place the error message into the HTML, then stick it in bold
|
|
// with a Bar underneath it
|
|
|
|
(*pErrTarget->isa->put_block)(pErrTarget,
|
|
cszBold,
|
|
sizeof(cszBold),
|
|
FALSE);
|
|
|
|
(*pErrTarget->isa->put_block)(pErrTarget,
|
|
pMessage,
|
|
strlen(pMessage),
|
|
FALSE);
|
|
|
|
(*pErrTarget->isa->put_block)(pErrTarget,
|
|
cszBar,
|
|
sizeof(cszBar),
|
|
FALSE);
|
|
|
|
}
|
|
else
|
|
{
|
|
DlgERR_AddError(tw, pMessage);
|
|
LocalFree(pMessage);
|
|
if (tw)
|
|
{
|
|
TBar_SetGlobe(tw,bGlobe);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Buffer an error. p1 and p2 are replacement strings which may
|
|
or may not be used depending on the error. */
|
|
void ERR_InternalReportError(struct Mwin *tw, enum GuitError geErr,
|
|
const char *p1, const char *p2, HTRequest *pRequest, HTStream **ppErrTarget,
|
|
HTStream **ppOrgTarget )
|
|
{
|
|
BOOL bForceErrorToBeShown = FALSE;
|
|
BOOL bDontPutErrorIn = FALSE;
|
|
// if we have this flag set in the request structure,
|
|
// then don't report the error, since its results in alot of noise
|
|
// to the user, Its done here to save multiple checks else where
|
|
// in the code.
|
|
if ( pRequest )
|
|
{
|
|
pRequest->iFlags |= HTREQ_HAD_ERROR; // mark it as having an error
|
|
if ( (pRequest->iFlags & HTREQ_STOP_WHINING) )
|
|
return;
|
|
// if its not a normal page download then do the old style error,
|
|
else if ( ! (pRequest->iFlags & HTREQ_HTML_PAGE_DOWNLOAD) )
|
|
goto LErr_UglyDlgError; // fall back to normal behavior
|
|
else if ( ppErrTarget && ppOrgTarget )
|
|
{
|
|
if ( *ppOrgTarget )
|
|
{
|
|
(*(*ppOrgTarget)->isa->abort)((*ppOrgTarget), HTERROR_CANCELLED);
|
|
*ppOrgTarget = NULL;
|
|
}
|
|
|
|
if ( ! *ppErrTarget )
|
|
{
|
|
pRequest->iFlags |= HTREQ_FORCE_NO_SHORTCUT;
|
|
pRequest->iFlags &= ~HTREQ_RECORD;
|
|
|
|
*ppErrTarget = HTMLPresent(tw, pRequest, NULL, WWW_HTML, pRequest->output_format, pRequest->output_stream);
|
|
|
|
if ((*ppErrTarget)->isa->init_Async)
|
|
{
|
|
/* The stream has an async initialization function that needs to be called
|
|
(probably to put up a dialog) before we continue. */
|
|
struct Params_InitStream *pis;
|
|
static int Thestatus;
|
|
|
|
pis = GTR_MALLOC(sizeof(*pis));
|
|
pis->me = (*ppErrTarget);
|
|
pis->request = pRequest;
|
|
pis->pResult = &Thestatus;
|
|
pis->atomMIMEType = WWW_HTML;
|
|
pis->fDCache = FALSE;
|
|
bForceErrorToBeShown = TRUE;
|
|
// we exclude a server error
|
|
// from generating a error message
|
|
// within in-pane errors.
|
|
if ( geErr == errServerError )
|
|
bDontPutErrorIn = TRUE;
|
|
Async_DoCall((*ppErrTarget)->isa->init_Async, pis);
|
|
}
|
|
|
|
|
|
if ( *ppErrTarget )
|
|
goto LErr_UglyDlgError; // fall back to normal behavior
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
LErr_UglyDlgError:
|
|
|
|
#ifdef FEATURE_IAPI
|
|
/* Do not display the error dialog if from SDI */
|
|
|
|
if (tw && (tw->transID != 0))
|
|
{
|
|
/* Set the window ID to the correct error value, but only
|
|
the first time (thus the greater than or equal to zero check) */
|
|
|
|
if (tw->serialID >= 0)
|
|
{
|
|
switch(geErr)
|
|
{
|
|
case errFileURLNotFound:
|
|
case errServerError:
|
|
case errHostNotFound:
|
|
tw->serialID = SDI_INVALID_URL;
|
|
break;
|
|
|
|
case errCantSaveFile:
|
|
tw->serialID = SDI_CANNOT_SAVE_FILE;
|
|
break;
|
|
|
|
default:
|
|
tw->serialID = SDI_UNDEFINED_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* BUGBUG: (DavidDi 5/18/95) We should allow DDE clients to specify whether
|
|
* or not they wish IExplorer to put up ui on error. Currently, any error
|
|
* during a DDE operation will cause IExplorer to put up an error dialog.
|
|
*/
|
|
|
|
if (bBuffer && ! bForceErrorToBeShown)
|
|
{
|
|
if (nErrorCount < MAXERRORS)
|
|
{
|
|
erRecords[nErrorCount].geErr = geErr;
|
|
if (p1)
|
|
{
|
|
strncpy(erRecords[nErrorCount].buf1, p1, ERRORBUFLEN);
|
|
erRecords[nErrorCount].buf1[ERRORBUFLEN - 1] = '\0';
|
|
}
|
|
else
|
|
erRecords[nErrorCount].buf1[0] = '\0';
|
|
|
|
if (p2)
|
|
{
|
|
strncpy(erRecords[nErrorCount].buf2, p2, ERRORBUFLEN);
|
|
erRecords[nErrorCount].buf2[ERRORBUFLEN - 1] = '\0';
|
|
}
|
|
else
|
|
erRecords[nErrorCount].buf2[0] = '\0';
|
|
}
|
|
nErrorCount++;
|
|
}
|
|
else
|
|
{
|
|
char dummy1[] = "";
|
|
char dummy2[] = "";
|
|
|
|
if (!p1)
|
|
p1 = dummy1;
|
|
if (!p2)
|
|
p2 = dummy2;
|
|
|
|
if ( ! bDontPutErrorIn )
|
|
ERR_ShowOneError(tw, errorIds[geErr], p1, p2, ppErrTarget ? *ppErrTarget :
|
|
NULL );
|
|
}
|
|
}
|
|
|
|
|
|
/* Alert to user to all of the accumulated errors. */
|
|
void ERR_ShowBufferedErrors(struct Mwin *tw)
|
|
{
|
|
int n, nmax;
|
|
|
|
nmax = nErrorCount;
|
|
if (nmax > MAXERRORS)
|
|
nmax = MAXERRORS;
|
|
|
|
for (n = 0; n < nmax; n++)
|
|
ERR_ShowOneError(tw, errorIds[erRecords[n].geErr], erRecords[n].buf1, erRecords[n].buf2, NULL);
|
|
|
|
n = nErrorCount - MAXERRORS;
|
|
if (n >= 1)
|
|
{
|
|
ERR_ShowOneError(tw, n > 1 ? RES_STRING_ADDITIONAL:RES_STRING_1ADDITIONAL, (LPSTR)(n), "", NULL);
|
|
}
|
|
nErrorCount = 0;
|
|
}
|
|
|
|
/* Like BufferError, but show the error immediately */
|
|
void ERR_ReportErrorNow(struct Mwin *tw, enum GuitError geErr, const char *p1, const char *p2)
|
|
{
|
|
char dummy1[] = "";
|
|
char dummy2[] = "";
|
|
|
|
if (!p1)
|
|
p1 = dummy1;
|
|
if (!p2)
|
|
p2 = dummy2;
|
|
ERR_ShowOneError(tw, errorIds[geErr], p1, p2, NULL);
|
|
}
|
|
|
|
void ERR_SetBuffering(struct Mwin *tw, BOOL bDoBuffer)
|
|
{
|
|
bBuffer = bDoBuffer;
|
|
|
|
if (!bBuffer)
|
|
ERR_ShowBufferedErrors(tw);
|
|
}
|