/*
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[] = "
";
const char cszBold[] = "";
// 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);
}