about summary refs log blame commit diff stats
path: root/src/LYMap.c
blob: f15e68a2bcf5886f51a1e92602ed023083709070 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 * $LynxId: GridText.h,v 1.69 2012/02/12 23:25:38 tom Exp $
 *
 * Specialities of GridText as subclass of HText
 */
#ifndef LYGRIDTEXT_H
#define LYGRIDTEXT_H

#include <HText.h>		/* Superclass */

#ifndef HTFORMS_H
#include <HTForms.h>
#endif /* HTFORMS_H */

#include <HTFont.h>

#include <HTCJK.h>

#ifdef __cplusplus
extern "C" {
#endif
#define TABSTOP 8
#define SPACES  "        "	/* must be at least TABSTOP spaces long */
#define SPLAT   '.'
#define NOCHOP 0
#define CHOP   1
/* just for information:
US-ASCII control characters <32 which are not defined in Unicode standard
=00	U+0000	NULL
=01	U+0001	START OF HEADING
=02	U+0002	START OF TEXT
=03	U+0003	END OF TEXT
=04	U+0004	END OF TRANSMISSION
=05	U+0005	ENQUIRY
=06	U+0006	ACKNOWLEDGE
=07	U+0007	BELL
=08	U+0008	BACKSPACE
=09	U+0009	HORIZONTAL TABULATION
=0A	U+000A	LINE FEED
=0B	U+000B	VERTICAL TABULATION
=0C	U+000C	FORM FEED
=0D	U+000D	CARRIAGE RETURN
=0E	U+000E	SHIFT OUT
=0F	U+000F	SHIFT IN
=10	U+0010	DATA LINK ESCAPE
=11	U+0011	DEVICE CONTROL ONE
=12	U+0012	DEVICE CONTROL TWO
=13	U+0013	DEVICE CONTROL THREE
=14	U+0014	DEVICE CONTROL FOUR
=15	U+0015	NEGATIVE ACKNOWLEDGE
=16	U+0016	SYNCHRONOUS IDLE
=17	U+0017	END OF TRANSMISSION BLOCK
=18	U+0018	CANCEL
=19	U+0019	END OF MEDIUM
=1A	U+001A	SUBSTITUTE
=1B	U+001B	ESCAPE
=1C	U+001C	FILE SEPARATOR
=1D	U+001D	GROUP SEPARATOR
=1E	U+001E	RECORD SEPARATOR
=1F	U+001F	UNIT SEPARATOR
=7F	U+007F	DELETE
*/ extern int HTCurSelectGroupType;
    extern char *HTCurSelectGroupSize;

#if defined(VMS) && defined(VAXC) && !defined(__DECC)
    extern int HTVirtualMemorySize;
#endif				/* VMS && VAXC && !__DECC */

    extern HTChildAnchor *HText_childNextNumber(int n, void **prev);
    extern int HText_findAnchorNumber(void *avoid);
    extern void HText_FormDescNumber(int n, const char **desc);

/*	Is there any file left?
*/
    extern BOOL HText_canScrollUp(HText *text);
    extern BOOL HText_canScrollDown(void);

/*	Move display within window
*/
    extern void HText_scrollUp(HText *text);	/* One page */
    extern void HText_scrollDown(HText *text);	/* One page */
    extern void HText_scrollTop(HText *text);
    extern void HText_scrollBottom(HText *text);
    extern void HText_pageDisplay(int line_num, char *target);
    extern BOOL HText_pageHasPrevTarget(void);

    extern int HText_LinksInLines(HText *text, int line_num, int Lines);

    extern int HText_getAbsLineNumber(HText *text, int anchor_number);
    extern int HText_closestAnchor(HText *text, int offset);
    extern int HText_locateAnchor(HText *text, int anchor_number);
    extern int HText_anchorRelativeTo(HText *text, int top_lineno, int anchor_num);

    extern void HText_setLastChar(HText *text, int ch);
    extern char HText_getLastChar(HText *text);

    extern int HText_sourceAnchors(HText *text);
    extern void HText_setStale(HText *text);
    extern void HText_refresh(HText *text);
    extern const char *HText_getTitle(void);
    extern const char *HText_getSugFname(void);
    extern void HTCheckFnameForCompression(char **fname,
					   HTParentAnchor *anchor,
					   int strip_ok);
    extern const char *HText_getLastModified(void);
    extern const char *HText_getDate(void);
    extern const char *HText_getHttpHeaders(void);
    extern const char *HText_getServer(void);
    extern const char *HText_getOwner(void);
    extern const char *HText_getContentBase(void);
    extern const char *HText_getContentLocation(void);
    extern const char *HText_getMessageID(void);
    extern const char *HText_getRevTitle(void);

#ifdef USE_COLOR_STYLE
    extern const char *HText_getStyle(void);
#endif
    extern void HText_setMainTextOwner(const char *owner);
    extern void print_wwwfile_to_fd(FILE *fp, int is_email, int is_reply);
    extern BOOL HText_select(HText *text);
    extern BOOL HText_POSTReplyLoaded(DocInfo *doc);
    extern BOOL HTFindPoundSelector(const char *selector);
    extern int HTGetRelLinkNum(int num, int rel, int cur);
    extern
/*
 * $LynxId: LYMap.c,v 1.45 2013/04/30 23:16:59 tom Exp $
 *			Lynx Client-side Image MAP Support	       LYMap.c
 *			==================================
 *
 *	Author: FM	Foteos Macrides (macrides@sci.wfbr.edu)
 *
 */

#include <HTUtils.h>
#include <HTTP.h>
#include <HTAnchor.h>
#include <HTAccess.h>
#include <HTFormat.h>
#include <HTParse.h>
#include <HTAlert.h>
#include <LYUtils.h>
#include <LYMap.h>
#include <GridText.h>
#include <LYGlobalDefs.h>
#include <LYKeymap.h>
#include <LYCharUtils.h>
#include <LYCharSets.h>
#include <LYStrings.h>

#ifdef DIRED_SUPPORT
#include <LYUpload.h>
#include <LYLocal.h>
#endif

#include <LYexit.h>
#include <LYLeaks.h>

#define NO_MAP_TITLE "[USEMAP]"

typedef struct _LYMapElement {
    char *address;
    char *title;
    BOOLEAN intern_flag;
} LYMapElement;

typedef struct _LYImageMap {
    char *address;
    char *title;
    HTList *elements;
} LYImageMap;

static HTList *LynxMaps = NULL;

BOOL LYMapsOnly = FALSE;

/*
 * Utility for freeing a list of MAPs.
 */
void ImageMapList_free(HTList *theList)
{
    LYImageMap *map;
    LYMapElement *element;
    HTList *cur = theList;
    HTList *current;

    if (!cur)
	return;

    while (NULL != (map = (LYImageMap *) HTList_nextObject(cur))) {
	FREE(map->address);
	FREE(map->title);
	if (map->elements) {
	    current = map->elements;
	    while (NULL !=
		   (element = (LYMapElement *) HTList_nextObject(current))) {
		FREE(element->address);
		FREE(element->title);
		FREE(element);
	    }
	    HTList_delete(map->elements);
	    map->elements = NULL;
	}
	FREE(map);
    }
    HTList_delete(theList);
    return;
}

#ifdef LY_FIND_LEAKS
/*
 * Utility for freeing the global list of MAPs.  - kw
 */
static void LYLynxMaps_free(void)
{
    ImageMapList_free(LynxMaps);
    LynxMaps = NULL;
    return;
}
#endif /* LY_FIND_LEAKS */

/*
 * We keep two kinds of lists:
 * - A global list (LynxMaps) shared by MAPs from all documents that
 *   do not have POST data.
 * - For each response to a POST which contains MAPs, a list specific
 *   to this combination of URL and post_data.  It is kept in the
 *   HTParentAnchor structure and is freed when the document is removed
 *   from memory, in the course of normal removal of anchors.
 *   MAPs from POST responses can only be accessed via internal links,
 *   i.e., from within the same document (with the same post_data).
 *   The notion of "same document" is extended, so that LYNXIMGMAP:
 *   and List Page screens are logically part of the document on which
 *   they are based. - kw
 *
 * If track_internal_links is false, only the global list will be used
 * for all MAPs.
 *
 */

/*
 * Utility for creating an LYImageMap list, if it doesn't exist already, adding
 * LYImageMap entry structures if needed, and removing any LYMapElements in a
 * pre-existing LYImageMap entry so that it will have only those from AREA tags
 * for the current analysis of MAP element content.  - FM
 */
BOOL LYAddImageMap(char *address,
		   char *title,
		   HTParentAnchor *node_anchor)
{
    LYImageMap *tmp = NULL;
    LYImageMap *old = NULL;
    HTList *cur = NULL;
    HTList *theList = NULL;
    HTList *curele = NULL;
    LYMapElement *ele = NULL;

    if (isEmpty(address))
	return FALSE;
    if (!(node_anchor && node_anchor->address))
	return FALSE;

    /*
     * Set theList to either the global LynxMaps list or, if we are associated
     * with post data, the specific list.  The list is created if it doesn't
     * already exist.  - kw
     */
    if (track_internal_links && node_anchor->post_data) {
	/*
	 * We are handling a MAP element found while parsing node_anchor's
	 * stream of data, and node_anchor has post_data associated and should
	 * therefore represent a POST response, so use the specific list.  - kw
	 */
	theList = node_anchor->imaps;
	if (!theList) {
	    theList = node_anchor->imaps = HTList_new();
	}
    } else {
	if (!LynxMaps) {
	    LynxMaps = HTList_new();
#ifdef LY_FIND_LEAKS
	    atexit(LYLynxMaps_free);
#endif
	}
	theList = LynxMaps;
    }

    if (theList) {
	cur = theList;
	while (NULL != (old = (LYImageMap *) HTList_nextObject(cur))) {
	    if (old->address == 0)	/* shouldn't happen */
		continue;
	    if (!strcmp(old->address, address)) {
		FREE(old->address);
		FREE(old->title);
		if (old->elements) {
		    curele = old->elements;
		    while (NULL !=
			   (ele = (LYMapElement *) HTList_nextObject(curele))) {
			FREE(ele->address);
			FREE(ele->title);
			FREE(ele);
		    }
		    HTList_delete(old->elements);
		    old->elements = NULL;
		}
		break;
	    }
	}
    }

    tmp = (old != NULL) ?
	old : typecalloc(LYImageMap);
    if (tmp == NULL) {
	outofmem(__FILE__, "LYAddImageMap");
	return FALSE;
    }
    StrAllocCopy(tmp->address, address);
    if (non_empty(title))
	StrAllocCopy(tmp->title, title);
    if (tmp != old)
	HTList_addObject(theList, tmp);
    return TRUE;
}

/*
 * Utility for adding LYMapElement's to LYImageMap's
 * in the appropriate list. - FM
 */
BOOL LYAddMapElement(char *map,
		     char *address,
		     char *title,
		     HTParentAnchor *node_anchor,
		     int intern_flag GCC_UNUSED)
{
    LYMapElement *tmp = NULL;
    LYImageMap *theMap = NULL;
    HTList *theList = NULL;
    HTList *cur = NULL;

    if (isEmpty(map) || isEmpty(address))
	return FALSE;
    if (!(node_anchor && node_anchor->address))
	return FALSE;

    /*
     * Set theList to either the global LynxMaps list or, if we are associated
     * with post data, the specific list.  The list should already exist, since
     * this function is only called if the AREA tag we are handling was within
     * a MAP element in node_anchor's stream of data, so that LYAddImageMap has
     * been called.  - kw
     */
    if (track_internal_links && node_anchor->post_data) {
	/*
	 * We are handling an AREA tag found while parsing node_anchor's stream
	 * of data, and node_anchor has post_data associated and should
	 * therefore represent a POST response, so use the specific list.  - kw
	 */
	theList = node_anchor->imaps;
	if (!theList) {
	    return FALSE;
	}
    } else {
	if (!LynxMaps)
	    LYAddImageMap(map, NULL, node_anchor);
	theList = LynxMaps;
    }

    cur = theList;
    while (NULL != (theMap = (LYImageMap *) HTList_nextObject(cur))) {
	if (!strcmp(theMap->address, map)) {
	    break;
	}
    }
    if (!theMap)
	return FALSE;
    if (!theMap->elements)
	theMap->elements = HTList_new();
    cur = theMap->elements;
    while (NULL != (tmp = (LYMapElement *) HTList_nextObject(cur))) {
	if (!strcmp(tmp->address, address)) {
	    FREE(tmp->address);
	    FREE(tmp->title);
	    HTList_removeObject(theMap->elements, tmp);
	    FREE(tmp);
	    break;
	}
    }

    tmp = typecalloc(LYMapElement);
    if (tmp == NULL) {
	perror("Out of memory in LYAddMapElement");
	return FALSE;
    }
    StrAllocCopy(tmp->address, address);
    if (non_empty(title))
	StrAllocCopy(tmp->title, title);
    else
	StrAllocCopy(tmp->title, address);
    if (track_internal_links)
	tmp->intern_flag = intern_flag;
    HTList_appendObject(theMap->elements, tmp);

    CTRACE((tfp,
	    "LYAddMapElement\n\tmap     %s\n\taddress %s\n\ttitle   %s)\n",
	    NonNull(map), NonNull(address), NonNull(title)));

    return TRUE;
}

/*
 * Utility for checking whether an LYImageMap entry with a given address
 * already exists in the LynxMaps structure.  - FM
 */
BOOL LYHaveImageMap(char *address)
{
    LYImageMap *Map;
    HTList *cur = LynxMaps;

    if (!(cur && non_empty(address)))
	return FALSE;

    while (NULL != (Map = (LYImageMap *) HTList_nextObject(cur))) {
	if (!strcmp(Map->address, address)) {
	    return TRUE;
	}
    }

    return FALSE;
}

/*
 * Fills in a DocAddress structure for getting the HTParentAnchor of the
 * underlying resource.  ALso returns a pointer to that anchor in
 * *punderlying if we are dealing with POST data.  - kw
 *
 * address  is the address of the underlying resource, i.e., the one
 *	    containing the MAP element, the MAP's name appended as
 *	    fragment is ignored.
 * anAnchor is the LYNXIMGMAP: anchor; if it is associated with POST
 *	    data, we want the specific list, otherwise the global list.
 */
static void fill_DocAddress(DocAddress *wwwdoc,
			    const char *address,
			    HTParentAnchor *anAnchor,
			    HTParentAnchor **punderlying)
{
    char *doc_address = NULL;
    HTParentAnchor *underlying;

    StrAllocCopy(doc_address, address);
    if (anAnchor && anAnchor->post_data) {
	wwwdoc->address = doc_address;
	wwwdoc->post_data = anAnchor->post_data;
	wwwdoc->post_content_type = anAnchor->post_content_type;
	wwwdoc->bookmark = NULL;
	wwwdoc->isHEAD = FALSE;
	wwwdoc->safe = FALSE;
	underlying = HTAnchor_findAddress(wwwdoc);
	if (underlying->safe)
	    wwwdoc->safe = TRUE;
	if (punderlying)
	    *punderlying = underlying;
    } else {
	wwwdoc->address = doc_address;
	wwwdoc->post_data = NULL;
	wwwdoc->post_content_type = NULL;
	wwwdoc->bookmark = NULL;
	wwwdoc->isHEAD = FALSE;
	wwwdoc->safe = FALSE;
	if (punderlying)
	    *punderlying = NULL;
    }
}

/*
 * Get the appropriate list for creating a LYNXIMGMAP:  pseudo- document: 
 * either the global list (LynxMaps), or the specific list if a List Page for a
 * POST response is requested.  Also fill in the DocAddress structure etc.  by
 * calling fill_DocAddress().
 *
 * address is the address of the underlying resource, i.e., the one
 *	   containing the MAP element, the MAP's name appended as
 *	   fragment is ignored.
 * anchor  is the LYNXIMGMAP: anchor for which LYLoadIMGmap() is
 *	   requested; if it is associated with POST data, we want the
 *	   specific list for this combination of address+post_data.
 *
 * if track_internal_links is false, the Anchor passed to
 * LYLoadIMGmap() will never have post_data, so that the global list
 * will be used. - kw
 */
static HTList *get_the_list(DocAddress *wwwdoc,
			    const char *address,
			    HTParentAnchor *anchor,
			    HTParentAnchor **punderlying)
{
    if (anchor && anchor->post_data) {
	fill_DocAddress(wwwdoc, address, anchor, punderlying);
	if (non_empty(punderlying))
	    return (*punderlying)->imaps;
	return anchor->imaps;
    } else {
	fill_DocAddress(wwwdoc, address, NULL, punderlying);
	return LynxMaps;
    }
}

/*	LYLoadIMGmap - F.Macrides (macrides@sci.wfeb.edu)
 *	------------
 *	Create a text/html stream with a list of links
 *	for HyperText References in AREAs of a MAP.
 */

static int LYLoadIMGmap(const char *arg,
			HTParentAnchor *anAnchor,
			HTFormat format_out,
			HTStream *sink)
{
    HTFormat format_in = WWW_HTML;
    HTStream *target = NULL;
    char *buf = NULL;
    LYMapElement *tmp = NULL;
    LYImageMap *theMap = NULL;
    char *MapTitle = NULL;
    char *MapAddress = NULL;
    HTList *theList;
    HTList *cur = NULL;
    const char *address = NULL;
    char *cp = NULL;
    DocAddress WWWDoc;
    HTParentAnchor *underlying;
    BOOL old_cache_setting = LYforce_no_cache;
    BOOL old_reloading = reloading;
    HTFormat old_format_out = HTOutputFormat;

    if (isLYNXIMGMAP(arg)) {
	address = (arg + LEN_LYNXIMGMAP);
    }
    if (!(address && strchr(address, ':'))) {
	HTAlert(MISDIRECTED_MAP_REQUEST);
	return (HT_NOT_LOADED);
    }

    theList = get_the_list(&WWWDoc, address, anAnchor, &underlying);
    if (WWWDoc.safe)
	anAnchor->safe = TRUE;

    if (!theList) {
	if (anAnchor->post_data && !WWWDoc.safe &&
	    ((underlying && underlying->document && !LYforce_no_cache) ||
	     HTConfirm(CONFIRM_POST_RESUBMISSION) != TRUE)) {
	    HTAlert(FAILED_MAP_POST_REQUEST);
	    return (HT_NOT_LOADED);
	}
	LYforce_no_cache = TRUE;
	reloading = TRUE;
	HTOutputFormat = WWW_PRESENT;
	LYMapsOnly = TRUE;
	if (!HTLoadAbsolute(&WWWDoc)) {
	    LYforce_no_cache = old_cache_setting;
	    reloading = old_reloading;
	    HTOutputFormat = old_format_out;
	    LYMapsOnly = FALSE;
	    HTAlert(MAP_NOT_ACCESSIBLE);
	    return (HT_NOT_LOADED);
	}
	LYforce_no_cache = old_cache_setting;
	reloading = old_reloading;
	HTOutputFormat = old_format_out;
	LYMapsOnly = FALSE;
	theList = get_the_list(&WWWDoc, address, anAnchor, &underlying);
    }

    if (!theList) {
	HTAlert(MAPS_NOT_AVAILABLE);
	return (HT_NOT_LOADED);
    }

    cur = theList;
    while (NULL != (theMap = (LYImageMap *) HTList_nextObject(cur))) {
	if (!strcmp(theMap->address, address)) {
	    break;
	}
    }
    if (theMap && HTList_count(theMap->elements) == 0) {
	/*
	 * We found a MAP without any usable AREA.  Fake a redirection to the
	 * address with fragment.  We do this even for post data (internal link
	 * within a document with post data) if it will not result in an
	 * unwanted network request.  - kw
	 */
	if (!anAnchor->post_data) {
	    StrAllocCopy(redirecting_url, address);
	    return (HT_REDIRECTING);
	} else if (WWWDoc.safe ||
		   (underlying->document && !anAnchor->document &&
		    (LYinternal_flag || LYoverride_no_cache))) {
	    StrAllocCopy(redirecting_url, address);
	    redirect_post_content = TRUE;
	    return (HT_REDIRECTING);
	}
    }
    if (!(theMap && theMap->elements)) {
	if (anAnchor->post_data && !WWWDoc.safe &&
	    ((underlying && underlying->document && !LYforce_no_cache) ||
	     HTConfirm(CONFIRM_POST_RESUBMISSION) != TRUE)) {
	    HTAlert(FAILED_MAP_POST_REQUEST);
	    return (HT_NOT_LOADED);
	}
	LYforce_no_cache = TRUE;
	reloading = TRUE;
	HTOutputFormat = WWW_PRESENT;
	LYMapsOnly = TRUE;
	if (!HTLoadAbsolute(&WWWDoc)) {
	    LYforce_no_cache = old_cache_setting;
	    reloading = old_reloading;
	    HTOutputFormat = old_format_out;
	    LYMapsOnly = FALSE;
	    HTAlert(MAP_NOT_ACCESSIBLE);
	    return (HT_NOT_LOADED);
	}
	LYforce_no_cache = old_cache_setting;
	reloading = old_reloading;
	HTOutputFormat = old_format_out;
	LYMapsOnly = FALSE;
	cur = get_the_list(&WWWDoc, address, anAnchor, &underlying);
	while (NULL != (theMap = (LYImageMap *) HTList_nextObject(cur))) {
	    if (!strcmp(theMap->address, address)) {
		break;
	    }
	}
	if (!(theMap && theMap->elements)) {
	    HTAlert(MAP_NOT_AVAILABLE);
	    return (HT_NOT_LOADED);
	}
    }
    if (track_internal_links)
	anAnchor->no_cache = TRUE;

    target = HTStreamStack(format_in,
			   format_out,
			   sink, anAnchor);

    if (!target || target == NULL) {
	HTSprintf0(&buf, CANNOT_CONVERT_I_TO_O,
		   HTAtom_name(format_in), HTAtom_name(format_out));
	HTAlert(buf);
	FREE(buf);
	return (HT_NOT_LOADED);
    }

    if (non_empty(theMap->title)) {
	StrAllocCopy(MapTitle, theMap->title);
    } else if (non_empty(anAnchor->title)) {
	StrAllocCopy(MapTitle, anAnchor->title);
    } else if (non_empty(LYRequestTitle) &&
	       strcasecomp(LYRequestTitle, NO_MAP_TITLE)) {
	StrAllocCopy(MapTitle, LYRequestTitle);
    } else if ((cp = strchr(address, '#')) != NULL) {
	StrAllocCopy(MapTitle, (cp + 1));
    }
    if (isEmpty(MapTitle)) {
	StrAllocCopy(MapTitle, NO_MAP_TITLE);
    } else {
	LYEntify(&MapTitle, TRUE);
    }

#define PUTS(buf)    (*target->isa->put_block)(target, buf, (int) strlen(buf))

    HTSprintf0(&buf, "<html>\n<head>\n");
    PUTS(buf);
    HTSprintf0(&buf, "<META %s content=\"text/html;charset=%s\">\n",
	       "http-equiv=\"content-type\"",
	       LYCharSet_UC[current_char_set].MIMEname);
    PUTS(buf);
    /*
     * This page is a list of titles and anchors for them.  Since titles
     * already passed SGML/HTML stage they are converted to current_char_set. 
     * That is why we insist on META charset for this page.
     */
    HTSprintf0(&buf, "<title>%s</title>\n", MapTitle);
    PUTS(buf);
    HTSprintf0(&buf, "</head>\n<body>\n");
    PUTS(buf);

    HTSprintf0(&buf, "<h1><em>%s</em></h1>\n", MapTitle);
    PUTS(buf);

    StrAllocCopy(MapAddress, address);
    LYEntify(&MapAddress, FALSE);
    HTSprintf0(&buf, "<h2><em>MAP:</em>&nbsp;%s</h2>\n", MapAddress);
    PUTS(buf);

    HTSprintf0(&buf, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
					"ol" : "ul"));
    PUTS(buf);
    cur = theMap->elements;
    while (NULL != (tmp = (LYMapElement *) HTList_nextObject(cur))) {
	StrAllocCopy(MapAddress, tmp->address);
	LYEntify(&MapAddress, FALSE);
	PUTS("<li><a href=\"");
	PUTS(MapAddress);
	PUTS("\"");
	if (track_internal_links && tmp->intern_flag) {
	    PUTS(" TYPE=\"internal link\"");
	}
	PUTS("\n>");
	LYformTitle(&MapTitle, tmp->title);
	LYEntify(&MapTitle, TRUE);
	PUTS(MapTitle);
	PUTS("</a>\n");
    }
    HTSprintf0(&buf, "</%s>\n</body>\n</html>\n",
	       ((keypad_mode == NUMBERS_AS_ARROWS)
		? "ol"
		: "ul"));
    PUTS(buf);

    (*target->isa->_free) (target);
    FREE(MapAddress);
    FREE(MapTitle);
    FREE(buf);
    return (HT_LOADED);
}

