gecko-dev/lib/xp/xp_cntxt.c
1998-03-28 02:44:41 +00:00

708 lines
17 KiB
C

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#define M12N
#ifdef MOZILLA_CLIENT
/*
* xp_cntxt.c
* Contains various XP context related functions
* Recomended when FE communicates with lib code in a complex way
*/
#include "xp.h"
#include "shist.h"
#include "glhist.h"
#include "ssl.h"
#include "libimg.h" /* Image Lib public API. */
#include "libmocha.h"
#include "libevent.h"
#include "intl_csi.h"
#include "xp_ncent.h"
static XP_List * xp_GlobalContextList = NULL;
static int32 global_context_id = 0;
void
XP_InitializeContext(MWContext *context)
{
if (context != NULL)
{
context->context_id = ++global_context_id;
context->INTL_tag = INTL_TAG;
}
}
/* WARNING ! the mac FE does not call this ! */
MWContext *
XP_NewContext(void)
{
MWContext *context;
context = XP_NEW_ZAP(MWContext);
XP_ASSERT(NULL != context);
if (NULL == context)
{
return NULL;
}
context->INTL_CSIInfo = INTL_CSICreate();
if (NULL == context->INTL_CSIInfo)
{
XP_FREE(context);
return NULL;
}
XP_InitializeContext(context);
return context;
}
/* WARNING ! the mac FE does not call this ! */
void
XP_DeleteContext(MWContext *context)
{
XP_ASSERT(context);
INTL_CSIDestroy(context->INTL_CSIInfo);
XP_FREE(context);
}
/* give access to the global context list to other code too.
*/
XP_List *XP_GetGlobalContextList(void)
{
return(xp_GlobalContextList);
}
/* cx_AddChildContext
* Adds child context to the parents children list
* NULL-safe
*/
void cx_AddChildContext(MWContext *parent, MWContext * child)
{
if ((parent == NULL) || (child == NULL))
return;
if (parent->grid_children == NULL)
parent->grid_children = XP_ListNew();
if (parent->grid_children == NULL)
return;
XP_ListAddObject(parent->grid_children, child);
}
/* cx_RemoveChildContext
* Removes child context from its parent
* NULL-safe
*/
void cx_RemoveChildContext(MWContext * child)
{
if ((child == NULL) || (child->grid_parent == NULL))
return;
XP_ListRemoveObject(child->grid_parent->grid_children, child);
}
/*
* if the passed context is in the global context list
* TRUE is returned. Otherwise false
*/
Bool XP_IsContextInList(MWContext *context)
{
if (context == NULL)
return FALSE;
if (xp_GlobalContextList == NULL)
return(FALSE);
return((XP_ListFindObject(xp_GlobalContextList, context)
? TRUE : FALSE));
}
/*
* The passed context is added to the global context list
*/
void XP_AddContextToList(MWContext *context)
{
if (context == NULL)
return;
if (xp_GlobalContextList == NULL)
xp_GlobalContextList = XP_ListNew();
if (xp_GlobalContextList == NULL)
return;
XP_ListRemoveObject(xp_GlobalContextList, context); /* No dups */
XP_ListAddObject(xp_GlobalContextList, context);
cx_AddChildContext(context->grid_parent, context);
}
void XP_UpdateParentContext(MWContext * child)
{
cx_AddChildContext(child->grid_parent, child);
}
/*
* Removes the context from the context list
* Notifies all its children
*/
void XP_RemoveContextFromList(MWContext *context)
{
int howMany;
int i;
if (context == NULL)
return;
cx_RemoveChildContext(context); /* Its parent does not point to it any more */
/* Now take care of the children, this should not really happen */
if (context->grid_children)
{
howMany = XP_ListCount(context->grid_children);
for (i = 1; i <= howMany; i++)
{
MWContext * child;
child = (MWContext *)XP_ListGetObjectNum(context->grid_children, 1);
if (child)
child->grid_parent = NULL;
XP_ListRemoveObject(context->grid_children, child);
}
XP_ListDestroy(context->grid_children);
context->grid_children = NULL;
}
XP_ListRemoveObject(xp_GlobalContextList, context);
/* Remove from last active stack.
* Remove any nav center info about the context.
*/
XP_RemoveContextFromLastActiveStack(context);
XP_RemoveNavCenterInfo(context);
}
/* the following was adapted from xp_FindNamedContextInChildren, but
simplified for simply matching pointers instead of names. */
Bool
XP_IsChildContext(MWContext* parent, MWContext* child)
{
int i;
if (parent == child) {
return TRUE;
}
if (parent->grid_children) {
int count = XP_ListCount(parent->grid_children);
for (i = 1; i <= count; i++) {
MWContext* tchild =
(MWContext*)XP_ListGetObjectNum(parent->grid_children, i);
if (child == tchild) {
return TRUE;
}
else{
XP_Bool found = XP_IsChildContext(tchild, child);
if (found) return found;
}
}
}
return FALSE;
}
MWContext*
xp_FindNamedContextInChildren(MWContext* self, char* name, MWContext* excludeChild)
{
int i;
/*
XP_TRACE(("Searching for %s: context %0x, name=%s, title=%s\n",
(name ? name : ""), self,
(self->name ? self->name : ""), (self->title ? self->title : "")));
*/
if (self->name && XP_STRCMP(self->name, name) == 0) {
/*
XP_TRACE(("Found %s context %0x name=%s\n", (name ? name : ""),
self, self->name));
*/
return self;
}
if (self->grid_children) {
int count = XP_ListCount(self->grid_children);
for (i = 1; i <= count; i++) {
MWContext* child =
(MWContext*)XP_ListGetObjectNum(self->grid_children, i);
if (child != excludeChild) {
MWContext* found = xp_FindNamedContextInChildren(child, name, NULL);
if (found) return found;
}
}
}
return NULL;
}
/*
* Finds a context that should be loaded with the URL, given
* a name and current (refering) context.
*
* If the context returned is not NULL, name is already assigned to context
* structure. You should load the URL into this context.
*
* If you get back a NULL, you should create a new window
*
* Both context and current context can be null.
* Once the grids are in, there should be some kind of a logic that searches
* siblings first.
*/
MWContext * XP_FindNamedContextInList(MWContext * context, char *name)
{
int i;
if ((name == NULL) || (xp_GlobalContextList == NULL))
return context;
/*
* Check for special magic window target names
*/
if (name[0] == '_')
{
if (XP_STRNCMP(name, "_self", 5) == 0)
{
return context;
}
else if (XP_STRNCMP(name, "_parent", 7) == 0)
{
if ((context)&&(context->grid_parent))
{
return context->grid_parent;
}
else
{
return context;
}
}
else if (XP_STRNCMP(name, "_top", 4) == 0)
{
MWContext *top;
top = context;
while ((top)&&(top->grid_parent))
{
top = top->grid_parent;
}
return top;
}
else if (XP_STRNCMP(name, "_blank", 6) == 0)
{
return NULL;
}
/* else, search for the name, below */
}
{
MWContext* cx = context;
MWContext* found;
if (context) {
/* If our current context has the right name, go there */
if (cx->name &&
(XP_STRCMP(cx->name, name) == 0))
return cx;
found = xp_FindNamedContextInChildren(cx, name, NULL);
if (found) return found;
while (cx->is_grid_cell) {
MWContext* parent = cx->grid_parent;
found = xp_FindNamedContextInChildren(parent, name, cx);
if (found) return found;
cx = parent;
}
}
/* otherwise, just get any other context */
for (i=1; i<= XP_ListCount(xp_GlobalContextList); i++)
{
MWContext* compContext = (MWContext *)XP_ListGetObjectNum(xp_GlobalContextList, i);
/* Only search other top-level contexts that aren't the one we just came from: */
if (!compContext->is_grid_cell && compContext != cx) {
found = xp_FindNamedContextInChildren(compContext, name, NULL);
if (found) return found;
}
}
}
return NULL;
}
/*
* Finds a context that should be loaded with the URL, given
* a type and current (refering) context. Return NULL if there is none.
*/
MWContext * XP_FindContextOfType (MWContext * context, MWContextType type)
{
int i;
/* The other types aren't "real" - they don't have windows. (Actually,
neither do all of these, but it's damned useful to be able to find the
biff context...) */
XP_ASSERT (type == MWContextBrowser ||
type == MWContextMail ||
type == MWContextNews ||
type == MWContextMessageComposition ||
type == MWContextBookmarks ||
type == MWContextAddressBook ||
type == MWContextBiff ||
type == MWContextMailMsg ||
type == MWContextNewsMsg ||
type == MWContextEditor ||
type == MWContextPane);
/* Added MWContextEditor, needed for bug 61630 */
/* If our current context has the right type, go there */
if (context && context->type == type)
return context;
/* otherwise, just get any other context */
for (i=1; i<= XP_ListCount(xp_GlobalContextList); i++)
{
MWContext * compContext = (MWContext *)XP_ListGetObjectNum(xp_GlobalContextList, i);
if (compContext->type == type)
return compContext;
}
return NULL;
}
MWContext*
XP_FindSomeContext()
{
MWContext* cx = XP_FindContextOfType(NULL, MWContextBrowser);
if (!cx)
cx = XP_FindContextOfType(NULL, MWContextMail);
if (!cx)
cx = XP_FindContextOfType(NULL, MWContextNews);
if (!cx)
cx = XP_FindContextOfType(NULL, MWContextPane);
#if 0 /* dp says don't do this */
if (!cx)
cx = fe_all_MWContexts->context;
#endif
return cx;
}
/* Returns the first non-grid parent of a given context (can be the context
* itself if it's not a grid cell).
*/
MWContext *
XP_GetNonGridContext(MWContext *context)
{
MWContext* ctxt = context;
while (ctxt && ctxt->is_grid_cell)
ctxt = ctxt->grid_parent;
return ctxt;
}
/* FE should call XP_FindNamedAnchor before getting a URL
* that is going into an HTML window (output_format is FO_CACHE_AND_PRESENT
*
* if named anchor is found:
* XP_FindNamedAnchor
* - updates context history, and global history properly
* if it is not found, we do not touch any arguments
*
* Usage:
* In your GetURL routine
* if (XP_FindNamedAnchor(context, url, &x, &y))
* {
* SetDocPosition(x,y);
* if (url->history_num == 0) // if you are not handling go back this way, do not do this
* SHIST_AddDocument( &fContext, SHIST_CreateHistoryEntry( url, he->title) );
* else
* SHIST_SetCurrent(&fContext->hist, url->history_num);
* SetURLTextField(url->address);
* SetURLTextFieldTitle( ... url->is_netsite ... );
* NET_FreeURLStruct(url);
* RegenerateHistoryMenuAndDialogBoxContents()
* }
* else
* NET_GetURL
*/
Bool XP_FindNamedAnchor(MWContext * context, URL_Struct * url,
int32 *xpos, int32 *ypos)
{
History_entry *he;
if (!context)
return FALSE;
he = SHIST_GetCurrent (&context->hist);
if (he
&& he->address
&& url
&& url->address
&& XP_STRCHR(url->address, '#') /* it must have a named hash */
&& url->method == URL_GET_METHOD
&& url->force_reload == NET_DONT_RELOAD
&& LO_LocateNamedAnchor(context, url, xpos, ypos))
{
GH_UpdateGlobalHistory( url );
/* don't do this - jwz. */
/* NET_FreeURLStruct( url ); */
return TRUE;
}
return FALSE;
}
/* XP_RefreshAnchors
* call it after loading a new URL to refresh all the anchors
*/
void XP_RefreshAnchors()
{
int i;
for (i=1; i<= XP_ListCount(xp_GlobalContextList); i++)
{
MWContext * compContext = (MWContext *)XP_ListGetObjectNum(xp_GlobalContextList, i);
LO_RefreshAnchors(compContext);
}
}
/* XP_InterruptContext
* interrupts this context, and all the grid cells it encloses
*/
void XP_InterruptContext(MWContext * context)
{
int i = 1;
MWContext * child;
if (context == NULL)
return;
/* Interrupt the children recursively first.
* This avoids the scenario where the context is destroyed during
* an interrupt and we end up dereferencing a freed context.
* This also avoids crazy hacks like caching the grid_children
* context list until after the interrupt, and then doing the
* below loop. That can also crash if the grid_children context
* list is freed off....
* Bug fix 58770
*/
while(child = (MWContext *)XP_ListGetObjectNum(context->grid_children, i++))
XP_InterruptContext(child);
NET_InterruptWindow(context);
if (context->img_cx)
IL_InterruptContext(context->img_cx);
ET_InterruptContext(context);
}
Bool XP_IsContextBusy(MWContext * context)
{
int i = 1;
MWContext * child;
if (context == NULL)
return FALSE;
if (NET_AreThereActiveConnectionsForWindow(context))
return TRUE;
while ((child = (MWContext*)XP_ListGetObjectNum (context->grid_children,
i++)))
if (XP_IsContextBusy(child))
return TRUE;
return FALSE;
}
Bool XP_IsContextStoppable(MWContext * context)
{
int i = 1;
MWContext * child;
if (context == NULL)
return FALSE;
if (NET_AreThereActiveConnectionsForWindow(context))
return TRUE;
if (LM_IsActive(context))
return TRUE;
while ((child = (MWContext*)XP_ListGetObjectNum (context->grid_children,
i++)))
if (XP_IsContextStoppable(child))
return TRUE;
return FALSE;
}
/*
* Will return the lowest security status of the context
* and it's children.
* Lowest means lowest in security, not in numberic value.
*
* Possible returns are:
* SSL_SECURITY_STATUS_NOOPT
* SSL_SECURITY_STATUS_OFF
* SSL_SECURITY_STATUS_ON_HIGH
* SSL_SECURITY_STATUS_ON_LOW
*/
int XP_GetSecurityStatus(MWContext *pContext) {
History_entry *pHistEnt;
MWContext *pChild;
int iRetval, iIndex;
/*
* No context, no security.
*/
if(pContext == NULL) {
return(SSL_SECURITY_STATUS_NOOPT);
}
/*
* Obtain the context's current history entry (it holds
* security info).
*/
pHistEnt = SHIST_GetCurrent(&(pContext->hist));
if(pHistEnt == NULL) {
/*
* Nothing loaded, Confusion ensues here.
* If we've a parent context, then our security
* is a noopt (shouldn't be counted towards
* the whole).
* If we've no parent context, then our security
* is off.
* This allows grids to have empty panes, but to
* still be secure if all grids which have
* something loaded are secure.
*/
if(pContext->grid_parent == NULL) {
return(SSL_SECURITY_STATUS_OFF);
}
else {
return(SSL_SECURITY_STATUS_NOOPT);
}
}
/*
* Our security status.
*/
iRetval = pHistEnt->security_on;
/*
* If we're a grid parent, our security status
* is a noopt (doesn't affect the whole).
* This allows the parent grid document to be non
* secure, and all the inner grids to be secure,
* and therefore the document should still be
* considered secure as a whole.
*/
if(XP_ListIsEmpty(pContext->grid_children)) {
return(iRetval);
}
iRetval = SSL_SECURITY_STATUS_NOOPT;
/*
* Go through each child, getting it's security status.
* We combine them all and return that value.
*/
iIndex = 1;
while((pChild = (MWContext *)XP_ListGetObjectNum(
pContext->grid_children, iIndex++))) {
switch(XP_GetSecurityStatus(pChild)) {
case SSL_SECURITY_STATUS_NOOPT:
/*
* No definable security status. Don't
* change our current value.
*/
break;
case SSL_SECURITY_STATUS_OFF:
/*
* No need in continuing if we're turning
* off security altogether.
*/
return(SSL_SECURITY_STATUS_OFF);
break;
case SSL_SECURITY_STATUS_ON_LOW:
/*
* Change the return value to lower security.
*/
iRetval = SSL_SECURITY_STATUS_ON_LOW;
break;
case SSL_SECURITY_STATUS_ON_HIGH:
/*
* If we're currently noopt, then we should
* change the security status to HIGH.
* Otherwise, don't change the cumulative status
* which could be lower than HIGH.
*/
if(iRetval == SSL_SECURITY_STATUS_NOOPT) {
iRetval = SSL_SECURITY_STATUS_ON_HIGH;
}
break;
#ifdef FORTEZZA
case SSL_SECURITY_STATUS_FORTEZZA:
/*
* If any fortezza, set to fortezza..
*/
iRetval = SSL_SECURITY_STATUS_FORTEZZA;
break;
#endif
default:
/*
* Shouldn't be here, unless new security status
* introduced.
*/
XP_ASSERT(0);
break;
}
}
/*
* Context is somewhat secure, either high or low.
* This could also be noopt, meaning no definable security,
* so turn off your UI as if SSL_SECURITY_STATUS_OFF.
* We can't just change the return value of
* SSL_SECURITY_STATUS_NOOPT to OFF because this
* breaks the recursive correctness of this routine.
* Handle it accordingly.
*/
return(iRetval);
}
/*
* Count the contexts of the said type.
* The second parameter is a flag indicating wether or not the contexts
* counted can have parent contexts (top level context switch).
*/
int XP_ContextCount(MWContextType cxType, XP_Bool bTopLevel)
{
int iRetval = 0;
int iTraverse;
MWContext *pContext;
/*
* Loop through the contexts.
*/
for(iTraverse = 1; iTraverse <= XP_ListCount(xp_GlobalContextList); iTraverse++) {
pContext = (MWContext *)XP_ListGetObjectNum(xp_GlobalContextList, iTraverse);
if(cxType == MWContextAny || pContext->type == cxType) {
/*
* See if there's to be no parent.
*/
if(bTopLevel == FALSE || pContext->is_grid_cell == FALSE) {
iRetval++;
}
}
}
return(iRetval);
}
#endif /* MOZILLA_CLIENT */