void LYPrintImgMaps(FILE *fp)
{
    const char *only = HTLoadedDocumentURL();
    size_t only_len = strlen(only);
    HTList *outer = LynxMaps;
    HTList *inner;
    LYImageMap *map;
    LYMapElement *elt;
    int count;

    if (HTList_count(outer) > 0) {
	while (NULL != (map = (LYImageMap *) HTList_nextObject(outer))) {
	    if (only_len != 0) {
		if (StrNCmp(only, map->address, only_len)
		    || (map->address[only_len] != '\0'
			&& map->address[only_len] != '#')) {
		    continue;
		}
	    }
	    fprintf(fp, "\n%s\n", isEmpty(map->title) ? NO_MAP_TITLE : map->title);
	    fprintf(fp, "%s\n", map->address);
	    inner = map->elements;
	    count = 0;
	    while (NULL != (elt = (LYMapElement *) HTList_nextObject(inner))) {
		fprintf(fp, "%4d. %s", ++count, elt->address);
		if (track_internal_links && elt->intern_flag)
		    fprintf(fp, " TYPE=\"internal link\"");
		fprintf(fp, "\n");
	    }
	}
    }
}

#ifdef GLOBALDEF_IS_MACRO
#define _LYIMGMAP_C_GLOBALDEF_1_INIT { "LYNXIMGMAP", LYLoadIMGmap, 0}
GLOBALDEF(HTProtocol, LYLynxIMGmap, _LYIMGMAP_C_GLOBALDEF_1_INIT);
#else
GLOBALDEF HTProtocol LYLynxIMGmap =
{"LYNXIMGMAP", LYLoadIMGmap, 0};
#endif /* GLOBALDEF_IS_MACRO */