about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorThomas E. Dickey <dickey@invisible-island.net>1997-01-29 21:25:58 -0500
committerThomas E. Dickey <dickey@invisible-island.net>1997-01-29 21:25:58 -0500
commitc3ec4181d988501e4d7116f32c669d5ca69e7060 (patch)
tree3a19fc17f13ca34edf02b209e19464f8041984cd /src
parent6bd78b38830217fa268e678d9637116ec516bf0e (diff)
downloadlynx-snapshots-c3ec4181d988501e4d7116f32c669d5ca69e7060.tar.gz
snapshot of project "lynx", label v2_6fm_970129
Diffstat (limited to 'src')
-rw-r--r--src/GridText.c827
-rw-r--r--src/GridText.h14
-rw-r--r--src/HTAlert.c284
-rw-r--r--src/HTAlert.h29
-rw-r--r--src/HTFWriter.c21
-rw-r--r--src/HTForms.h2
-rw-r--r--src/HTInit.c7
-rw-r--r--src/HTML.c3297
-rw-r--r--src/HTML.h178
-rw-r--r--src/LYBookmark.c329
-rw-r--r--src/LYBookmark.h3
-rw-r--r--src/LYCgi.c9
-rw-r--r--src/LYCharUtils.c866
-rw-r--r--src/LYCharUtils.h81
-rw-r--r--src/LYClean.c100
-rw-r--r--src/LYCookie.c1262
-rw-r--r--src/LYCookie.h23
-rw-r--r--src/LYCurses.c279
-rw-r--r--src/LYForms.c1
-rw-r--r--src/LYGetFile.c290
-rw-r--r--src/LYGlobalDefs.h12
-rw-r--r--src/LYHistory.c408
-rw-r--r--src/LYHistory.h7
-rw-r--r--src/LYKeymap.c30
-rw-r--r--src/LYKeymap.h59
-rw-r--r--src/LYLocal.c99
-rw-r--r--src/LYLocal.h3
-rw-r--r--src/LYMail.c473
-rw-r--r--src/LYMain.c1405
-rw-r--r--src/LYMainLoop.c1987
-rw-r--r--src/LYMap.c2
-rw-r--r--src/LYNews.c1
-rw-r--r--src/LYOptions.c270
-rw-r--r--src/LYOptions.h1
-rw-r--r--src/LYPrint.c98
-rw-r--r--src/LYReadCFG.c937
-rw-r--r--src/LYShowInfo.c4
-rw-r--r--src/LYStructs.h15
-rw-r--r--src/LYTraversal.c14
-rw-r--r--src/LYUtils.c1205
-rw-r--r--src/LYUtils.h65
-rw-r--r--src/LYexit.c174
-rw-r--r--src/LYrcFile.c1021
-rw-r--r--src/Makefile3
-rw-r--r--src/descrip.mms10
45 files changed, 10626 insertions, 5579 deletions
diff --git a/src/GridText.c b/src/GridText.c
index e988c7ba..b4b92503 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -55,16 +55,14 @@ extern HTCJKlang HTCJK;
 extern HTStyleSheet * styleSheet;	/* Default or overridden */
 
 extern int display_lines; /* number of lines in display */
-extern BOOLEAN ignore_excess; /* flag to ignore chararcters at wrap column */
-extern char HTML_Last_Char;
 
 /*	Exports
 */ 
 PUBLIC HText * HTMainText = NULL;		/* Equivalent of main window */
 PUBLIC HTParentAnchor * HTMainAnchor = NULL;	/* Anchor for HTMainText */
 
-PUBLIC char * HTAppName = "Lynx";      /* Application name */
-PUBLIC char * HTAppVersion = LYNX_VERSION;        /* Application version */
+PUBLIC char * HTAppName = "Lynx";		/* Application name */
+PUBLIC char * HTAppVersion = LYNX_VERSION;	/* Application version */
 
 PUBLIC int HTFormNumber = 0;
 PUBLIC int HTFormFields = 0;
@@ -91,21 +89,21 @@ typedef struct _line {
 	char	data[1];		/* Space for terminator at least! */
 } HTLine;
 
-#define LINE_SIZE(l) (sizeof(HTLine)+(l))	/* allow for terminator */
+#define LINE_SIZE(l) (sizeof(HTLine)+(l))	/* Allow for terminator */
 
 typedef struct _TextAnchor {
 	struct _TextAnchor *	next;
 	int			number;		/* For user interface */
 	int			start;		/* Characters */
-        int			line_pos;       /* position in text */
+        int			line_pos;	/* Position in text */
 	int			extent;		/* Characters */
-	int			line_num;       /* place in document */
-	char *		        hightext;       /* the link text */
-	char *		        hightext2;       /* a second line*/
-        int 		    	hightext2offset; /* offset from left */
-	int			link_type;	/* normal or form? */
-	FormInfo *		input_field;	/* info for form links */
-	BOOL			show_anchor;    /* show the anchor? */
+	int			line_num;	/* Place in document */
+	char *		        hightext;	/* The link text */
+	char *		        hightext2;	/* A second line*/
+        int 		    	hightext2offset;/* offset from left */
+	int			link_type;	/* Normal or form? */
+	FormInfo *		input_field;	/* Info for form links */
+	BOOL			show_anchor;	/* Show the anchor? */
 	HTChildAnchor *		anchor;
 } TextAnchor;
 
@@ -123,15 +121,18 @@ typedef struct _HTTabID {
 struct _HText {
 	HTParentAnchor *	node_anchor;
 	HTLine * 		last_line;
-	int			lines;		/* Number of them */
+	int			Lines;		/* Number of them */
 	int			chars;		/* Number of them */
 	TextAnchor *		first_anchor;	/* Singly linked list */
 	TextAnchor *		last_anchor;
 	int			last_anchor_number;	/* user number */
-	BOOL			source;		/* is the text source? */
+	BOOL			source;		/* Is the text source? */
 	BOOL			toolbar;	/* Toolbar set? */
 	HTList *		tabs;		/* TAB IDs */
 	BOOL			no_cache;	/* Always refresh? */
+	char			LastChar;	/* For aborbing white space */
+	BOOL			IgnoreExcess;	/* Ignore chars at wrap point */
+
 /* For Internal use: */	
 	HTStyle *		style;			/* Current style */
 	int			display_on_the_fly;	/* Lines left */
@@ -186,7 +187,8 @@ PRIVATE int HText_TrueLineSize PARAMS((HTLine *line));
 /*			Creation Method
 **			---------------
 */
-PUBLIC HText *	HText_new ARGS1(HTParentAnchor *,anchor)
+PUBLIC HText *	HText_new ARGS1(
+	HTParentAnchor *,	anchor)
 {
 #if defined(VMS) && defined(VAXC) && !defined(__DECC)
 #include <lib$routines.h>
@@ -194,7 +196,8 @@ PUBLIC HText *	HText_new ARGS1(HTParentAnchor *,anchor)
 #endif /* VMS && VAXC && !__DECC */
     HTLine * line = NULL;
     HText * self = (HText *) calloc(1, sizeof(*self));
-    if (!self) return self;
+    if (!self)
+        return self;
     
 #if defined(VMS) && defined (VAXC) && !defined(__DECC)
     status = lib$stat_vm(&VMType, &VMTotal);
@@ -245,7 +248,7 @@ PUBLIC HText *	HText_new ARGS1(HTParentAnchor *,anchor)
         outofmem(__FILE__, "HText_New");
     line->next = line->prev = line;
     line->offset = line->size = 0;
-    self->lines = self->chars = 0;
+    self->Lines = self->chars = 0;
     self->first_anchor = self->last_anchor = NULL;
     self->style = &default_style;
     self->top_of_screen = 0;
@@ -256,6 +259,9 @@ PUBLIC HText *	HText_new ARGS1(HTParentAnchor *,anchor)
     self->tabs = NULL;
     self->no_cache = ((anchor->no_cache || anchor->post_data) ?
     							  YES : NO);
+    self->LastChar = '\0';
+    self->IgnoreExcess = FALSE;
+
     if (HTOutputFormat == WWW_SOURCE)
         self->source = YES;
     else
@@ -285,13 +291,13 @@ PUBLIC HText *	HText_new ARGS1(HTParentAnchor *,anchor)
     if (underscore_string[0] != '.') {
         char *p;
 	/*
-	 * Create and array of dots for the UNDERSCORES macro. - FM
+	 *  Create and array of dots for the UNDERSCORES macro. - FM
 	 */
 	memset(underscore_string, '.', (MAX_LINE-1));
         underscore_string[(MAX_LINE-1)] = '\0';
         underscore_string[MAX_LINE] = '\0';
 	/*
-	 * Create and array of underscores for the STARS macro. - FM
+	 *  Create and array of underscores for the STARS macro. - FM
 	 */
 	memset(star_string, '_', (MAX_LINE-1));
         star_string[(MAX_LINE-1)] = '\0';
@@ -310,8 +316,8 @@ PUBLIC HText *	HText_new ARGS1(HTParentAnchor *,anchor)
 **      Stream is assumed open and left open.
 */
 PUBLIC HText *  HText_new2 ARGS2(
-                HTParentAnchor *,       anchor,
-                HTStream*,              stream)
+	HTParentAnchor *,	anchor,
+	HTStream *,		stream)
 
 {
     HText * this = HText_new(anchor);
@@ -326,7 +332,8 @@ PUBLIC HText *  HText_new2 ARGS2(
 /*	Free Entire Text
 **	----------------
 */
-PUBLIC void HText_free ARGS1(HText *,self)
+PUBLIC void HText_free ARGS1(
+	HText *,	self)
 {
     if (!self)
         return;
@@ -406,11 +413,11 @@ PUBLIC void HText_free ARGS1(HText *,self)
      *  Free the tabs list. - FM
      */
     if (self->tabs) {
-        HTTabID * tab = NULL;
+        HTTabID * Tab = NULL;
 	HTList * cur = self->tabs;
 
-	while (NULL != (tab = (HTTabID *)HTList_nextObject(cur))) {
-	    FREE(tab->name);
+	while (NULL != (Tab = (HTTabID *)HTList_nextObject(cur))) {
+	    FREE(Tab->name);
 	}
 	HTList_delete(self->tabs);
     }
@@ -434,7 +441,8 @@ PUBLIC void HText_free ARGS1(HText *,self)
 /*	Output a line
 **	-------------
 */
-PRIVATE int display_line ARGS1(HTLine *,line)
+PRIVATE int display_line ARGS1(
+	HTLine *,	line)
 {
     register int i,j;
     char buffer[3];
@@ -533,7 +541,8 @@ PRIVATE int display_line ARGS1(HTLine *,line)
 /*	Output the title line
 **	---------------------
 */
-PRIVATE void display_title ARGS1(HText *,text)
+PRIVATE void display_title ARGS1(
+	HText *,	text)
 {
     char *title = NULL;
     char percent[20], format[20];
@@ -564,7 +573,7 @@ PRIVATE void display_title ARGS1(HText *,text)
     /*
      *  Generate the page indicator (percent) string.
      */
-    if ((text->lines + 1) > (display_lines)) {
+    if ((text->Lines + 1) > (display_lines)) {
 	/*
 	 *  In a small attempt to correct the number of pages counted....
 	 *    GAB 07-14-94
@@ -573,10 +582,10 @@ PRIVATE void display_title ARGS1(HText *,text)
 	 *    FM 02-08-95
 	 */
 	int total_pages =
-	 	(((text->lines + 1) + (display_lines - 1))/(display_lines));
+	 	(((text->Lines + 1) + (display_lines - 1))/(display_lines));
 	int start_of_last_page =
-		((text->lines + 1) < display_lines) ? 0 :
-		((text->lines + 1) - display_lines);	
+		((text->Lines + 1) < display_lines) ? 0 :
+		((text->Lines + 1) - display_lines);	
 
 	sprintf(percent, " (p%d of %d)",
 		((text->top_of_screen >= start_of_last_page) ?
@@ -590,9 +599,12 @@ PRIVATE void display_title ARGS1(HText *,text)
     /*
      *  Generate format string.
      */
-    sprintf(format, "%%%d.%ds%%s\n",
-		    (LYcols-1)-strlen(percent),
-		    (LYcols-1)-strlen(percent));
+    sprintf(format, "%s%%%d.%ds%%s\n",
+    		    ((text->top_of_screen > 0 &&
+		      HText_hasToolbar(text)) ?
+		      			  "#" : " "),
+		    (LYcols-2)-strlen(percent),
+		    (LYcols-2)-strlen(percent));
 
     /*
      *  Generate and display the complete title string.
@@ -633,7 +645,10 @@ PRIVATE void display_title ARGS1(HText *,text)
 /*	Output a page
 **	-------------
 */
-PRIVATE void display_page ARGS3(HText *,text, int,line_number, char *, target)
+PRIVATE void display_page ARGS3(
+	HText *,	text,
+	int,		line_number,
+	char *,		target)
 {
     HTLine * line = NULL;
     int i;
@@ -643,6 +658,7 @@ PRIVATE void display_page ARGS3(HText *,text, int,line_number, char *, target)
     FormInfo *FormInfo_ptr;
     BOOL display_flag = FALSE;
     HTAnchor *link_dest;
+    static int last_nlinks = 0;
 
     lynx_mode = NORMAL_LYNX_MODE;
  
@@ -664,15 +680,15 @@ PRIVATE void display_page ARGS3(HText *,text, int,line_number, char *, target)
     }
 
     tmp[0] = tmp[1] = tmp[2] = '\0';
-    last_screen = text->lines - (display_lines-2);
+    last_screen = text->Lines - (display_lines-2);
     line = text->last_line->prev;
 
     /*
      *  Constrain the line number to be within the document.
      */
-    if (text->lines < (display_lines))
+    if (text->Lines < (display_lines))
         line_number = 0;
-    else if (line_number > text->lines)
+    else if (line_number > text->Lines)
         line_number = last_screen;
     else if (line_number < 0)
         line_number = 0;
@@ -783,7 +799,7 @@ PRIVATE void display_page ARGS3(HText *,text, int,line_number, char *, target)
     text->stale = NO;		/* Display is up-to-date */
 
     /*
-     *  Add the anchors to lynx structures.
+     *  Add the anchors to Lynx structures.
      */
     nlinks = 0;
     for (Anchor_ptr=text->first_anchor;  Anchor_ptr != NULL &&
@@ -886,11 +902,36 @@ PRIVATE void display_page ARGS3(HText *,text, int,line_number, char *, target)
 	    }
 	} 
 
-	if (Anchor_ptr == text->last_anchor || nlinks == MAXLINKS)
+	if (Anchor_ptr == text->last_anchor)
+	    /*
+	     *  No more links in document. - FM
+	     */
 	    break;
+
+	if (nlinks == MAXLINKS) {
+	    /*
+	     *  Links array is full.  If interactive, tell user
+	     *  to use half-page or two-line scrolling. - FM
+	     */
+	    if (LYCursesON) {
+		_statusline(MAXLINKS_REACHED);
+		sleep(AlertSecs);
+	    } 
+	    if (TRACE)
+	        fprintf(stderr, "\ndisplay_page: MAXLINKS reached.\n");
+	    break;
+	}
     }
 
     /*
+     *  Free any un-reallocated links[] entries
+     *  from the previous page draw. - FM
+     */
+    for (i = nlinks; i < last_nlinks; i++)
+        FREE(links[i].lname);
+    last_nlinks = nlinks;
+
+    /*
      *  If Anchor_ptr is not NULL and is not pointing to the last
      *  anchor, then there are anchors farther down in the document,
      *  and we need to flag this for traversals.
@@ -918,7 +959,8 @@ PRIVATE void display_page ARGS3(HText *,text, int,line_number, char *, target)
 **
 **	These are used by a parser to build the text in an object
 */
-PUBLIC void HText_beginAppend ARGS1(HText *,text)
+PUBLIC void HText_beginAppend ARGS1(
+	HText *,	text)
 {
     text->permissible_split = 0;
     text->in_line_1 = YES;
@@ -945,12 +987,12 @@ PUBLIC void HText_beginAppend ARGS1(HText *,text)
 */
 #define new_line(text) split_line(text, 0)
 
-PRIVATE void split_line ARGS2(HText *,text, int,split)
+PRIVATE void split_line ARGS2(
+	HText *,	text,
+	int,		split)
 {
     HTStyle * style = text->style;
-#if defined(AIX) || defined(ultrix)
-    HTLine * temp; /* for realloc() substitute. */
-#endif /* AIX || ultrix */	
+    HTLine * temp;
     int spare;
     int indent = text->in_line_1 ?
     	  text->style->indent1st : text->style->leftIndent;
@@ -964,14 +1006,14 @@ PRIVATE void split_line ARGS2(HText *,text, int,split)
     HTLine * line = (HTLine *)calloc(1, LINE_SIZE(MAX_LINE));
 
     ctrl_chars_on_this_line = 0; /*reset since we are going to a new line*/
-    HTML_Last_Char = ' ';
+    text->LastChar = ' ';
 
     if (TRACE)
 	fprintf(stderr,"GridText: split_line called\n");
     
     if (line == NULL)
         outofmem(__FILE__, "split_line");
-    text->lines++;
+    text->Lines++;
     
     previous->next->prev = line;
     line->prev = previous;
@@ -1116,31 +1158,24 @@ PRIVATE void split_line ARGS2(HText *,text, int,split)
 	strcat(linedata, p);
 	line->size += plen;
     }
-    
+
     /*
      *  Economize on space.
      */
     while ((previous->size > 0) &&
-    	(previous->data[previous->size-1] == ' '))	/* Strip trailers */
+    	(previous->data[previous->size-1] == ' ')) {
+	/*
+	 *  Strip trailers.
+	 */
+	previous->data[previous->size-1] = '\0';
         previous->size--;
-	
-#if !defined(AIX) && !defined(ultrix)	
-    previous = (HTLine *) realloc (previous, LINE_SIZE(previous->size));
-    if (previous == NULL)
-        outofmem(__FILE__, "split_line");
-#else
-    /*
-     *  RS6000 has a chaotic bug in realloc argument passing.  Same
-     *  problem with Ultrix (4.2) : realloc() is not declared properly.
-     *  So we'll use a substitute for realloc.
-     */
+    }
     temp = (HTLine *)calloc(1, LINE_SIZE(previous->size));
     if (temp == NULL)
         outofmem(__FILE__, "split_line");
     memcpy(temp, previous, LINE_SIZE(previous->size));
     FREE(previous);
     previous = temp;
-#endif /* !AIX && !ultrix */
 
     previous->prev->next = previous;	/* Link in new line */
     previous->next->prev = previous;	/* Could be same node of course */
@@ -1194,13 +1229,16 @@ PRIVATE void split_line ARGS2(HText *,text, int,split)
 /*	Allow vertical blank space
 **	--------------------------
 */
-PRIVATE void blank_lines ARGS2(HText *,text, int,newlines)
+PRIVATE void blank_lines ARGS2(
+	HText *,	text,
+	int,		newlines)
 {
     if (!HText_LastLineSize(text)) {	/* No text on current line */
 	HTLine * line = text->last_line->prev;
 	while ((line != text->last_line) &&
 	       (HText_TrueLineSize(line) == 0)) {
-	    if (newlines == 0) break;
+	    if (newlines == 0)
+	        break;
 	    newlines--;		/* Don't bother: already blank */
 	    line = line->prev;
 	}
@@ -1219,7 +1257,8 @@ PRIVATE void blank_lines ARGS2(HText *,text, int,newlines)
 **	------------------------------
 ** See also: setStyle.
 */
-PUBLIC void HText_appendParagraph ARGS1(HText *,text)
+PUBLIC void HText_appendParagraph ARGS1(
+	HText *,	text)
 {
     int after = text->style->spaceAfter;
     int before = text->style->spaceBefore;
@@ -1232,7 +1271,9 @@ PUBLIC void HText_appendParagraph ARGS1(HText *,text)
 **
 **	Does not filter unnecessary style changes.
 */
-PUBLIC void HText_setStyle ARGS2(HText *,text, HTStyle *,style)
+PUBLIC void HText_setStyle ARGS2(
+	HText *,	text,
+	HTStyle *,	style)
 {
     int after, before;
 
@@ -1251,7 +1292,9 @@ PUBLIC void HText_setStyle ARGS2(HText *,text, HTStyle *,style)
 /*	Append a character to the text object
 **	-------------------------------------
 */
-PUBLIC void HText_appendCharacter ARGS2(HText *,text, char,ch)
+PUBLIC void HText_appendCharacter ARGS2(
+	HText *,	text,
+	char,		ch)
 {
     HTLine * line;
     HTStyle * style;
@@ -1394,7 +1437,7 @@ PUBLIC void HText_appendCharacter ARGS2(HText *,text, char,ch)
 	        }
 	    }
 	} else {
-	    goto check_ignore_excess;
+	    goto check_IgnoreExcess;
 	}
     } else if (ch == '\033') {
 	return;
@@ -1463,7 +1506,7 @@ PUBLIC void HText_appendCharacter ARGS2(HText *,text, char,ch)
      *  Tabs.
      */
     if (ch == '\t') {
-        HTTabStop * tab;
+        HTTabStop * Tab;
 	int target;	/* Where to tab to */
 	int here;
 
@@ -1478,14 +1521,14 @@ PUBLIC void HText_appendCharacter ARGS2(HText *,text, char,ch)
 	here = (((int)line->size + (int)line->offset) + indent)
 		- ctrl_chars_on_this_line; /* Consider special chars GAB */
         if (style->tabs) {	/* Use tab table */
-	    for (tab = style->tabs;
-	    	tab->position <= here;
-		tab++)
-		if (!tab->position) {
+	    for (Tab = style->tabs;
+	    	Tab->position <= here;
+		Tab++)
+		if (!Tab->position) {
 		    new_line(text);
 		    return;
 		}
-	    target = tab->position;
+	    target = Tab->position;
 	} else if (text->in_line_1) {	/* Use 2nd indent */
 	    if (here >= (int)style->leftIndent) {
 	        new_line(text); /* wrap */
@@ -1537,8 +1580,8 @@ PUBLIC void HText_appendCharacter ARGS2(HText *,text, char,ch)
     /*
      *  Check if we should ignore characters at the wrap point.
      */    
-check_ignore_excess:
-    if (ignore_excess &&
+check_IgnoreExcess:
+    if (text->IgnoreExcess &&
         ((indent + (int)line->offset + (int)line->size) + 
 	(int)style->rightIndent - ctrl_chars_on_this_line) >= (LYcols-1))
         return;
@@ -1638,12 +1681,53 @@ check_ignore_excess:
     }
 }
 
+/*	Set LastChar element in the text object.
+**	----------------------------------------
+*/
+PUBLIC void HText_setLastChar ARGS2(
+	HText *,	text,
+	char,		ch)
+{
+    if (!text)
+        return;
+
+    text->LastChar = ch;
+}
+
+/*	Get LastChar element in the text object.
+**	----------------------------------------
+*/
+PUBLIC char HText_getLastChar ARGS1(
+	HText *,	text)
+{
+    if (!text)
+        return('\0');
+
+    return((char)text->LastChar);
+}
+
+/*	Set IgnoreExcess element in the text object.
+**	--------------------------------------------
+*/
+PUBLIC void HText_setIgnoreExcess ARGS2(
+	HText *,	text,
+	BOOL,		ignore)
+{
+    if (!text)
+        return;
+
+    text->IgnoreExcess = ignore;
+}
+
 /*		Anchor handling
 **		---------------
 */
+
 /*	Start an anchor field
 */
-PUBLIC void HText_beginAnchor ARGS2(HText *,text, HTChildAnchor *,anc)
+PUBLIC void HText_beginAnchor ARGS2(
+	HText *,		text,
+	HTChildAnchor *,	anc)
 {
     char marker[16];
 
@@ -1682,17 +1766,18 @@ PUBLIC void HText_beginAnchor ARGS2(HText *,text, HTChildAnchor *,anc)
 }
 
 
-PUBLIC void HText_endAnchor ARGS1(HText *,text)
+PUBLIC void HText_endAnchor ARGS1(
+	HText *,	text)
 {
     TextAnchor * a = text->last_anchor;
     if (a->number) {
         /*
-	 * If it goes somewhere...
+	 *  If it goes somewhere...
 	 */
         a->extent += text->chars + text->last_line->size - a->start;
 	if (a->extent <= 2) {
 	    /*
-	     * Might be a blank anchor from an ALT="". - FM
+	     *  Might be a blank anchor from an ALT="". - FM
 	     */
     	    int j;
 	    a->show_anchor = NO;
@@ -1714,7 +1799,9 @@ PUBLIC void HText_endAnchor ARGS1(HText *,text)
 }
 
 
-PUBLIC void HText_appendText ARGS2(HText *,text, CONST char *,str)
+PUBLIC void HText_appendText ARGS2(
+	HText *,	text,
+	CONST char *,	str)
 {
     CONST char *p;
 
@@ -1727,7 +1814,8 @@ PUBLIC void HText_appendText ARGS2(HText *,text, CONST char *,str)
 }
 
 
-PRIVATE void remove_special_attr_chars ARGS1(char *,buf)
+PRIVATE void remove_special_attr_chars ARGS1(
+	char *,		buf)
 {
     register char *cp;
 
@@ -1744,11 +1832,12 @@ PRIVATE void remove_special_attr_chars ARGS1(char *,buf)
 
 /*
 **  This function trims blank lines from the end of the document, and
-**  then get the hightext from the text by finding the char position,
+**  then gets the hightext from the text by finding the char position,
 **  and brings the anchors in line with the text by adding the text
 **  offset to each of the anchors
 */
-PUBLIC void HText_endAppend ARGS1(HText *,text)
+PUBLIC void HText_endAppend ARGS1(
+	HText *,	text)
 {
     int cur_line, cur_char;
     TextAnchor *anchor_ptr;
@@ -1770,7 +1859,7 @@ PUBLIC void HText_endAppend ARGS1(HText *,text)
     /*
      *  Remove the blank lines at the end of document.
      */
-    while (text->last_line->data[0] == '\0' && text->lines > 2) {
+    while (text->last_line->data[0] == '\0' && text->Lines > 2) {
         HTLine *next_to_the_last_line;
 
         if (TRACE)
@@ -1784,7 +1873,7 @@ PUBLIC void HText_endAppend ARGS1(HText *,text)
         line_ptr->prev = next_to_the_last_line;
 	FREE(text->last_line);
         text->last_line = next_to_the_last_line;
-        text->lines--;
+        text->Lines--;
 
         if (TRACE)
             fprintf(stderr, "GridText: New bottom line: %s\n",
@@ -1846,7 +1935,7 @@ re_parse:
 	 *  lines, then start the highlighting on the next line.
 	 */
 	if (anchor_ptr->line_pos >= strlen(line_ptr->data) &&
-	    cur_line < text->lines) {
+	    cur_line < text->Lines) {
 	    anchor_ptr->start++;
 
 	    if (TRACE)
@@ -1917,7 +2006,8 @@ re_parse:
 
 /* 	Dump diagnostics to stderr
 */
-PUBLIC void HText_dump ARGS1(HText *,text)
+PUBLIC void HText_dump ARGS1(
+	HText *,	text)
 {
     fprintf(stderr, "HText: Dump called\n");
 }
@@ -1925,7 +2015,8 @@ PUBLIC void HText_dump ARGS1(HText *,text)
 
 /*	Return the anchor associated with this node
 */
-PUBLIC HTParentAnchor * HText_nodeAnchor ARGS1(HText *,text)
+PUBLIC HTParentAnchor * HText_nodeAnchor ARGS1(
+	HText *,	text)
 {
     return text->node_anchor;
 }
@@ -1937,7 +2028,8 @@ PUBLIC HTParentAnchor * HText_nodeAnchor ARGS1(HText *,text)
 **
 **	The index corresponds to the number we print in the anchor.
 */
-PUBLIC HTChildAnchor * HText_childNumber ARGS1(int,number)
+PUBLIC HTChildAnchor * HText_childNumber ARGS1(
+	int,		number)
 {
     TextAnchor * a;
     for (a = HTMainText->first_anchor; a; a = a->next) {
@@ -1949,7 +2041,10 @@ PUBLIC HTChildAnchor * HText_childNumber ARGS1(int,number)
 /*
  *  HTGetLinkInfo returns some link info based on the number.
  */
-PUBLIC int HTGetLinkInfo ARGS3(int, number, char **, hightext, char **, lname)
+PUBLIC int HTGetLinkInfo ARGS3(
+	int,		number,
+	char **,	hightext,
+	char **,	lname)
 {
     TextAnchor * a;
     HTAnchor *link_dest;
@@ -1984,7 +2079,7 @@ PUBLIC int HTGetLinkInfo ARGS3(int, number, char **, hightext, char **, lname)
  */
 PUBLIC int HText_getNumOfLines NOARGS
 {
-     return(HTMainText->lines);
+     return(HTMainText->Lines);
 }
 
 /*
@@ -2038,7 +2133,9 @@ PUBLIC char * HText_getServer NOARGS
  *  starting from the line 'line_num'-1
  *  this is the primary call for lynx
  */
-PUBLIC void HText_pageDisplay ARGS2(int,line_num, char *, target)
+PUBLIC void HText_pageDisplay ARGS2(
+	int,		line_num,
+	char *,		target)
 {
     display_page(HTMainText, line_num-1, target);
 
@@ -2047,13 +2144,16 @@ PUBLIC void HText_pageDisplay ARGS2(int,line_num, char *, target)
 
 /*
  *  HText_LinksInLines returns the number of links in the
- *  'lines' number of lines beginning with 'line_num'-1. - FM
+ *  'Lines' number of lines beginning with 'line_num'-1. - FM
  */
-PUBLIC int HText_LinksInLines ARGS3(HText *,text, int,line_num, int,lines)
+PUBLIC int HText_LinksInLines ARGS3(
+	HText *,	text,
+	int,		line_num,
+	int,		Lines)
 {
     int total = 0;
     int start = (line_num - 1);
-    int end = (start + lines);
+    int end = (start + Lines);
     TextAnchor *Anchor_ptr = NULL;
 
     if (!text)
@@ -2073,23 +2173,27 @@ PUBLIC int HText_LinksInLines ARGS3(HText *,text, int,line_num, int,lines)
     return total;
 }
 
-PUBLIC void HText_setStale ARGS1(HText *,text)
+PUBLIC void HText_setStale ARGS1(
+	HText *,	text)
 {
     text->stale = YES;
 }
 
-PUBLIC void HText_refresh ARGS1(HText *,text)
+PUBLIC void HText_refresh ARGS1(
+	HText *,	text)
 {
     if (text->stale)
         display_page(text, text->top_of_screen, "");
 }
 
-PUBLIC int HText_sourceAnchors ARGS1(HText *,text)
+PUBLIC int HText_sourceAnchors ARGS1(
+	HText *,	text)
 {
     return (text ? text->last_anchor_number : -1);
 }
 
-PUBLIC BOOL HText_canScrollUp ARGS1(HText *,text)
+PUBLIC BOOL HText_canScrollUp ARGS1(
+	HText *,	text)
 {
     return (text->top_of_screen != 0);
 }
@@ -2098,29 +2202,33 @@ PUBLIC BOOL HText_canScrollDown NOARGS
 {
     HText * text = HTMainText;
 
-    return ((text->top_of_screen + display_lines) < text->lines+1);
+    return ((text->top_of_screen + display_lines) < text->Lines+1);
 }
 
 /*		Scroll actions
 */
-PUBLIC void HText_scrollTop ARGS1(HText *,text)
+PUBLIC void HText_scrollTop ARGS1(
+	HText *,	text)
 {
     display_page(text, 0, "");
 }
 
-PUBLIC void HText_scrollDown ARGS1(HText *,text)
+PUBLIC void HText_scrollDown ARGS1(
+	HText *,	text)
 {
     display_page(text, text->top_of_screen + display_lines, "");
 }
 
-PUBLIC void HText_scrollUp ARGS1(HText *,text)
+PUBLIC void HText_scrollUp ARGS1(
+	HText *,	text)
 {
     display_page(text, text->top_of_screen - display_lines, "");
 }
 
-PUBLIC void HText_scrollBottom ARGS1(HText *,text)
+PUBLIC void HText_scrollBottom ARGS1(
+	HText *,	text)
 {
-    display_page(text, text->lines - display_lines, "");
+    display_page(text, text->Lines - display_lines, "");
 }
 
 
@@ -2130,7 +2238,9 @@ PUBLIC void HText_scrollBottom ARGS1(HText *,text)
 
 /* Bring to front and highlight it
 */
-PRIVATE int line_for_char ARGS2(HText *,text, int,char_num)
+PRIVATE int line_for_char ARGS2(
+	HText *,	text,
+	int,		char_num)
 {
     int line_number = 0;
     int characters = 0;
@@ -2144,13 +2254,14 @@ PRIVATE int line_for_char ARGS2(HText *,text, int,char_num)
     }
 }
 
-PUBLIC BOOL HText_select ARGS1(HText *,text)
+PUBLIC BOOL HText_select ARGS1(
+	HText *,	text)
 {
     if (text != HTMainText) {
         HTMainText = text;
 	HTMainAnchor = text->node_anchor;
 	/*
-	 * Make this text the most current in the loaded texts list. - FM
+	 *  Make this text the most current in the loaded texts list. - FM
 	 */
 	if (loaded_texts && HTList_removeObject(loaded_texts, text))
 	    HTList_addObject(loaded_texts, text);
@@ -2160,7 +2271,53 @@ PUBLIC BOOL HText_select ARGS1(HText *,text)
     return YES;
 }
 
-PUBLIC BOOL HTFindPoundSelector ARGS1(char *,selector)
+/*
+ *  This function returns TRUE if doc's post_data, address
+ *  and isHEAD elements are identical to those of a loaded
+ *  (memory cached) text. - FM
+ */
+PUBLIC BOOL HText_POSTReplyLoaded ARGS1(
+	document *,	doc)
+{
+    HText *text = NULL;
+    HTList *cur = loaded_texts;
+    char *post_data, *address;
+    BOOL is_head;
+
+    /*
+     *  Make sure we have the structures. - FM
+     */
+    if (!cur || !doc)
+	return(FALSE);
+
+    /*
+     *  Make sure doc is for a POST reply. - FM
+     */
+    if ((post_data = doc->post_data) == NULL ||
+        (address = doc->address) == NULL)
+	return(FALSE);
+    is_head = doc->isHEAD;
+
+    /*
+     *  Loop through the loaded texts looking for a
+     *  POST reply match. - FM
+     */
+    while (NULL != (text = (HText *)HTList_nextObject(cur))) {
+	if (text->node_anchor &&
+	    text->node_anchor->post_data &&
+	    !strcmp(post_data, text->node_anchor->post_data) &&
+	    text->node_anchor->address &&
+	    !strcmp(address, text->node_anchor->address) &&
+	    is_head == text->node_anchor->isHEAD) {
+	    return(TRUE);
+	}
+    }
+
+    return(FALSE);
+}
+
+PUBLIC BOOL HTFindPoundSelector ARGS1(
+	char *,		selector)
 {
     TextAnchor * a;
 
@@ -2185,7 +2342,9 @@ PUBLIC BOOL HTFindPoundSelector ARGS1(char *,selector)
 
 }
 
-PUBLIC BOOL HText_selectAnchor ARGS2(HText *,text, HTChildAnchor *,anchor)
+PUBLIC BOOL HText_selectAnchor ARGS2(
+	HText *,		text,
+	HTChildAnchor *,	anchor)
 {
     TextAnchor * a;
 
@@ -2238,7 +2397,9 @@ PUBLIC BOOL HText_selectAnchor ARGS2(HText *,text, HTChildAnchor *,anchor)
 */
 /*	Apply this style to the selection
 */
-PUBLIC void HText_applyStyle ARGS2(HText *, me, HTStyle *,style)
+PUBLIC void HText_applyStyle ARGS2(
+	HText *,	me,
+	HTStyle *,	style)
 {
     
 }
@@ -2246,7 +2407,9 @@ PUBLIC void HText_applyStyle ARGS2(HText *, me, HTStyle *,style)
 
 /*	Update all text with changed style.
 */
-PUBLIC void HText_updateStyle ARGS2(HText *, me, HTStyle *,style)
+PUBLIC void HText_updateStyle ARGS2(
+	HText *,	me,
+	HTStyle *,	style)
 {
     
 }
@@ -2255,8 +2418,8 @@ PUBLIC void HText_updateStyle ARGS2(HText *, me, HTStyle *,style)
 /*	Return style of  selection
 */
 PUBLIC HTStyle * HText_selectionStyle ARGS2(
-	HText *,me,
-	HTStyleSheet *,sheet)
+	HText *,		me,
+	HTStyleSheet *,		sheet)
 {
     return 0;
 }
@@ -2265,9 +2428,9 @@ PUBLIC HTStyle * HText_selectionStyle ARGS2(
 /*	Paste in styled text
 */
 PUBLIC void HText_replaceSel ARGS3(
-	HText *,me,
-	CONST char *,aString, 
-	HTStyle *,aStyle)
+	HText *,	me,
+	CONST char *,	aString,
+	HTStyle *,	aStyle)
 {
 }
 
@@ -2275,7 +2438,9 @@ PUBLIC void HText_replaceSel ARGS3(
 /*	Apply this style to the selection and all similarly formatted text
 **	(style recovery only)
 */
-PUBLIC void HTextApplyToSimilar ARGS2(HText *,me, HTStyle *,style)
+PUBLIC void HTextApplyToSimilar ARGS2(
+	HText *,	me,
+	HTStyle *,	style)
 {
     
 }
@@ -2284,7 +2449,9 @@ PUBLIC void HTextApplyToSimilar ARGS2(HText *,me, HTStyle *,style)
 /*	Select the first unstyled run.
 **	(style recovery only)
 */
-PUBLIC void HTextSelectUnstyled ARGS2(HText *,me, HTStyleSheet *,sheet)
+PUBLIC void HTextSelectUnstyled ARGS2(
+	HText *,		me,
+	HTStyleSheet *,		sheet)
 {
     
 }
@@ -2292,12 +2459,14 @@ PUBLIC void HTextSelectUnstyled ARGS2(HText *,me, HTStyleSheet *,sheet)
 
 /*	Anchor handling:
 */
-PUBLIC void		HText_unlinkSelection ARGS1(HText *,me)
+PUBLIC void HText_unlinkSelection ARGS1(
+	HText *,	me)
 {
     
 }
 
-PUBLIC HTAnchor *	HText_referenceSelected ARGS1(HText *,me)
+PUBLIC HTAnchor * HText_referenceSelected ARGS1(
+	HText *,	me)
 {
      return 0;   
 }
@@ -2309,18 +2478,21 @@ PUBLIC int HText_getTopOfScreen NOARGS
       return text->top_of_screen;
 }
 
-PUBLIC int HText_getLines ARGS1(HText *,text)
+PUBLIC int HText_getLines ARGS1(
+	HText *,	text)
 {
-      return text->lines;
+      return text->Lines;
 }
 
-PUBLIC HTAnchor * HText_linkSelTo ARGS2(HText *,me, HTAnchor *,anchor)
+PUBLIC HTAnchor * HText_linkSelTo ARGS2(
+	HText *,	me,
+	HTAnchor *,	anchor)
 {
     return 0;
 }
 
 /* 
- * Utility for freeing the list of previous isindex and whereis queries. - FM
+ *  Utility for freeing the list of previous isindex and whereis queries. - FM
  */
 PUBLIC void HTSearchQueries_free NOARGS
 {
@@ -2339,10 +2511,11 @@ PUBLIC void HTSearchQueries_free NOARGS
 }
 
 /* 
- * Utility for listing isindex and whereis queries, making
- * any repeated queries the most current in the list. - FM
+ *  Utility for listing isindex and whereis queries, making
+ *  any repeated queries the most current in the list. - FM
  */
-PUBLIC void HTAddSearchQuery ARGS1(char *, query)
+PUBLIC void HTAddSearchQuery ARGS1(
+	char *,		query)
 {
     char *new;
     char *old;
@@ -2375,7 +2548,8 @@ PUBLIC void HTAddSearchQuery ARGS1(char *, query)
     return;
 }
 
-PUBLIC int do_www_search ARGS1(document *,doc)
+PUBLIC int do_www_search ARGS1(
+	document *,	doc)
 {
     char searchstring[256], temp[256], *cp, *tmpaddress = NULL;
     int ch, recall, i;
@@ -2384,12 +2558,12 @@ PUBLIC int do_www_search ARGS1(document *,doc)
     BOOLEAN PreviousSearch = FALSE;
 
     /*
-     * Load the default query buffer
+     *  Load the default query buffer
      */
     if ((cp=strchr(doc->address, '?')) != NULL) {
         /*
-	 * This is an index from a previous search.
-	 * Use its query as the default.
+	 *  This is an index from a previous search.
+	 *  Use its query as the default.
 	 */
 	PreviousSearch = TRUE;
 	strcpy(searchstring, ++cp);
@@ -2399,19 +2573,19 @@ PUBLIC int do_www_search ARGS1(document *,doc)
 	HTUnEscape(searchstring);
 	strcpy(temp, searchstring);
 	/*
-	 * Make sure it's treated as the most recent query. - FM
+	 *  Make sure it's treated as the most recent query. - FM
 	 */
 	HTAddSearchQuery(searchstring);
     } else {
         /*
-	 * New search; no default.
+	 *  New search; no default.
 	 */
         searchstring[0] = '\0';
 	temp[0] = '\0';
     }
 
     /*
-     * Prompt for a query string.
+     *  Prompt for a query string.
      */
     if (searchstring[0] == '\0') {
         if (HTMainAnchor->isIndexPrompt)
@@ -2431,19 +2605,19 @@ get_query:
 	if (recall && ch == UPARROW) {
 	    if (PreviousSearch) {
 	        /*
-		 * Use the second to last query in the list. - FM
+		 *  Use the second to last query in the list. - FM
 		 */
 	        QueryNum = 1;
 		PreviousSearch = FALSE;
 	    } else {
 	        /*
-		 * Go back to the previous query in the list. - FM
+		 *  Go back to the previous query in the list. - FM
 		 */
 	        QueryNum++;
 	    }
 	    if (QueryNum >= QueryTotal)
 	        /*
-		 * Roll around to the last query in the list. - FM
+		 *  Roll around to the last query in the list. - FM
 		 */
 	        QueryNum = 0;
 	    if ((cp=(char *)HTList_objectAt(search_queries,
@@ -2462,19 +2636,19 @@ get_query:
 	} else if (recall && ch == DNARROW) {
 	    if (PreviousSearch) {
 	        /*
-		 * Use the first query in the list. - FM
+		 *  Use the first query in the list. - FM
 		 */
 	        QueryNum = QueryTotal - 1;
 		PreviousSearch = FALSE;
 	    } else {
 	        /*
-		 * Advance to the next query in the list. - FM
+		 *  Advance to the next query in the list. - FM
 		 */
 	        QueryNum--;
 	    }
 	    if (QueryNum < 0)
 	        /*
-		 * Roll around to the first query in the list. - FM
+		 *  Roll around to the first query in the list. - FM
 		 */
 		QueryNum = QueryTotal - 1;
 	    if ((cp=(char *)HTList_objectAt(search_queries,
@@ -2493,7 +2667,7 @@ get_query:
 	}
 
         /*
-	 * Search cancelled.
+	 *  Search cancelled.
 	 */
         _statusline(CANCELLED);
         sleep(InfoSecs);
@@ -2501,7 +2675,7 @@ get_query:
     }
 
     /*
-     * Strip leaders and trailers. - FM
+     *  Strip leaders and trailers. - FM
      */
     cp = searchstring;
     while (*cp && isspace((unsigned char)*cp))
@@ -2521,7 +2695,7 @@ get_query:
         *cp-- = '\0';
 
     /*
-     * Don't resubmit the same query unintentionally.
+     *  Don't resubmit the same query unintentionally.
      */
     if (!LYforce_no_cache && 0 == strcmp(temp, searchstring)) {
 	_statusline(USE_C_R_TO_RESUB_CUR_QUERY);
@@ -2530,13 +2704,13 @@ get_query:
     }
 
     /*
-     * Add searchstring to the query list,
-     * or make it the most current. - FM
+     *  Add searchstring to the query list,
+     *  or make it the most current. - FM
      */
     HTAddSearchQuery(searchstring);
 
     /*
-     * Show the URL with the new query.
+     *  Show the URL with the new query.
      */
     if ((cp=strchr(doc->address, '?')) != NULL)
         *cp = '\0';
@@ -2554,7 +2728,7 @@ get_query:
         *cp = '?';
 
     /*
-     * OK, now we do the search.
+     *  OK, now we do the search.
      */
     if (HTSearch(searchstring, HTMainAnchor)) {
 	/*
@@ -2573,27 +2747,30 @@ get_query:
 	    fprintf(stderr,"\ndo_www_search: newfile: %s\n",doc->address);
 
         /*
-	 * Yah, the search succeeded.
+	 *  Yah, the search succeeded.
 	 */
 	return(NORMAL);
     }
 
     /*
-     * Either the search failed (Yuk), or we got redirection.
-     * If it's redirection, use_this_url_instead is set, and
-     * mainloop() will deal with it such that security features
-     * and restrictions are checked before acting on the URL, or
-     * rejecting it. - FM
+     *  Either the search failed (Yuk), or we got redirection.
+     *  If it's redirection, use_this_url_instead is set, and
+     *  mainloop() will deal with it such that security features
+     *  and restrictions are checked before acting on the URL, or
+     *  rejecting it. - FM
      */
     return(NOT_FOUND);
 }
 
-/* print the contents of the file in HTMainText to
- * the file descripter fp.
- * if is_reply is true add ">" to the beginning of each
- * line to specify the file is a replied to message
+/*
+ *  Print the contents of the file in HTMainText to
+ *  the file descripter fp.
+ *  If is_reply is TRUE add ">" to the beginning of each
+ *  line to specify the file is a reply to message.
  */
-PUBLIC void print_wwwfile_to_fd ARGS2(FILE *,fp, int,is_reply)
+PUBLIC void print_wwwfile_to_fd ARGS2(
+	FILE *,		fp,
+	int,		is_reply)
 {
       register int i;
       HTLine * line = HTMainText->last_line->next;
@@ -2640,12 +2817,15 @@ PUBLIC void print_wwwfile_to_fd ARGS2(FILE *,fp, int,is_reply)
 
 }
 
-/* print the contents of the file in HTMainText to
- * the file descripter fp.
- * First output line is "thelink", ie, the URL for this file
+/*
+ *  Print the contents of the file in HTMainText to
+ *  the file descripter fp.
+ *  First output line is "thelink", ie, the URL for this file.
  */
-PUBLIC void print_crawl_to_fd ARGS3(FILE *, fp, char *, thelink,
-				    char *, thetitle)
+PUBLIC void print_crawl_to_fd ARGS3(
+	FILE *,		fp,
+	char *,		thelink,
+	char *,		thetitle)
 {
     register int i;
     HTLine * line = HTMainText->last_line->next;
@@ -2682,7 +2862,9 @@ PUBLIC void print_crawl_to_fd ARGS3(FILE *, fp, char *, thelink,
 #endif /* VMS */
 }
 
-PUBLIC void www_user_search ARGS2(int,start_line, char *,target)
+PUBLIC void www_user_search ARGS2(
+	int,		start_line,
+	char *,		target)
 {
     register HTLine * line = HTMainText->last_line->next;
     register int count;
@@ -2738,7 +2920,9 @@ PUBLIC void www_user_search ARGS2(int,start_line, char *,target)
 
 }
 
-PUBLIC  void  user_message ARGS2(char *,message, char *,argument) 
+PUBLIC void user_message ARGS2(
+	char *,		message,
+	char *,		argument) 
 {
     char *temp = NULL;
     char temp_arg[256];
@@ -2762,18 +2946,21 @@ PUBLIC  void  user_message ARGS2(char *,message, char *,argument)
     return;
 }
 
-/* HText_getOwner returns the owner of the
- * current document
+/*
+ *  HText_getOwner returns the owner of the
+ *  current document.
  */
 PUBLIC char * HText_getOwner NOARGS
 {
     return((char *)HTAnchor_owner(HTMainText->node_anchor));
 }
 
-/* HText_setMainTextOwner sets the owner for the
- * current document
+/*
+*   HText_setMainTextOwner sets the owner for the
+ *  current document.
  */
-PUBLIC void HText_setMainTextOwner ARGS1(CONST char *, owner)
+PUBLIC void HText_setMainTextOwner ARGS1(
+	CONST char *,	owner)
 {
     if (!HTMainText)
         return;
@@ -2781,15 +2968,34 @@ PUBLIC void HText_setMainTextOwner ARGS1(CONST char *, owner)
     HTAnchor_setOwner(HTMainText->node_anchor, owner);
 }
 
-/* HText_getRevTitle returns the RevTitle element of the
- * current document, used as the subject for mailto comments
- * to the owner.
+/*
+ *  HText_getRevTitle returns the RevTitle element of the
+ *  current document, used as the subject for mailto comments
+ *  to the owner.
  */
 PUBLIC char * HText_getRevTitle NOARGS
 {
     return((char *)HTAnchor_RevTitle(HTMainText->node_anchor));
 }
 
+/*
+ *  HText_getContentBase returns the Content-Base header
+ *  of the current document.
+ */
+PUBLIC char * HText_getContentBase NOARGS
+{
+    return((char *)HTAnchor_content_base(HTMainText->node_anchor));
+}
+
+/*
+ *  HText_getContentLocation returns the Content-Location header
+ *  of the current document.
+ */
+PUBLIC char * HText_getContentLocation NOARGS
+{
+    return((char *)HTAnchor_content_location(HTMainText->node_anchor));
+}
+
 PUBLIC void HTuncache_current_document NOARGS
 {
     /* should remove current document from memory */
@@ -2847,6 +3053,17 @@ PUBLIC BOOLEAN HTLoadedDocumentIsHEAD NOARGS
 	return (FALSE);
 }
 
+PUBLIC BOOLEAN HTLoadedDocumentIsSafe NOARGS
+{
+    if (!HTMainText)
+	return (FALSE);
+
+    if (HTMainText->node_anchor && HTMainText->node_anchor->safe) 
+       	return(HTMainText->node_anchor->safe);
+    else
+	return (FALSE);
+}
+
 PUBLIC char * HTLoadedDocumentCharset NOARGS
 {
     if (!HTMainText)
@@ -2879,14 +3096,16 @@ PUBLIC char * HTLoadedDocumentBookmark NOARGS
 	return (NULL);
 }
 
-PUBLIC int HText_LastLineSize ARGS1(HText *,text)
+PUBLIC int HText_LastLineSize ARGS1(
+	HText *,	text)
 {
     if (!text || !text->last_line || !text->last_line->size)
         return 0;
     return HText_TrueLineSize(text->last_line);
 }
 
-PUBLIC int HText_PreviousLineSize ARGS1(HText *,text)
+PUBLIC int HText_PreviousLineSize ARGS1(
+	HText *,	text)
 {
     HTLine * line;
 
@@ -2897,7 +3116,8 @@ PUBLIC int HText_PreviousLineSize ARGS1(HText *,text)
     return HText_TrueLineSize(line);
 }
 
-PRIVATE int HText_TrueLineSize ARGS1(HTLine *,line)
+PRIVATE int HText_TrueLineSize ARGS1(
+	HTLine *,	line)
 {
     int i, true_size = 0;
 
@@ -2912,7 +3132,8 @@ PRIVATE int HText_TrueLineSize ARGS1(HTLine *,line)
     return true_size;
 }
 
-PUBLIC void HText_NegateLineOne ARGS1(HText *,text)
+PUBLIC void HText_NegateLineOne ARGS1(
+	HText *,	text)
 {
     if (text) {
         text->in_line_1 = NO;
@@ -2921,13 +3142,44 @@ PUBLIC void HText_NegateLineOne ARGS1(HText *,text)
 }
 
 /*
- * NOTE: This function presently is correct only if the
- *	 alignment is HT_LEFT.  The offset is still zero,
- *	 because that's not determined for HT_CENTER or
- *	 HT_RIGHT until subsequent characters are received
- *	 and split_line() is called. - FM
+ *  This function is for removing the first of two
+ *  successive blank lines.  It should be called after
+ *  checking the situation with HText_LastLineSize()
+ *  and HText_PreviousLineSize().  Any characters in
+ *  the removed line (i.e., control characters, or it
+ *  wouldn't have tested blank) should have been
+ *  reiterated by split_line() in the retained blank
+ *  line. - FM
+ */
+PUBLIC void HText_RemovePreviousLine ARGS1(
+	HText *,	text)
+{
+    HTLine *line, *previous;
+    char *data;
+
+    if (!(text && text->Lines > 1))
+        return;
+
+    line = text->last_line->prev;
+    data = line->data;
+    previous = line->prev;
+    previous->next = text->last_line;
+    text->last_line->prev = previous;
+    text->chars -= ((data && *data == '\0') ?
+    					  1 : strlen(line->data) + 1);
+    text->Lines--;
+    FREE(line);
+}
+
+/*
+ *  NOTE: This function presently is correct only if the
+ *	  alignment is HT_LEFT.  The offset is still zero,
+ *	  because that's not determined for HT_CENTER or
+ *	  HT_RIGHT until subsequent characters are received
+ *	  and split_line() is called. - FM
  */
-PUBLIC int HText_getCurrentColumn ARGS1(HText *,text)
+PUBLIC int HText_getCurrentColumn ARGS1(
+	HText *,	text)
 {
     int column = 0;
 
@@ -2939,7 +3191,8 @@ PUBLIC int HText_getCurrentColumn ARGS1(HText *,text)
     return column;
 }
 
-PUBLIC int HText_getMaximumColumn ARGS1(HText *,text)
+PUBLIC int HText_getMaximumColumn ARGS1(
+	HText *,	text)
 {
     int column = (LYcols-2);
     if (text) {
@@ -2950,13 +3203,15 @@ PUBLIC int HText_getMaximumColumn ARGS1(HText *,text)
 }
 
 /*
- * NOTE: This function uses HText_getCurrentColumn() which
- *	 presently is correct only if the alignment is
- *	 HT_LEFT. - FM
+ *  NOTE: This function uses HText_getCurrentColumn() which
+ *	  presently is correct only if the alignment is
+ *	  HT_LEFT. - FM
  */
-PUBLIC void HText_setTabID ARGS2(HText *,text, CONST char *,name)
+PUBLIC void HText_setTabID ARGS2(
+	HText *,	text,
+	CONST char *,	name)
 {
-    HTTabID * tab = NULL;
+    HTTabID * Tab = NULL;
     HTList * cur = text->tabs;
     HTList * last = NULL;
 
@@ -2966,43 +3221,46 @@ PUBLIC void HText_setTabID ARGS2(HText *,text, CONST char *,name)
     if (!cur) {
         cur = text->tabs = HTList_new();
     } else {
-        while (NULL != (tab = (HTTabID *)HTList_nextObject(cur))) {
-	    if (tab->name && !strcmp(tab->name, name))
+        while (NULL != (Tab = (HTTabID *)HTList_nextObject(cur))) {
+	    if (Tab->name && !strcmp(Tab->name, name))
 	        return; /* Already set.  Keep the first value. */
 	    last = cur;
 	}
 	cur = last;
     }
-    if (!tab) { /* New name.  Create a new node */
-	tab = (HTTabID *)calloc(1, sizeof(HTTabID));
-	if (tab == NULL)
+    if (!Tab) { /* New name.  Create a new node */
+	Tab = (HTTabID *)calloc(1, sizeof(HTTabID));
+	if (Tab == NULL)
 	    outofmem(__FILE__, "HText_setTabID");
-	HTList_addObject(cur, tab);
-	StrAllocCopy(tab->name, name);
+	HTList_addObject(cur, Tab);
+	StrAllocCopy(Tab->name, name);
     }
-    tab->column = HText_getCurrentColumn(text);
+    Tab->column = HText_getCurrentColumn(text);
     return;
 }
 
-PUBLIC int HText_getTabIDColumn ARGS2(HText *,text, CONST char *,name)
+PUBLIC int HText_getTabIDColumn ARGS2(
+	HText *,	text,
+	CONST char *,	name)
 {
     int column = 0;
-    HTTabID * tab;
+    HTTabID * Tab;
     HTList * cur = text->tabs;
 
     if (text && name && *name && cur) {
-        while (NULL != (tab = (HTTabID *)HTList_nextObject(cur))) {
-	    if (tab->name && !strcmp(tab->name, name))
+        while (NULL != (Tab = (HTTabID *)HTList_nextObject(cur))) {
+	    if (Tab->name && !strcmp(Tab->name, name))
 	        break;
 	}
-	if (tab)
-	    column = tab->column;
+	if (Tab)
+	    column = Tab->column;
     }
     return column;
 }
 
 
-/*  Form methods
+/*
+ *  Form methods
  *    These routines are used to build forms consisting
  *    of input fields 
  */
@@ -3072,23 +3330,24 @@ PUBLIC void HText_beginForm ARGS4(
 		(HTFormEnctype ? HTFormEnctype : ""));
 }
 
-PUBLIC void HText_endForm ARGS1(HText *,text)
+PUBLIC void HText_endForm ARGS1(
+	HText *,	text)
 {
     if (HTFormFields == 1 && text && text->first_anchor) {
         /*
-	 * Support submission of a single text input field in
-	 * the form via <return> instead of a submit botton. - FM
+	 *  Support submission of a single text input field in
+	 *  the form via <return> instead of a submit botton. - FM
 	 */
         TextAnchor * a = text->first_anchor;
 	/*
-	 * Go through list of anchors and get our input field. - FM
+	 *  Go through list of anchors and get our input field. - FM
 	 */
 	while (1) {
 	    if (a->link_type == INPUT_ANCHOR &&
 	        a->input_field->number == HTFormNumber &&
 		a->input_field->type == F_TEXT_TYPE) {
 		/*
-		 * Got it.  Make it submitting. - FM
+		 *  Got it.  Make it submitting. - FM
 		 */
 		a->input_field->submit_action = NULL;
 		StrAllocCopy(a->input_field->submit_action, HTFormAction);
@@ -3118,7 +3377,10 @@ PUBLIC void HText_endForm ARGS1(HText *,text)
     HTFormDisabled = FALSE;
 }
 
-PUBLIC void HText_beginSelect ARGS3(char *,name, BOOLEAN,multiple, char *, size)
+PUBLIC void HText_beginSelect ARGS3(
+	char *,		name,
+	BOOLEAN,	multiple,
+	char *,		size)
 {
    /*
     *  Save the group name.
@@ -3137,7 +3399,7 @@ PUBLIC void HText_beginSelect ARGS3(char *,name, BOOLEAN,multiple, char *, size)
       HTCurSelectGroupType = F_RADIO_TYPE;
 
     /*
-     * Length of an option list.
+     *  Length of an option list.
      */
     StrAllocCopy(HTCurSelectGroupSize, size);
 
@@ -3155,9 +3417,12 @@ PUBLIC void HText_beginSelect ARGS3(char *,name, BOOLEAN,multiple, char *, size)
 **  tag so we have to do it now.  Assume that the last anchor
 **  was the previous options tag.
 */
-PUBLIC char * HText_setLastOptionValue ARGS5(HText *, text, char *, value,
-						char*, submit_value,
-						int, order, BOOLEAN, checked)
+PUBLIC char * HText_setLastOptionValue ARGS5(
+	HText *,	text,
+	char *,		value,
+	char*,		submit_value,
+	int,		order,
+	BOOLEAN,	checked)
 {
     char *cp;
     unsigned char *tmp = NULL;
@@ -3345,7 +3610,9 @@ PUBLIC char * HText_setLastOptionValue ARGS5(HText *, text, char *, value,
  *  returns the number of charactors to leave blank
  *  so that the input field can fit
  */
-PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
+PUBLIC int HText_beginInput ARGS2(
+	HText *,		text,
+	InputFieldData *,	I)
 {
 	
     TextAnchor * a = (TextAnchor *) calloc(1, sizeof(*a));
@@ -3488,7 +3755,8 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
      */
     if (I->size != NULL) {
 	f->size = atoi(I->size);
-	/* Leave at zero for option lists.
+	/*
+	 *  Leave at zero for option lists.
 	 */
 	if (f->size == 0 && cp_option == NULL) {
 	   f->size = 20;  /* default */
@@ -3528,15 +3796,7 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
 	} else if (!strcasecomp(I->type,"submit")) {
 	    f->type = F_SUBMIT_TYPE;
 	} else if (!strcasecomp(I->type,"image")) {
-	    /*
-	     *  Ugh, we have a clickable image submit button.
-	     *  Set the type to submit, and fake an ALT string.
-	     *  If the user activates it, we'll send a 0,0
-	     *  coordinate pair, which typically will return
-	     *  the image's default. FM
-	     */
-	    f->type = F_SUBMIT_TYPE;
-	    StrAllocCopy(f->value, "[IMAGE]-Submit");
+	    f->type = F_IMAGE_SUBMIT_TYPE;
 	} else if (!strcasecomp(I->type,"reset")) {
 	    f->type = F_RESET_TYPE;
 	} else if (!strcasecomp(I->type,"OPTION_LIST")) {
@@ -3552,7 +3812,9 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
 	} else if (!strcasecomp(I->type,"file")) {
 	    f->type = F_FILE_TYPE;
 	} else {
-	    /* Note that TYPE="scribble" defaults to TYPE="text". - FM */
+	    /*
+	     *  Note that TYPE="scribble" defaults to TYPE="text". - FM
+	     */
 	    f->type = F_TEXT_TYPE; /* default */
 	}
     } else {
@@ -3565,11 +3827,17 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
     if (I->name != NULL) {
         StrAllocCopy(f->name,I->name);
     } else {
-	if (f->type == F_RESET_TYPE || f->type == F_SUBMIT_TYPE) {
-	    /* set name to empty string */
+	if (f->type == F_RESET_TYPE ||
+	    f->type == F_SUBMIT_TYPE ||
+	    f->type == F_IMAGE_SUBMIT_TYPE) {
+	    /*
+	     *  Set name to empty string.
+	     */
 	    StrAllocCopy(f->name, "");
 	} else {
-	    /* error! name must be present */
+	    /*
+	     *  Error!  NAME must be present.
+	     */
 	    if (TRACE)
 		fprintf(stderr,
 		  "GridText: No name present in input field; not displaying\n");
@@ -3581,46 +3849,49 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
     }
 
     /* 
-     *  Set VALUE (if it exists).
+     *  Set VALUE, if it exists.  Otherwise, if it's not
+     *  an option list make it a zero-length string. - FM
      */
     if (IValue != NULL) {
 	/*
 	 *  OPTION VALUE is not actually the value to be seen but is to
 	 *    be sent....
 	 */
-	if (f->type != F_OPTION_LIST_TYPE && f->type != F_CHECKBOX_TYPE) {
-	    StrAllocCopy(f->value, IValue);
-	} else {
+	if (f->type == F_OPTION_LIST_TYPE ||
+	    f->type == F_CHECKBOX_TYPE) {
 	    /*
 	     *  Fill both with the value.  The f->value may be
 	     *  overwritten in HText_setLastOptionValue....
 	     */
-	    if (!f->value || strcmp(f->value, "[IMAGE]-Submit"))
-		StrAllocCopy(f->value, IValue);
+	    StrAllocCopy(f->value, IValue);
 	    StrAllocCopy(f->cp_submit_value, IValue);
+	} else {
+	    StrAllocCopy(f->value, IValue);
 	}
-    } else if (!f->value || strcmp(f->value, "[IMAGE]-Submit")) {
-        if (f->type != F_OPTION_LIST_TYPE) {
-	    StrAllocCopy(f->value, "");
-	}
+    } else if (f->type != F_OPTION_LIST_TYPE) {
+	StrAllocCopy(f->value, "");
     }
 
     /*
      *  Run checks and fill in neccessary values.
      */
     if (f->type == F_RESET_TYPE) {
-	if (IValue != NULL) {
-	    f->size = strlen(IValue);
+	if (f->value && *f->value != '\0') {
+	    f->size = strlen(f->value);
 	} else {
 	    StrAllocCopy(f->value, "Reset");
 	    f->size = 5;
 	}
-    } else if (f->type == F_SUBMIT_TYPE) {
-        if (f->value && !strcmp(f->value, "[IMAGE]-Submit")) {
+    } else if (f->type == F_IMAGE_SUBMIT_TYPE ||
+    	       f->type == F_SUBMIT_TYPE) {
+        if (f->value && *f->value != '\0') {
 	    f->size = strlen(f->value);
-	} else if (IValue != NULL) {
-	    f->size = strlen(IValue);
+	} else if (f->type == F_IMAGE_SUBMIT_TYPE) {
+	    StrAllocCopy(f->value, "[IMAGE]-Submit");
+	    f->size = 14;
 	} else {
+	    StrAllocCopy(f->value, "[IMAGE]-Submit");
+	    f->size = 14;
 	    StrAllocCopy(f->value, "Submit");
 	    f->size = 6;
 	}
@@ -3678,8 +3949,11 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
 }
 
 
-PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
-				   char *,link_name, char *, link_value)
+PUBLIC void HText_SubmitForm ARGS4(
+	FormInfo *,	submit_item,
+	document *,	doc,
+	char *,		link_name,
+	char *,		link_value)
 {
     TextAnchor *anchor_ptr = HTMainText->first_anchor;
     int form_number = submit_item->number;
@@ -3754,7 +4028,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 	
 	        len += (strlen(form_ptr->name) + (Boundary ? 100 : 10));
 		/*
-		 *	Calculate by the option submit value if present.
+		 *  Calculate by the option submit value if present.
 		 */
 		if (form_ptr->cp_submit_value != NULL) {
 		    len += (strlen(form_ptr->cp_submit_value) + 10);
@@ -3874,12 +4148,15 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 
 	        case F_SUBMIT_TYPE:
 	        case F_TEXT_SUBMIT_TYPE:
+	        case F_IMAGE_SUBMIT_TYPE:
 		    /*
 		     *  If it has a non-zero length name (e.g., because
-		     *  it's really a type="image" that's been converted
-		     *  to SUBMIT_TYPE, or one of multiple submit buttons,
-		     *  or a single type="text" that's been converted to
-		     *  a TEXT_SUBMIT_TYPE), include the name=value pair. - FM
+		     *  it's IMAGE_SUBMIT_TYPE to be handled homologously
+		     *  to an image map, or a SUBMIT_TYPE in a set of
+		     *  multiple submit buttons, or a single type="text"
+		     *  that's been converted to a TEXT_SUBMIT_TYPE),
+		     *  include the name=value pair, or fake name.x=0 and
+		     *  name.y=0 pairs for IMAGE_SUBMIT_TYPE. - FM
 		     */
 		    if ((form_ptr->name && *form_ptr->name != '\0' &&
 		        !strcmp(form_ptr->name, link_name)) &&
@@ -3921,7 +4198,8 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			}
 
 		        /*
-		         * Be sure to actually look at the option submit value.
+		         *  Be sure to actually look at
+			 *  the option submit value.
 		         */
 		        if (form_ptr->cp_submit_value != NULL) {
 			    for (i = 0; form_ptr->cp_submit_value[i]; i++) {
@@ -3972,11 +4250,11 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			    }
 		        }
 
-			if (!strcmp(form_ptr->value, "[IMAGE]-Submit")) {
+			if (form_ptr->type == F_IMAGE_SUBMIT_TYPE) {
 			    /*
-			     * It's a clickable image submit button.
-			     * Fake a 0,0 coordinate pair, which
-			     * typically returns the image's default. - FM
+			     *  It's a clickable image submit button.
+			     *  Fake a 0,0 coordinate pair, which
+			     *  typically returns the image's default. - FM
 			     */
 			    if (Boundary) {
 			        escaped1[(strlen(escaped1) - 4)] = '\0';
@@ -3998,8 +4276,8 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			    }
 			} else {
 			    /*
-			     * It's a standard submit button.
-			     * Use the name=value pair. = FM
+			     *  It's a standard submit button.
+			     *  Use the name=value pair. = FM
 			     */
 			    sprintf(&query[strlen(query)],
 				    "%s%s%s%s%s",
@@ -4019,7 +4297,9 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 
 	        case F_RADIO_TYPE:
                 case F_CHECKBOX_TYPE:
-		    /* only add if selected */
+		    /*
+		     *  Only add if selected.
+		     */
 		    if (form_ptr->num_value) {
 	                if (first_one) {
 			    if (Boundary) {
@@ -4056,7 +4336,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 		            escaped1 = HTEscape(form_ptr->name, URL_XALPHAS);
 			}
 			/*
-			 *	Be sure to use the submit option value.
+			 *  Be sure to use the submit option value.
 			 */
 			if (form_ptr->cp_submit_value != NULL) {
 			    for (i = 0; form_ptr->cp_submit_value[i]; i++) {
@@ -4418,7 +4698,8 @@ PUBLIC void HText_DisableCurrentForm NOARGS
     return;
 }
 
-PUBLIC void HText_ResetForm ARGS1(FormInfo *,form)
+PUBLIC void HText_ResetForm ARGS1(
+	FormInfo *,	form)
 {
     TextAnchor * anchor_ptr = HTMainText->first_anchor;
 
@@ -4465,7 +4746,8 @@ PUBLIC void HText_ResetForm ARGS1(FormInfo *,form)
     }
 }
 
-PUBLIC void HText_activateRadioButton ARGS1(FormInfo *,form)
+PUBLIC void HText_activateRadioButton ARGS1(
+	FormInfo *,	form)
 {
     TextAnchor * anchor_ptr = HTMainText->first_anchor;
     int form_number = form->number;
@@ -4550,7 +4832,8 @@ PRIVATE void free_all_texts NOARGS
 **  of N internal links.  Since the parent link has already been taken,
 **  it won't go again, hence the (incorrect) links won't cause problems.
 */
-PUBLIC char * stub_HTAnchor_address ARGS1 (HTAnchor *,me)
+PUBLIC char * stub_HTAnchor_address ARGS1(
+	HTAnchor *,	me)
 {
     char *addr = NULL;
     if (me)
@@ -4558,26 +4841,30 @@ PUBLIC char * stub_HTAnchor_address ARGS1 (HTAnchor *,me)
     return addr;
 }
 
-PUBLIC void HText_setToolbar ARGS1 (HText *, text)
+PUBLIC void HText_setToolbar ARGS1(
+	HText *,	text)
 {
     if (text)
         text->toolbar = TRUE;
     return;
 }
 
-PUBLIC BOOL HText_hasToolbar ARGS1 (HText *, text)
+PUBLIC BOOL HText_hasToolbar ARGS1(
+	HText *,	text)
 {
     return ((text && text->toolbar) ? TRUE : FALSE);
 }
 
-PUBLIC void HText_setNoCache ARGS1 (HText *, text)
+PUBLIC void HText_setNoCache ARGS1(
+	HText *,	text)
 {
     if (text)
         text->no_cache = TRUE;
     return;
 }
 
-PUBLIC BOOL HText_hasNoCacheSet ARGS1 (HText *, text)
+PUBLIC BOOL HText_hasNoCacheSet ARGS1(
+	HText *,	text)
 {
     return ((text && text->no_cache) ? TRUE : FALSE);
 }
diff --git a/src/GridText.h b/src/GridText.h
index 0ed5cad0..e027c17c 100644
--- a/src/GridText.h
+++ b/src/GridText.h
@@ -58,7 +58,11 @@ extern void HText_scrollTop PARAMS((HText * text));
 extern void HText_scrollBottom PARAMS((HText * text));
 extern void HText_pageDisplay PARAMS((int line_num, char *target));
 
-extern int HText_LinksInLines PARAMS((HText *text, int line_num, int lines));
+extern int HText_LinksInLines PARAMS((HText *text, int line_num, int Lines));
+
+extern void HText_setLastChar PARAMS((HText *text, char ch));
+extern char HText_getLastChar PARAMS((HText *text));
+extern void HText_setIgnoreExcess PARAMS((HText *text, BOOL ignore));
 
 extern int HText_sourceAnchors PARAMS((HText * text));
 extern void HText_setStale PARAMS((HText * text));
@@ -69,10 +73,14 @@ extern char * HText_getLastModified NOPARAMS;
 extern char * HText_getDate NOPARAMS;
 extern char * HText_getServer NOPARAMS;
 extern char * HText_getOwner NOPARAMS;
+extern char * HText_getContentBase NOPARAMS;
+extern char * HText_getContentLocation NOPARAMS;
 extern void HText_setMainTextOwner PARAMS((CONST char * owner));
 extern char * HText_getRevTitle NOPARAMS;
 extern void print_wwwfile_to_fd PARAMS((FILE * fp, int is_reply));
-extern BOOLEAN HTFindPoundSelector PARAMS((char *selector));
+extern BOOL HText_select PARAMS((HText *text));
+extern BOOL HText_POSTReplyLoaded PARAMS((document *doc));
+extern BOOL HTFindPoundSelector PARAMS((char *selector));
 extern int HTGetLinkInfo PARAMS((int number, char **hightext, char **lname));
 extern int HTisDocumentSource NOPARAMS;
 extern void HTuncache_current_document NOPARAMS;
@@ -83,12 +91,14 @@ extern char * HTLoadedDocumentURL NOPARAMS;
 extern char * HTLoadedDocumentPost_data NOPARAMS;
 extern char * HTLoadedDocumentTitle NOPARAMS;
 extern BOOLEAN HTLoadedDocumentIsHEAD NOPARAMS;
+extern BOOLEAN HTLoadedDocumentIsSafe NOPARAMS;
 extern char * HTLoadedDocumentCharset NOPARAMS;
 extern void HText_setNodeAnchorBookmark PARAMS((CONST char *bookmark));
 extern char * HTLoadedDocumentBookmark NOPARAMS;
 extern int HText_LastLineSize PARAMS((HText *me));
 extern int HText_PreviousLineSize PARAMS((HText *me));
 extern void HText_NegateLineOne PARAMS((HText *text));
+extern void HText_RemovePreviousLine PARAMS((HText *text));
 extern int HText_getCurrentColumn PARAMS((HText *text));
 extern int HText_getMaximumColumn PARAMS((HText *text));
 extern void HText_setTabID PARAMS((HText *text, CONST char *name));
diff --git a/src/HTAlert.c b/src/HTAlert.c
index 5a3ddc1c..46243c37 100644
--- a/src/HTAlert.c
+++ b/src/HTAlert.c
@@ -9,7 +9,6 @@
 **
 */
 
-
 #include "HTUtils.h"
 #include "tcp.h"
 #include "HTAlert.h"
@@ -19,15 +18,20 @@
 #include "LYUtils.h"
 #include "LYSignal.h"
 #include "GridText.h"
+#include "LYCookie.h"
 
 #include "LYLeaks.h"
 
 #define FREE(x) if (x) {free(x); x = NULL;}
 
 
-PUBLIC void HTAlert ARGS1(CONST char *, Msg)
+/*	Issue a message about a problem.		HTAlert()
+**	--------------------------------
+*/
+PUBLIC void HTAlert ARGS1(
+	CONST char *,	Msg)
 {
-    if(TRACE) {
+    if (TRACE) {
         fprintf(stderr, "\nAlert!: %s", (char *)Msg);
 	fflush(stderr);
         _user_message("Alert!: %s", (char *)Msg);
@@ -39,16 +43,21 @@ PUBLIC void HTAlert ARGS1(CONST char *, Msg)
     sleep(AlertSecs);
 }
 
-
-PUBLIC void HTProgress ARGS1(CONST char *, Msg)
+/*	Issue a progress message.			HTProgress()
+**	-------------------------
+*/
+PUBLIC void HTProgress ARGS1(
+	CONST char *,	Msg)
 {
-    if(TRACE)
+    if (TRACE)
         fprintf(stderr, "%s\n", (char *)Msg);
     else
         statusline((char *)Msg);
 }
 
-
+/*	Seek confirmation.				HTConfirm()
+**	------------------
+*/
 PUBLIC BOOL HTConfirm ARGS1(CONST char *, Msg)
 {
     if (dump_output_immediately) { /* Non-interactive, can't respond */
@@ -59,27 +68,30 @@ PUBLIC BOOL HTConfirm ARGS1(CONST char *, Msg)
 	extern BOOLEAN HadVMSInterrupt;
 #endif /* VMS */
 	
-	_user_message("WWW: %s (y/n) ", (char *) Msg);
+	_user_message("%s (y/n) ", (char *)Msg);
 	
-	while(1) {
+	while (1) {
 	    c = LYgetch();
 #ifdef VMS
-	    if(HadVMSInterrupt) {
+	    if (HadVMSInterrupt) {
 		HadVMSInterrupt = FALSE;
 		c = 'N';
 	    }
 #endif /* VMS */
-	    if(TOUPPER(c)=='Y')
+	    if (TOUPPER(c) == 'Y')
 		return(YES);
-	    if(TOUPPER(c)=='N' || c == 7 || c == 3) /* ^G or ^C cancels */
+	    if (TOUPPER(c) == 'N' || c == 7 || c == 3) /* ^G or ^C cancels */
 		return(NO);
 	}
     }
 }
 
-/*	Prompt for answer and get text back
+/*	Prompt for answer and get text back.		HTPrompt()
+**	------------------------------------
 */
-PUBLIC char * HTPrompt ARGS2(CONST char *, Msg, CONST char *, deflt)
+PUBLIC char * HTPrompt ARGS2(
+	CONST char *,	Msg,
+	CONST char *,	deflt)
 {
     char * rep = NULL;
     char Tmp[200];
@@ -99,14 +111,17 @@ PUBLIC char * HTPrompt ARGS2(CONST char *, Msg, CONST char *, deflt)
     return rep;
 }
 
-/*      Prompt for password without echoing the reply
+/*
+**	Prompt for password without echoing the reply.	HTPromptPassword()
+**	----------------------------------------------
 */
-PUBLIC char * HTPromptPassword ARGS1(CONST char *, Msg)
+PUBLIC char * HTPromptPassword ARGS1(
+	CONST char *,	Msg)
 {
     char *result = NULL;
     char pw[120];
 
-    pw[0]='\0';
+    pw[0] = '\0';
 
     if (!dump_output_immediately) {
         _statusline(Msg ? (char *)Msg : PASSWORD_PROMPT);
@@ -119,10 +134,10 @@ PUBLIC char * HTPromptPassword ARGS1(CONST char *, Msg)
     return result;
 }
 
-
-/*      Prompt both username and password       HTPromptUsernameAndPassword()
-**      ---------------------------------
-** On entry,
+/*     	Prompt both username and password.       HTPromptUsernameAndPassword()
+**      ----------------------------------
+**
+**  On entry,
 **      Msg             is the prompting message.
 **      *username and
 **      *password       are char pointers; they are changed
@@ -133,22 +148,23 @@ PUBLIC char * HTPromptPassword ARGS1(CONST char *, Msg)
 **                      Initial value of *password is
 **                      completely discarded.
 **
-** On exit,
+**  On exit,
 **      *username and *password point to newly allocated
 **      strings -- original strings pointed to by them
 **      are NOT freed.
 **
 */
-PUBLIC void HTPromptUsernameAndPassword ARGS3(CONST char *,     Msg,
-                                              char **,          username,
-                                              char **,          password)
+PUBLIC void HTPromptUsernameAndPassword ARGS3(
+	CONST char *,	Msg,
+	char **,	username,
+	char **,	password)
 {
     if (authentication_info[0] && authentication_info[1]) {
 	/* 
-	 *  -auth parameter gave us both the username and password
-	 *  to use for the first realm, so just use them without
-	 *  any prompting. - FM
-	 */
+	**  -auth parameter gave us both the username and password
+	**  to use for the first realm, so just use them without
+	**  any prompting. - FM
+	*/
  	StrAllocCopy(*username, authentication_info[0]);
 	FREE(authentication_info[0]);
 	StrAllocCopy(*password, authentication_info[1]);
@@ -156,79 +172,204 @@ PUBLIC void HTPromptUsernameAndPassword ARGS3(CONST char *,     Msg,
     } else if (dump_output_immediately) {
         if (authentication_info[0]) {
 	    /*
-	     *  Use the command line username. - FM
-	     */
+	    **  Use the command line username. - FM
+	    */
 	    StrAllocCopy(*username, authentication_info[0]);
 	    FREE(authentication_info[0]);
 	} else {
 	    /*
-	     *  Default to "WWWuser". - FM
-	     */
+	    **  Default to "WWWuser". - FM
+	    */
             StrAllocCopy(*username, "WWWuser");
 	}
 	if (authentication_info[1]) {
 	    /*
-	     *  Use the command line password. - FM
-	     */
+	    **  Use the command line password. - FM
+	    */
 	    StrAllocCopy(*password, authentication_info[1]);
 	    FREE(authentication_info[1]);
 	} else {
 	    /*
-	     *  Default to a zero-length string. - FM
-	     */
+	    **  Default to a zero-length string. - FM
+	    */
 	    StrAllocCopy(*password, "");
 	}
 	printf("\n%s\n", USERNAME_PASSWORD_REQUIRED);
     } else {
         if (authentication_info[0]) {
 	    /*
-	     *  Offer command line username in the prompt
-	     *  for the first realm. - FM
-	     */
+	    **  Offer command line username in the prompt
+	    **  for the first realm. - FM
+	    */
 	    StrAllocCopy(*username, authentication_info[0]);
 	    FREE(authentication_info[0]);
 	}
-	if (Msg) {
+	if (Msg != NULL) {
 	    *username = HTPrompt(Msg, *username);
 	} else {
 	    *username = HTPrompt(USERNAME_PROMPT, *username);
 	}
 	if (authentication_info[1]) {
 	    /*
-	     *  Use the command line password for the first realm. - FM
-	     */
+	    **  Use the command line password for the first realm. - FM
+	    */
 	    StrAllocCopy(*password, authentication_info[1]);
 	    FREE(authentication_info[1]);
 	} else if (*username != NULL && *username[0] != '\0') {
 	    /*
-	     *  If we have a non-zero length username,
-	     *  prompt for the password. - FM
-	     */
+	    **  If we have a non-zero length username,
+	    **  prompt for the password. - FM
+	    */
 	    *password = HTPromptPassword(PASSWORD_PROMPT);
 	} else {
 	    /*
-	     *  Return a zero-length password. - FM
-	     */
-	     StrAllocCopy(*password, "");
+	    **  Return a zero-length password. - FM
+	    */
+	    StrAllocCopy(*password, "");
 	}
 	
     }
 }
 
+/*	Confirm a cookie operation.			HTConfirmCookie()
+**	---------------------------
+**
+**  On entry,
+**	server			is the server sending the Set-Cookie.
+**	domain			is the domain of the cookie.
+**	path			is the path of the cookie.
+**	name			is the name of the cookie.
+**	value			is the value of the cookie.
+**
+**  On exit,
+**	Returns FALSE on cancel,
+**		TRUE if the cookie should be set.
+*/
+PUBLIC BOOL HTConfirmCookie ARGS6(
+	void *,		dp,
+	CONST char *,	server,
+	CONST char *,	domain,
+	CONST char *,	path,
+	CONST char *,	name,
+	CONST char *,	value)
+{
+    char message[256];
+    HTList *hl;
+    domain_entry *de;
+    int ch, namelen, valuelen, space_free;
 
-#define	SERVER_ASKED_FOR_REDIRECTION \
- "Server asked for redirection of POST content to"
-#define	PROCEED_GET_CANCEL "P)roceed, use G)ET or C)ancel "
-#define	ADVANCED_POST_REDIRECT \
- "Redirection of POST content. P)roceed, see U)RL, use G)ET or C)ancel"
-#define	LOCATION_HEADER "Location: "
+#ifdef VMS
+    extern BOOLEAN HadVMSInterrupt;
+#endif /* VMS */
+
+    if ((de = (domain_entry *)dp) == NULL)
+        return FALSE;
+  
+    /*
+    **  If the user has specified a constant action, don't prompt at all.
+    */
+    if (de->bv == ACCEPT_ALWAYS)
+        return TRUE;
+    if (de->bv == REJECT_ALWAYS)
+        return FALSE;
+
+    if (dump_output_immediately) {
+        /*
+	**  Non-interactive, can't respond.  Use the LYSetCookies value
+	*   based on its compilation or configuration setting, or on the
+	**  command line toggle. - FM
+	*/
+        return LYSetCookies;
+    }
 
-/*      Confirm redirection of POST		HTConfirmPostRedirect()
+    /*
+    **  Figure out how much of the cookie we can show.
+    **  The '37' is the length of ADVANCED_COOKIE_CONFIRMATION,
+    **  minus the length of the %s directives (10 chars)
+    */
+    if (de != NULL) {
+        if (de->bv == ACCEPT_ALWAYS) 
+	    return TRUE;
+	if (de->bv == REJECT_ALWAYS) 
+	    return FALSE;
+    }
+    space_free = (((LYcols - 1) - 37) - strlen(server));
+    if (space_free < 0)
+        space_free = 0;
+    namelen = strlen(name);
+    valuelen = strlen(value);
+    if ((namelen + valuelen) > space_free) {
+        /*
+	**  Argh... there isn't enough space on our single line for
+	**  the whole cookie.  Reduce them both by a percentage.
+	**  This should be smarter.
+	*/
+        float percentage;
+        percentage = (float)space_free/(float)(namelen + valuelen);
+        namelen = (int)(percentage*(float)namelen);
+        valuelen = (int)(percentage*(float)valuelen);
+    }
+    sprintf(message, ADVANCED_COOKIE_CONFIRMATION,
+    	    server, namelen, name, valuelen, value);
+    _user_message(message, "");
+    while (1) {
+	ch = LYgetch();
+#ifdef VMS
+	if (HadVMSInterrupt) {
+	    HadVMSInterrupt = FALSE;
+	    ch = 'N';
+	}
+#endif /* VMS */
+	switch(TOUPPER(ch)) {
+	    case 'A':
+	        /*
+		**  Set to accept all cookies for this domain.
+		*/
+		de->bv = ACCEPT_ALWAYS;
+		_user_message(ALWAYS_ALLOWING_COOKIES, de->domain);
+		sleep(MessageSecs);
+		return TRUE;
+
+	    case 'N':
+	    case 7:	/* Ctrl-G */
+	    case 3:	/* Ctrl-C */
+	        /*
+		**  Reject the cookie.
+		*/
+		_statusline(REJECTING_COOKIE);
+		sleep(MessageSecs);
+		return FALSE;
+
+    	    case 'V':
+	        /*
+		**  Set to reject all cookies from this domain.
+		*/
+		de->bv = REJECT_ALWAYS;
+		_user_message(NEVER_ALLOWING_COOKIES, de->domain);
+		sleep(MessageSecs);
+		return FALSE;
+
+	    case 'Y':
+	        /*
+		**  Accept the cookie.
+		*/
+		_statusline(ALLOWING_COOKIE);
+		sleep(InfoSecs);
+		return TRUE;
+
+	    default:
+	        continue;
+	}
+    }
+}
+
+/*      Confirm redirection of POST.		HTConfirmPostRedirect()
+**	----------------------------
 **
-** On entry,
+**  On entry,
 **      redirecting_url             is the Location.
 **
-** On exit,
+**  On exit,
 **      Returns 0 on cancel,
 **	  1 for redirect of POST with content,
 **	303 for redirect as GET without content
@@ -244,8 +385,8 @@ PUBLIC int HTConfirmPostRedirect ARGS1(
 
     if (dump_output_immediately)
 	/*
-	 *  Treat as 303 (GET without content) if not interactive.
-	 */
+	**  Treat as 303 (GET without content) if not interactive.
+	*/
         return 303;
 
     if (user_mode == NOVICE_MODE) {
@@ -277,31 +418,31 @@ PUBLIC int HTConfirmPostRedirect ARGS1(
 	switch (TOUPPER(c)) {
 	    case 'P':
 		/*
-		 *  Proceed with 301 or 302 redirect of POST
-		 *  (we check only for 0 and 303 in HTTP.c).
-		 */
+		**  Proceed with 301 or 302 redirect of POST
+		**  (we check only for 0 and 303 in HTTP.c).
+		*/
 	        FREE(show_POST_url);
 		return 1;	
 
  	    case 7:
  	    case 'C':
 	        /*
-		 * Cancel request.
-		 */
+		** Cancel request.
+		*/
 	        FREE(show_POST_url);
 		return 0;
 
 	    case 'G':
 	        /*
-		 *  Treat as 303 (GET without content).
-		 */
+		**  Treat as 303 (GET without content).
+		*/
 	        FREE(show_POST_url);
 		return 303;
 
 	    case 'U':
 	        /*
-		 *  Show URL for intermediate or advanced mode.
-		 */
+		**  Show URL for intermediate or advanced mode.
+		*/
 	        if (user_mode != NOVICE_MODE)
 		    if (on_screen == 1)
 			on_screen = 0;
@@ -311,8 +452,8 @@ PUBLIC int HTConfirmPostRedirect ARGS1(
 
 	    default:
 	        /*
-		 *  Get another character.
-		 */
+		**  Get another character.
+		*/
 		if (on_screen == 1)
 		    on_screen = 0;
 		else
@@ -320,4 +461,3 @@ PUBLIC int HTConfirmPostRedirect ARGS1(
 	}
     }
 }
-
diff --git a/src/HTAlert.h b/src/HTAlert.h
index dc470cfd..73013918 100644
--- a/src/HTAlert.h
+++ b/src/HTAlert.h
@@ -82,12 +82,35 @@ extern void HTPromptUsernameAndPassword PARAMS((
 	char **		password));
 
 
-/*      Confirm redirection of POST		HTConfirmPostRedirect()
+/*	Confirm a cookie operation.			HTConfirmCookie()
+**	---------------------------
 **
-** On entry,
+**  On entry,
+**	server			is the server sending the Set-Cookie.
+**	domain			is the domain of the cookie.
+**	path			is the path of the cookie.
+**	name			is the name of the cookie.
+**	value			is the value of the cookie.
+**
+**  On exit,
+**	Returns FALSE on cancel,
+**		TRUE if the cookie should be set.
+*/
+extern BOOL HTConfirmCookie PARAMS((
+	void *		dp,
+	CONST char *	server,
+	CONST char *	domain,
+	CONST char *	path,
+	CONST char *	name,
+	CONST char *	value));
+
+
+/*      Confirm redirection of POST.		HTConfirmPostRedirect()
+**	----------------------------
+**  On entry,
 **      redirecting_url             is the Location.
 **
-** On exit,
+**  On exit,
 **      Returns 0 on cancel,
 **	  1 for redirect of POST with content,
 **	303 for redirect as GET without content
diff --git a/src/HTFWriter.c b/src/HTFWriter.c
index e9f7d1ee..820d0fa0 100644
--- a/src/HTFWriter.c
+++ b/src/HTFWriter.c
@@ -710,14 +710,31 @@ PUBLIC HTStream* HTSaveToFile ARGS3(
     StrAllocCopy(anchor->FileCache, fnam);
     if (!strncasecomp(pres->rep->name, "text/html", 9)) {
         /*
-	 *  Add the document's URL as a BASE tag at the top of the file,
+	 *  Add the document's base as a BASE tag at the top of the file,
 	 *  so that any partial or relative URLs within it will be resolved
 	 *  relative to that if no BASE tag is present and replaces it.
 	 *  Note that the markup will be technically invalid if a DOCTYPE
 	 *  declaration, or HTML or HEAD tags, are present, and thus the
 	 *  file may need editing for perfection. - FM
 	 */
-        fprintf(ret_obj->fp, "<BASE HREF=\"%s\">\n\n", anchor->address);
+	char *temp = NULL;
+
+	if (anchor->content_base && *anchor->content_base) {
+	    StrAllocCopy(temp, anchor->content_base);
+	} else if (anchor->content_location && *anchor->content_location) {
+	    StrAllocCopy(temp, anchor->content_location);
+	}
+	if (temp) {
+	    collapse_spaces(temp);
+	    if (!is_url(temp)) {
+	        FREE(temp);
+	    }
+	}
+
+        fprintf(ret_obj->fp,
+		"<!-- X-URL: %s -->\n<BASE HREF=\"%s\">\n\n",
+		anchor->address, (temp ? temp : anchor->address));
+	FREE(temp);
     }
     return ret_obj;
 }
diff --git a/src/HTForms.h b/src/HTForms.h
index 269f6b18..612bbb89 100644
--- a/src/HTForms.h
+++ b/src/HTForms.h
@@ -89,6 +89,8 @@ typedef struct _FormInfo {
 #define F_RANGE_TYPE      10
 #define F_FILE_TYPE       11
 #define F_TEXT_SUBMIT_TYPE 12
+#define F_IMAGE_SUBMIT_TYPE 13
+#define F_KEYGEN_TYPE     14
 
 #define WWW_FORM_LINK_TYPE  1
 #define WWW_LINK_TYPE   2
diff --git a/src/HTInit.c b/src/HTInit.c
index 63933236..0864816c 100644
--- a/src/HTInit.c
+++ b/src/HTInit.c
@@ -59,6 +59,7 @@ PUBLIC void HTFormatInit NOARGS
   							    1.0, 3.0, 0.0, 0);
   HTSetPresentation("image/gif",        XLOADIMAGE_COMMAND, 1.0, 3.0, 0.0, 0);
   HTSetPresentation("image/x-xbm",      XLOADIMAGE_COMMAND, 1.0, 3.0, 0.0, 0);
+  HTSetPresentation("image/x-xbitmap",  XLOADIMAGE_COMMAND, 1.0, 3.0, 0.0, 0);
   HTSetPresentation("image/x-png",      XLOADIMAGE_COMMAND, 1.0, 3.0, 0.0, 0);
   HTSetPresentation("image/x-rgb",      XLOADIMAGE_COMMAND, 1.0, 3.0, 0.0, 0);
   HTSetPresentation("image/x-tiff",     XLOADIMAGE_COMMAND, 1.0, 3.0, 0.0, 0);
@@ -397,7 +398,7 @@ PRIVATE int ProcessMailcapEntry ARGS2(FILE *,fp, struct MailcapEntry *,mc)
 		/* ExceptionalNewline(mc->contenttype, atoi(eq)); */
 	    } else if (eq && !strcmp(arg, "q")) {
 	        mc->quality = atof(eq);
-		if (mc->quality < 0.001)
+		if (mc->quality > 0.000 && mc->quality < 0.001)
 		    mc->quality = 0.001;
 	    } else if (eq && !strcmp(arg, "mxb")) {
 	        mc->maxbytes = atol(eq);
@@ -490,6 +491,7 @@ PRIVATE int PassesTest ARGS1(struct MailcapEntry *,mc)
      *  Save overhead of system() calls by faking these. - FM
      */
     if (0 == strcasecomp(mc->testcommand, "test -n \"$DISPLAY\"")) {
+        FREE(mc->testcommand);
         if (TRACE)
 	    fprintf(stderr,"Testing for XWINDOWS environment.\n");
     	if ((cp = getenv(DISPLAY)) != NULL && *cp != '\0') {
@@ -503,6 +505,7 @@ PRIVATE int PassesTest ARGS1(struct MailcapEntry *,mc)
 	}
     }
     if (0 == strcasecomp(mc->testcommand, "test -z \"$DISPLAY\"")) {
+        FREE(mc->testcommand);
         if (TRACE)
 	    fprintf(stderr,"Testing for NON_XWINDOWS environment.\n");
     	if (!((cp = getenv(DISPLAY)) != NULL && *cp != '\0')) {
@@ -520,6 +523,7 @@ PRIVATE int PassesTest ARGS1(struct MailcapEntry *,mc)
      *  Why do anything but return success for this one! - FM
      */
     if (0 == strcasecomp(mc->testcommand, "test -n \"$LYNX_VERSION\"")){
+        FREE(mc->testcommand);
         if (TRACE) {
 	    fprintf(stderr,"Testing for LYNX environment.\n");
 	    fprintf(stderr,"[HTInit] Test passed!\n");
@@ -530,6 +534,7 @@ PRIVATE int PassesTest ARGS1(struct MailcapEntry *,mc)
      *  ... or failure for this one! - FM
      */
     if (0 == strcasecomp(mc->testcommand, "test -z \"$LYNX_VERSION\"")) {
+        FREE(mc->testcommand);
         if (TRACE) {
 	    fprintf(stderr,"Testing for non-LYNX environment.\n");
 	    fprintf(stderr,"[HTInit] Test failed!\n");
diff --git a/src/HTML.c b/src/HTML.c
index e96ab89d..5ca1756c 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -13,24 +13,29 @@
 */
 #include "HTUtils.h"
 #include "tcp.h"
-#include "HTML.h"
-#include "HTCJK.h"
-#include "HTAtom.h"
+
+#define Lynx_HTML_Handler
 #include "HTChunk.h"
 #include "HText.h"
 #include "HTStyle.h"
-#include "HTAlert.h"
+#include "HTML.h"
+
+#include "HTCJK.h"
+#include "HTAtom.h"
 #include "HTMLGen.h"
 #include "HTParse.h"
-#include "HTNestedList.h"
+
+#include "LYGlobalDefs.h"
+#include "LYCharUtils.h"
+#include "LYCharSets.h"
+
+#include "HTAlert.h"
+#include "HTFont.h"
 #include "HTForms.h"
+#include "HTNestedList.h"
 #include "GridText.h"
-#include "HTFont.h"
-#include "LYGlobalDefs.h"
 #include "LYSignal.h"
 #include "LYUtils.h"
-#include "LYCharSets.h"
-#include "LYCharUtils.h"
 #include "LYMap.h"
 #include "LYBookmark.h"
 
@@ -49,10 +54,6 @@ extern HTCJKlang HTCJK;
 
 extern BOOLEAN HT_Is_Gopher_URL;
 
-PRIVATE char *LastOptionValue = NULL;
-
-PUBLIC BOOLEAN ignore_excess = FALSE;
-
 /* from Curses.h */
 extern int LYcols;
 
@@ -65,67 +66,9 @@ PRIVATE HTStyle *styles[HTML_ELEMENTS+31]; /* adding 24 nested list styles  */
 					   /* and 3 header alignment styles */
 					   /* and 3 div alignment styles    */
 PRIVATE HTStyle *default_style;
-PUBLIC char HTML_Last_Char = '\0';  /* the last character put on the screen */
-PRIVATE char *textarea_name = NULL;
-PRIVATE char *textarea_cols = NULL;
-PRIVATE int textarea_rows = 4;
-PRIVATE int textarea_disabled = NO;
-PRIVATE char *textarea_id = NULL;
-PRIVATE BOOLEAN LastOptionChecked = FALSE;
-PRIVATE BOOLEAN B_hide_mail_header = FALSE;
-PRIVATE char *base_href = NULL;
-PRIVATE int select_disabled = NO;
-PRIVATE int current_default_alignment = HT_LEFT;
-PRIVATE BOOLEAN LYUsePlainSpace = FALSE;
-PRIVATE BOOLEAN LYHiddenValue = FALSE;
-
-/*		HTML Object
-**		-----------
-*/
-#define MAX_NESTING 800		/* Should be checked by parser */
-
-/*      Track if we are in an anchor, paragraph, address, base, etc.
- */
-PRIVATE BOOLEAN B_inA = FALSE;
-PRIVATE BOOLEAN B_inAPPLET = FALSE;
-PRIVATE BOOLEAN B_inAPPLETwithP = FALSE;
-PRIVATE BOOLEAN B_inBadHTML = FALSE;
-PRIVATE BOOLEAN B_inBASE = FALSE;
-PRIVATE BOOLEAN B_inBoldA = FALSE;
-PRIVATE BOOLEAN B_inBoldH = FALSE;
-PRIVATE BOOLEAN B_inCAPTION = FALSE;
-PRIVATE BOOLEAN B_inCREDIT = FALSE;
-PRIVATE BOOLEAN B_inFIG = FALSE;
-PRIVATE BOOLEAN B_inFIGwithP = FALSE;
-PRIVATE BOOLEAN B_inFORM = FALSE;
-PRIVATE BOOLEAN B_inLABEL = FALSE;
-PRIVATE BOOLEAN B_inP = FALSE;
-PRIVATE BOOLEAN B_inPRE = FALSE;
-PRIVATE BOOLEAN B_inSELECT = FALSE;
-PRIVATE BOOLEAN B_inTABLE = FALSE;
-PRIVATE BOOLEAN B_inTEXTAREA = FALSE;
-PRIVATE BOOLEAN B_inUnderline = FALSE;
-
-PRIVATE BOOLEAN B_needBoldH = FALSE;
 
 PUBLIC char *LYToolbarName = "LynxPseudoToolbar";
 
-PUBLIC char *LYMapName = NULL;
-
-/* used for nested lists */
-PRIVATE int List_Nesting_Level= -1;  /* counter for list nesting level */
-PRIVATE int OL_Counter[7];	     /* counter for ordered lists */
-PRIVATE char OL_Type[7];	     /* types for ordered lists */
-PRIVATE int Last_OL_Count = 0;	     /* last count in ordered lists */
-PRIVATE char Last_OL_Type = '1';     /* last type in ordered lists */
-PRIVATE int OL_CONTINUE = -29999;    /* flag for whether CONTINUE is set */
-PRIVATE int OL_VOID = -29998;	     /* flag for whether a count is set */
-
-PRIVATE int Division_Level = -1;
-PRIVATE short DivisionAlignments[MAX_NESTING];
-PRIVATE int Underline_Level = 0;
-PRIVATE int Quote_Level = 0;
-
 /* used to turn off a style if the HTML author forgot to
 PRIVATE int i_prior_style = -1;
  */
@@ -136,101 +79,18 @@ PRIVATE int i_prior_style = -1;
 PRIVATE void HTML_end_element PARAMS((HTStructured *me,
 				      int element_number,
 				      char **include));
-PRIVATE void HTML_put_entity PARAMS((HTStructured *me, int entity_number));
-PRIVATE BOOLEAN HTML_override_default_alignment PARAMS((HTStructured *me));
-PRIVATE void HTML_zero_OL_Counter NOPARAMS;
-PRIVATE void HTML_EnsureDoubleSpace PARAMS((HTStructured *me));
-PRIVATE void HTML_EnsureSingleSpace PARAMS((HTStructured *me));
-PRIVATE void HTML_ResetParagraphAlignment PARAMS((HTStructured *me));
-PRIVATE void HTMLFillLocalFileURL PARAMS((char **href, char *base));
-
-typedef struct _stack_element {
-        HTStyle *	style;
-	int		tag_number;
-} stack_element;
-
-struct _HTStructured {
-    CONST HTStructuredClass * 	isa;
-    HTParentAnchor * 		node_anchor;
-    HText * 			text;
-
-    HTStream*			target;			/* Output stream */
-    HTStreamClass		targetClass;		/* Output routines */
-
-    HTChunk 			title;		/* Grow by 128 */
-    HTChunk			object;		/* Grow by 128 */
-    BOOL			object_started;
-    BOOL			object_declare;
-    BOOL			object_shapes;
-    BOOL			object_ismap;
-    char *			object_usemap;
-    char *			object_id;
-    char *			object_title;
-    char *			object_data;
-    char *			object_type;
-    char *			object_classid;
-    char *			object_codebase;
-    char *			object_codetype;
-    char *			object_name;
-    HTChunk			option;		/* Grow by 128 */
-    HTChunk			textarea;	/* Grow by 128 */
-    HTChunk			math;		/* Grow by 128 */
-    HTChunk			style_block;	/* Grow by 128 */
-    HTChunk			script;		/* Grow by 128 */
-
-    char *			comment_start;	/* for literate programming */
-    char *			comment_end;
-
-    HTTag *			current_tag;
-    BOOL			style_change;
-    HTStyle *			new_style;
-    HTStyle *			old_style;
-    BOOL			in_word;  /* Have just had a non-white char */
-    stack_element 	stack[MAX_NESTING];
-    stack_element 	*sp;		/* Style stack pointer */
-};
-
-struct _HTStream {
-    CONST HTStreamClass *	isa;
-    /* .... */
-};
 
 /*		Forward declarations of routines
 */
 PRIVATE void get_styles NOPARAMS;
-
-
 PRIVATE void actually_set_style PARAMS((HTStructured * me));
 PRIVATE void change_paragraph_style PARAMS((HTStructured * me,
 					    HTStyle * style));
-PRIVATE void HTML_CheckForID PARAMS((HTStructured * me,
-				     CONST BOOL * present,
-				     CONST char ** value,
-				     int attribute));
-PRIVATE void HTML_HandleID PARAMS((HTStructured * me, char * id));
-
 
 /*	Style buffering avoids dummy paragraph begin/ends.
 */
 #define UPDATE_STYLE if (me->style_change) { actually_set_style(me); }
 
-PUBLIC BOOLEAN LYCheckForCSI ARGS2(
-	HTStructured *, 	me,
-	char **,		url)
-{
-    if (me == NULL || !me->node_anchor->address)
-        return FALSE;
-
-    if (strncasecomp(me->node_anchor->address, "file:", 5))
-        return FALSE;
-
-    if (!LYisLocalHost(me->node_anchor->address))
-        return FALSE;
-     
-    StrAllocCopy(*url, me->node_anchor->address);
-    return TRUE;
-}
-
 
 /*		Flattening the style structure
 **		------------------------------
@@ -251,6 +111,7 @@ PRIVATE void actually_set_style ARGS1(HTStructured *, me)
 	    HText_beginAppend(me->text);
 	    HText_setStyle(me->text, me->new_style);
 	    me->in_word = NO;
+	    LYCheckForContentBase(me);
     } else {
 	    HText_setStyle(me->text, me->new_style);
     }
@@ -280,16 +141,8 @@ PRIVATE void change_paragraph_style ARGS2(HTStructured *, me, HTStyle *,style)
 /*	Character handling
 **	------------------
 */
-PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
+PUBLIC void HTML_put_character ARGS2(HTStructured *, me, char, c)
 {
-   /*
-    * Convert EOL styles:
-    *  macintosh:  cr    --> lf
-    *  ascii:      cr-lf --> lf
-    *  unix:       lf    --> lf
-    */
-    static int lastraw = -1;
-
     /*
      *  Ignore all non-MAP content when just
      *  scanning a document for MAPs. - FM
@@ -299,12 +152,17 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
 
     /*
      *  Do EOL conversion if needed. - FM
+     *
+     *  Convert EOL styles:
+     *   macintosh:  cr    --> lf
+     *   ascii:      cr-lf --> lf
+     *   unix:       lf    --> lf
      */
-    if ((lastraw == '\r') && c == '\n') {
-	lastraw = -1;
+    if ((me->lastraw == '\r') && c == '\n') {
+	me->lastraw = -1;
 	return;
     }
-    lastraw = c;
+    me->lastraw = c;
     if (c == '\r')
 	c = '\n';
 
@@ -364,13 +222,13 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
 	 *  But we still want to strip \r's
 	 */
 	if (c != '\r' &&
-	    !(c == '\n' && B_inLABEL && !B_inP) &&
-	    !(c == '\n' && !B_inPRE)) {
-	    B_inP = TRUE;
-	    B_inLABEL = FALSE; 
+	    !(c == '\n' && me->inLABEL && !me->inP) &&
+	    !(c == '\n' && !me->inPRE)) {
+	    me->inP = TRUE;
+	    me->inLABEL = FALSE; 
 	    HText_appendCharacter(me->text, c);
 	}
-	B_inPRE = TRUE;
+	me->inPRE = TRUE;
 	break;
 
     case HTML_LISTING:				/* Litteral text */
@@ -381,8 +239,8 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
 	 *  But we still want to strip \r's
 	 */
 	if (c != '\r')	{
-	    B_inP = TRUE;
-	    B_inLABEL = FALSE; 
+	    me->inP = TRUE;
+	    me->inLABEL = FALSE; 
 	    HText_appendCharacter(me->text, c);
 	}
 	break;
@@ -393,19 +251,19 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
 	 */
 	if (!strcmp(me->sp->style->name,"Preformatted")) {
 	    if (c != '\r' &&
-	        !(c == '\n' && B_inLABEL && !B_inP) &&
-		!(c == '\n' && !B_inPRE)) {
-		B_inP = TRUE; 
-		B_inLABEL = FALSE; 
+	        !(c == '\n' && me->inLABEL && !me->inP) &&
+		!(c == '\n' && !me->inPRE)) {
+		me->inP = TRUE; 
+		me->inLABEL = FALSE; 
 	        HText_appendCharacter(me->text, c);
 	    }
-	    B_inPRE = TRUE;
+	    me->inPRE = TRUE;
 
 	} else if (!strcmp(me->sp->style->name,"Listing") ||
 		   !strcmp(me->sp->style->name,"Example")) {
 	    if (c != '\r') {
-		B_inP = TRUE; 
-		B_inLABEL = FALSE; 
+		me->inP = TRUE; 
+		me->inLABEL = FALSE; 
 	        HText_appendCharacter(me->text, c);
 	    }
 	
@@ -417,18 +275,18 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
 	    }
 	    if (c == '\n') {
 	        if (me->in_word) {
-	            if (HTML_Last_Char != ' ') {
-			B_inP = TRUE;
-			B_inLABEL = FALSE;
+	            if (HText_getLastChar(me->text) != ' ') {
+			me->inP = TRUE;
+			me->inLABEL = FALSE;
 		        HText_appendCharacter(me->text, ' ');
 		    }
 		    me->in_word = NO;
 	        }
 
 	    } else if (c == ' ' || c == '\t') {
-	        if (HTML_Last_Char != ' ') {
-		    B_inP = TRUE;
-		    B_inLABEL = FALSE; 
+	        if (HText_getLastChar(me->text) != ' ') {
+		    me->inP = TRUE;
+		    me->inLABEL = FALSE; 
 	            HText_appendCharacter(me->text, ' ');
 		}
 
@@ -436,8 +294,8 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
 	       /* ignore */
 
 	    } else {
-		B_inP = TRUE;
-		B_inLABEL = FALSE;
+		me->inP = TRUE;
+		me->inLABEL = FALSE;
 	        HText_appendCharacter(me->text, c);
 	        me->in_word = YES;
 	    }
@@ -445,17 +303,17 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
     } /* end second switch */
 
     if (c == '\n' || c == '\t') {
-     	HTML_Last_Char = ' '; /* set it to a generic seperater */
+     	HText_setLastChar(me->text, ' '); /* set it to a generic seperater */
 
 	/*
 	 *  \r's are ignored.  In order to keep collapsing spaces
 	 *  correctly we must default back to the previous
 	 *  seperater if there was one
 	 */
-    } else if (c == '\r' && HTML_Last_Char == ' ') {
-     	HTML_Last_Char = ' '; /* set it to a generic seperater */
+    } else if (c == '\r' && HText_getLastChar(me->text) == ' ') {
+     	HText_setLastChar(me->text, ' '); /* set it to a generic seperater */
     } else {
-     	HTML_Last_Char = c;
+     	HText_setLastChar(me->text, c);
     }
 }
 
@@ -465,7 +323,7 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
 **	This is written separately from put_character becuase the loop can
 **	in some cases be promoted to a higher function call level for speed.
 */
-PRIVATE void HTML_put_string ARGS2(HTStructured *, me, CONST char*, s)
+PUBLIC void HTML_put_string ARGS2(HTStructured *, me, CONST char *, s)
 {
    if (LYMapsOnly || s == NULL)
       return;
@@ -532,13 +390,13 @@ PRIVATE void HTML_put_string ARGS2(HTStructured *, me, CONST char*, s)
 		}
 		if (*p == '\n') {
 		    if (me->in_word) {
-		        if (HTML_Last_Char != ' ')
+		        if (HText_getLastChar(me->text) != ' ')
 			    HText_appendCharacter(me->text, ' ');
 			me->in_word = NO;
 		    }
 
 		} else if (*p == ' ' || *p == '\t') {
-		   if (HTML_Last_Char != ' ')
+		   if (HText_getLastChar(me->text) != ' ')
 			HText_appendCharacter(me->text, ' ');
 			
 		} else if (*p == '\r') {
@@ -550,16 +408,19 @@ PRIVATE void HTML_put_string ARGS2(HTStructured *, me, CONST char*, s)
 
 		/* set the Last Character */
     		if (*p == '\n' || *p == '\t') {
-        	    HTML_Last_Char = ' '; /* set it to a generic seperater */
-    		} else if (*p == '\r' && HTML_Last_Char == ' ') {
+		    /* set it to a generic seperater */
+        	    HText_setLastChar(me->text, ' ');
+    		} else if (*p == '\r' &&
+			   HText_getLastChar(me->text) == ' ') {
 		    /* 
 		     *  \r's are ignored.  In order to keep collapsing
 		     *  spaces correctly, we must default back to the
-		     *  previous seperator, if there was one.
+		     *  previous seperator, if there was one.  So we
+		     *  set LastChar to a generic seperater.
 		     */
-       		    HTML_Last_Char = ' '; /* set it to a generic seperater */
+       		    HText_setLastChar(me->text, ' ');
     		} else {
-       		    HTML_Last_Char = *p;
+       		    HText_setLastChar(me->text, *p);
     		}
 
 	    } /* for */
@@ -570,7 +431,7 @@ PRIVATE void HTML_put_string ARGS2(HTStructured *, me, CONST char*, s)
 /*	Buffer write
 **	------------
 */
-PRIVATE void HTML_write ARGS3(HTStructured *, me, CONST char*, s, int, l)
+PUBLIC void HTML_write ARGS3(HTStructured *, me, CONST char*, s, int, l)
 {
     CONST char* p;
     CONST char* e = s+l;
@@ -599,11 +460,11 @@ PRIVATE void HTML_start_element ARGS5(
     char *title = NULL;
     char *temp = NULL;
     static BOOLEAN first_option = TRUE;	     /* is this the first option tag? */
-    static HTChildAnchor *B_CurrentA = NULL; /* current HTML_A anchor */
-    HTParentAnchor *dest = NULL;	     /* the anchor's destination */
+    HTParentAnchor *dest = NULL;	     /* an anchor's destination */
     BOOL dest_ismap = FALSE;	     	     /* is dest an image map script? */
-    HTChildAnchor *B_ID_A = NULL;	     /* HTML_foo_ID anchor */
-    int url_type;
+    HTChildAnchor *ID_A = NULL;		     /* HTML_foo_ID anchor */
+    int url_type = 0, i = 0;
+    char *cp = NULL;
 
     if (LYMapsOnly) {
         if (!(element_number == HTML_MAP || element_number == HTML_AREA)) {
@@ -615,27 +476,17 @@ PRIVATE void HTML_start_element ARGS5(
 
     case HTML_HTML:
         UPDATE_STYLE;
-	List_Nesting_Level = -1;
-	HTML_zero_OL_Counter();
-	Division_Level = -1;
-	Underline_Level = 0;
-	Quote_Level = 0;
-	if (B_inUnderline) {
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
-	    B_inUnderline = FALSE;
+	if (me->inUnderline) {
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    me->inUnderline = FALSE;
 	}
 	break;
 
     case HTML_HEAD:
         UPDATE_STYLE;
-	List_Nesting_Level = -1;
-	HTML_zero_OL_Counter();
-	Division_Level = -1;
-	Underline_Level = 0;
-	Quote_Level = 0;
-	if (B_inUnderline) {
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
-	    B_inUnderline = FALSE;
+	if (me->inUnderline) {
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    me->inUnderline = FALSE;
 	}
 	break;
 
@@ -645,6 +496,11 @@ PRIVATE void HTML_start_element ARGS5(
 	    char *base = NULL;
 	    char *related = NULL;
 
+	    StrAllocCopy(base, (char *)value[HTML_BASE_HREF]);
+	    if (!(url_type = LYLegitimizeHREF(me, (char**)&base, TRUE))) {
+	        HTAlert(BASE_NOT_ABSOLUTE);
+	    }
+
 	    /* 
 	     *  Get parent's address for defaulted fields.
 	     */
@@ -653,16 +509,15 @@ PRIVATE void HTML_start_element ARGS5(
 	    /* 
 	     *  Create the access field.
 	     */
-	    StrAllocCopy(base, (char *)value[HTML_BASE_HREF]);
-	    convert_to_spaces(base);
-	    LYUnEscapeToLatinOne(&base, TRUE);
 	    if ((temp = HTParse(base, related,
 	    			PARSE_ACCESS+PARSE_PUNCTUATION)) &&
-		*temp != '\0')
-	        StrAllocCopy(base_href, temp);
-	    else
-	        StrAllocCopy(base_href, (temp = HTParse(related, "",
+		*temp != '\0') {
+	        StrAllocCopy(me->base_href, temp);
+	    } else {
+	        StrAllocCopy(me->base_href, (temp = HTParse(related, "",
 					 PARSE_ACCESS+PARSE_PUNCTUATION)));
+	    }
+	    FREE(temp);
 
 	    /*
 	     *  Create the host[:port] field.
@@ -670,395 +525,58 @@ PRIVATE void HTML_start_element ARGS5(
 	    if ((temp = HTParse(base, "",
 	    			PARSE_HOST+PARSE_PUNCTUATION)) &&
 	    	!strncmp(temp, "//", 2)) {
-	        StrAllocCat(base_href, temp);
-		if (!strcmp(base_href, "file://"))
-		    StrAllocCat(base_href, "localhost");
+	        StrAllocCat(me->base_href, temp);
+		if (!strcmp(me->base_href, "file://")) {
+		    StrAllocCat(me->base_href, "localhost");
+		}
 	    } else {
-	        if (!strcmp(base_href, "file:"))
-		    StrAllocCat(base_href, "//localhost");
-		else
-	            StrAllocCat(base_href, (temp = HTParse(related, "",
+	        if (!strcmp(me->base_href, "file:")) {
+		    StrAllocCat(me->base_href, "//localhost");
+		} else if (strcmp(me->base_href, "news:")) {
+	            StrAllocCat(me->base_href, (temp = HTParse(related, "",
 					    PARSE_HOST+PARSE_PUNCTUATION)));
+		}
 	    }
+	    FREE(temp);
+	    FREE(related);
 
 	    /*
 	     *  Create the path field.
 	     */
 	    if ((temp = HTParse(base, "",
 	    			PARSE_PATH+PARSE_PUNCTUATION)) &&
-		*temp != '\0')
-	        StrAllocCat(base_href, temp);
-	    else
-	        StrAllocCat(base_href, "/");
-
-            B_inBASE = TRUE;
-
+		*temp != '\0') {
+	        StrAllocCat(me->base_href, temp);
+		FREE(temp);
+	    } else if (!strcmp(me->base_href, "news:")) {
+	        StrAllocCat(me->base_href, "*");
+	    } else if (!strncmp(me->base_href, "news:", 5) ||
+	    	       !strncmp(me->base_href, "nntp:", 5) ||
+		       !strncmp(me->base_href, "snews:", 6)) {
+	        StrAllocCat(me->base_href, "/*");
+	    } else {
+	        StrAllocCat(me->base_href, "/");
+	    }
 	    FREE(base);
-	    FREE(related);
-	    FREE(temp);
+
+            me->inBASE = TRUE;
 	}
 	break;
 
     case HTML_META:
         if (!me->text)
 	    UPDATE_STYLE;
-
-	if (present) {
-	    char *http_equiv = NULL, *name = NULL, *content = NULL;
-	    /*
-	     *  Load the attributes for possible use by Lynx. - FM
-	     */
-	    if (present[HTML_META_HTTP_EQUIV] &&
-		value[HTML_META_HTTP_EQUIV] && *value[HTML_META_HTTP_EQUIV]) {
-		StrAllocCopy(http_equiv, value[HTML_META_HTTP_EQUIV]);
-		LYUnEscapeToLatinOne(&http_equiv, FALSE);
-		LYTrimHead(http_equiv);
-		LYTrimTail(http_equiv);
-		if (*http_equiv == '\0') {
-		    FREE(http_equiv);
-		}
-	    }
-	    if (present[HTML_META_NAME] &&
-		value[HTML_META_NAME] && *value[HTML_META_NAME]) {
-		StrAllocCopy(name, value[HTML_META_NAME]);
-		LYUnEscapeToLatinOne(&http_equiv, FALSE);
-		LYTrimHead(name);
-		LYTrimTail(name);
-		if (*name == '\0') {
-		    FREE(name);
-		}
-	    }
-	    if (present[HTML_META_CONTENT] &&
-		value[HTML_META_CONTENT] && *value[HTML_META_CONTENT]) {
-		/*
-		 *  Technically, we should be creating a comma-separated
-		 *  list, but META tags come one at a time, and we'll
-		 *  handle (or ignore) them as each is received.  Also,
-		 *  at this point, we only trim leading and trailing
-		 *  blanks from the CONTENT value, without translating
-		 *  any named entities or numeric character references,
-		 *  because how we should do that depends on what type
-		 *  of information it contains, and whether or not any
-		 *  of it might be sent to the screen. - FM
-		 */
-		StrAllocCopy(content, value[HTML_META_CONTENT]);
-		LYTrimHead(content);
-		LYTrimTail(content);
-		if (*content == '\0') {
-		    FREE(content);
-		}
-	    }
-
-	    if (TRACE) {
-	        fprintf(stderr,
-		"HTML: META HTTP-EQUIV=\"%s\" NAME=\"%s\" CONTENT=\"%s\"\n",
-			(http_equiv ? http_equiv : "NULL"),
-			(name ? name : "NULL"),
-			(content ? content : "NULL"));
-	    }
-
-	    /*
-	     *  Add META-handling code or function calls here. - FM
-	     */
-	    if ((http_equiv || name) && content) {
-		char *cp, *cp1;
-
-	        /*
-		 * Check for a no-cache Pragma
-		 * or Cache-Control directive. - FM
-		 */
-	    	if (!strcasecomp((name ? name : http_equiv),
-				 "Pragma") ||
-		    !strcasecomp((name ? name : http_equiv),
-		     		 "Cache-Control")) {
-		    LYUnEscapeToLatinOne(&content, FALSE);
-		    LYTrimHead(content);
-		    LYTrimTail(content);
-		    if (!strcasecomp(content, "no-cache")) {
-		        me->node_anchor->no_cache = TRUE;
-		        HText_setNoCache(me->text);
-		    }
-
-	            /*
-		     *  If we didn't get a Cache-Control MIME
-		     *  header, and the META has one, store it
-		     *  in the anchor element. - FM
-		     */
-		    if ((!me->node_anchor->cache_control) &&
-			!strcasecomp((name ? name : http_equiv),
-				     "Cache-Control")) {
-			StrAllocCopy(me->node_anchor->cache_control,
-				     (name ? name : http_equiv));
-		    }
-
-	        /*
-		 *  Check for a text/html Content-Type with a
-		 *  charset directive, if we didn't already set
-		 *  the charset via a server's header. - AAC & FM
-		 */
-		} else if (!(me->node_anchor->charset &&
-			     *me->node_anchor->charset) && 
-			   !strcasecomp((name ? name : http_equiv),
-					"Content-Type")) {
-		    LYUnEscapeToLatinOne(&content, FALSE);
-		    LYTrimHead(content);
-		    LYTrimTail(content);
-		    /*
-		     *  Force the Content-type value to all lower case. - FM
-		     */
-		    for (cp = content; *cp; cp++)
-		        *cp = TOLOWER(*cp);
-
-		    if ((cp=strstr(content, "text/html;")) != NULL &&
-			(cp1=strstr(content, "charset")) != NULL &&
-			cp1 > cp) {
-			cp1 += 7;
-			while (*cp1 == ' ' || *cp1 == '=')
-			    cp1++;
-			if (!strncmp(cp1, "us-ascii", 8) ||
-			    !strncmp(cp1, "iso-8859-1", 10)) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "iso-8859-1");
-			    HTCJK = NOCJK;
-			} else if (!strncmp(cp1, "iso-8859-2", 10) &&
-				   !strncmp(LYchar_set_names[current_char_set],
-				   	    "ISO Latin 2", 11)) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "iso-8859-2");
-			    HTPassEightBitRaw = TRUE;
-			} else if (!strncmp(cp1, "iso-8859-", 9) &&
-				   !strncmp(LYchar_set_names[current_char_set],
-				   	    "Other ISO Latin", 15)) {
-			    /*
-			    **  Hope it's a match, for now. - FM
-			    */
-			    StrAllocCopy(me->node_anchor->charset,
-					 "iso-8859- ");
-			    me->node_anchor->charset[9] = cp1[9];
-			    HTPassEightBitRaw = TRUE;
-			    HTAlert(me->node_anchor->charset);
-			} else if (!strncmp(cp1, "koi8-r", 6) &&
-				   !strncmp(LYchar_set_names[current_char_set],
-					    "KOI8-R character set", 20)) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "koi8-r");
-			    HTPassEightBitRaw = TRUE;
-			} else if (!strncmp(cp1, "euc-jp", 6) &&
-			           HTCJK == JAPANESE) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "euc-jp");
-			} else if (!strncmp(cp1, "shift_jis", 9) &&
-			           HTCJK == JAPANESE) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "shift_jis");
-			} else if (!strncmp(cp1, "iso-2022-jp", 11) &&
-			           HTCJK == JAPANESE) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "iso-2022-jp");
-			} else if (!strncmp(cp1, "iso-2022-jp-2", 13) &&
-			           HTCJK == JAPANESE) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "iso-2022-jp-2");
-			} else if (!strncmp(cp1, "euc-kr", 6) &&
-			           HTCJK == KOREAN) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "euc-kr");
-			} else if (!strncmp(cp1, "iso-2022-kr", 11) &&
-			           HTCJK == KOREAN) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "iso-2022-kr");
-			} else if ((!strncmp(cp1, "big5", 4) ||
-				    !strncmp(cp1, "cn-big5", 7)) &&
-			           HTCJK == TAIPEI) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "big5");
-			} else if (!strncmp(cp1, "euc-cn", 6) &&
-			           HTCJK == CHINESE) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "euc-cn");
-			} else if ((!strncmp(cp1, "gb2312", 6) ||
-				    !strncmp(cp1, "cn-gb", 5)) &&
-			           HTCJK == CHINESE) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "gb2312");
-			} else if (!strncmp(cp1, "iso-2022-cn", 11) &&
-			           HTCJK == CHINESE) {
-			    StrAllocCopy(me->node_anchor->charset,
-					 "iso-2022-cn");
-			}
-			if (TRACE && me->node_anchor->charset) {
-			    fprintf(stderr, "HTML: New charset: %s\n",
-					    me->node_anchor->charset);
-			}
-		    }
-		    /*
-		     *  Set the kcode element based on the charset. - FM
-		     */
-		    HText_setKcode(me->text, me->node_anchor->charset);
-
-		/*
-		 *  Check for a Refresh directive. - FM
-		 */
-		} else if (!strcasecomp((name ? name : http_equiv),
-					"Refresh")) {
-		    char *Seconds = NULL;
-
-		    /*
-		     *  Look for the Seconds field. - FM
-		     */
-		    cp = content;
-		    while (*cp && isspace((unsigned char)*cp))
-		        cp++;
-		    if (*cp && isdigit(*cp)) {
-		        cp1 = cp;
-			while (*cp1 && isdigit(*cp1))
-		            cp1++;
-			*cp1 = '\0';
-		        StrAllocCopy(Seconds, cp);
-			cp1++;
-		    }
-		    if (Seconds) {
-		        /*
-			 *  We have the seconds field.
-			 *  Now look for a URL field - FM
-			 */
-			while (*cp1) {
-			    if (!strncasecomp(cp1, "URL", 3)) {
-			        cp = (cp1 + 3);
-				while (*cp && (*cp == '=' ||
-					       isspace((unsigned char)*cp)))
-				    cp++;
-				cp1 = cp;
-				while (*cp1 && !isspace((unsigned char)*cp1))
-				    cp1++;
-				*cp1 = '\0';
-				if (*cp) {
-				    StrAllocCopy(href, cp);
-				    convert_to_spaces(href);
-				    /*
-				     *  Translate any named or numeric
-				     *  character references with the
-				     *  isURL flag set. - FM
-				     */
-				    LYUnEscapeToLatinOne(&href, TRUE);
-				}
-				break;
-			    }
-			    cp1++;
-			}
-			if (href) {
-			    /*
-			     *  We found a URL field, so check it out. - FM
-			     */
-			    if (!is_url(href)) {
-			        /*
-				 *  The specs require a complete URL,
-				 *  but this is a Netscapism, so don't
-				 *  expect the author to know that. - FM
-				 */
-				if (*href != '\0' && *href != '/')
-				    HTSimplify(href);
-				/*
-				 *  Use the document's address
-				 *  as the base. - FM
-				 */
-				if (*href != '\0') {
-				    temp = HTParse(href,
-					           me->node_anchor->address,
-					           PARSE_ALL);
-				    StrAllocCopy(href, temp);
-				    FREE(temp);
-				} else {
-				    StrAllocCopy(href,
-				    		 me->node_anchor->address);
-				    HText_setNoCache(me->text);
-				}
-			    }
-			    /*
-			     *  Check whether to fill in localhost. - FM
-			     */
-			    HTMLFillLocalFileURL((char **)&href,
-						 (B_inBASE ? base_href :
-						  me->node_anchor->address));
-			    /*
-			     *  Set the no_cache flag if the Refresh URL
-			     *  is the same as the document's address. - FM
-			     */
-			    if (!strcmp(href, me->node_anchor->address)) {
-			        HText_setNoCache(me->text);
-			    } 
-			} else {
-			    /*
-			     *  We didn't find a URL field, so use
-			     *  the document's own address and set
-			     *  the no_cache flag. - FM
-			     */
-			    StrAllocCopy(href, me->node_anchor->address);
-			    HText_setNoCache(me->text);
-			}
-			/*
-			 *  Check for an anchor in http or https URLs. - FM
-			 */
-			if ((strncmp(href, "http", 4) == 0) &&
-			    (cp = strrchr(href, '#')) != NULL) {
-			    StrAllocCopy(id_string, cp);
-			    *cp = '\0';
-			}
-			B_CurrentA = HTAnchor_findChildAndLink(
-				me->node_anchor,		/* Parent */
-				id_string,			/* Tag */
-				href,				/* Addresss */
-				(void *)0);			/* Type */
-			if (id_string)
-			    *cp = '#';
-			FREE(id_string);
-			HTML_EnsureSingleSpace(me);
-			if (B_inUnderline == FALSE)
-			    HText_appendCharacter(me->text,
-			    			  LY_UNDERLINE_START_CHAR);
-			HTML_put_string(me, "REFRESH(");
-			HTML_put_string(me, Seconds);
-			HTML_put_string(me, " sec):");
-			FREE(Seconds);
-			if (B_inUnderline == FALSE)
-			    HText_appendCharacter(me->text,
-			    			  LY_UNDERLINE_END_CHAR);
-			HTML_put_character(me, ' ');
-			me->in_word = NO;
-			HText_beginAnchor(me->text, B_CurrentA);
-			if (B_inBoldH == FALSE)
-			    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
-			HTML_put_string(me, href);
-			FREE(href);
-			if (B_inBoldH == FALSE)
-			    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-			HText_endAnchor(me->text);
-			HTML_EnsureSingleSpace(me);
-		    }
-		}
-	    }
-
-	    /*
-	     *  Free the copies. - FM
-	     */
-	    FREE(http_equiv);
-	    FREE(name);
-	    FREE(content);
-	}
+	if (present)
+	    LYHandleMETA(me, present, (CONST char **)value, (char **)&include);
 	break;
 
     case HTML_TITLE:
         HTChunkClear(&me->title);
-	List_Nesting_Level = -1;
-	HTML_zero_OL_Counter();
-	Division_Level = -1;
-	Underline_Level = 0;
-	Quote_Level = 0;
-	if (B_inUnderline) {
+	if (me->inUnderline) {
 	    if (!me->text)
 	        UPDATE_STYLE;
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
-	    B_inUnderline = FALSE;
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    me->inUnderline = FALSE;
 	}
 	break;
 
@@ -1067,30 +585,22 @@ PRIVATE void HTML_start_element ARGS5(
 	    /*
 	     *  Prepare to do housekeeping on the reference. - FM
 	     */
-	    if (!(value[HTML_LINK_HREF] && *value[HTML_LINK_HREF])) {
-		if (B_inBASE && base_href && *base_href) {
-		    StrAllocCopy(href, base_href);
+	    if (!value[HTML_LINK_HREF]) {
+		if (me->inBASE && me->base_href && *me->base_href) {
+		    StrAllocCopy(href, me->base_href);
 		} else {
 		    StrAllocCopy(href, me->node_anchor->address);
 		}
 	    } else {
 		StrAllocCopy(href, value[HTML_LINK_HREF]);
-		convert_to_spaces(href);
-		LYUnEscapeToLatinOne(&href, TRUE);
+		url_type = LYLegitimizeHREF(me, (char**)&href, TRUE);
 	    }
-	    url_type = is_url(href);
-
-	    /*
-	     *  Don't simplify absolute HREFs. - FM
-	     */
-	    if (!url_type && *href != '/' && *href != '\0')
-		HTSimplify(href);
 
 	    /*
 	     *  Check whether a base tag is in effect. - FM
 	     */
-	    if ((B_inBASE) &&
-		(temp = HTParse(href, base_href, PARSE_ALL)) &&
+	    if ((me->inBASE && *href != '\0' && *href != '#') &&
+		(temp = HTParse(href, me->base_href, PARSE_ALL)) &&
 		*temp != '\0')
 		/*
 		 *  Use reference related to the base.
@@ -1101,41 +611,65 @@ PRIVATE void HTML_start_element ARGS5(
 	    /*
 	     *  Check whether to fill in localhost. - FM
 	     */
-	    HTMLFillLocalFileURL((char **)&href,
-				 (B_inBASE ? base_href :
-					     me->node_anchor->address));
+	    LYFillLocalFileURL((char **)&href,
+			       ((*href != '\0' && *href != '#' &&
+			         me->inBASE) ?
+			       me->base_href : me->node_anchor->address));
 
 	    /*
-	     *  Handle REV="made" or REV="owner". - LM & FM
+	     *  Handle links with a REV attribute. - FM
 	     */
 	    if (present &&
 	        present[HTML_LINK_REV] && value[HTML_LINK_REV]) {
-	        if (!strcasecomp("made", value[HTML_LINK_REV]) ||
-		    !strcasecomp("owner", value[HTML_LINK_REV]))
-		    HTAnchor_setOwner(me->node_anchor, href);
 		/*
-		 *  Load the RevTitle element if a TITLE attribute
-		 *  and value are present. - FM
-		 */ 
-		if (present && present[HTML_LINK_TITLE] &&
-		    value[HTML_LINK_TITLE] &&
-		    *value[HTML_LINK_TITLE] != '\0') {
-		    StrAllocCopy(title, value[HTML_LINK_TITLE]);
-		    if (current_char_set)
-		        LYExpandString(&title);
+		 *  Handle REV="made" or REV="owner". - LM & FM
+		 */
+	        if (!strcasecomp("made", value[HTML_LINK_REV]) ||
+		    !strcasecomp("owner", value[HTML_LINK_REV])) {
 		    /*
-		     *  Convert any HTML entities or decimal escaping. - FM
+		     *  Load the owner element. - FM
 		     */
-		    LYUnEscapeEntities(title, TRUE, FALSE);
-		    LYTrimHead(title);
-		    LYTrimTail(title);
-		    if (*title != '\0')
-		        HTAnchor_setRevTitle(me->node_anchor, title);
-		    FREE(title);
-		}
+		    if (!is_url(href)) {
+		        temp = HTParse(href,
+				       (me->inBASE ?
+				     me->base_href : me->node_anchor->address),
+				        PARSE_ALL);
+			StrAllocCopy(href, temp);
+			FREE(temp);
+			LYFillLocalFileURL((char **)&href,
+					   (me->inBASE ?
+					 me->base_href :
+					 me->node_anchor->address));
+		    }
+		    HTAnchor_setOwner(me->node_anchor, href);
+		    if (TRACE)
+		        fprintf(stderr,
+				"HTML: DOC OWNER '%s' found\n", href);
+		    FREE(href);
 
-		if (TRACE)
-		    fprintf(stderr,"HTML.c: DOC OWNER found\n");
+		    /*
+		     *  Load the RevTitle element if a TITLE attribute
+		     *  and value are present. - FM
+		     */ 
+		    if (present && present[HTML_LINK_TITLE] &&
+		        value[HTML_LINK_TITLE] &&
+			*value[HTML_LINK_TITLE] != '\0') {
+			StrAllocCopy(title, value[HTML_LINK_TITLE]);
+			if (current_char_set)
+			    LYExpandString(&title);
+			/*
+			 *  Convert any HTML entities
+			 *  or decimal escaping. - FM
+			 */
+			LYUnEscapeEntities(title, TRUE, FALSE);
+			LYTrimHead(title);
+			LYTrimTail(title);
+			if (*title != '\0')
+			    HTAnchor_setRevTitle(me->node_anchor, title);
+			FREE(title);
+		    }
+		    break;
+		}
 	    }
 
 	    /*
@@ -1143,14 +677,13 @@ PRIVATE void HTML_start_element ARGS5(
 	     */
 	    if (present &&
 	        present[HTML_LINK_REL] && value[HTML_LINK_REL]) {
-		
 		/*
 		 *  Ignore style sheets, for now. - FM
 		 */
 		if (!strcasecomp(value[HTML_LINK_REL], "StyleSheet")) {
 		    if (TRACE) {
 		        fprintf(stderr,
-				"HTML.c: StyleSheet link found.\n");
+				"HTML: StyleSheet link found.\n");
 		        fprintf(stderr,
 				"        StyleSheets not yet implemented.\n");
 		    }
@@ -1159,40 +692,94 @@ PRIVATE void HTML_start_element ARGS5(
 		}
 
 		/*
-		 *  Ignore anything not registered as of 28-Mar-95
-		 *  IETF specs.  We'll make this more efficient when
-		 *  the situation stabilizes, and for now, we'll treat
-		 *  "Banner" as another toolbar element. - FM
+		 *  Ignore anything not registered in the the 28-Mar-95
+		 *  IETF HTML 3.0 draft and W3C HTML 3.2 draft, or not
+		 *  appropriate for Lynx banner links in the expired
+		 *  Maloney and Quin relrev draft.  We'll make this more
+		 *  efficient when the situation stabilizes, and for now,
+		 *  we'll treat "Banner" as another toolbar element. - FM
 		 */
-		if (strcasecomp(value[HTML_LINK_REL], "Home") &&
-		    strcasecomp(value[HTML_LINK_REL], "ToC") &&
-		    strcasecomp(value[HTML_LINK_REL], "Index") &&
-		    strcasecomp(value[HTML_LINK_REL], "Glossary") &&
-		    strcasecomp(value[HTML_LINK_REL], "Copyright") &&
-		    strcasecomp(value[HTML_LINK_REL], "Up") &&
-		    strcasecomp(value[HTML_LINK_REL], "Next") &&
-		    strcasecomp(value[HTML_LINK_REL], "Previous") &&
-		    strcasecomp(value[HTML_LINK_REL], "Help") &&
-		    strcasecomp(value[HTML_LINK_REL], "Bookmark") &&
-		    strcasecomp(value[HTML_LINK_REL], "Banner")) {
+		if (!strcasecomp(value[HTML_LINK_REL], "Home") ||
+		    !strcasecomp(value[HTML_LINK_REL], "ToC") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Contents") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Index") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Glossary") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Copyright") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Up") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Next") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Previous") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Prev") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Help") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Search") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Bookmark") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Banner") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Top") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Origin") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Navigator") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Child") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Disclaimer") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Sibling") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Parent") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Author") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Editor") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Publisher") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Trademark") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Meta") ||
+		    !strcasecomp(value[HTML_LINK_REL], "URC") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Hotlist") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Begin") ||
+		    !strcasecomp(value[HTML_LINK_REL], "First") ||
+		    !strcasecomp(value[HTML_LINK_REL], "End") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Last") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Pointer") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Translation") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Definition") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Chapter") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Documentation") ||
+		    !strcasecomp(value[HTML_LINK_REL], "Biblioentry") ||
+ 		    !strcasecomp(value[HTML_LINK_REL], "Bibliography")) {
+		    StrAllocCopy(title, value[HTML_LINK_REL]);
+		} else {
 		    if (TRACE) {
 		        fprintf(stderr,
-				"HTML.c: LINK with REL=\"%s\" ignored.\n",
+				"HTML: LINK with REL=\"%s\" ignored.\n",
 				 value[HTML_LINK_REL]);
 		    }
 		    FREE(href);
 		    break;
 		}
-
-		/*
-		 *  Create a title (link name) from the TITLE value,
-		 *  if present, or default to the REL value. - FM
-		 */ 
-		if (present && present[HTML_LINK_TITLE] &&
-		    value[HTML_LINK_TITLE] && *value[HTML_LINK_TITLE] != '\0')
-		    StrAllocCopy(title, value[HTML_LINK_TITLE]);
-		else
-		    StrAllocCopy(title, value[HTML_LINK_REL]);
+	    }
+	} else if (present &&
+		   present[HTML_LINK_REL] && value[HTML_LINK_REL]) {
+	    /*
+	     *  If no HREF was specified, handle special REL links
+	     *  with self-designated HREFs. - FM
+	     */
+	    if (!strcasecomp(value[HTML_LINK_REL], "Home")) {
+	        StrAllocCopy(href, LynxHome);
+	    } else if (!strcasecomp(value[HTML_LINK_REL], "Help")) {
+	        StrAllocCopy(href, helpfile);
+	    } else if (!strcasecomp(value[HTML_LINK_REL], "Index")) {
+	        StrAllocCopy(href, indexfile);
+	    } else { 
+	        if (TRACE) {
+		    fprintf(stderr,
+			    "HTML: LINK with REL=\"%s\" and no HREF ignored.\n",
+			    value[HTML_LINK_REL]);
+		}
+		break;
+	    }
+	    StrAllocCopy(title, value[HTML_LINK_REL]);
+	}
+	if (href) {
+	    /*
+	     *  Create a title (link name) from the TITLE value,
+	     *  if present, or default to the REL value that was
+	     *  loaded into title. - FM
+	     */ 
+	    if (present && present[HTML_LINK_TITLE] &&
+		value[HTML_LINK_TITLE] && *value[HTML_LINK_TITLE] != '\0') {
+		StrAllocCopy(title, value[HTML_LINK_TITLE]);
 		if (current_char_set)
 		    LYExpandString(&title);
 		/*
@@ -1201,55 +788,57 @@ PRIVATE void HTML_start_element ARGS5(
 		LYUnEscapeEntities(title, TRUE, FALSE);
 		LYTrimHead(title);
 		LYTrimTail(title);
+	    }
+	    if (!(title && *title)) {
+	        FREE(href);
+		FREE(title);
+		break;
+	    }
 
-		/*
-		 *  Create anchors for the links that simulate
-		 *  a toolbar. - FM
-		 */
-	        B_CurrentA = HTAnchor_findChildAndLink(
+	    /*
+	     *  Create anchors for the links that simulate
+	     *  a toolbar. - FM
+	     */
+	    me->CurrentA = HTAnchor_findChildAndLink(
 				me->node_anchor,	/* Parent */
 		    		NULL,			/* Tag */
 		    		href,			/* Addresss */
 		    		(void *)0);		/* Type */
-		{
-		    if (dest = HTAnchor_parent(
-			    HTAnchor_followMainLink((HTAnchor*)B_CurrentA)
-			    		      )) {
-		        if (!HTAnchor_title(dest))
-			    HTAnchor_setTitle(dest, title);
-		    }
-		    UPDATE_STYLE;
-		    if (!HText_hasToolbar(me->text) &&
-		        (B_ID_A = HTAnchor_findChildAndLink(
+	    if (dest = HTAnchor_parent(
+			    HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
+			    	      )) {
+		if (!HTAnchor_title(dest))
+		    HTAnchor_setTitle(dest, title);
+		dest = NULL;
+	    }
+	    UPDATE_STYLE;
+	    if (!HText_hasToolbar(me->text) &&
+		(ID_A = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					LYToolbarName,		/* Tag */
 					NULL,			/* Addresss */
 					(void *)0))) {		/* Type */
-			HText_beginAnchor(me->text, B_ID_A);
-			HText_endAnchor(me->text);
-			HText_setToolbar(me->text);
-		    }
-		    HText_beginAnchor(me->text, B_CurrentA);
-		    if (B_inBoldH == FALSE)
-		        HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
-		    HTML_put_string(me, title);
-		    if (B_inBoldH == FALSE)
-		        HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
-		    HText_endAnchor(me->text);
-		    dest = NULL;
-		}
-		FREE(title);
+		HText_appendCharacter(me->text, '#');
+		HText_beginAnchor(me->text, ID_A);
+		HText_endAnchor(me->text);
+		HText_setToolbar(me->text);
 	    }
-	    FREE(href);
+	    HText_beginAnchor(me->text, me->CurrentA);
+	    if (me->inBoldH == FALSE)
+	        HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+	    HTML_put_string(me, title);
+	    if (me->inBoldH == FALSE)
+	        HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+	    HText_endAnchor(me->text);
 	}
+	FREE(href);
+	FREE(title);
 	break;
 
     case HTML_ISINDEX:
-	if (present &&
-	    ((present[HTML_ISINDEX_HREF] &&
-	      value[HTML_ISINDEX_HREF] && *value[HTML_ISINDEX_HREF]) ||
-	    (present[HTML_ISINDEX_ACTION] &&
-	     value[HTML_ISINDEX_ACTION] && *value[HTML_ISINDEX_ACTION]))) {
+	if (((present)) &&
+	    ((present[HTML_ISINDEX_HREF] && value[HTML_ISINDEX_HREF]) ||
+	     (present[HTML_ISINDEX_ACTION] && value[HTML_ISINDEX_ACTION]))) {
 	    char * action = NULL;
 	    char * isindex_href = NULL;
 
@@ -1259,44 +848,35 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  use that too, but allow use of ACTION as an alternate
 	     *  until people have fully switched over. - FM
 	     */
-	    if (present[HTML_ISINDEX_HREF])
+	    if (present[HTML_ISINDEX_HREF] && value[HTML_ISINDEX_HREF])
 	        StrAllocCopy(isindex_href, value[HTML_ISINDEX_HREF]);
 	    else
 	        StrAllocCopy(isindex_href, value[HTML_ISINDEX_ACTION]);
-	    convert_to_spaces(isindex_href);
-	    LYUnEscapeToLatinOne(&isindex_href, TRUE);
-	    url_type = is_url(isindex_href);
-	    if (!url_type && *isindex_href != '/' && *isindex_href != '\0')
-	        HTSimplify(isindex_href);
+	    url_type = LYLegitimizeHREF(me, (char**)&isindex_href, TRUE);
 
 	    /*
 	     *  Check whether a base tag is in effect.
 	     */
-	    if (B_inBASE)
-		action = HTParse(isindex_href, base_href, PARSE_ALL);
-	    if (!(action && *action)) {
-	        char *related = NULL;
+	    if (me->inBASE && *isindex_href != '\0' && *isindex_href != '#')
+		action = HTParse(isindex_href, me->base_href, PARSE_ALL);
+	    if (!(action && *action))
+	        action = HTParse(isindex_href,
+				 me->node_anchor->address, PARSE_ALL);
+	    FREE(isindex_href);
 
-		StrAllocCopy(related, me->node_anchor->address);
-	        action = HTParse(isindex_href, related, PARSE_ALL);
-		FREE(related);
-	    }
 	    if (action && *action) {
    	        HTAnchor_setIndex(me->node_anchor, action);
-	    } else if (B_inBASE) {
-	        HTAnchor_setIndex(me->node_anchor, base_href);
 	    } else {
 	        HTAnchor_setIndex(me->node_anchor, me->node_anchor->address);
 	    }
-	    FREE(isindex_href);
 	    FREE(action);
 
 	} else {
-	    if (B_inBASE)
+	    if (me->inBASE)
 	        /*
 	         *  Use base.
 	         */
-   	        HTAnchor_setIndex(me->node_anchor, base_href);
+   	        HTAnchor_setIndex(me->node_anchor, me->base_href);
 	    else
 	        /*
 	         *  Use index's address.
@@ -1360,16 +940,13 @@ PRIVATE void HTML_start_element ARGS5(
 
     case HTML_BODY:
         UPDATE_STYLE;
-	List_Nesting_Level = -1;
-	HTML_zero_OL_Counter();
-	Division_Level = -1;
-	Underline_Level = 0;
-	Quote_Level = 0;
-	if (B_inUnderline) {
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
-	    B_inUnderline = FALSE;
+	if (me->inUnderline) {
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    me->inUnderline = FALSE;
 	}
-	HTML_CheckForID(me, present, value, (int)HTML_BODY_ID);
+	LYCheckForID(me, present, value, (int)HTML_BODY_ID);
+	if (HText_hasToolbar(me->text))
+	    HText_appendParagraph(me->text);
 	break;
 
     case HTML_FRAMESET:
@@ -1395,17 +972,13 @@ PRIVATE void HTML_start_element ARGS5(
 	if (present && present[HTML_FRAME_SRC] &&
 	    value[HTML_FRAME_SRC] && *value[HTML_FRAME_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_FRAME_SRC]);
-	    convert_to_spaces(href);
-	    LYUnEscapeToLatinOne(&href, TRUE);
-	    url_type = is_url(href);
-	    if (!url_type && *href != '/' && *href != '\0')
-	        HTSimplify(href);
+	    url_type = LYLegitimizeHREF(me, (char**)&href, TRUE);
 
 	    /*
 	     *  Check whether a base tag is in effect. - FM
 	     */
-	    if ((B_inBASE) &&
-		(temp = HTParse(href, base_href, PARSE_ALL)) &&
+	    if ((me->inBASE && *href != '\0' && *href != '#') &&
+		(temp = HTParse(href, me->base_href, PARSE_ALL)) &&
 		*temp != '\0')
 		/*
 		 *  Use reference related to the base.
@@ -1416,99 +989,102 @@ PRIVATE void HTML_start_element ARGS5(
 	    /*
 	     *  Check whether to fill in localhost. - FM
 	     */
-	    HTMLFillLocalFileURL((char **)&href,
-				 (B_inBASE ? base_href :
-					     me->node_anchor->address));
+	    LYFillLocalFileURL((char **)&href,
+			       ((*href != '\0' && *href != '#' &&
+			         me->inBASE) ?
+			       me->base_href : me->node_anchor->address));
 
-	    B_CurrentA = HTAnchor_findChildAndLink(
+	    me->CurrentA = HTAnchor_findChildAndLink(
 				me->node_anchor,	/* Parent */
 				NULL,			/* Tag */
 				href,			/* Addresss */
 				(void *)0);		/* Type */
-	    HTML_EnsureSingleSpace(me);
-	    if (B_inUnderline == FALSE)
-	        HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
+	    LYEnsureSingleSpace(me);
+	    if (me->inUnderline == FALSE)
+	        HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
 	    HTML_put_string(me, "FRAME:");
-	    if (B_inUnderline == FALSE)
-	        HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
+	    if (me->inUnderline == FALSE)
+	        HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	    HTML_put_character(me, ' ');
 	    me->in_word = NO;
-	    HText_beginAnchor(me->text, B_CurrentA);
-	    if (B_inBoldH == FALSE)
-		HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
+	    HText_beginAnchor(me->text, me->CurrentA);
+	    if (me->inBoldH == FALSE)
+		HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 	    HTML_put_string(me, (id_string ? id_string : href));
 	    FREE(href);
 	    FREE(id_string);
-	    if (B_inBoldH == FALSE)
-		HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+	    if (me->inBoldH == FALSE)
+		HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 	    HText_endAnchor(me->text);
-	    HTML_EnsureSingleSpace(me);
+	    LYEnsureSingleSpace(me);
 	}
 	break;
 
     case HTML_NOFRAMES:
 	if (!me->text)
 	    UPDATE_STYLE;
-	HTML_EnsureDoubleSpace(me);
-	HTML_ResetParagraphAlignment(me);
+	LYEnsureDoubleSpace(me);
+	LYResetParagraphAlignment(me);
 	break;
 
     case HTML_BANNER:
     case HTML_MARQUEE:
     	change_paragraph_style(me, styles[HTML_BANNER]);
 	UPDATE_STYLE;
+	if (me->sp->tag_number == element_number)
+	    LYEnsureDoubleSpace(me);
 	if (!HText_hasToolbar(me->text) &&
-	    (B_ID_A = HTAnchor_findChildAndLink(
+	    (ID_A = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					LYToolbarName,		/* Tag */
 					NULL,			/* Addresss */
 					(void *)0))) {		/* Type */
-	    HText_beginAnchor(me->text, B_ID_A);
+	    HText_beginAnchor(me->text, ID_A);
 	    HText_endAnchor(me->text);
 	    HText_setToolbar(me->text);
 	}
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
 	break;
 
     case HTML_CENTER:
     case HTML_DIV:
-	if (Division_Level < MAX_NESTING) {
-	    Division_Level++;
+	if (me->Division_Level < MAX_NESTING) {
+	    me->Division_Level++;
 	} else if (TRACE) {
             fprintf(stderr, 
 		"HTML: ****** Maximum nesting of %d divisions exceeded!\n",
             	MAX_NESTING);
 	}
 	if (element_number == HTML_CENTER) {
-	    DivisionAlignments[Division_Level] = HT_CENTER;
+	    me->DivisionAlignments[me->Division_Level] = HT_CENTER;
     	    change_paragraph_style(me, styles[HTML_DCENTER]);
 	    UPDATE_STYLE;
-	    current_default_alignment = styles[HTML_DCENTER]->alignment;
+	    me->current_default_alignment = styles[HTML_DCENTER]->alignment;
 	} else if (present && present[HTML_DIV_ALIGN] &&
 		   value[HTML_DIV_ALIGN] && *value[HTML_DIV_ALIGN]) {
 	    if (!strcasecomp(value[HTML_DIV_ALIGN], "center")) {
-	        DivisionAlignments[Division_Level] = HT_CENTER;
+	        me->DivisionAlignments[me->Division_Level] = HT_CENTER;
 		change_paragraph_style(me, styles[HTML_DCENTER]);
 		UPDATE_STYLE;
-		current_default_alignment = styles[HTML_DCENTER]->alignment;
+		me->current_default_alignment = styles[HTML_DCENTER]->alignment;
 	    } else if (!strcasecomp(value[HTML_DIV_ALIGN], "right")) {
-	        DivisionAlignments[Division_Level] = HT_RIGHT;
+	        me->DivisionAlignments[me->Division_Level] = HT_RIGHT;
 		change_paragraph_style(me, styles[HTML_DRIGHT]);
 		UPDATE_STYLE;
-		current_default_alignment = styles[HTML_DRIGHT]->alignment;
+		me->current_default_alignment = styles[HTML_DRIGHT]->alignment;
 	    } else {
-	        DivisionAlignments[Division_Level] = HT_LEFT;
+	        me->DivisionAlignments[me->Division_Level] = HT_LEFT;
 		change_paragraph_style(me, styles[HTML_DLEFT]);
 		UPDATE_STYLE;
-		current_default_alignment = styles[HTML_DLEFT]->alignment;
+		me->current_default_alignment = styles[HTML_DLEFT]->alignment;
 	    }
 	} else {
-	    DivisionAlignments[Division_Level] = HT_LEFT;
+	    me->DivisionAlignments[me->Division_Level] = HT_LEFT;
 	    change_paragraph_style(me, styles[HTML_DLEFT]);
 	    UPDATE_STYLE;
-	    current_default_alignment = styles[HTML_DLEFT]->alignment;
+	    me->current_default_alignment = styles[HTML_DLEFT]->alignment;
 	}
-	HTML_CheckForID(me, present, value, (int)HTML_DIV_ID);
+	LYCheckForID(me, present, value, (int)HTML_DIV_ID);
 	break;
 
     case HTML_H1:
@@ -1541,27 +1117,27 @@ PRIVATE void HTML_start_element ARGS5(
 	        change_paragraph_style(me, styles[HTML_HLEFT]);
 	    else
 	        change_paragraph_style(me, styles[element_number]);
-	} else if (Division_Level >= 0) {
-	    if (DivisionAlignments[Division_Level] == HT_CENTER) {
+	} else if (me->Division_Level >= 0) {
+	    if (me->DivisionAlignments[me->Division_Level] == HT_CENTER) {
 		change_paragraph_style(me, styles[HTML_HCENTER]);
-	    } else if (DivisionAlignments[Division_Level] == HT_LEFT) {
+	    } else if (me->DivisionAlignments[me->Division_Level] == HT_LEFT) {
 		change_paragraph_style(me, styles[HTML_HLEFT]);
-	    } else if (DivisionAlignments[Division_Level] == HT_RIGHT) {
+	    } else if (me->DivisionAlignments[me->Division_Level] == HT_RIGHT) {
 		change_paragraph_style(me, styles[HTML_HRIGHT]);
 	    }
 	} else {
     	    change_paragraph_style(me, styles[element_number]);
 	}
 	UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_H_ID);
+	LYCheckForID(me, present, value, (int)HTML_H_ID);
 	    
 	if ((bold_headers == TRUE ||
 	     (element_number == HTML_H1 && bold_H1 == TRUE)) &&
 	    (styles[element_number]->font&HT_BOLD)) {
-	    if (B_inBoldA == FALSE && B_inBoldH == FALSE) {
-	        HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
+	    if (me->inBoldA == FALSE && me->inBoldH == FALSE) {
+	        HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 	    }
-	    B_inBoldH = TRUE;
+	    me->inBoldH = TRUE;
 	}
 	break;
 
@@ -1573,28 +1149,28 @@ PRIVATE void HTML_start_element ARGS5(
 	 *  If we encounter a P in either's content, we set flags to treat
 	 *  the content as a block.  - FM
 	 */
-	if (B_inFIG)
-	    B_inFIGwithP = TRUE;
+	if (me->inFIG)
+	    me->inFIGwithP = TRUE;
 
-	if (B_inAPPLET)
-	    B_inAPPLETwithP = TRUE;
+	if (me->inAPPLET)
+	    me->inAPPLETwithP = TRUE;
 
 	UPDATE_STYLE;
-	if (List_Nesting_Level >= 0) {
+	if (me->List_Nesting_Level >= 0) {
 	    /*
 	     *  We're in a list.  Treat P as an instruction to
 	     *  create one blank line, if not already present,
 	     *  then fall through to handle attributes, with
 	     *  the "second line" margins. - FM
 	     */
-	    if (B_inP) {
-	        if (B_inFIG || B_inAPPLET ||
-		    B_inCAPTION || B_inCREDIT ||
+	    if (me->inP) {
+	        if (me->inFIG || me->inAPPLET ||
+		    me->inCAPTION || me->inCREDIT ||
 		    me->sp->style->spaceAfter > 0 ||
 		    me->sp->style->spaceBefore > 0) {
-	            HTML_EnsureDoubleSpace(me);
+	            LYEnsureDoubleSpace(me);
 		} else {
-	            HTML_EnsureSingleSpace(me);
+	            LYEnsureSingleSpace(me);
 		}
 	    }
 	} else if (me->sp[0].tag_number == HTML_ADDRESS) {
@@ -1606,75 +1182,79 @@ PRIVATE void HTML_start_element ARGS5(
 	    if (HText_LastLineSize(me->text)) {
 	        HText_appendCharacter(me->text, '\r');
 	    }
-	} else if (!(B_inLABEL && !B_inP)) {
+	} else if (!(me->inLABEL && !me->inP)) {
 	    HText_appendParagraph(me->text);
-	    B_inLABEL = FALSE;
+	    me->inLABEL = FALSE;
 	}
 	me->in_word = NO;
 
-	if (HTML_override_default_alignment(me)) {
+	if (LYoverride_default_alignment(me)) {
 	    me->sp->style->alignment = styles[me->sp[0].tag_number]->alignment;
-	} else if (List_Nesting_Level >= 0 ||
-		   ((Division_Level < 0) &&
+	} else if (me->List_Nesting_Level >= 0 ||
+		   ((me->Division_Level < 0) &&
 		    (!strcmp(me->sp->style->name, "Normal") ||
 		     !strcmp(me->sp->style->name, "Preformatted")))) {
 	        me->sp->style->alignment = HT_LEFT;
 	} else {
-	    me->sp->style->alignment = current_default_alignment;
+	    me->sp->style->alignment = me->current_default_alignment;
 	}
 	if (present && present[HTML_P_ALIGN] && value[HTML_P_ALIGN]) {
 	    if (!strcasecomp(value[HTML_P_ALIGN], "center") &&
-	        !(List_Nesting_Level >= 0 && !B_inP))
+	        !(me->List_Nesting_Level >= 0 && !me->inP))
 	        me->sp->style->alignment = HT_CENTER;
 	    else if (!strcasecomp(value[HTML_P_ALIGN], "right") &&
-	        !(List_Nesting_Level >= 0 && !B_inP))
+	        !(me->List_Nesting_Level >= 0 && !me->inP))
 	        me->sp->style->alignment = HT_RIGHT;
 	    else if (!strcasecomp(value[HTML_H_ALIGN], "left") ||
 	    	     !strcasecomp(value[HTML_H_ALIGN], "justify"))
 	        me->sp->style->alignment = HT_LEFT;
 	}
 
-	HTML_CheckForID(me, present, value, (int)HTML_P_ID);
+	LYCheckForID(me, present, value, (int)HTML_P_ID);
 
 	/*
 	 *  Mark that we are starting a new paragraph
 	 *  and don't have any of it's text yet. - FM
 	 *
 	 */
-	B_inP = FALSE;
+	me->inP = FALSE;
 
 	break;
 
     case HTML_BR:
         UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
-	HTML_Last_Char = ' ';  /* absorb white space */
-	HText_appendCharacter(me->text, '\r');
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
+	if (LYCollapseBRs == FALSE || HText_LastLineSize(me->text)) {
+	    HText_setLastChar(me->text, ' ');  /* absorb white space */
+	    HText_appendCharacter(me->text, '\r');
+	}
 	me->in_word = NO;
-	B_inP = FALSE;
+	me->inP = FALSE;
 	break;
 
     case HTML_HR:
 	{
-	    register int i, width, old_alignment;
+	    int width;
 
 	    /*
 	     *  Start a new line only if we had printable
 	     *  characters following the previous newline,
-	     *  and save the current style's alignment. - FM
+	     *  or remove the previous line if both it and
+	     *  the last line are blank. - FM
 	     */
 	    UPDATE_STYLE;
 	    if (HText_LastLineSize(me->text)) {
 	        HText_appendCharacter(me->text, '\r');
-	        me->in_word = NO;
-		B_inP = FALSE;
+	    } else if (!HText_PreviousLineSize(me->text)) {
+	        HText_RemovePreviousLine(me->text);
 	    }
-	    old_alignment = me->sp->style->alignment;
+	    me->in_word = NO;
+	    me->inP = FALSE;
 
 	    /*
-	     *  Add and ID link if needed. - FM
+	     *  Add an ID link if needed. - FM
 	     */
-	    HTML_CheckForID(me, present, value, (int)HTML_HR_ID);
+	    LYCheckForID(me, present, value, (int)HTML_HR_ID);
 
            /*
 	    *  Center lines within the current margins, if
@@ -1719,12 +1299,38 @@ PRIVATE void HTML_start_element ARGS5(
 	    }
 	    for (i = 0; i < width; i++)
 	        HTML_put_character(me, '_');
-
-	    HText_appendCharacter(me->text, '\r');
 	    HText_appendCharacter(me->text, '\r');
 	    me->in_word = NO;
-	    B_inP = FALSE;
-	    me->sp->style->alignment = old_alignment;
+	    me->inP = FALSE;
+
+	    /*
+	     *  Reset the alignment appropriately
+	     *  for the division and/or block. - FM
+	     */
+	    if (me->List_Nesting_Level < 0 &&
+	        me->Division_Level >= 0) {
+	        me->sp->style->alignment =
+	    			me->DivisionAlignments[me->Division_Level];
+	    } else if (!strcmp(me->sp->style->name, "HeadingCenter") ||
+		       !strcmp(me->sp->style->name, "Heading1")) {
+		me->sp->style->alignment = HT_CENTER;
+	    } else if (!strcmp(me->sp->style->name, "HeadingRight")) {
+		me->sp->style->alignment = HT_RIGHT;
+	    } else {
+		me->sp->style->alignment = HT_LEFT;
+	    }
+
+	    /*
+	     *  Add a blank line and set the second line
+	     *  indentation for lists and addresses, or a
+	     *  paragraph separator for other blocks. - FM
+	     */
+	    if (me->List_Nesting_Level >= 0 ||
+	        me->sp[0].tag_number == HTML_ADDRESS) {
+	        HText_appendCharacter(me->text, '\r');
+	    } else {
+	        HText_appendParagraph(me->text);
+	    }
 	}
 	break;
 
@@ -1749,8 +1355,8 @@ PRIVATE void HTML_start_element ARGS5(
 	        fprintf(stderr,
 		     "HTML: ALIGN not 'left'. Using space instead of TAB.\n");
 
-	} else if (!HTML_override_default_alignment(me) &&
-		   current_default_alignment != HT_LEFT) {
+	} else if (!LYoverride_default_alignment(me) &&
+		   me->current_default_alignment != HT_LEFT) {
 	    /*
 	     *  Just ensure a collapsible space, until we
 	     *  can replace HText_getCurrentColumn() in
@@ -1767,7 +1373,7 @@ PRIVATE void HTML_start_element ARGS5(
 		   (present[HTML_TAB_INDENT] &&
 		    value[HTML_TAB_INDENT] &&
 		    isdigit(*value[HTML_TAB_INDENT]))) {
-	    int i, column, target = -1;
+	    int column, target = -1;
 	    int enval = 2;
 
 	    column = HText_getCurrentColumn(me->text);
@@ -1841,25 +1447,25 @@ PRIVATE void HTML_start_element ARGS5(
     case HTML_EM:
     case HTML_STRONG:
 	UPDATE_STYLE;
-	Underline_Level++;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
+	me->Underline_Level++;
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
 	/*
 	 *  Ignore this if inside of a bold anchor or header.
 	 *  Can't display both underline and bold at same time.
 	 */
-	if (B_inBoldA == TRUE || B_inBoldH == TRUE)	{
+	if (me->inBoldA == TRUE || me->inBoldH == TRUE)	{
 	    if (TRACE)
-	        fprintf(stderr,"Underline Level is %d\n", Underline_Level);
+	        fprintf(stderr,"Underline Level is %d\n", me->Underline_Level);
 	    break;
 	}
-	if (B_inUnderline == FALSE) {
-	    HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
-	    B_inUnderline = TRUE;
+	if (me->inUnderline == FALSE) {
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
+	    me->inUnderline = TRUE;
 	    if (TRACE)
 	        fprintf(stderr,"Beginning underline\n");
 	} else {
 	    if (TRACE)
-	        fprintf(stderr,"Underline Level is %d\n", Underline_Level);
+	        fprintf(stderr,"Underline Level is %d\n", me->Underline_Level);
 	}
     	break;
 	
@@ -1879,7 +1485,7 @@ PRIVATE void HTML_start_element ARGS5(
     case HTML_VAR:
         if (!me->text)
 	    UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
 	break; /* ignore */
 
     case HTML_DEL:
@@ -1887,12 +1493,12 @@ PRIVATE void HTML_start_element ARGS5(
     case HTML_STRIKE:
         if (!me->text)
 	    UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
 	HTML_put_string(me, "[DEL:");
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	HTML_put_character(me, ' ');
 	me->in_word = NO;
 	break;
@@ -1900,12 +1506,12 @@ PRIVATE void HTML_start_element ARGS5(
     case HTML_INS:
         if (!me->text)
 	    UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
 	HTML_put_string(me, "[INS:");
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	HTML_put_character(me, ' ');
 	me->in_word = NO;
 	break;
@@ -1913,7 +1519,7 @@ PRIVATE void HTML_start_element ARGS5(
     case HTML_Q:
 	if (!me->text)
 	    UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
         /*
 	 *  Should check LANG and/or DIR attributes, and the
 	 *  me->node_anchor->charset and/or yet to be added
@@ -1921,24 +1527,24 @@ PRIVATE void HTML_start_element ARGS5(
 	 *  use chevrons, but for now we'll always use double-
 	 *  or single-quotes. - FM
 	 */
-	if (!(Quote_Level & 1))
+	if (!(me->Quote_Level & 1))
 	    HText_appendCharacter(me->text, '"');
 	else
 	    HText_appendCharacter(me->text, '`');
-	Quote_Level++;
+	me->Quote_Level++;
 	break;
 
     case HTML_PRE:				/* Formatted text */
         if (!HText_PreviousLineSize(me->text))
-	    B_inPRE = FALSE;
+	    me->inPRE = FALSE;
 	else
-            B_inPRE = TRUE;
+            me->inPRE = TRUE;
     case HTML_LISTING:				/* Litteral text */
     case HTML_XMP:
     case HTML_PLAINTEXT:
 	change_paragraph_style(me, styles[element_number]);
 	UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
     	if (me->comment_end)
     	    HText_appendText(me->text, me->comment_end);
 	break;
@@ -1947,16 +1553,19 @@ PRIVATE void HTML_start_element ARGS5(
     case HTML_BQ:
     	change_paragraph_style(me, styles[element_number]);
 	UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_BQ_ID);
+	if (me->sp->tag_number == element_number)
+	    LYEnsureDoubleSpace(me);
+	LYCheckForID(me, present, value, (int)HTML_BQ_ID);
 	break;
 
     case HTML_NOTE:
     	change_paragraph_style(me, styles[element_number]);
 	UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_NOTE_ID);
+	if (me->sp->tag_number == element_number)
+	    LYEnsureDoubleSpace(me);
+	LYCheckForID(me, present, value, (int)HTML_NOTE_ID);
 	{
 	    char *note = NULL;
-	    int i;
 
 	    /*
 	     *  Indicate the type of NOTE.
@@ -1980,77 +1589,79 @@ PRIVATE void HTML_start_element ARGS5(
 	    } else {
 	        StrAllocCopy(note, "NOTE:");
 	    }
-	    if (B_inUnderline == FALSE)
-	        HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
+	    if (me->inUnderline == FALSE)
+	        HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
 	    HTML_put_string(me, note);
-	    if (B_inUnderline == FALSE)
-	        HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
+	    if (me->inUnderline == FALSE)
+	        HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	    HTML_put_character(me, ' ');
 	    FREE(note);
 	}
-	B_inLABEL = TRUE;
+	me->inLABEL = TRUE;
 	me->in_word = NO;
-	B_inP = FALSE;
+	me->inP = FALSE;
 	break;
 
     case HTML_ADDRESS:
     	change_paragraph_style(me, styles[element_number]);
 	UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_ADDRESS_ID);
+	if (me->sp->tag_number == element_number)
+	    LYEnsureDoubleSpace(me);
+	LYCheckForID(me, present, value, (int)HTML_ADDRESS_ID);
 	break;
 
     case HTML_DL:
-	List_Nesting_Level++;  /* increment the List nesting level */
-	if (List_Nesting_Level <= 0) {
+	me->List_Nesting_Level++;  /* increment the List nesting level */
+	if (me->List_Nesting_Level <= 0) {
             change_paragraph_style(me, present && present[HTML_DL_COMPACT]
     			              ? styles[HTML_DLC] : styles[HTML_DL]);
 
-	} else if (List_Nesting_Level >= 6) {
+	} else if (me->List_Nesting_Level >= 6) {
             change_paragraph_style(me, present && present[HTML_DL_COMPACT]
     			              ? styles[HTML_DLC6] : styles[HTML_DL6]);
 
 	} else {
             change_paragraph_style(me, present && present[HTML_DL_COMPACT]
-    		 ? styles[(HTML_DLC1 - 1) + List_Nesting_Level] 
-		 : styles[(HTML_DL1 - 1) + List_Nesting_Level]);
+    		 ? styles[(HTML_DLC1 - 1) + me->List_Nesting_Level] 
+		 : styles[(HTML_DL1 - 1) + me->List_Nesting_Level]);
 	}
 	UPDATE_STYLE;	  /* update to the new style */
-	HTML_CheckForID(me, present, value, (int)HTML_DL_ID);
+	LYCheckForID(me, present, value, (int)HTML_DL_ID);
 	break;
 	
     case HTML_DLC:
-        List_Nesting_Level++;  /* increment the List nesting level */
-        if (List_Nesting_Level <= 0) {
+        me->List_Nesting_Level++;  /* increment the List nesting level */
+        if (me->List_Nesting_Level <= 0) {
             change_paragraph_style(me, styles[HTML_DLC]);
 
-        } else if (List_Nesting_Level >= 6) {
+        } else if (me->List_Nesting_Level >= 6) {
             change_paragraph_style(me, styles[HTML_DLC6]);
 
         } else {
             change_paragraph_style(me, 
-                               styles[(HTML_DLC1 - 1) + List_Nesting_Level]);
+                            styles[(HTML_DLC1 - 1) + me->List_Nesting_Level]);
         }
 	UPDATE_STYLE;	  /* update to the new style */
-	HTML_CheckForID(me, present, value, (int)HTML_DL_ID);
+	LYCheckForID(me, present, value, (int)HTML_DL_ID);
         break;
 
     case HTML_DT:
 	if (!me->text)
 	    UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
         if (!me->style_change) {
 	    HText_appendParagraph(me->text);
 	    me->in_word = NO;
 	    me->sp->style->alignment = HT_LEFT;
 	}
-	B_inP = FALSE;
+	me->inP = FALSE;
 	break;
 	
     case HTML_DD:
 	if (!me->text)
 	    UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
-	HTML_Last_Char = ' ';  /* absorb white space */
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
+	HText_setLastChar(me->text, ' ');  /* absorb white space */
         if (!me->style_change) 
 	    HText_appendCharacter(me->text, '\r');
 	else 
@@ -2060,15 +1671,15 @@ PRIVATE void HTML_start_element ARGS5(
 	  }
 	me->sp->style->alignment = HT_LEFT;
 	me->in_word = NO;
-	B_inP = FALSE;
+	me->inP = FALSE;
 	break;
 
     case HTML_OL:
 	/*
 	 * Set the default TYPE.
 	 */
-	 OL_Type[(List_Nesting_Level < 5 ?
-	    		List_Nesting_Level+1 : 6)] = '1';
+	 me->OL_Type[(me->List_Nesting_Level < 5 ?
+			me->List_Nesting_Level+1 : 6)] = '1';
 
 	/*
 	 *  Check whether we have a starting sequence number,
@@ -2101,23 +1712,23 @@ PRIVATE void HTML_start_element ARGS5(
 	     */
 	    if (present[HTML_OL_TYPE] && value[HTML_OL_TYPE]) {
 	        if (*value[HTML_OL_TYPE] == 'A') {
-		    OL_Type[(List_Nesting_Level < 5 ?
-			     List_Nesting_Level+1 : 6)] = 'A';
+		    me->OL_Type[(me->List_Nesting_Level < 5 ?
+				   me->List_Nesting_Level+1 : 6)] = 'A';
 		    if (seqnum < 1)
 		        seqnum = 1;
 		} else if (*value[HTML_OL_TYPE] == 'a') {
-		    OL_Type[(List_Nesting_Level < 5 ?
-			     List_Nesting_Level+1 : 6)] = 'a';
+		    me->OL_Type[(me->List_Nesting_Level < 5 ?
+				   me->List_Nesting_Level+1 : 6)] = 'a';
 		    if (seqnum < 1)
 		        seqnum = 1;
 		} else if (*value[HTML_OL_TYPE] == 'I') {
-		    OL_Type[(List_Nesting_Level < 5 ?
-			     List_Nesting_Level+1 : 6)] = 'I';
+		    me->OL_Type[(me->List_Nesting_Level < 5 ?
+				   me->List_Nesting_Level+1 : 6)] = 'I';
 		    if (seqnum < 1)
 		        seqnum = 1;
 		} else if (*value[HTML_OL_TYPE] == 'i') {
-		    OL_Type[(List_Nesting_Level < 5 ?
-			     List_Nesting_Level+1 : 6)] = 'i';
+		    me->OL_Type[(me->List_Nesting_Level < 5 ?
+				   me->List_Nesting_Level+1 : 6)] = 'i';
 		    if (seqnum < 1)
 		        seqnum = 1;
 		} else {
@@ -2128,52 +1739,52 @@ PRIVATE void HTML_start_element ARGS5(
 	        seqnum = OL_VOID + 1;
 	    }
 
-	    OL_Counter[(List_Nesting_Level < 5 ?
-	    		List_Nesting_Level+1 : 6)] = seqnum;
+	    me->OL_Counter[(me->List_Nesting_Level < 5 ?
+	    		      me->List_Nesting_Level+1 : 6)] = seqnum;
 
 	} else if (present && present[HTML_OL_CONTINUE]) {
-	    OL_Counter[List_Nesting_Level < 5 ?
-	    	       List_Nesting_Level+1 : 6] = OL_CONTINUE;
+	    me->OL_Counter[me->List_Nesting_Level < 5 ?
+			     me->List_Nesting_Level+1 : 6] = OL_CONTINUE;
 
 	} else {
-	    OL_Counter[(List_Nesting_Level < 5 ?
-	    	List_Nesting_Level+1 : 6)] = 1;
+	    me->OL_Counter[(me->List_Nesting_Level < 5 ?
+			      me->List_Nesting_Level+1 : 6)] = 1;
 	    if (present && present[HTML_OL_TYPE] && value[HTML_OL_TYPE]) {
 	        if (*value[HTML_OL_TYPE] == 'A') {
-		    OL_Type[(List_Nesting_Level < 5 ?
-			     List_Nesting_Level+1 : 6)] = 'A';
+		    me->OL_Type[(me->List_Nesting_Level < 5 ?
+				   me->List_Nesting_Level+1 : 6)] = 'A';
 		} else if (*value[HTML_OL_TYPE] == 'a') {
-		    OL_Type[(List_Nesting_Level < 5 ?
-			     List_Nesting_Level+1 : 6)] = 'a';
+		    me->OL_Type[(me->List_Nesting_Level < 5 ?
+				   me->List_Nesting_Level+1 : 6)] = 'a';
 		} else if (*value[HTML_OL_TYPE] == 'I') {
-		    OL_Type[(List_Nesting_Level < 5 ?
-			     List_Nesting_Level+1 : 6)] = 'I';
+		    me->OL_Type[(me->List_Nesting_Level < 5 ?
+				   me->List_Nesting_Level+1 : 6)] = 'I';
 		} else if (*value[HTML_OL_TYPE] == 'i') {
-		    OL_Type[(List_Nesting_Level < 5 ?
-			     List_Nesting_Level+1 : 6)] = 'i';
+		    me->OL_Type[(me->List_Nesting_Level < 5 ?
+				   me->List_Nesting_Level+1 : 6)] = 'i';
 		}
 	    }
 	}
-	List_Nesting_Level++;
+	me->List_Nesting_Level++;
 
-	if (List_Nesting_Level <= 0) {
+	if (me->List_Nesting_Level <= 0) {
        	    change_paragraph_style(me, styles[element_number]);
 
-	} else if (List_Nesting_Level >= 6) {
+	} else if (me->List_Nesting_Level >= 6) {
        	    change_paragraph_style(me, styles[HTML_OL6]);
 
 	} else {
             change_paragraph_style(me, 
-		          styles[HTML_OL1 + List_Nesting_Level - 1]);
+		          styles[HTML_OL1 + me->List_Nesting_Level - 1]);
 	}
 	UPDATE_STYLE;  /* update to the new style */
-	HTML_CheckForID(me, present, value, (int)HTML_OL_ID);
+	LYCheckForID(me, present, value, (int)HTML_OL_ID);
 	break;
 
     case HTML_UL:
-	List_Nesting_Level++;
+	me->List_Nesting_Level++;
 
-	if (List_Nesting_Level <= 0) {
+	if (me->List_Nesting_Level <= 0) {
 	    if (!(present && present[HTML_UL_PLAIN]) &&
 	        !(present && present[HTML_UL_TYPE] &&
 		  value[HTML_UL_TYPE] &&
@@ -2184,7 +1795,7 @@ PRIVATE void HTML_start_element ARGS5(
 		element_number = HTML_DIR;
 	    }
 
-	} else if (List_Nesting_Level >= 6) {
+	} else if (me->List_Nesting_Level >= 6) {
 	    if (!(present && present[HTML_UL_PLAIN]) &&
 	        !(present && present[HTML_UL_TYPE] &&
 		  value[HTML_UL_TYPE] &&
@@ -2201,39 +1812,39 @@ PRIVATE void HTML_start_element ARGS5(
 		  value[HTML_UL_TYPE] &&
 		  0==strcasecomp(value[HTML_UL_TYPE], "PLAIN"))) {
                 change_paragraph_style(me, 
-		          styles[HTML_OL1 + List_Nesting_Level - 1]);
+		          styles[HTML_OL1 + me->List_Nesting_Level - 1]);
 	    } else {
                 change_paragraph_style(me, 
-		          styles[HTML_MENU1 + List_Nesting_Level - 1]);
+		          styles[HTML_MENU1 + me->List_Nesting_Level - 1]);
 		element_number = HTML_DIR;
 	    }
 	}
 	UPDATE_STYLE;  /* update to the new style */
-	HTML_CheckForID(me, present, value, (int)HTML_UL_ID);
+	LYCheckForID(me, present, value, (int)HTML_UL_ID);
 	break;
 
     case HTML_MENU:
     case HTML_DIR:
-	List_Nesting_Level++;
+	me->List_Nesting_Level++;
 
-	if (List_Nesting_Level <= 0) {
+	if (me->List_Nesting_Level <= 0) {
        	    change_paragraph_style(me, styles[element_number]);
 
-	} else if (List_Nesting_Level >= 6) {
+	} else if (me->List_Nesting_Level >= 6) {
        	    change_paragraph_style(me, styles[HTML_MENU6]);
 
 	} else {
             change_paragraph_style(me, 
-		          styles[HTML_MENU1 + List_Nesting_Level - 1]);
+		          styles[HTML_MENU1 + me->List_Nesting_Level - 1]);
 	}
 	UPDATE_STYLE;  /* update to the new style */
-	HTML_CheckForID(me, present, value, (int)HTML_UL_ID);
+	LYCheckForID(me, present, value, (int)HTML_UL_ID);
 	break;
 	
     case HTML_LH:
         UPDATE_STYLE;  /* update to the new style */
 	HText_appendParagraph(me->text);
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
 	HText_appendCharacter(me->text, ' ');
 	me->in_word = NO;
 	break;
@@ -2242,24 +1853,24 @@ PRIVATE void HTML_start_element ARGS5(
         UPDATE_STYLE;  /* update to the new style */
 	HText_appendParagraph(me->text);
 	me->sp->style->alignment = HT_LEFT;
-	HTML_CheckForID(me, present, value, (int)HTML_LI_ID);
+	LYCheckForID(me, present, value, (int)HTML_LI_ID);
 	if (me->sp[0].tag_number == HTML_OL) {
 	    char number_string[20];
-	    register int i, counter, seqnum;
+	    int counter, seqnum;
 	    char seqtype;
 
-	    counter = List_Nesting_Level < 6 ? List_Nesting_Level : 6;
+	    counter = me->List_Nesting_Level < 6 ? me->List_Nesting_Level : 6;
 	    if (present && present[HTML_LI_TYPE] && value[HTML_LI_TYPE]) {
 	        if (*value[HTML_LI_TYPE] == '1') {
-		    OL_Type[counter] = '1';
+		    me->OL_Type[counter] = '1';
 	        } else if (*value[HTML_LI_TYPE] == 'A') {
-		    OL_Type[counter] = 'A';
+		    me->OL_Type[counter] = 'A';
 	        } else if (*value[HTML_LI_TYPE] == 'a') {
-		    OL_Type[counter] = 'a';
+		    me->OL_Type[counter] = 'a';
 	        } else if (*value[HTML_LI_TYPE] == 'I') {
-		    OL_Type[counter] = 'I';
+		    me->OL_Type[counter] = 'I';
 	        } else if (*value[HTML_LI_TYPE] == 'i') {
-		    OL_Type[counter] = 'i';
+		    me->OL_Type[counter] = 'i';
 		}
 	    }
 	    if (present && present[HTML_LI_VALUE] &&
@@ -2271,24 +1882,24 @@ PRIVATE void HTML_start_element ARGS5(
 		seqnum = atoi(value[HTML_LI_VALUE]);
 		if (seqnum <= OL_VOID)
 		    seqnum = OL_VOID + 1;
-		seqtype = OL_Type[counter];
+		seqtype = me->OL_Type[counter];
 		if (seqtype != '1' && seqnum < 1)
 		    seqnum = 1;
-		OL_Counter[counter] = seqnum + 1;
-	    } else if (OL_Counter[counter] >= OL_VOID) {
-	        seqnum = OL_Counter[counter]++;
-		seqtype = OL_Type[counter];
+		me->OL_Counter[counter] = seqnum + 1;
+	    } else if (me->OL_Counter[counter] >= OL_VOID) {
+	        seqnum = me->OL_Counter[counter]++;
+		seqtype = me->OL_Type[counter];
 		if (seqtype != '1' && seqnum < 1) {
 		    seqnum = 1;
-		    OL_Counter[counter] = seqnum + 1;
+		    me->OL_Counter[counter] = seqnum + 1;
 		}
 	    } else {
-	        seqnum = Last_OL_Count + 1;
-		seqtype = Last_OL_Type;
+	        seqnum = me->Last_OL_Count + 1;
+		seqtype = me->Last_OL_Type;
 		for (i = (counter - 1); i >= 0; i--) {
-		    if (OL_Counter[i] > OL_VOID) {
-		        seqnum = OL_Counter[i]++;
-			seqtype = OL_Type[i];
+		    if (me->OL_Counter[i] > OL_VOID) {
+		        seqnum = me->OL_Counter[i]++;
+			seqtype = me->OL_Type[i];
 			i = 0;
 		    }
 		}
@@ -2304,8 +1915,8 @@ PRIVATE void HTML_start_element ARGS5(
 	    } else {
 	        sprintf(number_string, "%2d.", seqnum);
 	    }
-	    Last_OL_Count = seqnum;
-	    Last_OL_Type = seqtype;
+	    me->Last_OL_Count = seqnum;
+	    me->Last_OL_Type = seqtype;
 	    /* hack, because there is no append string! */
 	    for (i = 0; number_string[i] != '\0'; i++)
 		if (number_string[i] == ' ')
@@ -2314,7 +1925,7 @@ PRIVATE void HTML_start_element ARGS5(
 	    	    HTML_put_character(me, number_string[i]);
 
 	    /* use HTML_put_character so that any other spaces
-	     * comming through will be collapsed
+	     * coming through will be collapsed
 	     */
 	    HTML_put_character(me, ' ');  /* the spacing charactor */	
 
@@ -2328,7 +1939,7 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  Use HTML_put_character so that any other spaces
 	     *  comming through will be collapsed
 	     */
-	    switch(List_Nesting_Level % 7) {
+	    switch(me->List_Nesting_Level % 7) {
 		case 0:
 	    	    HTML_put_character(me, '*');
 		    break;
@@ -2361,13 +1972,13 @@ PRIVATE void HTML_start_element ARGS5(
 	    HText_appendCharacter(me->text, ' ');
 	}
 	me->in_word = NO;
-	B_inP = FALSE;
+	me->inP = FALSE;
 	break;
 
     case HTML_SPAN:
 	if (!me->text)
 	    UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
         /*
 	 *  Should check LANG and/or DIR attributes, and the
 	 *  me->node_anchor->charset and/or yet to be added
@@ -2378,7 +1989,7 @@ PRIVATE void HTML_start_element ARGS5(
     case HTML_BDO:
 	if (!me->text)
 	    UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
         /*
 	 *  Should check DIR (and LANG) attributes, and the
 	 *  me->node_anchor->charset and/or yet to be added
@@ -2389,117 +2000,109 @@ PRIVATE void HTML_start_element ARGS5(
     case HTML_SPOT:
 	if (!me->text)
 	    UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
 	break;
 
     case HTML_FN:
     	change_paragraph_style(me, styles[element_number]);
 	UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_FN_ID);
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
+	if (me->sp->tag_number == element_number)
+	    LYEnsureDoubleSpace(me);
+	LYCheckForID(me, present, value, (int)HTML_FN_ID);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
 	HTML_put_string(me, "FOOTNOTE:");
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	HTML_put_character(me, ' ');
-	B_inLABEL = TRUE;
+	me->inLABEL = TRUE;
 	me->in_word = NO;
-	B_inP = FALSE;
+	me->inP = FALSE;
 	break;
 
     case HTML_A:
-	{
-	    /*
-	     *  Set to know we are in an anchor.
-	     */
-	    B_inA = TRUE;
+	/*
+	 *  Set to know we are in an anchor.
+	 */
+	me->inA = TRUE;
 
+	/*
+	 *  Load id_string if we have an ID or NAME. - FM
+	 */
+	if (present && present[HTML_A_ID] &&
+	    value[HTML_A_ID] && *value[HTML_A_ID]) {
+	    StrAllocCopy(id_string, value[HTML_A_ID]);
+	} else if (present && present[HTML_A_NAME] &&
+		   value[HTML_A_NAME] && *value[HTML_A_NAME]) {
+	    StrAllocCopy(id_string, value[HTML_A_NAME]);
+	}
+	if (id_string) {
+	    LYUnEscapeToLatinOne(&id_string, TRUE);
+	    if (*id_string == '\0') {
+		FREE(id_string);
+	    }
+	}
+
+	/*
+	 *  Handle the reference. - FM
+	 */
+	if (present && present[HTML_A_HREF]) {
 	    /*
-	     *  Load id_string if we have an ID or NAME. - FM
+	     *  Prepare to do housekeeping on the reference. - FM
 	     */
-	    if (present && present[HTML_A_ID] &&
-	        value[HTML_A_ID] && *value[HTML_A_ID]) {
-		StrAllocCopy(id_string, value[HTML_A_ID]);
-	    } else if (present && present[HTML_A_NAME] &&
-		       value[HTML_A_NAME] && *value[HTML_A_NAME]) {
-		StrAllocCopy(id_string, value[HTML_A_NAME]);
-	    }
-	    if (id_string) {
-	        LYUnEscapeToLatinOne(&id_string, TRUE);
-		if (*id_string == '\0') {
-		    FREE(id_string);
+	    if (!value[HTML_A_HREF] || *value[HTML_A_HREF] == '\0') {
+	        StrAllocCopy(href, me->node_anchor->address);
+	    } else if (*value[HTML_A_HREF] == '#') {
+	        StrAllocCopy(href, me->node_anchor->address);
+		if (strlen(value[HTML_A_HREF]) > 1) {
+		    StrAllocCat(href, value[HTML_A_HREF]);
 		}
+	    } else {
+		StrAllocCopy(href, value[HTML_A_HREF]);
 	    }
+	    url_type = LYLegitimizeHREF(me, (char**)&href, TRUE);
 
 	    /*
-	     *  Handle the reference. - FM
+	     *  Deal with our ftp gateway kludge. - FM
 	     */
-	    if (present && present[HTML_A_HREF]) {
-	        /*
-		 *  Prepare to do housekeeping on the reference. - FM
-		 */
-		if (!(value[HTML_A_HREF] && *value[HTML_A_HREF])) {
-		    if (B_inBASE && base_href && *base_href) {
-		        StrAllocCopy(href, base_href);
-		    } else {
-		        StrAllocCopy(href, me->node_anchor->address);
-		    }
-		} else {
-		    StrAllocCopy(href, value[HTML_A_HREF]);
-		    convert_to_spaces(href);
-		    LYUnEscapeToLatinOne(&href, TRUE);
-		}
-	        url_type = is_url(href);
-
-		/*
-		 *  Deal with our ftp gateway kludge. - FM
-		 */
-		if (!url_type && !strncmp(href, "/foo/..", 7) &&
-		    (!strncmp(me->node_anchor->address, "ftp:", 4) ||
-		     !strncmp(me->node_anchor->address, "file:", 5))) {
-		    int i;
-		    for (i = 0; href[i]; i++)
-		        href[i] = href[i+7];
-		}
+	    if (!url_type && !strncmp(href, "/foo/..", 7) &&
+		(!strncmp(me->node_anchor->address, "ftp:", 4) ||
+		 !strncmp(me->node_anchor->address, "file:", 5))) {
+		for (i = 0; href[i]; i++)
+		    href[i] = href[i+7];
+	    }
 
-		/*
-		 *  Don't simplify gopher gateway URLs or absolute HREFs. - FM
-		 */
-		if (HT_Is_Gopher_URL) {
-		    HT_Is_Gopher_URL = FALSE;
-		} else if (!url_type && *href != '/' && *href != '\0')
-		    HTSimplify(href);
+	    /*
+	     *  Set to know we are making the content bold.
+	     */
+	    me->inBoldA = TRUE;
 
+	    /*
+	     *  Check whether a base tag is in effect. - FM
+	     */
+	    if ((me->inBASE && *href != '\0' && *href != '#') &&
+		(temp = HTParse(href, me->base_href, PARSE_ALL)) &&
+		*temp != '\0')
 	        /*
-		 *  Set to know we are making the content bold.
-		 */
-		B_inBoldA = TRUE;
-
-		/*
-		 *  Check whether a base tag is in effect. - FM
+		 *  Use reference related to the base.
 		 */
-		if ((B_inBASE) &&
-		    (temp = HTParse(href, base_href, PARSE_ALL)) &&
-		    *temp != '\0')
-	            /*
-		     *  Use reference related to the base.
-		     */
-		    StrAllocCopy(href, temp);
-		FREE(temp);
+		StrAllocCopy(href, temp);
+	    FREE(temp);
 
-		/*
-		 *  Check whether to fill in localhost. - FM
-		 */
-		HTMLFillLocalFileURL((char **)&href,
-				     (B_inBASE ? base_href :
-						 me->node_anchor->address));
-	    } else {
-	        if (bold_name_anchors == TRUE) {
-	            B_inBoldA = TRUE;
-		}
+	    /*
+	     *  Check whether to fill in localhost. - FM
+	     */
+	    LYFillLocalFileURL((char **)&href,
+			       ((*href != '\0' && *href != '#' &&
+			         me->inBASE) ?
+			       me->base_href : me->node_anchor->address));
+	} else {
+	    if (bold_name_anchors == TRUE) {
+	        me->inBoldA = TRUE;
 	    }
+	}
 
-	    B_CurrentA = HTAnchor_findChildAndLink(
+	me->CurrentA = HTAnchor_findChildAndLink(
 			me->node_anchor,			/* Parent */
 			id_string,				/* Tag */
 			href,					/* Address */
@@ -2508,49 +2111,48 @@ PRIVATE void HTML_start_element ARGS5(
 			   value[HTML_A_TYPE]) ? 
    (HTLinkType*)HTAtom_for(value[HTML_A_TYPE]) : (void *)0);	/* Type */
 
-	    /*
-	     *	Get rid of href since no longer needed.
-	     *	Memory leak fixed
-	     *	06-16-94 Lynx 2-3-1 Garrett Arch Blythe
-	     */
-	    FREE(href);
-	    FREE(id_string);
+	/*
+	 *  Get rid of href since no longer needed.
+	 *  Memory leak fixed
+	 *  06-16-94 Lynx 2-3-1 Garrett Arch Blythe
+	 */
+	FREE(href);
+	FREE(id_string);
 	    
-	    if (B_CurrentA && present) {
-	        if (present[HTML_A_TITLE] &&
-		    value[HTML_A_TITLE] && *value[HTML_A_TITLE] != '\0') {
-		    StrAllocCopy(title, value[HTML_A_TITLE]);
-		    if (current_char_set)
-		        LYExpandString(&title);
-		    /*
-		     *  Convert any HTML entities or decimal escaping. - FM
-		     */
-		    LYUnEscapeEntities(title, TRUE, FALSE);
-		    LYTrimHead(title);
-		    LYTrimTail(title);
-		    if (*title == '\0') {
-		        FREE(title);
-		    }
+	if (me->CurrentA && present) {
+	    if (present[HTML_A_TITLE] &&
+	        value[HTML_A_TITLE] && *value[HTML_A_TITLE] != '\0') {
+		StrAllocCopy(title, value[HTML_A_TITLE]);
+		if (current_char_set)
+		    LYExpandString(&title);
+		/*
+		 *  Convert any HTML entities or decimal escaping. - FM
+		 */
+		LYUnEscapeEntities(title, TRUE, FALSE);
+		LYTrimHead(title);
+		LYTrimTail(title);
+		if (*title == '\0') {
+		    FREE(title);
 		}
-	        if (present[HTML_A_ISMAP])
-		    dest_ismap = TRUE;
-		if (title != NULL || dest_ismap == TRUE)
-	            dest = HTAnchor_parent(
-			HTAnchor_followMainLink((HTAnchor*)B_CurrentA)
-		    			  );
-		if (dest && title != NULL && HTAnchor_title(dest) == NULL)
-		    HTAnchor_setTitle(dest, title);
-		if (dest && dest_ismap)
-		    dest->isISMAPScript = TRUE;
-		dest = NULL;
-		dest_ismap = FALSE;
-		FREE(title);
 	    }
-	    UPDATE_STYLE;
-	    HText_beginAnchor(me->text, B_CurrentA);
-	    if (B_inBoldA == TRUE && B_inBoldH == FALSE)
-	        HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
+	    if (present[HTML_A_ISMAP])
+		dest_ismap = TRUE;
+	    if (title != NULL || dest_ismap == TRUE)
+	        dest = HTAnchor_parent(
+			HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
+		    		      );
+	    if (dest && title != NULL && HTAnchor_title(dest) == NULL)
+		HTAnchor_setTitle(dest, title);
+	    if (dest && dest_ismap)
+		dest->isISMAPScript = TRUE;
+	    dest = NULL;
+	    dest_ismap = FALSE;
+	    FREE(title);
 	}
+	UPDATE_STYLE;
+	HText_beginAnchor(me->text, me->CurrentA);
+	if (me->inBoldA == TRUE && me->inBoldH == FALSE)
+	    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
     	break;
 
     case HTML_IMG:			/* Images */
@@ -2561,9 +2163,9 @@ PRIVATE void HTML_start_element ARGS5(
 	 *  set our flags for faking a 0,0 coordinate pair,
 	 *  which typically returns the image's default. - FM
 	 */
-	if (B_inA && B_CurrentA) {
+	if (me->inA && me->CurrentA) {
 	    if (dest = HTAnchor_parent(
-				HTAnchor_followMainLink((HTAnchor*)B_CurrentA)
+			HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
 				      )) {
 		if (dest->isISMAPScript == TRUE) {
 		    dest_ismap = TRUE;
@@ -2588,22 +2190,18 @@ PRIVATE void HTML_start_element ARGS5(
 	if (present && present[HTML_IMG_USEMAP] &&
 	    value[HTML_IMG_USEMAP] && *value[HTML_IMG_USEMAP]) {
 	    StrAllocCopy(map_href, value[HTML_IMG_USEMAP]);
-	    convert_to_spaces(map_href);
-	    LYUnEscapeToLatinOne(&map_href, TRUE);
+	    url_type = LYLegitimizeHREF(me, (char**)&map_href, TRUE);
 	    if (*map_href == '\0') {
 	        FREE(map_href);
 	    }
 	}
 	if (map_href && strchr(map_href, '#')) {
-	    url_type = is_url(map_href);
-	    if (!url_type && *map_href != '#')
-	        HTSimplify(map_href);
 
 	    /*
 	     *  Check whether a base tag is in effect. - FM
 	     */
-	    if ((B_inBASE) &&
-	        (temp = HTParse(map_href, base_href, PARSE_ALL)) &&
+	    if ((me->inBASE && *map_href != '#') &&
+	        (temp = HTParse(map_href, me->base_href, PARSE_ALL)) &&
 	        *temp != '\0')
 		/*
 		 *  Use reference related to the base.
@@ -2614,9 +2212,10 @@ PRIVATE void HTML_start_element ARGS5(
 	    /*
 	     *  Check whether to fill in localhost. - FM
 	     */
-	    HTMLFillLocalFileURL((char **)&map_href,
-				 (B_inBASE ? base_href :
-					     me->node_anchor->address));
+	    LYFillLocalFileURL((char **)&map_href,
+			       ((*map_href != '\0' && *map_href != '#' &&
+			         me->inBASE) ?
+			      me->base_href : me->node_anchor->address));
 
 	    /*
 	     *  If it's not yet a URL, resolve versus
@@ -2673,7 +2272,7 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  Convert any HTML entities or decimal escaping. - FM
 	     */
 	    LYUnEscapeEntities(alt_string,
-	    		       LYUsePlainSpace, LYHiddenValue);
+	    		       me->UsePlainSpace, me->HiddenValue);
 	    /*
 	     *  If it's all spaces and we are making SRC or
 	     *  USEMAP links, treat it as zero-length. - FM
@@ -2688,7 +2287,7 @@ PRIVATE void HTML_start_element ARGS5(
 		    else if (dest_ismap || present[HTML_IMG_ISMAP]) {
 		        StrAllocCopy(alt_string, (title ?
 						  title : "[ISMAP]"));
-		    } else if (B_inA == TRUE) {
+		    } else if (me->inA == TRUE) {
 		        StrAllocCopy(alt_string, (title ?
 						  title : "[LINK]"));
 		    } else {
@@ -2708,7 +2307,7 @@ PRIVATE void HTML_start_element ARGS5(
 	    StrAllocCopy(alt_string, (title ?
 	    			      title : "[ISMAP]"));
 
-	} else if (B_inA == TRUE) {
+	} else if (me->inA == TRUE) {
 	    StrAllocCopy(alt_string, (title ?
 	    			      title : "[LINK]"));
 
@@ -2732,7 +2331,7 @@ PRIVATE void HTML_start_element ARGS5(
 		    map_href ? 1 : 0,
 		    (dest_ismap ||
 		     (present && present[HTML_IMG_ISMAP])) ? 1 : 0,
-		    B_inA, B_inP);
+		    me->inA, me->inP);
 	}
 
 	/*
@@ -2754,17 +2353,13 @@ PRIVATE void HTML_start_element ARGS5(
 	    present && present[HTML_IMG_SRC] &&
 	    value[HTML_IMG_SRC] && *value[HTML_IMG_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_IMG_SRC]);
-	    convert_to_spaces(href);
-	    LYUnEscapeToLatinOne(&href, TRUE);
-	    url_type = is_url(href);
-	    if (!url_type && *href != '\0')
-	        HTSimplify(href);
+	    url_type = LYLegitimizeHREF(me, (char**)&href, TRUE);
 
 	    /*
 	     *  Check whether a base tag is in effect. - FM
 	     */
-	    if ((B_inBASE) &&
-		(temp = HTParse(href, base_href, PARSE_ALL)) &&
+	    if ((me->inBASE && *href != '\0' && *href != '#') &&
+		(temp = HTParse(href, me->base_href, PARSE_ALL)) &&
 		*temp != '\0')
 		/*
 		 *  Use reference related to the base.
@@ -2775,15 +2370,16 @@ PRIVATE void HTML_start_element ARGS5(
 	    /*
 	     *  Check whether to fill in localhost. - FM
 	     */
-	    HTMLFillLocalFileURL((char **)&href,
-				 (B_inBASE ? base_href :
-					     me->node_anchor->address));
+	    LYFillLocalFileURL((char **)&href,
+			       ((*href != '\0' && *href != '#' &&
+			         me->inBASE) ?
+			       me->base_href : me->node_anchor->address));
 
 	    /*
 	     *  If it's an ISMAP and/or USEMAP, or graphic for an
 	     *  anchor, end that anchor and start one for the SRC. - FM
 	     */
-	    if (B_inA) {
+	    if (me->inA) {
 	        /*
 		 *  If we have a USEMAP, end this anchor and
 		 *  start a new one for the client-side MAP. - FM
@@ -2794,46 +2390,46 @@ PRIVATE void HTML_start_element ARGS5(
 		    } else {
 		        HTML_put_string(me, "[LINK]");
 		    }
-		    if (B_inBoldA == TRUE && B_inBoldH == FALSE) {
-		        HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+		    if (me->inBoldA == TRUE && me->inBoldH == FALSE) {
+		        HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		    }
-		    B_inBoldA = FALSE;
+		    me->inBoldA = FALSE;
 		    HText_endAnchor(me->text);
 		    HText_appendCharacter(me->text, '-');
 		    if (id_string) {
-		        if (B_ID_A = HTAnchor_findChildAndLink(
+		        if (ID_A = HTAnchor_findChildAndLink(
 				  me->node_anchor,	/* Parent */
 				  id_string,		/* Tag */
 				  NULL,			/* Addresss */
 				  (void *)0)) {		/* Type */
-		            HText_beginAnchor(me->text, B_ID_A);
+		            HText_beginAnchor(me->text, ID_A);
 		            HText_endAnchor(me->text);
 		        }
 		    }
-		    B_CurrentA = HTAnchor_findChildAndLink(
+		    me->CurrentA = HTAnchor_findChildAndLink(
 		    		me->node_anchor,	/* Parent */
 				NULL,			/* Tag */
 				map_href,		/* Addresss */
 				(void *)0);		/* Type */
-		    if (B_CurrentA && title) {
+		    if (me->CurrentA && title) {
 			if (dest = HTAnchor_parent(
-				HTAnchor_followMainLink((HTAnchor*)B_CurrentA)
+				HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
 					          )) {
 			    if (!HTAnchor_title(dest))
 			        HTAnchor_setTitle(dest, title);
 			}
 		    }
-		    HText_beginAnchor(me->text, B_CurrentA);
-		    if (B_inBoldA == FALSE && B_inBoldH == FALSE) {
-		        HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
+		    HText_beginAnchor(me->text, me->CurrentA);
+		    if (me->inBoldA == FALSE && me->inBoldH == FALSE) {
+		        HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 		    }
-		    B_inBoldA = TRUE;
+		    me->inBoldA = TRUE;
 		}
 	        HTML_put_string(me, alt_string);
-		if (B_inBoldA == TRUE && B_inBoldH == FALSE) {
-		    HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+		if (me->inBoldA == TRUE && me->inBoldH == FALSE) {
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		}
-		B_inBoldA = FALSE;
+		me->inBoldA = FALSE;
 		HText_endAnchor(me->text);
 		HText_appendCharacter(me->text, '-');
 		StrAllocCopy(alt_string,
@@ -2842,12 +2438,12 @@ PRIVATE void HTML_start_element ARGS5(
 		   ((map_href || dest_ismap) ?
 			     	   "(IMAGE)" : "(OBJECT)") : "[IMAGE]"));
 		if (id_string && !map_href) {
-		    if (B_ID_A = HTAnchor_findChildAndLink(
+		    if (ID_A = HTAnchor_findChildAndLink(
 				  me->node_anchor,	/* Parent */
 				  id_string,		/* Tag */
 				  NULL,			/* Addresss */
 				  (void *)0)) {		/* Type */
-		        HText_beginAnchor(me->text, B_ID_A);
+		        HText_beginAnchor(me->text, ID_A);
 		        HText_endAnchor(me->text);
 		    }
 		}
@@ -2855,37 +2451,37 @@ PRIVATE void HTML_start_element ARGS5(
 	        HTML_put_character(me, ' ');  /* space char may be ignored */
 		me->in_word = NO;
 		if (id_string) {
-		    if (B_ID_A = HTAnchor_findChildAndLink(
+		    if (ID_A = HTAnchor_findChildAndLink(
 				  me->node_anchor,	/* Parent */
 				  id_string,		/* Tag */
 				  NULL,			/* Addresss */
 				  (void *)0)) {		/* Type */
-		        HText_beginAnchor(me->text, B_ID_A);
+		        HText_beginAnchor(me->text, ID_A);
 		        HText_endAnchor(me->text);
 		    }
 		}
-		B_CurrentA = HTAnchor_findChildAndLink(
+		me->CurrentA = HTAnchor_findChildAndLink(
 		    		me->node_anchor,	/* Parent */
 				NULL,			/* Tag */
 				map_href,		/* Addresss */
 				(void *)0);		/* Type */
-		if (B_CurrentA && title) {
+		if (me->CurrentA && title) {
 		    if (dest = HTAnchor_parent(
-				HTAnchor_followMainLink((HTAnchor*)B_CurrentA)
+				HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
 					      )) {
 		        if (!HTAnchor_title(dest))
 			    HTAnchor_setTitle(dest, title);
 		    }
 		}
-		HText_beginAnchor(me->text, B_CurrentA);
-		if (B_inBoldA == FALSE && B_inBoldH == FALSE)
-		    HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
-		B_inBoldA = TRUE;
+		HText_beginAnchor(me->text, me->CurrentA);
+		if (me->inBoldA == FALSE && me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+		me->inBoldA = TRUE;
 	        HTML_put_string(me, alt_string);
-		if (B_inBoldA == TRUE && B_inBoldH == FALSE) {
-		    HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+		if (me->inBoldA == TRUE && me->inBoldH == FALSE) {
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		}
-		B_inBoldA = FALSE;
+		me->inBoldA = FALSE;
 		HText_endAnchor(me->text);
 		HText_appendCharacter(me->text, '-');
 		StrAllocCopy(alt_string,
@@ -2896,12 +2492,12 @@ PRIVATE void HTML_start_element ARGS5(
 	        HTML_put_character(me, ' ');  /* space char may be ignored */
 		me->in_word = NO;
 		if (id_string) {
-		    if (B_ID_A = HTAnchor_findChildAndLink(
+		    if (ID_A = HTAnchor_findChildAndLink(
 				  me->node_anchor,	/* Parent */
 				  id_string,		/* Tag */
 				  NULL,			/* Addresss */
 				  (void *)0)) {		/* Type */
-		        HText_beginAnchor(me->text, B_ID_A);
+		        HText_beginAnchor(me->text, ID_A);
 		        HText_endAnchor(me->text);
 		    }
 		}
@@ -2910,27 +2506,27 @@ PRIVATE void HTML_start_element ARGS5(
 	    /*
 	     *  Create the link to the SRC. - FM
 	     */
-	    B_CurrentA = HTAnchor_findChildAndLink(
+	    me->CurrentA = HTAnchor_findChildAndLink(
 			me->node_anchor,		/* Parent */
 			NULL,				/* Tag */
 			href,				/* Addresss */
 			(void *)0);			/* Type */
 	    FREE(href);
-	    HText_beginAnchor(me->text, B_CurrentA);
-	    if (B_inBoldH == FALSE)
-		HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
+	    HText_beginAnchor(me->text, me->CurrentA);
+	    if (me->inBoldH == FALSE)
+		HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 	    HTML_put_string(me, alt_string);
-	    if (!B_inA) {
-	        if (B_inBoldH == FALSE)
-		    HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+	    if (!me->inA) {
+	        if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		HText_endAnchor(me->text);
 		HTML_put_character(me, ' ');  /* space char may be ignored */
 		me->in_word = NO;
 	    } else {
-	        B_inBoldA = TRUE;
+	        me->inBoldA = TRUE;
 	    }
 	} else if (map_href) {
-	    if (B_inA) {
+	    if (me->inA) {
 	        /*
 		 *  We're in an anchor and have a USEMAP, so end the anchor
 		 *  and start a new one for the client-side MAP. - FM
@@ -2940,40 +2536,40 @@ PRIVATE void HTML_start_element ARGS5(
 		} else {
 		    HTML_put_string(me, "[LINK]");
 		}
-		if (B_inBoldA == TRUE && B_inBoldH == FALSE) {
-		    HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+		if (me->inBoldA == TRUE && me->inBoldH == FALSE) {
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		}
-		B_inBoldA = FALSE;
+		me->inBoldA = FALSE;
 		HText_endAnchor(me->text);
 		HText_appendCharacter(me->text, '-');
 	    } else {
 	        HTML_put_character(me, ' ');
 	        me->in_word = NO;
 	    }
-	    B_CurrentA = HTAnchor_findChildAndLink(
+	    me->CurrentA = HTAnchor_findChildAndLink(
 		    		me->node_anchor,	/* Parent */
 				NULL,			/* Tag */
 				map_href,		/* Addresss */
 				(void *)0);		/* Type */
-	    if (B_CurrentA && title) {
+	    if (me->CurrentA && title) {
 		if (dest = HTAnchor_parent(
-				HTAnchor_followMainLink((HTAnchor*)B_CurrentA)
+				HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
 				          )) {
 		    if (!HTAnchor_title(dest))
 		        HTAnchor_setTitle(dest, title);
 		}
 	    }
-	    HText_beginAnchor(me->text, B_CurrentA);
-	    if (B_inBoldA == FALSE && B_inBoldH == FALSE) {
-		HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
+	    HText_beginAnchor(me->text, me->CurrentA);
+	    if (me->inBoldA == FALSE && me->inBoldH == FALSE) {
+		HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 	    }
-	    B_inBoldA = TRUE;
+	    me->inBoldA = TRUE;
 	    HTML_put_string(me, alt_string);
-	    if (!B_inA) {
-	        if (B_inBoldA == TRUE && B_inBoldH == FALSE) {
-		    HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+	    if (!me->inA) {
+	        if (me->inBoldA == TRUE && me->inBoldH == FALSE) {
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		}
-		B_inBoldA = FALSE;
+		me->inBoldA = FALSE;
 		HText_endAnchor(me->text);
 	    }
 	} else {
@@ -2982,22 +2578,22 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  for the current anchor or inline, with an
 	     *  ID link if indicated. - FM
 	     */
-	    if (!B_inA) {
+	    if (!me->inA) {
 	        HTML_put_character(me, ' ');  /* space char may be ignored */
 		me->in_word = NO;
 	    }
 	    if (id_string) {
-		if (B_ID_A = HTAnchor_findChildAndLink(
+		if (ID_A = HTAnchor_findChildAndLink(
 				  me->node_anchor,	/* Parent */
 				  id_string,		/* Tag */
 				  NULL,			/* Addresss */
 				  (void *)0)) {		/* Type */
-		    HText_beginAnchor(me->text, B_ID_A);
+		    HText_beginAnchor(me->text, ID_A);
 		    HText_endAnchor(me->text);
 		}
 	    }
 	    HTML_put_string(me, alt_string);
-	    if (!B_inA) {
+	    if (!me->inA) {
 	        HTML_put_character(me, ' ');  /* space char may be ignored */
 		me->in_word = NO;
 	    }
@@ -3029,19 +2625,18 @@ PRIVATE void HTML_start_element ARGS5(
 	}
 
 	/*
-	 *  Load LYMapName. - FM
+	 *  Load map_address. - FM
 	 */
 	if (id_string) {
-	    char * cp;
-	    if (B_inBASE && base_href && *base_href) {
-		StrAllocCopy(LYMapName, base_href);
+	    if (me->inBASE && me->base_href && *me->base_href) {
+		StrAllocCopy(me->map_address, me->base_href);
 	    } else {
-		StrAllocCopy(LYMapName, me->node_anchor->address);
+		StrAllocCopy(me->map_address, me->node_anchor->address);
 	    }
-	    if ((cp=strrchr(LYMapName, '#')) != NULL)
+	    if ((cp = strrchr(me->map_address, '#')) != NULL)
 	        *cp = '\0';
-	    StrAllocCat(LYMapName, "#");
-	    StrAllocCat(LYMapName, id_string);
+	    StrAllocCat(me->map_address, "#");
+	    StrAllocCat(me->map_address, id_string);
 	    FREE(id_string);
 	    if (present && present[HTML_MAP_TITLE] &&
 	        value[HTML_MAP_TITLE] && *value[HTML_MAP_TITLE] != '\0') {
@@ -3058,30 +2653,26 @@ PRIVATE void HTML_start_element ARGS5(
 		    FREE(title);
 		}
 	    }
-	    LYAddImageMap(LYMapName, title);
+	    LYAddImageMap(me->map_address, title);
 	    FREE(title);
 	}
         break;
 
     case HTML_AREA:
-        if (LYMapName &&
+        if (me->map_address &&
 	    present && present[HTML_AREA_HREF] &&
 	    value[HTML_AREA_HREF] && *value[HTML_AREA_HREF]) {
 	    /*
 	     * Resolve the HREF. - FM
 	     */
 	    StrAllocCopy(href, value[HTML_AREA_HREF]);
-	    convert_to_spaces(href);
-	    LYUnEscapeToLatinOne(&href, TRUE);
-	    url_type = is_url(href);
-	    if (!url_type && *href != '/' && *href != '\0')
-	        HTSimplify(href);
+	    url_type = LYLegitimizeHREF(me, (char**)&href, TRUE);
 
 	    /*
 	     *  Check whether a base tag is in effect. - FM
 	     */
-	    if ((B_inBASE) &&
-		(temp = HTParse(href, base_href, PARSE_ALL)) &&
+	    if ((me->inBASE && *href != '\0' && *href != '#') &&
+		(temp = HTParse(href, me->base_href, PARSE_ALL)) &&
 		*temp != '\0')
 		/*
 		 *  Use reference related to the base.
@@ -3092,9 +2683,10 @@ PRIVATE void HTML_start_element ARGS5(
 	    /*
 	     *  Check whether to fill in localhost. - FM
 	     */
-	    HTMLFillLocalFileURL((char **)&href,
-				 (B_inBASE ? base_href :
-					     me->node_anchor->address));
+	    LYFillLocalFileURL((char **)&href,
+			       ((*href != '\0' && *href != '#' &&
+			         me->inBASE) ?
+			       me->base_href : me->node_anchor->address));
 
 	    if (!(url_type = is_url(href))) {
 	        temp = HTParse(href, me->node_anchor->address, PARSE_ALL);
@@ -3127,7 +2719,7 @@ PRIVATE void HTML_start_element ARGS5(
 		 *  Convert any HTML entities or decimal escaping. - FM
 		 */
 		LYUnEscapeEntities(alt_string,
-				   LYUsePlainSpace, LYHiddenValue);
+				   me->UsePlainSpace, me->HiddenValue);
 		/*
 		 *  Make sure it's not just space(s). - FM
 		 */
@@ -3143,7 +2735,7 @@ PRIVATE void HTML_start_element ARGS5(
 	        StrAllocCopy(alt_string, href);
 	    }
 
-	    LYAddMapElement(LYMapName, href, alt_string);
+	    LYAddMapElement(me->map_address, href, alt_string);
 	    FREE(href);
 	    FREE(alt_string);
 	}
@@ -3158,7 +2750,7 @@ PRIVATE void HTML_start_element ARGS5(
 	break;
 
     case HTML_BODYTEXT:
-        HTML_CheckForID(me, present, value, (int)HTML_BODYTEXT_ID);
+        LYCheckForID(me, present, value, (int)HTML_BODYTEXT_ID);
         /*
 	 *  We may need to look at this someday to deal with
 	 *  OBJECTs optimally, but just ignore it for now. - FM
@@ -3166,7 +2758,7 @@ PRIVATE void HTML_start_element ARGS5(
 	break;
 
     case HTML_TEXTFLOW:
-        HTML_CheckForID(me, present, value, (int)HTML_BODYTEXT_ID);
+        LYCheckForID(me, present, value, (int)HTML_BODYTEXT_ID);
         /*
 	 *  We may need to look at this someday to deal with
 	 *  APPLETs optimally, but just ignore it for now. - FM
@@ -3174,37 +2766,32 @@ PRIVATE void HTML_start_element ARGS5(
 	break;
 
     case HTML_FIG:
-        B_inFIG = TRUE;
+        me->inFIG = TRUE;
 	if (!me->text)
 	    UPDATE_STYLE;
 	if (!present ||
 	    (present && !present[HTML_FIG_ISOBJECT])) {
-	    HTML_EnsureDoubleSpace(me);
-	    HTML_ResetParagraphAlignment(me);
-	    B_inFIGwithP = TRUE;
+	    LYEnsureDoubleSpace(me);
+	    LYResetParagraphAlignment(me);
+	    me->inFIGwithP = TRUE;
 	} else {
-	    B_inFIGwithP = FALSE;
+	    me->inFIGwithP = FALSE;
 	    HTML_put_character(me, ' ');  /* space char may be ignored */
 	}
-	HTML_CheckForID(me, present, value, (int)HTML_FIG_ID);
+	LYCheckForID(me, present, value, (int)HTML_FIG_ID);
 	me->in_word = NO;
-	B_inP = FALSE;
+	me->inP = FALSE;
 
 	if (clickable_images && present && present[HTML_FIG_SRC] &&
 	    value[HTML_FIG_SRC] && *value[HTML_FIG_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_FIG_SRC]);
-	    convert_to_spaces(href);
-	    LYUnEscapeToLatinOne(&href, TRUE);
+	    url_type = LYLegitimizeHREF(me, (char**)&href, TRUE);
 	    if (*href) {
-	        url_type = is_url(href);
-		if (!url_type && *href != '/')
-		    HTSimplify(href);
-
 		/*
 		 *  Check whether a base tag is in effect. - FM
 		 */
-		if ((B_inBASE) &&
-		    (temp = HTParse(href, base_href, PARSE_ALL)) &&
+		if ((me->inBASE && *href != '#') &&
+		    (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
 		    *temp != '\0')
 		    /*
 		     *  Use reference related to the base.
@@ -3215,27 +2802,28 @@ PRIVATE void HTML_start_element ARGS5(
 		/*
 		 *  Check whether to fill in localhost. - FM
 		 */
-		HTMLFillLocalFileURL((char **)&href,
-				     (B_inBASE ?
-				     base_href : me->node_anchor->address));
+		LYFillLocalFileURL((char **)&href,
+				   ((*href != '#' &&
+				     me->inBASE) ?
+				   me->base_href : me->node_anchor->address));
 
-		if ((B_CurrentA = HTAnchor_findChildAndLink(
+		if ((me->CurrentA = HTAnchor_findChildAndLink(
 		       			me->node_anchor,	/* Parent */
 		       			NULL,			/* Tag */
 		       			href,			/* Addresss */
 		       			(void *)0))) {		/* Type */
-		    HText_beginAnchor(me->text, B_CurrentA);
-		    if (B_inBoldH == FALSE)
-			HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
+		    HText_beginAnchor(me->text, me->CurrentA);
+		    if (me->inBoldH == FALSE)
+			HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 		    HTML_put_string(me,
 		    		    (present[HTML_FIG_ISOBJECT] ?
 		      (present[HTML_FIG_IMAGEMAP] ?
 					"(IMAGE)" : "(OBJECT)") : "[FIGURE]"));
-		    if (B_inBoldH == FALSE)
-			HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+		    if (me->inBoldH == FALSE)
+			HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		    HText_endAnchor(me->text);
 		    HText_appendCharacter(me->text, '-');
-		    HTML_put_character(me, ' ');  /* space char may be ignored */
+		    HTML_put_character(me, ' '); /* space char may be ignored */
 		    me->in_word = NO;
 		}
 	    }
@@ -3366,22 +2954,17 @@ PRIVATE void HTML_start_element ARGS5(
 	break;
 
     case HTML_OVERLAY:
-	if (clickable_images && B_inFIG &&
+	if (clickable_images && me->inFIG &&
 	    present && present[HTML_OVERLAY_SRC] &&
 	    value[HTML_OVERLAY_SRC] && *value[HTML_OVERLAY_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_OVERLAY_SRC]);
-	    convert_to_spaces(href);
-	    LYUnEscapeToLatinOne(&href, TRUE);
+	    url_type = LYLegitimizeHREF(me, (char**)&href, TRUE);
 	    if (*href) {
-		url_type = is_url(href);
-		if (!url_type && *href != '/')
-		    HTSimplify(href);
-
 		/*
 		 *  Check whether a base tag is in effect. - FM
 		 */
-		if ((B_inBASE) &&
-		    (temp = HTParse(href, base_href, PARSE_ALL)) &&
+		if ((me->inBASE && *href != '#') &&
+		    (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
 		    *temp != '\0')
 		    /*
 		     *  Use reference related to the base.
@@ -3392,11 +2975,12 @@ PRIVATE void HTML_start_element ARGS5(
 		/*
 		 *  Check whether to fill in localhost. - FM
 		 */
-		HTMLFillLocalFileURL((char **)&href,
-				     (B_inBASE ?
-				     base_href : me->node_anchor->address));
+		LYFillLocalFileURL((char **)&href,
+				   ((*href != '#' &&
+				     me->inBASE) ?
+				   me->base_href : me->node_anchor->address));
 
-		if ((B_CurrentA = HTAnchor_findChildAndLink(
+		if ((me->CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					NULL,			/* Tag */
 					href,			/* Addresss */
@@ -3407,12 +2991,12 @@ PRIVATE void HTML_start_element ARGS5(
 		        HTML_put_character(me, ' ');
 			HText_appendCharacter(me->text, '+');
 		    }
-		    HText_beginAnchor(me->text, B_CurrentA);
-		    if (B_inBoldH == FALSE)
-			HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
+		    HText_beginAnchor(me->text, me->CurrentA);
+		    if (me->inBoldH == FALSE)
+			HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 		    HTML_put_string(me, "[OVERLAY]");
-		    if (B_inBoldH == FALSE)
-			HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+		    if (me->inBoldH == FALSE)
+			HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		    HText_endAnchor(me->text);
 		    HTML_put_character(me, ' ');
 		    me->in_word = NO;
@@ -3423,8 +3007,8 @@ PRIVATE void HTML_start_element ARGS5(
 	break;
 
     case HTML_APPLET:
-        B_inAPPLET = TRUE;
-	B_inAPPLETwithP = FALSE;
+        me->inAPPLET = TRUE;
+	me->inAPPLETwithP = FALSE;
 	if (!me->text)
 	    UPDATE_STYLE;
 	HTML_put_character(me, ' ');  /* space char may be ignored */
@@ -3440,7 +3024,7 @@ PRIVATE void HTML_start_element ARGS5(
 	}
 	if (id_string) {
 	    LYUnEscapeToLatinOne(&id_string, TRUE);
-	    HTML_HandleID(me, id_string);
+	    LYHandleID(me, id_string);
 	    FREE(id_string);
 	}
 	me->in_word = NO;
@@ -3459,7 +3043,7 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  Convert any HTML entities or decimal escaping. - FM
 	     */
 	    LYUnEscapeEntities(alt_string,
-	    		       LYUsePlainSpace, LYHiddenValue);
+	    		       me->UsePlainSpace, me->HiddenValue);
 	    /*
 	     *  If it's all spaces and we are making sources links,
 	     *  treat it as zero-length. - FM
@@ -3493,7 +3077,7 @@ PRIVATE void HTML_start_element ARGS5(
 	    if (present[HTML_APPLET_CODEBASE] &&
 	        value[HTML_APPLET_CODEBASE] && *value[HTML_APPLET_CODEBASE]) {
 	        StrAllocCopy(base, value[HTML_APPLET_CODEBASE]);
-		convert_to_spaces(base);
+		collapse_spaces(base);
 		LYUnEscapeToLatinOne(&base, TRUE);
 		/*
 		 *  Force it to be a directory. - FM
@@ -3502,27 +3086,21 @@ PRIVATE void HTML_start_element ARGS5(
 		    StrAllocCopy(base, "/");
 		if (base[strlen(base)-1] != '/')
 		    StrAllocCat(base, "/");
-		url_type = is_url(base);
-
-		/*
-		 *  Don't simplify absolute CODEBASEs. - FM
-		 */
-		if (!url_type && *base != '/')
-		    HTSimplify(base);
+		url_type = LYLegitimizeHREF(me, (char**)&base, TRUE);
 
 		/*
 		 *  Check whether to fill in localhost. - FM
 		 */
-		HTMLFillLocalFileURL((char **)&base,
-				     (B_inBASE ? base_href :
-						 me->node_anchor->address));
+		LYFillLocalFileURL((char **)&base,
+				   (me->inBASE ?
+				 me->base_href : me->node_anchor->address));
 
 		if (!(url_type = is_url(base))) {
 		    /*
 		     *  Check whether a base tag is in effect.
 		     */
-		    if (B_inBASE) {
-		        temp = HTParse(base, base_href, PARSE_ALL);
+		    if (me->inBASE) {
+		        temp = HTParse(base, me->base_href, PARSE_ALL);
 		    } else {
 		        temp = HTParse(base, me->node_anchor->address,
 							PARSE_ALL);
@@ -3531,33 +3109,31 @@ PRIVATE void HTML_start_element ARGS5(
 		    FREE(temp);
 		}
 	    } else {
-		if (B_inBASE) {
-		    StrAllocCopy(base, base_href);
+		if (me->inBASE) {
+		    StrAllocCopy(base, me->base_href);
 		} else {
 		    StrAllocCopy(base, me->node_anchor->address);
 		}
 	    }
 
 	    StrAllocCopy(code, value[HTML_APPLET_CODE]);
-	    convert_to_spaces(code);
-	    LYUnEscapeToLatinOne(&code, TRUE);
-	    HTSimplify(code);
+	    url_type = LYLegitimizeHREF(me, (char**)&code, TRUE);
 	    href = HTParse(code, base, PARSE_ALL);
 	    FREE(base);
 	    FREE(code);
 
 	    if ((href && *href) &&
-	        (B_CurrentA = HTAnchor_findChildAndLink(
+	        (me->CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					NULL,			/* Tag */
 					href,			/* Addresss */
 					(void *)0))) {		/* Type */
-		HText_beginAnchor(me->text, B_CurrentA);
-		if (B_inBoldH == FALSE)
-		    HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
+		HText_beginAnchor(me->text, me->CurrentA);
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 		HTML_put_string(me, alt_string);
-		if (B_inBoldH == FALSE)
-		    HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		HText_endAnchor(me->text);
 		HTML_put_character(me, ' ');  /* space char may be ignored */
 		me->in_word = NO;
@@ -3582,21 +3158,17 @@ PRIVATE void HTML_start_element ARGS5(
 	if (clickable_images && present && present[HTML_BGSOUND_SRC] &&
 	    value[HTML_BGSOUND_SRC] && *value[HTML_BGSOUND_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_BGSOUND_SRC]);
-	    convert_to_spaces(href);
-	    LYUnEscapeToLatinOne(&href, TRUE);
+	    url_type = LYLegitimizeHREF(me, (char**)&href, TRUE);
 	    if (*href == '\0') {
 	        FREE(href);
 		break;
 	    }
-	    url_type = is_url(href);
-	    if (!url_type && *href != '/')
-	        HTSimplify(href);
 
 	    /*
 	     *  Check whether a base tag is in effect. - FM
 	     */
-	    if ((B_inBASE) &&
-		(temp = HTParse(href, base_href, PARSE_ALL)) &&
+	    if ((me->inBASE && *href != '#') &&
+		(temp = HTParse(href, me->base_href, PARSE_ALL)) &&
 		*temp != '\0')
 		/*
 		 *  Use reference related to the base.
@@ -3607,25 +3179,26 @@ PRIVATE void HTML_start_element ARGS5(
 	    /*
 	     *  Check whether to fill in localhost. - FM
 	     */
-	    HTMLFillLocalFileURL((char **)&href,
-				 (B_inBASE ? base_href :
-					     me->node_anchor->address));
+	    LYFillLocalFileURL((char **)&href,
+			       ((*href != '#' &&
+			         me->inBASE) ?
+			       me->base_href : me->node_anchor->address));
 
 	    if (!me->text)
 	        UPDATE_STYLE;
-	    if ((B_CurrentA = HTAnchor_findChildAndLink(
+	    if ((me->CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					NULL,			/* Tag */
 					href,			/* Addresss */
 					(void *)0))) {		/* Type */
 		HTML_put_character(me, ' ');  /* space char may be ignored */
 		me->in_word = NO;
-		HText_beginAnchor(me->text, B_CurrentA);
-		if (B_inBoldH == FALSE)
-		    HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
+		HText_beginAnchor(me->text, me->CurrentA);
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 		HTML_put_string(me, "[BGSOUND]");
-		if (B_inBoldH == FALSE)
-		    HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		HText_endAnchor(me->text);
 		HTML_put_character(me, ' ');  /* space char may be ignored */
 		me->in_word = NO;
@@ -3651,7 +3224,7 @@ PRIVATE void HTML_start_element ARGS5(
 	}
 	if (id_string) {
 	    LYUnEscapeToLatinOne(&id_string, TRUE);
-	    HTML_HandleID(me, id_string);
+	    LYHandleID(me, id_string);
 	    FREE(id_string);
 	}
 	if (pseudo_inline_alts || clickable_images)
@@ -3671,7 +3244,7 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  Convert any HTML entities or decimal escaping. - FM
 	     */
 	    LYUnEscapeEntities(alt_string,
-	    		       LYUsePlainSpace, LYHiddenValue);
+	    		       me->UsePlainSpace, me->HiddenValue);
 	    /*
 	     *  If it's all spaces and we are making sources links,
 	     *  treat it as zero-length. - FM
@@ -3696,18 +3269,13 @@ PRIVATE void HTML_start_element ARGS5(
 	if (clickable_images && present && present[HTML_EMBED_SRC] &&
 	    value[HTML_EMBED_SRC] && *value[HTML_EMBED_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_EMBED_SRC]);
-	    convert_to_spaces(href);
-	    LYUnEscapeToLatinOne(&href, TRUE);
+	    url_type = LYLegitimizeHREF(me, (char**)&href, TRUE);
 	    if (*href != '\0') {
-		url_type = is_url(href);
-		if (!url_type && *href != '/')
-		     HTSimplify(href);
-
 		/*
 		 *  Check whether a base tag is in effect. - FM
 		 */
-		if ((B_inBASE) &&
-		    (temp = HTParse(href, base_href, PARSE_ALL)) &&
+		if ((me->inBASE && *href != '#') &&
+		    (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
 		    *temp != '\0')
 		    /*
 		     *  Use reference related to the base.
@@ -3718,21 +3286,22 @@ PRIVATE void HTML_start_element ARGS5(
 		/*
 		 *  Check whether to fill in localhost. - FM
 		 */
-		HTMLFillLocalFileURL((char **)&href,
-				     (B_inBASE ?
-				     base_href : me->node_anchor->address));
+		LYFillLocalFileURL((char **)&href,
+				   ((*href != '#' &&
+				     me->inBASE) ?
+				   me->base_href : me->node_anchor->address));
 
-		if ((B_CurrentA = HTAnchor_findChildAndLink(
+		if ((me->CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					NULL,			/* Tag */
 					href,			/* Addresss */
 					(void *)0))) {		/* Type */
-		    HText_beginAnchor(me->text, B_CurrentA);
-		    if (B_inBoldH == FALSE)
-			HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
+		    HText_beginAnchor(me->text, me->CurrentA);
+		    if (me->inBoldH == FALSE)
+			HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 		    HTML_put_string(me, alt_string);
-		    if (B_inBoldH == FALSE)
-			HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+		    if (me->inBoldH == FALSE)
+			HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		    HText_endAnchor(me->text);
 		    HTML_put_character(me, ' ');
 		    me->in_word = NO;
@@ -3754,67 +3323,67 @@ PRIVATE void HTML_start_element ARGS5(
     case HTML_CREDIT:
 	if (!me->text)
 	    UPDATE_STYLE;
-	HTML_EnsureDoubleSpace(me);
-	HTML_ResetParagraphAlignment(me);
-	B_inCREDIT = TRUE;
-	HTML_CheckForID(me, present, value, (int)HTML_CREDIT_ID);
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
+	LYEnsureDoubleSpace(me);
+	LYResetParagraphAlignment(me);
+	me->inCREDIT = TRUE;
+	LYCheckForID(me, present, value, (int)HTML_CREDIT_ID);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
 	HTML_put_string(me, "CREDIT:");
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	HTML_put_character(me, ' ');
 
-	if (B_inFIG)
+	if (me->inFIG)
 	    /*
 	     *  Assume all text in the FIG container is intended
 	     *  to be paragraphed. - FM
 	     */
-	    B_inFIGwithP = TRUE;
+	    me->inFIGwithP = TRUE;
 
-	if (B_inAPPLET)
+	if (me->inAPPLET)
 	    /*
 	     *  Assume all text in the APPLET container is intended
 	     *  to be paragraphed. - FM
 	     */
-	    B_inAPPLETwithP = TRUE;
+	    me->inAPPLETwithP = TRUE;
 
-	B_inLABEL = TRUE;
+	me->inLABEL = TRUE;
 	me->in_word = NO;
-	B_inP = FALSE;
+	me->inP = FALSE;
 	break;
 
     case HTML_CAPTION:
 	if (!me->text)
 	    UPDATE_STYLE;
-	HTML_EnsureDoubleSpace(me);
-	HTML_ResetParagraphAlignment(me);
-	B_inCAPTION = TRUE;
-	HTML_CheckForID(me, present, value, (int)HTML_CAPTION_ID);
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
+	LYEnsureDoubleSpace(me);
+	LYResetParagraphAlignment(me);
+	me->inCAPTION = TRUE;
+	LYCheckForID(me, present, value, (int)HTML_CAPTION_ID);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
 	HTML_put_string(me, "CAPTION:");
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	HTML_put_character(me, ' ');
 
-	if (B_inFIG)
+	if (me->inFIG)
 	    /*
 	     *  Assume all text in the FIG container is intended
 	     *  to be paragraphed. - FM
 	     */
-	    B_inFIGwithP = TRUE;
+	    me->inFIGwithP = TRUE;
 
-	if (B_inAPPLET)
+	if (me->inAPPLET)
 	    /*
 	     *  Assume all text in the APPLET container is intended
 	     *  to be paragraphed. - FM
 	     */
-	    B_inAPPLETwithP = TRUE;
+	    me->inAPPLETwithP = TRUE;
 
-	B_inLABEL = TRUE;
+	me->inLABEL = TRUE;
 	me->in_word = NO;
-	B_inP = FALSE;
+	me->inP = FALSE;
 	break;
 
     case HTML_FORM:
@@ -3822,14 +3391,13 @@ PRIVATE void HTML_start_element ARGS5(
 	    char * action = NULL;
 	    char * method = NULL;
 	    char * enctype = NULL;
-	    char * cp;
 	    HTChildAnchor * source;
 	    HTAnchor *link_dest;
 
 	    /*
 	     *  Set to know we are in a form.
 	     */
-	    B_inFORM = TRUE;
+	    me->inFORM = TRUE;
 	    UPDATE_STYLE;
 
 	    if (present && present[HTML_FORM_ACTION] &&
@@ -3838,30 +3406,34 @@ PRIVATE void HTML_start_element ARGS5(
 		 *  Prepare to do housekeeping on the reference. - FM
 		 */
 		StrAllocCopy(action, value[HTML_FORM_ACTION]);
-		convert_to_spaces(action);
-		LYUnEscapeToLatinOne(&action, TRUE);
-	        url_type = is_url(action);
+		url_type = LYLegitimizeHREF(me, (char**)&action, TRUE);
 
 		/*
-		 *  Don't simplify absolute ACTIONs. - FM
-		 */
-		if (!url_type && *action != '/' && *action != '\0')
-		    HTSimplify(action);
-		/*
 		 *  Check whether a base tag is in effect.
 		 */
-		if ((B_inBASE) &&
-		    (temp = HTParse(action, base_href, PARSE_ALL)) &&
-		    *temp != '\0')
+		if ((me->inBASE && *action != '\0' && *action != '#') &&
+		    (temp = HTParse(action, me->base_href, PARSE_ALL)) &&
+		    *temp != '\0') {
 	            /*
 		     *  Use action related to the base.
 		     */
 		    StrAllocCopy(action, temp);
+	        } else if ((temp = HTParse(action,
+					   me->node_anchor->address,
+					   PARSE_ALL)) &&
+		    *temp != '\0') {
+	            /*
+		     *  Use action related to the current document.
+		     */
+		    StrAllocCopy(action, temp);
+	        } else {
+		    FREE(action);
+		}
 		FREE(temp);
 	    }
 	    if (!(action && *action)) {
-	    	if (B_inBASE && base_href && *base_href) {
-		     StrAllocCopy(action, base_href);
+	    	if (me->inBASE && me->base_href && *me->base_href) {
+		     StrAllocCopy(action, me->base_href);
 		} else {
 		     StrAllocCopy(action, me->node_anchor->address);
 		}
@@ -3938,31 +3510,37 @@ PRIVATE void HTML_start_element ARGS5(
 	}
 	if (!me->text)
 	    UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_FORM_ID);
+	LYCheckForID(me, present, value, (int)HTML_FORM_ID);
 	break;
 
     case HTML_FIELDSET:
-        HTML_CheckForID(me, present, value, (int)HTML_FIELDSET_ID);
+        LYCheckForID(me, present, value, (int)HTML_FIELDSET_ID);
         break;
 
     case HTML_LABEL:
-        HTML_CheckForID(me, present, value, (int)HTML_LABEL_ID);
+        LYCheckForID(me, present, value, (int)HTML_LABEL_ID);
+        break;
+
+    case HTML_KEYGEN:
+        LYCheckForID(me, present, value, (int)HTML_KEYGEN_ID);
         break;
 
     case HTML_INPUT:
 	{
 	    InputFieldData I;
 	    int chars;
+	    BOOL UseALTasVALUE = FALSE;
+	    BOOL HaveSRClink = FALSE;
 
 	    /*
 	     *  Make sure we're in a form.
 	     */
-	    if (!B_inFORM) {
+	    if (!me->inFORM) {
 	        if (TRACE) {
 		    fprintf(stderr, "HTML: INPUT tag not within FORM tag\n");
-		} else if (!B_inBadHTML) {
+		} else if (!me->inBadHTML) {
 	            _statusline(BAD_HTML_USE_TRACE);
-		    B_inBadHTML = TRUE;
+		    me->inBadHTML = TRUE;
 		    sleep(MessageSecs);
 		}
 		/*
@@ -3974,12 +3552,12 @@ PRIVATE void HTML_start_element ARGS5(
 	    }
 
 	    /* Check for unclosed TEXTAREA */
-	    if (B_inTEXTAREA) {
+	    if (me->inTEXTAREA) {
 	        if (TRACE) {
 		    fprintf(stderr, "HTML: Missing TEXTAREA end tag\n");
-		} else if (!B_inBadHTML) {
+		} else if (!me->inBadHTML) {
 		    _statusline(BAD_HTML_USE_TRACE);
-		    B_inBadHTML = TRUE;
+		    me->inBadHTML = TRUE;
 		    sleep(MessageSecs);
 		}
 	    }
@@ -4027,12 +3605,12 @@ PRIVATE void HTML_start_element ARGS5(
 		    /*
 		     *  Not yet implemented.
 		     */
-		    if (B_inUnderline == FALSE) {
+		    if (me->inUnderline == FALSE) {
 		        HText_appendCharacter(me->text,
 					      LY_UNDERLINE_START_CHAR);
 		    }
 		    HTML_put_string(me,"[FILE Input] (Not yet implemented.)");
-		    if (B_inUnderline == FALSE) {
+		    if (me->inUnderline == FALSE) {
 		        HText_appendCharacter(me->text,
 					      LY_UNDERLINE_END_CHAR);
 		    }
@@ -4042,8 +3620,75 @@ PRIVATE void HTML_start_element ARGS5(
 		    break;
 		}
 	    }
-	    if (present && present[HTML_INPUT_VALUE] &&
-	        value[HTML_INPUT_VALUE] && *value[HTML_INPUT_VALUE]) {
+	    if ((present && present[HTML_INPUT_ALT] &&
+		 value[HTML_INPUT_ALT] && *value[HTML_INPUT_ALT] &&
+		 I.type && !strcasecomp(I.type, "image")) &&
+		!(present && present[HTML_INPUT_VALUE] &&
+	          value[HTML_INPUT_VALUE] && *value[HTML_INPUT_VALUE])) {
+		/*
+		 *  This is a TYPE="image" using an ALT rather than
+		 *  VALUE attribute to indicate the link string for
+		 *  text clients or GUIs with image loading off, so
+		 *  set the flag to use that at if it were a VALUE
+		 *  attribute. - FM
+		 */
+		UseALTasVALUE = TRUE;
+	    }
+	    if (clickable_images == TRUE &&
+	        present && present[HTML_INPUT_SRC] &&
+	        value[HTML_INPUT_SRC] && *value[HTML_INPUT_SRC] &&
+		I.type && !strcasecomp(I.type, "image")) {
+		StrAllocCopy(href, (char *)value[HTML_INPUT_SRC]);
+		/*
+		 *  We have a TYPE="image" with a non-zero-length SRC
+		 *  attribute and want clickable images.  Make the
+		 *  SRC's value a link if it's still not zero-length
+		 *  legitiimizing it. - FM
+		 */
+		url_type = LYLegitimizeHREF(me, (char**)&href, TRUE);
+		if (*href) {
+		    /*
+		     *  Check whether a base tag is in effect. - FM
+		     */
+		    if ((me->inBASE && *href != '#') &&
+			(temp = HTParse(href, me->base_href, PARSE_ALL)) &&
+			*temp != '\0')
+			/*
+			 *  Use reference related to the base.
+			 */
+			StrAllocCopy(href, temp);
+		    FREE(temp);
+
+		    /*
+		     *  Check whether to fill in localhost. - FM
+		     */
+		    LYFillLocalFileURL((char **)&href,
+				       ((*href != '#' &&
+				         me->inBASE) ?
+				       me->base_href :
+				       me->node_anchor->address));
+
+		    if ((me->CurrentA = HTAnchor_findChildAndLink(
+		       			me->node_anchor,	/* Parent */
+		       			NULL,			/* Tag */
+		       			href,			/* Addresss */
+		       			(void *)0))) {		/* Type */
+		        HText_beginAnchor(me->text, me->CurrentA);
+			if (me->inBoldH == FALSE)
+			    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+			HTML_put_string(me, "[IMAGE]");
+			if (me->inBoldH == FALSE)
+			    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+			HText_endAnchor(me->text);
+			HText_appendCharacter(me->text, '-');
+		    }
+		    HaveSRClink = TRUE;
+	        }
+	        FREE(href);
+	    }
+	    if ((UseALTasVALUE == TRUE) ||
+	        (present && present[HTML_INPUT_VALUE] &&
+	         value[HTML_INPUT_VALUE] && *value[HTML_INPUT_VALUE])) {
 	        /*
 		 *  Convert any HTML entities or decimal escaping. - FM
 		 */
@@ -4054,24 +3699,31 @@ PRIVATE void HTML_start_element ARGS5(
 		int len;
 		
 		if (I.type && !strcasecomp(I.type, "hidden")) {
-		    LYHiddenValue = TRUE;
+		    me->HiddenValue = TRUE;
 		    current_char_set = 0;	/* Default ISO-Latin1 */
 		    LYUseDefaultRawMode = TRUE;
 		    HTMLSetCharacterHandling(current_char_set);
 		}
 
 		if (!I.type)
-		    LYUsePlainSpace = TRUE;
+		    me->UsePlainSpace = TRUE;
 		else if (!strcasecomp(I.type, "text") ||
 			 !strcasecomp(I.type, "submit") ||
+			 !strcasecomp(I.type, "image") ||
 			 !strcasecomp(I.type, "reset"))
-		    LYUsePlainSpace = TRUE;
-		if (current_char_set && LYUsePlainSpace)
-		    LYExpandString((char**)&value[HTML_INPUT_VALUE]);
-	        LYUnEscapeEntities((char *)value[HTML_INPUT_VALUE],
-				   LYUsePlainSpace, LYHiddenValue);
-		I.value = (char *)value[HTML_INPUT_VALUE];
-		if (LYUsePlainSpace == TRUE) {
+		    me->UsePlainSpace = TRUE;
+		if (current_char_set && me->UsePlainSpace)
+		    LYExpandString(((UseALTasVALUE == TRUE) ?
+			    (char **)&value[HTML_INPUT_ALT] :
+			    (char **)&value[HTML_INPUT_VALUE]));
+	        LYUnEscapeEntities(((UseALTasVALUE == TRUE) ?
+			      (char *)value[HTML_INPUT_ALT] :
+			      (char *)value[HTML_INPUT_VALUE]),
+				   me->UsePlainSpace, me->HiddenValue);
+		I.value = ((UseALTasVALUE == TRUE) ?
+		     (char *)value[HTML_INPUT_ALT] :
+		     (char *)value[HTML_INPUT_VALUE]);
+		if (me->UsePlainSpace == TRUE) {
 		    /*
 		     *  Convert any newlines or tabs to spaces,
 		     *  and trim any lead or trailing spaces. - FM
@@ -4083,17 +3735,25 @@ PRIVATE void HTML_start_element ARGS5(
 		    while (len > 0 && I.value[len] == ' ')
 		        I.value[len--] = '\0';
 		}
-		LYUsePlainSpace = FALSE;
+		me->UsePlainSpace = FALSE;
 		
 
 		if (I.type && !strcasecomp(I.type, "hidden")) {
-		    LYHiddenValue = FALSE;
+		    me->HiddenValue = FALSE;
 		    current_char_set = CurrentCharSet;
 		    LYUseDefaultRawMode = CurrentUseDefaultRawMode;
 		    HTMLSetCharacterHandling(current_char_set);
 		    HTPassEightBitRaw = CurrentEightBitRaw;
 		    HTCJK = CurrentHTCJK;
 		}
+	    } else if (HaveSRClink == TRUE) {
+	        /*
+		 *  We put up an [IMAGE] link and '-' for a TYPE="image"
+		 *  and didn't get a VALUE or ALT string, so fake a
+		 *  "Submit" value.  If we didn't put up a link, then
+		 *  HText_beginInput() will use "[IMAGE]-Submit". - FM
+		 */
+		I.value = "Submit";
 	    }
 	    if (present && present[HTML_INPUT_CHECKED])
 		I.checked = YES;
@@ -4124,7 +3784,7 @@ PRIVATE void HTML_start_element ARGS5(
 	    if (present && present[HTML_INPUT_ID] &&
 	        value[HTML_INPUT_ID] && *value[HTML_INPUT_ID]) {
 		I.id = (char *)value[HTML_INPUT_ID];
-		HTML_CheckForID(me, present, value, (int)HTML_INPUT_ID);
+		LYCheckForID(me, present, value, (int)HTML_INPUT_ID);
 	    }
 	    if (present && present[HTML_INPUT_LANG] && /* Not yet used. */
 	        value[HTML_INPUT_LANG] && *value[HTML_INPUT_LANG])
@@ -4132,9 +3792,6 @@ PRIVATE void HTML_start_element ARGS5(
 	    if (present && present[HTML_INPUT_MD] && /* Not yet used. */
 	        value[HTML_INPUT_MD] && *value[HTML_INPUT_MD])
 		I.md = (char *)value[HTML_INPUT_MD];
-	    if (present && present[HTML_INPUT_SRC] && /* Not yet used. */
-	        value[HTML_INPUT_MD] && *value[HTML_INPUT_MD])
-		I.src = (char *)value[HTML_INPUT_SRC]; /* Should be resolved. */
 
 	    chars = HText_beginInput(me->text, &I);
 	    if (me->sp[0].tag_number == HTML_PRE && chars > 20) {
@@ -4143,16 +3800,15 @@ PRIVATE void HTML_start_element ARGS5(
 		 *  We'll put up a minimum of 20 underscores, and if any
 		 *  more would exceed the wrap column, we'll ignore them.
 		 */
-	        int i;
 		for (i = 0; i < 20; i++) {
 	            HTML_put_character(me, '_');
 		    chars--;
 		}
-		ignore_excess = TRUE;
+		HText_setIgnoreExcess(me->text, TRUE);
 	    }
 	    for (; chars > 0; chars--)
 	    	HTML_put_character(me, '_');
-	    ignore_excess = FALSE;
+	    HText_setIgnoreExcess(me->text, FALSE);
 	}
 	break;
 
@@ -4160,13 +3816,13 @@ PRIVATE void HTML_start_element ARGS5(
 	/*
 	 *  Make sure we're in a form.
 	 */
-	if (!B_inFORM) {
+	if (!me->inFORM) {
 	    if (TRACE) {
 		fprintf(stderr,
 			"HTML: TEXTAREA start tag not within FORM tag\n");
-	    } else if (!B_inBadHTML) {
+	    } else if (!me->inBadHTML) {
 	        _statusline(BAD_HTML_USE_TRACE);
-		B_inBadHTML = TRUE;
+		me->inBadHTML = TRUE;
 	        sleep(MessageSecs);
 	    }
 	    /*
@@ -4178,7 +3834,7 @@ PRIVATE void HTML_start_element ARGS5(
 	/* 
 	 *  Set to know we are in a textarea.
 	 */
-	B_inTEXTAREA = TRUE;
+	me->inTEXTAREA = TRUE;
 
 	/*
 	 *  Get ready for the value.
@@ -4186,50 +3842,50 @@ PRIVATE void HTML_start_element ARGS5(
         HTChunkClear(&me->textarea);
 	if (present && present[HTML_TEXTAREA_NAME] &&
 	    value[HTML_TEXTAREA_NAME])  
-	    StrAllocCopy(textarea_name, value[HTML_TEXTAREA_NAME]);
+	    StrAllocCopy(me->textarea_name, value[HTML_TEXTAREA_NAME]);
 	else
-	    StrAllocCopy(textarea_name, "");
+	    StrAllocCopy(me->textarea_name, "");
 
 	if (present && present[HTML_TEXTAREA_COLS] &&
 	    value[HTML_TEXTAREA_COLS] &&
 	    isdigit((unsigned char)*value[HTML_TEXTAREA_COLS]))  
-	    StrAllocCopy(textarea_cols, value[HTML_TEXTAREA_COLS]);
+	    StrAllocCopy(me->textarea_cols, value[HTML_TEXTAREA_COLS]);
 	else
-	    StrAllocCopy(textarea_cols, "60");
+	    StrAllocCopy(me->textarea_cols, "60");
 
 	if (present && present[HTML_TEXTAREA_ROWS] &&
 	    value[HTML_TEXTAREA_ROWS] &&
 	    isdigit((unsigned char)*value[HTML_TEXTAREA_ROWS]))  
-	    textarea_rows = atoi(value[HTML_TEXTAREA_ROWS]);
+	    me->textarea_rows = atoi(value[HTML_TEXTAREA_ROWS]);
 	else
-	    textarea_rows = 4;
+	    me->textarea_rows = 4;
 
 	if (present && present[HTML_TEXTAREA_DISABLED])
-	    textarea_disabled = YES;
+	    me->textarea_disabled = YES;
 	else
-	    textarea_disabled = NO;
+	    me->textarea_disabled = NO;
 
 	if (present && present[HTML_TEXTAREA_ID]
 	    && value[HTML_TEXTAREA_ID] && *value[HTML_TEXTAREA_ID]) {
 	    StrAllocCopy(id_string, value[HTML_TEXTAREA_ID]);
 	    LYUnEscapeToLatinOne(&id_string, TRUE);
 	    if ((id_string != '\0') &&
-	        (B_ID_A = HTAnchor_findChildAndLink(
+	        (ID_A = HTAnchor_findChildAndLink(
 				me->node_anchor,	 /* Parent */
 				id_string,		 /* Tag */
 				NULL,			 /* Addresss */
 				(void *)0))) {		 /* Type */
 		if (!me->text)
 		    UPDATE_STYLE;
-		HText_beginAnchor(me->text, B_ID_A);
+		HText_beginAnchor(me->text, ID_A);
 		HText_endAnchor(me->text);
-		StrAllocCopy(textarea_id, id_string);
+		StrAllocCopy(me->textarea_id, id_string);
 	    } else {
-	        FREE(textarea_id);
+	        FREE(me->textarea_id);
 	    }
 	    FREE(id_string);
 	} else {
-	    FREE(textarea_id);
+	    FREE(me->textarea_id);
 	}
 	break;
 
@@ -4242,18 +3898,18 @@ PRIVATE void HTML_start_element ARGS5(
             /*
 	     *  Initialize the disable attribute.
 	     */
-	    select_disabled = NO;
+	    me->select_disabled = FALSE;
 
 	    /*
 	     *  Make sure we're in a form.
 	     */
-	    if (!B_inFORM) {
+	    if (!me->inFORM) {
 	        if (TRACE) {
 		    fprintf(stderr,
 			    "HTML: SELECT start tag not within FORM tag\n");
-		} else if (!B_inBadHTML) {
+		} else if (!me->inBadHTML) {
 		    _statusline(BAD_HTML_USE_TRACE);
-		    B_inBadHTML = TRUE;
+		    me->inBadHTML = TRUE;
 		    sleep(MessageSecs);
 		}
 
@@ -4266,12 +3922,12 @@ PRIVATE void HTML_start_element ARGS5(
 	    /*
 	     *  Check for unclosed TEXTAREA.
 	     */
-	    if (B_inTEXTAREA) {
+	    if (me->inTEXTAREA) {
 	        if (TRACE) {
 		    fprintf(stderr, "HTML: Missing TEXTAREA end tag\n");
-		} else if (!B_inBadHTML) {
+		} else if (!me->inBadHTML) {
 		    _statusline(BAD_HTML_USE_TRACE);
-		    B_inBadHTML = TRUE;
+		    me->inBadHTML = TRUE;
 		    sleep(MessageSecs);
 		}
 	    }
@@ -4279,7 +3935,7 @@ PRIVATE void HTML_start_element ARGS5(
 	    /*
 	     *  Set to know we are in a select tag.
 	     */
-	    B_inSELECT = TRUE;
+	    me->inSELECT = TRUE;
 
 	    if (!me->text)
 	        UPDATE_STYLE;
@@ -4291,7 +3947,7 @@ PRIVATE void HTML_start_element ARGS5(
 	    if (present && present[HTML_SELECT_MULTIPLE])  
 		multiple=YES;
 	    if (present && present[HTML_SELECT_DISABLED])  
-		select_disabled=YES;
+		me->select_disabled = TRUE;
 	    if (present && present[HTML_SELECT_SIZE] &&
 	        value[HTML_SELECT_SIZE] && *value[HTML_SELECT_SIZE]) {
 #ifdef NOTDEFINED
@@ -4307,19 +3963,19 @@ PRIVATE void HTML_start_element ARGS5(
 #endif /* NOTDEFINED */
 	    }
 
-	    if (B_inBoldH == TRUE &&
+	    if (me->inBoldH == TRUE &&
 	        (multiple == NO || LYSelectPopups == FALSE)) {
-	        HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
-		B_inBoldH = FALSE;
-		B_needBoldH = TRUE;
+	        HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		me->inBoldH = FALSE;
+		me->needBoldH = TRUE;
 	    }
-	    if (B_inUnderline == TRUE &&
+	    if (me->inUnderline == TRUE &&
 	        (multiple == NO || LYSelectPopups == FALSE)) {
-	        HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
-		B_inUnderline = FALSE;
+	        HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+		me->inUnderline = FALSE;
 	    }
 
-	    HTML_CheckForID(me, present, value, (int)HTML_SELECT_ID);
+	    LYCheckForID(me, present, value, (int)HTML_SELECT_ID);
 
 	    HText_beginSelect(name, multiple, size);
 	    FREE(name);
@@ -4335,18 +3991,17 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  An option is a special case of an input field.
 	     */
 	    InputFieldData I;
-	    int i;
 
 	    /*
 	     *  Make sure we're in a select tag.
 	     */
-	    if (!B_inSELECT) {
+	    if (!me->inSELECT) {
 	        if (TRACE) {
 		    fprintf(stderr,
 			    "HTML: OPTION tag not within SELECT tag\n");
-		} else if (!B_inBadHTML) {
+		} else if (!me->inBadHTML) {
 		    _statusline(BAD_HTML_USE_TRACE);
-		    B_inBadHTML = TRUE;
+		    me->inBadHTML = TRUE;
 		    sleep(MessageSecs);
 		}
 
@@ -4368,8 +4023,10 @@ PRIVATE void HTML_start_element ARGS5(
 		 *  Finish the previous option @@@@@
 		 */
 	        HText_setLastOptionValue(me->text,
-					 me->option.data, LastOptionValue,
-				         MIDDLE_ORDER, LastOptionChecked);
+					 me->option.data,
+					 me->LastOptionValue,
+				         MIDDLE_ORDER,
+					 me->LastOptionChecked);
 	    }
 
 	    /*
@@ -4385,7 +4042,7 @@ PRIVATE void HTML_start_element ARGS5(
 	            /*
 		     *  Start a newline before each option.
 		     */
-		    HTML_EnsureSingleSpace(me);
+		    LYEnsureSingleSpace(me);
 		} else {
 		    /*
 		     *  Add option list designation character.
@@ -4426,7 +4083,7 @@ PRIVATE void HTML_start_element ARGS5(
 			HTMLSetCharacterHandling(current_char_set);
 		    }
 	            LYUnEscapeEntities((char *)value[HTML_OPTION_VALUE],
-		    		       LYUsePlainSpace, LYHiddenValue);
+		    		       me->UsePlainSpace, me->HiddenValue);
 		    if (CurrentCharSet) {
 		        current_char_set = CurrentCharSet;
 			LYUseDefaultRawMode = CurrentUseDefaultRawMode;
@@ -4438,18 +4095,18 @@ PRIVATE void HTML_start_element ARGS5(
 		    I.value = (char *)value[HTML_OPTION_VALUE];
 		}
 
-	        if (select_disabled ||
+	        if (me->select_disabled ||
 		   (present && present[HTML_OPTION_DISABLED]))
 		    I.disabled=YES;
 
 	        if (present && present[HTML_OPTION_ID]
 		    && value[HTML_OPTION_ID] && *value[HTML_OPTION_ID]) {
-		    if (B_ID_A = HTAnchor_findChildAndLink(
+		    if (ID_A = HTAnchor_findChildAndLink(
 				    me->node_anchor,	   /* Parent */
 				    value[HTML_OPTION_ID], /* Tag */
 				    NULL,		   /* Addresss */
 				    (void *)0)) {	   /* Type */
-			HText_beginAnchor(me->text, B_ID_A);
+			HText_beginAnchor(me->text, ID_A);
 			HText_endAnchor(me->text);
 		        I.id = (char *)value[HTML_OPTION_ID];
 		    }
@@ -4476,24 +4133,24 @@ PRIVATE void HTML_start_element ARGS5(
 	    if ((present && present[HTML_OPTION_SELECTED]) ||
 	        (first_option && LYSelectPopups == FALSE &&
 		 HTCurSelectGroupType == F_RADIO_TYPE))
-		LastOptionChecked = TRUE;
+		me->LastOptionChecked = TRUE;
 	    else
-		LastOptionChecked = FALSE;
+		me->LastOptionChecked = FALSE;
 	    first_option = FALSE;
 
 
 	    if (present && present[HTML_OPTION_VALUE] &&
 	        value[HTML_OPTION_VALUE])
-	        StrAllocCopy(LastOptionValue, value[HTML_OPTION_VALUE]);
+	        StrAllocCopy(me->LastOptionValue, value[HTML_OPTION_VALUE]);
 	    else
-	        StrAllocCopy(LastOptionValue, me->option.data);
+	        StrAllocCopy(me->LastOptionValue, me->option.data);
 	}
 	break;
 
     case HTML_TABLE:
         UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_TABLE_ID);
-	B_inTABLE = TRUE;
+	LYCheckForID(me, present, value, (int)HTML_TABLE_ID);
+	me->inTABLE = TRUE;
         break;
 
     case HTML_TR:
@@ -4505,7 +4162,7 @@ PRIVATE void HTML_start_element ARGS5(
 	if (HText_LastLineSize(me->text)) {
 	    HText_appendCharacter(me->text, '\r');
 	}
-	HTML_CheckForID(me, present, value, (int)HTML_TR_ID);
+	LYCheckForID(me, present, value, (int)HTML_TR_ID);
 	me->in_word = NO;
         break;
 
@@ -4516,7 +4173,7 @@ PRIVATE void HTML_start_element ARGS5(
 	 *  Not yet implemented.  Just check for an ID link. - FM
 	 */
         UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_TR_ID);
+	LYCheckForID(me, present, value, (int)HTML_TR_ID);
         break;
     
     case HTML_COL:
@@ -4525,12 +4182,12 @@ PRIVATE void HTML_start_element ARGS5(
 	 *  Not yet implemented.  Just check for an ID link. - FM
 	 */
         UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_COL_ID);
+	LYCheckForID(me, present, value, (int)HTML_COL_ID);
         break;
     
     case HTML_TH:
         UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_TD_ID);
+	LYCheckForID(me, present, value, (int)HTML_TD_ID);
         /*
 	 *  Not yet implemented.  Just add a collapsible space and break. - FM
 	 */
@@ -4540,7 +4197,7 @@ PRIVATE void HTML_start_element ARGS5(
 
     case HTML_TD:
         UPDATE_STYLE;
-	HTML_CheckForID(me, present, value, (int)HTML_TD_ID);
+	LYCheckForID(me, present, value, (int)HTML_TD_ID);
         /*
 	 *  Not yet implemented.  Just add a collapsible space and break. - FM
 	 */
@@ -4556,7 +4213,7 @@ PRIVATE void HTML_start_element ARGS5(
 	if (!me->text)
 	    UPDATE_STYLE;
 	HTChunkClear(&me->math);
-	HTML_CheckForID(me, present, value, (int)HTML_GEN_ID);
+	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
 	break;
 
     default:
@@ -4601,8 +4258,8 @@ PRIVATE void HTML_end_element ARGS3(
 	int,			element_number,
 	char **,		include)
 {
-    int i;
-    char *temp = NULL;
+    int i = 0;
+    char *temp = NULL, *cp = NULL;
 
 #ifdef CAREFUL			/* parser assumed to produce good nesting */
     if (element_number != me->sp[0].tag_number) {
@@ -4642,12 +4299,12 @@ PRIVATE void HTML_end_element ARGS3(
     /*
      *  Check for unclosed TEXTAREA. - FM
      */
-    if (B_inTEXTAREA && element_number != HTML_TEXTAREA)
+    if (me->inTEXTAREA && element_number != HTML_TEXTAREA)
         if (TRACE) {
 	    fprintf(stderr, "HTML: Missing TEXTAREA end tag\n");
-	} else if (!B_inBadHTML) {
+	} else if (!me->inBadHTML) {
 	    _statusline(BAD_HTML_USE_TRACE);
-	    B_inBadHTML = TRUE;
+	    me->inBadHTML = TRUE;
 	    sleep(MessageSecs);
 	}
 
@@ -4657,44 +4314,35 @@ PRIVATE void HTML_end_element ARGS3(
     switch(element_number) {
 
     case HTML_HTML:
-	List_Nesting_Level = -1;
-	HTML_zero_OL_Counter();
-	Division_Level = -1;
-	Underline_Level = 0;
-	Quote_Level = 0;
-	if (B_inUnderline) {
+	if (me->inUnderline) {
 	    if (!me->text)
 	        UPDATE_STYLE;
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
-	    B_inUnderline = FALSE;
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    me->inUnderline = FALSE;
 	}
-	if (B_inA || B_inFORM || B_inSELECT || B_inTEXTAREA)
+	if (me->inA || me->inFORM || me->inSELECT || me->inTEXTAREA)
 	    if (TRACE)
 	        fprintf(stderr,
 			"HTML: Something not closed before HTML close-tag\n");
-	    else if (!B_inBadHTML) {
+	    else if (!me->inBadHTML) {
 	        _statusline(BAD_HTML_USE_TRACE);
 	    }
 	break;
 
     case HTML_HEAD:
-        List_Nesting_Level = -1;
-	HTML_zero_OL_Counter();
-	Division_Level = -1;
-	Underline_Level = 0;
-	Quote_Level = 0;
-	if (B_inUnderline) {
-	    if (!me->text)
-	        UPDATE_STYLE;
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
-	    B_inUnderline = FALSE;
+	UPDATE_STYLE;
+	if (me->inUnderline) {
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    me->inUnderline = FALSE;
 	}
+	if (HText_hasToolbar(me->text))
+	    HText_appendParagraph(me->text);
 	break;
 
 #ifdef NOT_DEFINED /* BASE will be a container in HTML+ */
     case HTML_BASE:
-	FREE(base_href);
-        B_inBASE = FALSE;
+	FREE(me->base_href);
+        me->inBASE = FALSE;
 	break;
 #endif /* NOT_DEFINED */
 
@@ -4703,32 +4351,43 @@ PRIVATE void HTML_end_element ARGS3(
     	HTAnchor_setTitle(me->node_anchor, me->title.data);
         HTChunkClear(&me->title);
 	/*
-	 *  Check if it's a bookmark file, and if so, insert the
-	 *  current description string and filepath for it. - FM
+	 *  Check if it's a bookmark file, and if so, and multiple
+	 *  bookmark support is on, or it's off but this isn't the
+	 *  default bookmark file (e.g., because it was on before,
+	 *  and this is another bookmark file that has been retrieved
+	 *  as a previous document), insert the current description
+	 *  string and filepath for it.  We pass the strings back to
+	 *  the SGML parser so that any 8 bit or multibyte/CJK
+	 *  characters will be handled by the parser's state and
+	 *  charset routines. - FM
 	 */
 	if (me->node_anchor->bookmark && *me->node_anchor->bookmark) {
-	    for (i = 0; i <= MBM_V_MAXFILES; i++) {
-	        if (MBM_A_subbookmark[i] &&
-		    !strcmp(MBM_A_subbookmark[i],
-		    	    me->node_anchor->bookmark)) {
-		    StrAllocCat(*include, "<H2><EM>Description:</EM> ");
-		    StrAllocCopy(temp,
-		    		 ((MBM_A_subdescript[i] &&
-				   *MBM_A_subdescript[i]) ?
-				     MBM_A_subdescript[i] : "(none)"));
-		    LYEntify((char **)&temp, TRUE);
-		    StrAllocCat(*include, temp);
-		    StrAllocCat(*include,
-		    		"<BR><EM>&nbsp;&nbsp;&nbsp;Filepath:</EM> ");
-		    StrAllocCopy(temp,
-		    		 ((MBM_A_subbookmark[i] &&
-				   *MBM_A_subbookmark[i]) ?
-				     MBM_A_subbookmark[i] : "(unknown)"));
-		    LYEntify((char **)&temp, TRUE);
-		    StrAllocCat(*include, temp);
-		    FREE(temp);
-		    StrAllocCat(*include, "</H2>");
-		    break;
+	    if ((LYMultiBookmarks == TRUE) ||
+		((bookmark_page && *bookmark_page) &&
+		 strcmp(me->node_anchor->bookmark, bookmark_page))) {
+		for (i = 0; i <= MBM_V_MAXFILES; i++) {
+		    if (MBM_A_subbookmark[i] &&
+			!strcmp(MBM_A_subbookmark[i],
+				me->node_anchor->bookmark)) {
+			StrAllocCat(*include, "<H2><EM>Description:</EM> ");
+			StrAllocCopy(temp,
+				     ((MBM_A_subdescript[i] &&
+				       *MBM_A_subdescript[i]) ?
+					 MBM_A_subdescript[i] : "(none)"));
+			LYEntify((char **)&temp, TRUE);
+			StrAllocCat(*include, temp);
+			StrAllocCat(*include,
+				"<BR><EM>&nbsp;&nbsp;&nbsp;Filepath:</EM> ");
+			StrAllocCopy(temp,
+				     ((MBM_A_subbookmark[i] &&
+				       *MBM_A_subbookmark[i]) ?
+					 MBM_A_subbookmark[i] : "(unknown)"));
+			LYEntify((char **)&temp, TRUE);
+			StrAllocCat(*include, temp);
+			FREE(temp);
+			StrAllocCat(*include, "</H2>");
+			break;
+		    }
 		}
 	    }
 	}
@@ -4765,22 +4424,17 @@ PRIVATE void HTML_end_element ARGS3(
 	break;
 
     case HTML_BODY:
-	List_Nesting_Level = -1;
-	HTML_zero_OL_Counter();
-	Division_Level = -1;
-	Underline_Level = 0;
-	Quote_Level = 0;
-	if (B_inUnderline) {
+	if (me->inUnderline) {
 	    if (!me->text)
 	        UPDATE_STYLE;
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
-	    B_inUnderline = FALSE;
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    me->inUnderline = FALSE;
 	}
-	if (B_inA || B_inFORM || B_inSELECT || B_inTEXTAREA)
+	if (me->inA || me->inFORM || me->inSELECT || me->inTEXTAREA)
 	    if (TRACE)
 	        fprintf(stderr,
 			"HTML: Something not closed before BODY close-tag\n");
-	    else if (!B_inBadHTML) {
+	    else if (!me->inBadHTML) {
 	        _statusline(BAD_HTML_USE_TRACE);
 	    }
 	break;
@@ -4794,8 +4448,8 @@ PRIVATE void HTML_end_element ARGS3(
     case HTML_NOFRAMES:
 	if (!me->text)
 	    UPDATE_STYLE;
-	HTML_EnsureDoubleSpace(me);
-	HTML_ResetParagraphAlignment(me);
+	LYEnsureDoubleSpace(me);
+	LYResetParagraphAlignment(me);
 	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
 	break;
 
@@ -4811,20 +4465,23 @@ PRIVATE void HTML_end_element ARGS3(
 		 */
 	change_paragraph_style(me, me->sp->style);
 	UPDATE_STYLE;
-	if (List_Nesting_Level >= 0)
+	if (me->sp->tag_number == element_number)
+	    LYEnsureDoubleSpace(me);
+	if (me->List_Nesting_Level >= 0)
 	    HText_NegateLineOne(me->text);
 	break;
 
     case HTML_CENTER:
     case HTML_DIV:
-	if (Division_Level >= 0)
-	    Division_Level--;
-	if (Division_Level >= 0)
-	    me->sp->style->alignment = DivisionAlignments[Division_Level];
+	if (me->Division_Level >= 0)
+	    me->Division_Level--;
+	if (me->Division_Level >= 0)
+	    me->sp->style->alignment =
+	    			me->DivisionAlignments[me->Division_Level];
 	change_paragraph_style(me, me->sp->style);
 	UPDATE_STYLE;
-	current_default_alignment = me->sp->style->alignment;
-	if (List_Nesting_Level >= 0)
+	me->current_default_alignment = me->sp->style->alignment;
+	if (me->List_Nesting_Level >= 0)
 	    HText_NegateLineOne(me->text);
 	break;
 
@@ -4834,22 +4491,30 @@ PRIVATE void HTML_end_element ARGS3(
     case HTML_H4:
     case HTML_H5:
     case HTML_H6:
-	if (Division_Level >= 0) {
-	    me->sp->style->alignment = DivisionAlignments[Division_Level];
+	if (me->Division_Level >= 0) {
+	    me->sp->style->alignment =
+	    			me->DivisionAlignments[me->Division_Level];
+	} else if (!strcmp(me->sp->style->name, "HeadingCenter") ||
+		   !strcmp(me->sp->style->name, "Heading1")) {
+	    me->sp->style->alignment = HT_CENTER;
+	} else if (!strcmp(me->sp->style->name, "HeadingRight")) {
+	    me->sp->style->alignment = HT_RIGHT;
+	} else {
+	    me->sp->style->alignment = HT_LEFT;
 	}
 	change_paragraph_style(me, me->sp->style);
 	UPDATE_STYLE;
 	if (styles[element_number]->font & HT_BOLD) {
-	    if (B_inBoldA == FALSE && B_inBoldH == TRUE) {
-	        HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+	    if (me->inBoldA == FALSE && me->inBoldH == TRUE) {
+	        HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 	    }
-	    B_inBoldH = FALSE;
+	    me->inBoldH = FALSE;
 	}
-	if (List_Nesting_Level >= 0)
+	if (me->List_Nesting_Level >= 0)
 	    HText_NegateLineOne(me->text);
-	if (Underline_Level > 0 && B_inUnderline == FALSE) {
-	    HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
-	    B_inUnderline = TRUE;
+	if (me->Underline_Level > 0 && me->inUnderline == FALSE) {
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
+	    me->inUnderline = TRUE;
 	}
 	break;
 
@@ -4868,16 +4533,16 @@ PRIVATE void HTML_end_element ARGS3(
     case HTML_STRONG:
 	if (!me->text)
 	    UPDATE_STYLE;
-	if (Underline_Level > 0)
-	    Underline_Level--;
-	if (B_inUnderline == TRUE && Underline_Level < 1) {
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
-	    B_inUnderline = FALSE;
+	if (me->Underline_Level > 0)
+	    me->Underline_Level--;
+	if (me->inUnderline == TRUE && me->Underline_Level < 1) {
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    me->inUnderline = FALSE;
 	    if (TRACE)
 	        fprintf(stderr,"Ending underline\n");
 	} else {
 	    if (TRACE)
-	        fprintf(stderr,"Underline Level is %d\n", Underline_Level);
+	        fprintf(stderr,"Underline Level is %d\n", me->Underline_Level);
 	}
     	break;
 	
@@ -4903,11 +4568,11 @@ PRIVATE void HTML_end_element ARGS3(
         if (!me->text)
 	    UPDATE_STYLE;
 	HTML_put_character(me, ' ');
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
 	HTML_put_string(me, ":DEL]");
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	HTML_put_character(me, ' ');
 	me->in_word = NO;
 	break;
@@ -4916,18 +4581,18 @@ PRIVATE void HTML_end_element ARGS3(
         if (!me->text)
 	    UPDATE_STYLE;
 	HTML_put_character(me, ' ');
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
 	HTML_put_string(me, ":INS]");
-	if (B_inUnderline == FALSE)
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
+	if (me->inUnderline == FALSE)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	HTML_put_character(me, ' ');
 	me->in_word = NO;
 	break;
 
     case HTML_Q:
-        if (Quote_Level > 0)
-	    Quote_Level--;
+        if (me->Quote_Level > 0)
+	    me->Quote_Level--;
         /*
 	 *  Should check LANG and/or DIR attributes, and the
 	 *  me->node_anchor->charset and/or yet to be added
@@ -4935,7 +4600,7 @@ PRIVATE void HTML_end_element ARGS3(
 	 *  use chevrons, but for now we'll always use double-
 	 *  or single-quotes. - FM
 	 */
-	if (!(Quote_Level & 1))
+	if (!(me->Quote_Level & 1))
 	    HText_appendCharacter(me->text, '"');
 	else
 	    HText_appendCharacter(me->text, '\'');
@@ -4956,25 +4621,27 @@ PRIVATE void HTML_end_element ARGS3(
     case HTML_FN:
 	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
 	UPDATE_STYLE;
-	if (List_Nesting_Level >= 0)
+	if (me->sp->tag_number == element_number)
+	    LYEnsureDoubleSpace(me);
+	if (me->List_Nesting_Level >= 0)
 	    HText_NegateLineOne(me->text);
-	B_inLABEL = FALSE;
+	me->inLABEL = FALSE;
 	break;
 
     case HTML_OL:
-        OL_Counter[List_Nesting_Level < 6 ?
-		   List_Nesting_Level : 6] = OL_VOID;
+        me->OL_Counter[me->List_Nesting_Level < 6 ?
+			   me->List_Nesting_Level : 6] = OL_VOID;
     case HTML_DL:
     case HTML_UL:
     case HTML_MENU:
     case HTML_DIR:
-	List_Nesting_Level--;
+	me->List_Nesting_Level--;
 	if (TRACE)
-	    fprintf(stderr,"Reducing List Nesting Level to %d\n",
-						    List_Nesting_Level);
+	    fprintf(stderr, "Reducing List Nesting Level to %d\n",
+			    me->List_Nesting_Level);
 	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
 	UPDATE_STYLE;
-	if (List_Nesting_Level >= 0)
+	if (me->List_Nesting_Level >= 0)
 	    HText_NegateLineOne(me->text);
         break;
 
@@ -4995,23 +4662,24 @@ PRIVATE void HTML_end_element ARGS3(
         break;
 
     case HTML_A:
-	/*	Set to know that we are no longer in an anchor.
+	/*
+	 *  Set to know that we are no longer in an anchor.
 	 */
-	B_inA = FALSE;
+	me->inA = FALSE;
 
 	UPDATE_STYLE;
-	if (B_inBoldA == TRUE && B_inBoldH == FALSE)
-	    HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
+	if (me->inBoldA == TRUE && me->inBoldH == FALSE)
+	    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 	HText_endAnchor(me->text);
-	B_inBoldA = FALSE;
-	if (Underline_Level > 0 && B_inUnderline == FALSE) {
-	    HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
-	    B_inUnderline = TRUE;
+	me->inBoldA = FALSE;
+	if (me->Underline_Level > 0 && me->inUnderline == FALSE) {
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
+	    me->inUnderline = TRUE;
 	}
 	break;
 
     case HTML_MAP:
-        FREE(LYMapName);
+        FREE(me->map_address);
         break;
 
     case HTML_BODYTEXT:
@@ -5031,14 +4699,14 @@ PRIVATE void HTML_end_element ARGS3(
 	break;
 
     case HTML_FIG:
-	if (B_inFIGwithP) {
-	    HTML_EnsureDoubleSpace(me);
+	if (me->inFIGwithP) {
+	    LYEnsureDoubleSpace(me);
 	} else {
 	    HTML_put_character(me, ' ');  /* space char may be ignored */
 	}
-	HTML_ResetParagraphAlignment(me);
-	B_inFIGwithP = FALSE;
-    	B_inFIG = FALSE;
+	LYResetParagraphAlignment(me);
+	me->inFIGwithP = FALSE;
+    	me->inFIG = FALSE;
 	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
 	break;
 
@@ -5049,10 +4717,10 @@ PRIVATE void HTML_end_element ARGS3(
 	 *  Finish the data off.
 	 */
 	{
-	    int s = 0, e = 0, i = 0, n = 0;
+	    int s = 0, e = 0, n = 0;
 	    char *start = NULL, *first_end = NULL;
 	    BOOL have_param = FALSE;
-	    char *cp = NULL, *data = NULL;
+	    char *data = NULL;
 	    HTPresentation *Pres;
 
 	    HTChunkTerminate(&me->object);
@@ -5110,9 +4778,9 @@ PRIVATE void HTML_end_element ARGS3(
 		    fprintf(stderr,
       "HTML: Unmatched OBJECT start and end tags.  Discarding content:\n%s\n",
 			    me->object.data);
-		} else if (!B_inBadHTML) {
+		} else if (!me->inBadHTML) {
 		    _statusline(BAD_HTML_USE_TRACE);
-		    B_inBadHTML = TRUE;
+		    me->inBadHTML = TRUE;
 		    sleep(MessageSecs);
 		}
 		goto End_Object;
@@ -5136,7 +4804,7 @@ PRIVATE void HTML_end_element ARGS3(
 	     */
 	    if (me->object_declare == TRUE) {
 	        if (me->object_id && *me->object_id)
-		    HTML_HandleID(me, me->object_id);
+		    LYHandleID(me, me->object_id);
 		if (TRACE)
 		    fprintf(stderr, "HTML: DECLAREd OBJECT.  Ignoring!\n");
 	        goto End_Object;
@@ -5150,7 +4818,7 @@ PRIVATE void HTML_end_element ARGS3(
 	     */
 	    if (me->object_name != NULL) {
 	        if (me->object_id && *me->object_id)
-		    HTML_HandleID(me, me->object_id);
+		    LYHandleID(me, me->object_id);
 		if (TRACE)
 		    fprintf(stderr, "HTML: NAMEd OBJECT.  Ignoring!\n");
 	        goto End_Object;
@@ -5188,9 +4856,9 @@ PRIVATE void HTML_end_element ARGS3(
 			fprintf(stderr,
 	"HTML: Unmatched OBJECT start and end tags.  Discarding content.\n");
 			goto End_Object;
-		    } else if (!B_inBadHTML) {
+		    } else if (!me->inBadHTML) {
 		        _statusline(BAD_HTML_USE_TRACE);
-			B_inBadHTML = TRUE;
+			me->inBadHTML = TRUE;
 			sleep(MessageSecs);
 			goto End_Object;
 		    }
@@ -5285,7 +4953,7 @@ Object_as_IMG:
 	     *  Add an ID link if needed. - FM
 	     */
 	    if (me->object_id && *me->object_id)
-	        HTML_HandleID(me, me->object_id);
+	        LYHandleID(me, me->object_id);
 
 	    /*
 	     *  Add the OBJECTs content if not empty. - FM
@@ -5315,7 +4983,7 @@ Object_as_IMG:
 		     *  an image or not, and set the link name
 		     *  accordingly. - FM
 		     */
-		    if (B_inA)
+		    if (me->inA)
 		        StrAllocCat(*include, "</A>");
 		    StrAllocCat(*include, " -<A HREF=\"");
 		    StrAllocCat(*include, me->object_data);
@@ -5354,41 +5022,41 @@ End_Object:
 	break;
 
     case HTML_APPLET:
-	if (B_inAPPLETwithP) {
-	    HTML_EnsureDoubleSpace(me);
+	if (me->inAPPLETwithP) {
+	    LYEnsureDoubleSpace(me);
 	} else {
 	    HTML_put_character(me, ' ');  /* space char may be ignored */
 	}
-	HTML_ResetParagraphAlignment(me);
-	B_inAPPLETwithP = FALSE;
-    	B_inAPPLET = FALSE;
+	LYResetParagraphAlignment(me);
+	me->inAPPLETwithP = FALSE;
+    	me->inAPPLET = FALSE;
 	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
 	break;
 
     case HTML_CAPTION:
-	HTML_EnsureDoubleSpace(me);
-	HTML_ResetParagraphAlignment(me);
-	B_inCAPTION = FALSE;
+	LYEnsureDoubleSpace(me);
+	LYResetParagraphAlignment(me);
+	me->inCAPTION = FALSE;
 	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
-	B_inLABEL = FALSE;
+	me->inLABEL = FALSE;
 	break;
 
     case HTML_CREDIT:
-	HTML_EnsureDoubleSpace(me);
-	HTML_ResetParagraphAlignment(me);
-	B_inCREDIT = FALSE;
+	LYEnsureDoubleSpace(me);
+	LYResetParagraphAlignment(me);
+	me->inCREDIT = FALSE;
 	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
-	B_inLABEL = FALSE;
+	me->inLABEL = FALSE;
 	break;
 
     case HTML_FORM:
 	/* Make sure we had a form start tag. */
-	if (!B_inFORM) {
+	if (!me->inFORM) {
 	    if (TRACE) {
 		fprintf(stderr, "HTML: Unmatched FORM end tag\n");
-	    } else if (!B_inBadHTML) {
+	    } else if (!me->inBadHTML) {
 	        _statusline(BAD_HTML_USE_TRACE);
-		B_inBadHTML = TRUE;
+		me->inBadHTML = TRUE;
 		sleep(MessageSecs);
 	    }
 	    /*
@@ -5402,7 +5070,7 @@ End_Object:
 	/*
 	 *  Set to know that we are no longer in an form.
 	 */
-	B_inFORM = FALSE;
+	me->inFORM = FALSE;
 
 	UPDATE_STYLE;
 	HText_endForm(me->text);
@@ -5419,18 +5087,16 @@ End_Object:
         {
             InputFieldData I;
             int chars;
- 	    char *cp = NULL;
-	    int i;
 
 	    /*
 	     *  Make sure we had a textarea start tag.
 	     */
-	    if (!B_inTEXTAREA) {
+	    if (!me->inTEXTAREA) {
 	        if (TRACE) {
 		    fprintf(stderr, "HTML: Unmatched TEXTAREA end tag\n");
-		} else if (!B_inBadHTML) {
+		} else if (!me->inBadHTML) {
 		    _statusline(BAD_HTML_USE_TRACE);
-		    B_inBadHTML = TRUE;
+		    me->inBadHTML = TRUE;
 		    sleep(MessageSecs);
 		}
 		break;
@@ -5439,7 +5105,7 @@ End_Object:
 	    /*
 	     *  Set to know that we are no longer in a textarea tag.
 	     */
-	    B_inTEXTAREA = FALSE;
+	    me->inTEXTAREA = FALSE;
 
             /*
 	     *  Initialize.
@@ -5467,19 +5133,18 @@ End_Object:
             HTChunkTerminate(&me->textarea);
 
 	    I.type = "textarea";
-	    I.value = cp;  /* may be NULL */
-	    I.size = textarea_cols;
-	    I.name = textarea_name;
-	    I.disabled = textarea_disabled;
-	    I.id = textarea_id;
+	    I.size = me->textarea_cols;
+	    I.name = me->textarea_name;
+	    I.disabled = me->textarea_disabled;
+	    I.id = me->textarea_id;
 
-	    LYUsePlainSpace = TRUE;
+	    me->UsePlainSpace = TRUE;
 	    if (current_char_set)
 	        LYExpandString(&me->textarea.data);
 
 	    cp = strtok(me->textarea.data, "\n");
-	    LYUnEscapeEntities(cp, LYUsePlainSpace, LYHiddenValue);
-	    for (i = 0; i < textarea_rows; i++) {
+	    LYUnEscapeEntities(cp, me->UsePlainSpace, me->HiddenValue);
+	    for (i = 0; i < me->textarea_rows; i++) {
 		I.value = cp;
 
                 chars = HText_beginInput(me->text, &I);
@@ -5488,7 +5153,7 @@ End_Object:
 	        HText_appendCharacter(me->text, '\r');
 	
 		cp = strtok(NULL, "\n");
-		LYUnEscapeEntities(cp, LYUsePlainSpace, LYHiddenValue);
+		LYUnEscapeEntities(cp, me->UsePlainSpace, me->HiddenValue);
 	    }
 
 	    /*
@@ -5498,20 +5163,20 @@ End_Object:
 		I.value = cp;
 
                 chars = HText_beginInput(me->text, &I);
-                for (chars = atoi(textarea_cols); chars>0; chars--)
+                for (chars = atoi(me->textarea_cols); chars>0; chars--)
                     HTML_put_character(me, '_');
                 HText_appendCharacter(me->text, '\r');
         
                 cp = strtok(NULL, "\n");
-		LYUnEscapeEntities(cp, LYUsePlainSpace, LYHiddenValue);
+		LYUnEscapeEntities(cp, me->UsePlainSpace, me->HiddenValue);
             }
 
-	    LYUsePlainSpace = FALSE;
+	    me->UsePlainSpace = FALSE;
 
 	    HTChunkClear(&me->textarea);
-	    FREE(textarea_name);
-	    FREE(textarea_cols);
-	    FREE(textarea_id);
+	    FREE(me->textarea_name);
+	    FREE(me->textarea_cols);
+	    FREE(me->textarea_id);
 	    break;
 	}
 
@@ -5524,12 +5189,12 @@ End_Object:
 	    /*
 	     *  Make sure we had a select start tag.
 	     */
-	    if (!B_inSELECT) {
+	    if (!me->inSELECT) {
 	        if (TRACE) {
 		    fprintf(stderr, "HTML: Unmatched SELECT end tag\n");
-		} else if (!B_inBadHTML) {
+		} else if (!me->inBadHTML) {
 		    _statusline(BAD_HTML_USE_TRACE);
-		    B_inBadHTML = TRUE;
+		    me->inBadHTML = TRUE;
 		    sleep(MessageSecs);
 		}
 		break;
@@ -5538,12 +5203,12 @@ End_Object:
 	    /*
 	     *  Set to know that we are no longer in a select tag.
 	     */
-	    B_inSELECT = FALSE;
+	    me->inSELECT = FALSE;
 
 	    /*
 	     *  Clear the disable attribute.
 	     */
-	    select_disabled=NO;
+	    me->select_disabled = FALSE;
 
 	    /*
 	     *  Finish the data off.
@@ -5551,18 +5216,20 @@ End_Object:
        	    HTChunkTerminate(&me->option);
 	    /* finish the previous option @@@@@ */
 	    ptr = HText_setLastOptionValue(me->text,
-	    				   me->option.data, LastOptionValue,
-					   LAST_ORDER, LastOptionChecked);
-	    FREE(LastOptionValue);
+	    				   me->option.data,
+					   me->LastOptionValue,
+					   LAST_ORDER,
+					   me->LastOptionChecked);
+	    FREE(me->LastOptionValue);
 
-	    LastOptionChecked = FALSE;
+	    me->LastOptionChecked = FALSE;
 
 	    if (HTCurSelectGroupType == F_CHECKBOX_TYPE ||
 	        LYSelectPopups == FALSE) {
 	            /*
 		     *  Start a newline after the last checkbox/button option.
 		     */
-		    HTML_EnsureSingleSpace(me);
+		    LYEnsureSingleSpace(me);
 	    } else {
 	        /*
 		 *  Output popup box with the default option to screen,
@@ -5575,7 +5242,6 @@ End_Object:
 		     *  We'll put up a minimum of 20 characters, and if any
 		     *  more would exceed the wrap column, we'll ignore them.
 		     */
-	            int i;
 		    for (i = 0; i < 20; i++) {
 		        if (*ptr == ' ')
 	    	            HText_appendCharacter(me->text,HT_NON_BREAK_SPACE); 
@@ -5583,7 +5249,7 @@ End_Object:
 	    	            HText_appendCharacter(me->text,*ptr);
 			ptr++;
 		    }
-		    ignore_excess = TRUE;
+		    HText_setIgnoreExcess(me->text, TRUE);
 	        }
 	        for (; ptr && *ptr != '\0'; ptr++) {
 		    if (*ptr == ' ')
@@ -5595,26 +5261,26 @@ End_Object:
 		 *  Add end option character.
 		 */
 	        HText_appendCharacter(me->text, ']');
-		HTML_Last_Char = ']';
+		HText_setLastChar(me->text, ']');
 		me->in_word = YES;
-		ignore_excess = FALSE; 
+		HText_setIgnoreExcess(me->text, FALSE); 
 	    }
     	    HTChunkClear(&me->option);
 
-	    if (Underline_Level > 0 && B_inUnderline == FALSE) {
-	        HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
-	        B_inUnderline = TRUE;
+	    if (me->Underline_Level > 0 && me->inUnderline == FALSE) {
+	        HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
+	        me->inUnderline = TRUE;
 	    }
-	    if (B_needBoldH == TRUE && B_inBoldH == FALSE) {
-	        HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
-		B_inBoldH = TRUE;
-		B_needBoldH = FALSE;
+	    if (me->needBoldH == TRUE && me->inBoldH == FALSE) {
+	        HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+		me->inBoldH = TRUE;
+		me->needBoldH = FALSE;
 	    }
 	}
 	break;
 
     case HTML_TABLE:
-        B_inTABLE = FALSE;
+        me->inTABLE = FALSE;
         break;
 
 #ifdef NOTDEFINED /* These are SGML_EMPTY for now. - FM */
@@ -5637,33 +5303,30 @@ End_Object:
 #endif /* NOTDEFINED */
 
     case HTML_MATH:
-	{
-	    int i;
-	    if (!me->text)
-	        UPDATE_STYLE;
-            /*
-	     *  We're getting it as Litteral text, which, until we can process
-	     *  it, we'll display as is, within brackets to alert the user. - FM
-	     */
-	    HTChunkPutc(&me->math, ' ');
-            HTChunkTerminate(&me->math);
-	    if (me->math.size > 2) {
-	        HTML_EnsureSingleSpace(me);
-	        if (B_inUnderline == FALSE)
-		    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
-		HTML_put_string(me, "[MATH:");
-		HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
-	        HTML_put_character(me, ' ');
-		HTML_put_string(me, me->math.data);
+	if (!me->text)
+	    UPDATE_STYLE;
+        /*
+	 *  We're getting it as Litteral text, which, until we can process
+	 *  it, we'll display as is, within brackets to alert the user. - FM
+	 */
+	HTChunkPutc(&me->math, ' ');
+        HTChunkTerminate(&me->math);
+	if (me->math.size > 2) {
+	    LYEnsureSingleSpace(me);
+	    if (me->inUnderline == FALSE)
 		HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
-		HTML_put_string(me, ":MATH]");
-	        if (B_inUnderline == FALSE)
-		    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
-		HTML_EnsureSingleSpace(me);
-	    }
-	    HTChunkClear(&me->math);
-	    break;
+	    HTML_put_string(me, "[MATH:");
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    HTML_put_character(me, ' ');
+	    HTML_put_string(me, me->math.data);
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
+	    HTML_put_string(me, ":MATH]");
+	    if (me->inUnderline == FALSE)
+		HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    LYEnsureSingleSpace(me);
 	}
+	HTChunkClear(&me->math);
+	break;
 
     default:
 	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
@@ -5677,7 +5340,7 @@ End_Object:
 */
 /*	(In fact, they all shrink!)
 */
-PRIVATE void HTML_put_entity ARGS2(HTStructured *, me, int, entity_number)
+PUBLIC void HTML_put_entity ARGS2(HTStructured *, me, int, entity_number)
 {
     HTML_put_string(me, p_entity_values[entity_number]);
 }
@@ -5697,11 +5360,11 @@ PUBLIC void HTML_free ARGS1(HTStructured *, me)
 {
     UPDATE_STYLE;		/* Creates empty document here! */
     if (me->comment_end)
-		HTML_put_string(me,me->comment_end);
+	HTML_put_string(me, me->comment_end);
     if (me->text) {
-	if (B_inUnderline) {
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
-	    B_inUnderline = FALSE;
+	if (me->inUnderline) {
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    me->inUnderline = FALSE;
 	}
 	HText_endAppend(me->text);
     }
@@ -5709,14 +5372,10 @@ PUBLIC void HTML_free ARGS1(HTStructured *, me)
     if (me->target) {
         (*me->targetClass._free)(me->target);
     }
-    List_Nesting_Level = -1;
-    HTML_zero_OL_Counter();
-    Division_Level = -1;
-    Underline_Level = 0;
-    Quote_Level = 0;
     if (me->sp && me->sp->style && me->sp->style->name) {
         if (!strcmp(me->sp->style->name, "DivCenter") ||
-	    !strcmp(me->sp->style->name, "HeadingCenter")) {
+	    !strcmp(me->sp->style->name, "HeadingCenter") ||
+	    !strcmp(me->sp->style->name, "Heading1")) {
 	    me->sp->style->alignment = HT_CENTER;
 	} else if (!strcmp(me->sp->style->name, "DivRight") ||
 		   !strcmp(me->sp->style->name, "HeadingRight")) {
@@ -5726,25 +5385,17 @@ PUBLIC void HTML_free ARGS1(HTStructured *, me)
 	}
 	styles[HTML_PRE]->alignment = HT_LEFT;
     }
-    FREE(base_href);
-    B_inBASE = FALSE;
-    FREE(LYMapName);
+    FREE(me->base_href);
+    FREE(me->map_address);
+    FREE(me->LastOptionValue);
     FREE(me);
 }
 
 PRIVATE void HTML_abort ARGS2(HTStructured *, me, HTError, e)
 {
-    List_Nesting_Level = -1;
-    HTML_zero_OL_Counter();
-    Division_Level = -1;
-    Underline_Level = 0;
-    Quote_Level = 0;
-
     if (me->text) {
-	if (B_inUnderline) {
-	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
-	    B_inUnderline = FALSE;
-	}
+	if (me->inUnderline)
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	HText_endAppend(me->text);
     }
 
@@ -5753,7 +5404,8 @@ PRIVATE void HTML_abort ARGS2(HTStructured *, me, HTError, e)
     }
     if (me->sp && me->sp->style && me->sp->style->name) {
         if (!strcmp(me->sp->style->name, "DivCenter") ||
-	    !strcmp(me->sp->style->name, "HeadingCenter")) {
+	    !strcmp(me->sp->style->name, "HeadingCenter") ||
+	    !strcmp(me->sp->style->name, "Heading1")) {
 	    me->sp->style->alignment = HT_CENTER;
 	} else if (!strcmp(me->sp->style->name, "DivRight") ||
 		   !strcmp(me->sp->style->name, "HeadingRight")) {
@@ -5763,9 +5415,12 @@ PRIVATE void HTML_abort ARGS2(HTStructured *, me, HTError, e)
 	}
 	styles[HTML_PRE]->alignment = HT_LEFT;
     }
-    FREE(base_href);
-    B_inBASE = FALSE;
-    FREE(LYMapName);
+    FREE(me->base_href);
+    FREE(me->map_address);
+    FREE(me->textarea_name);
+    FREE(me->textarea_cols);
+    FREE(me->textarea_id);
+    FREE(me->LastOptionValue);
     FREE(me);
 }
 
@@ -5841,6 +5496,7 @@ PRIVATE void get_styles NOARGS
     styles[HTML_PRE] =		HTStyleNamed(styleSheet, "Preformatted");
     styles[HTML_LISTING] =	HTStyleNamed(styleSheet, "Listing");
 }
+
 /*				P U B L I C
 */
 
@@ -5871,39 +5527,6 @@ PUBLIC HTStructured* HTML_new ARGS3(
 
     HTStructured * me;
    
-	/*  Reset to know that we aren't in a list, anchor, bold header
-	 *  or paragraph.  Hmm... May as well reset all of the flags.
-	 */
-	List_Nesting_Level = -1;
-	HTML_zero_OL_Counter();
-	Division_Level = -1;
-	Underline_Level = 0;
-	Quote_Level = 0;
-	FREE(base_href);
-	FREE(LYMapName);
-
-	B_inA = FALSE;
-	B_inAPPLET = FALSE;
-	B_inAPPLETwithP = FALSE;
-	B_inBadHTML = FALSE;
-        B_inBASE = FALSE;
-	B_inBoldA = FALSE;
-	B_inBoldH = FALSE;
-	B_inCAPTION = FALSE;
-	B_inCREDIT = FALSE;
-	B_inFIG = FALSE;
-	B_inFIGwithP = FALSE;
-	B_inFORM = FALSE;
-	B_inLABEL = FALSE;
-	B_inP = FALSE;
-	B_inPRE = FALSE;
-	B_inSELECT = FALSE;
-	B_inTABLE = FALSE;
-	B_inUnderline = FALSE;
-
-	B_needBoldH = FALSE;
-	current_default_alignment=HT_LEFT;
- 
     if (format_out != WWW_PLAINTEXT && format_out != WWW_PRESENT) {
         HTStream * intermediate = HTStreamStack(WWW_HTML, format_out,
 						stream, anchor);
@@ -5933,15 +5556,21 @@ PUBLIC HTStructured* HTML_new ARGS3(
         default_style =	HTStyleNamed(styleSheet, "Normal");
 
     me->isa = &HTMLPresentation;
-    me->node_anchor =  anchor;
+    me->node_anchor = anchor;
+
+    me->CurrentA = NULL;
+    me->base_href = NULL;;
+    me->map_address = NULL;
+
     me->title.size = 0;
     me->title.growby = 128;
     me->title.allocated = 0;
-    me->title.data = 0;
+    me->title.data = NULL;
+
     me->object.size = 0;
     me->object.growby = 128;
     me->object.allocated = 0;
-    me->object.data = 0;
+    me->object.data = NULL;
     me->object_started = FALSE;
     me->object_declare = FALSE;
     me->object_shapes = FALSE;
@@ -5955,37 +5584,90 @@ PUBLIC HTStructured* HTML_new ARGS3(
     me->object_codetype = NULL;
     me->object_usemap = NULL;
     me->object_name = NULL;
+ 
     me->option.size = 0;
     me->option.growby = 128;
     me->option.allocated = 0;
-    me->option.data = 0;
+    me->option.data = NULL;
+    me->LastOptionValue = NULL;
+    me->LastOptionChecked = FALSE;
+    me->select_disabled = FALSE;
+
     me->textarea.size = 0;
     me->textarea.growby = 128;
     me->textarea.allocated = 0;
-    me->textarea.data = 0;
+    me->textarea.data = NULL;
+    me->textarea_name = NULL;
+    me->textarea_cols = NULL;
+    me->textarea_rows = 4;
+    me->textarea_disabled = NO;
+    me->textarea_id = NULL;
+
     me->math.size = 0;
     me->math.growby = 128;
     me->math.allocated = 0;
-    me->math.data = 0;
+    me->math.data = NULL;
+
     me->style_block.size = 0;
     me->style_block.growby = 128;
     me->style_block.allocated = 0;
-    me->style_block.data = 0;
+    me->style_block.data = NULL;
+
     me->script.size = 0;
     me->script.growby = 128;
     me->script.allocated = 0;
-    me->script.data = 0;
+    me->script.data = NULL;
+
     me->text = 0;
     me->style_change = YES;	/* Force check leading to text creation */
     me->new_style = default_style;
     me->old_style = 0;
+    me->current_default_alignment = HT_LEFT;
     me->sp = me->stack + MAX_NESTING - 1;
     me->sp->tag_number = -1;				/* INVALID */
     me->sp->style = default_style;			/* INVALID */
     me->sp->style->alignment = HT_LEFT;
 
+    me->Division_Level = -1;
+    me->Underline_Level = 0;
+    me->Quote_Level = 0;
+
+    me->UsePlainSpace = FALSE;
+    me->HiddenValue = FALSE;
+    me->lastraw = -1;
+
+    /*
+     *  Used for nested lists. - FM
+     */
+    me->List_Nesting_Level = -1; /* counter for list nesting level */
+    LYZero_OL_Counter(me);	 /* Initializes OL_Counter[7] and OL_Type[7] */
+    me->Last_OL_Count = 0;	 /* last count in ordered lists */
+    me->Last_OL_Type = '1';	 /* last type in ordered lists */
+
+    me->inA = FALSE;
+    me->inAPPLET = FALSE;
+    me->inAPPLETwithP = FALSE;
+    me->inBadHTML = FALSE;
+    me->inBASE = FALSE;
+    me->inBoldA = FALSE;
+    me->inBoldH = FALSE;
+    me->inCAPTION = FALSE;
+    me->inCREDIT = FALSE;
+    me->inFIG = FALSE;
+    me->inFIGwithP = FALSE;
+    me->inFORM = FALSE;
+    me->inLABEL = FALSE;
+    me->inP = FALSE;
+    me->inPRE = FALSE;
+    me->inSELECT = FALSE;
+    me->inTABLE = FALSE;
+    me->inUnderline = FALSE;
+
+    me->needBoldH = FALSE;
+ 
     me->comment_start = NULL;
     me->comment_end = NULL;
+
     me->target = stream;
     if (stream)
         me->targetClass = *stream->isa;			/* Copy pointers */
@@ -6071,254 +5753,3 @@ PUBLIC int HTLoadError ARGS3(
     HTAlert(message);		/* @@@@@@@@@@@@@@@@@@@ */
     return -number;
 } 
-
-/*
-**  This function checks whether we want to overrride
-**  the current default alignment for parargraphs and
-**  instead use that specified in the element's style
-**  sheet. - FM
-*/
-PRIVATE BOOLEAN HTML_override_default_alignment ARGS1(
-	HTStructured *, me)
-{
-    switch(me->sp[0].tag_number) {
-	case HTML_BLOCKQUOTE:
-	case HTML_BQ:
-	case HTML_NOTE:
-	case HTML_FN:
-        case HTML_ADDRESS:
-	    me->sp->style->alignment = HT_LEFT;
-	    return YES;
-	    break;
-
-	default:
-	    break;
-    }
-    return NO;
-}
-
-/*
-**  This function initializes the Ordered List counter. - FM
-*/
-PRIVATE void HTML_zero_OL_Counter NOARGS
-{
-    int i;
-
-    for (i = 0; i < 7; i++) {
-        OL_Counter[i] = OL_VOID;
-	OL_Type[i] = '1';
-    }
-	
-    Last_OL_Count = 0;
-    Last_OL_Type = '1';
-    
-    return;
-}
-
-/*
-**  This function inserts newlines if needed to create double spacing,
-**  and sets the left margin for subsequent text to the second line
-**  indentation of the current style. - FM
-*/
-PRIVATE void HTML_EnsureDoubleSpace ARGS1(
-	HTStructured *, me)
-{
-    if (!me || !me->text)
-        return;
-
-    if (HText_LastLineSize(me->text)) {
-	HText_appendCharacter(me->text, '\r');
-	HText_appendCharacter(me->text, '\r');
-    } else if (HText_PreviousLineSize(me->text)) {
-	HText_appendCharacter(me->text, '\r');
-    } else if (List_Nesting_Level >= 0) {
-	HText_NegateLineOne(me->text);
-    }
-    me->in_word = NO;
-    return;
-}
-
-/*
-**  This function inserts a newline if needed to create single spacing,
-**  and sets the left margin for subsequent text to the second line
-**  indentation of the current style. - FM
-*/
-PRIVATE void HTML_EnsureSingleSpace ARGS1(
-	HTStructured *, me)
-{
-    if (!me || !me->text)
-        return;
-
-    if (HText_LastLineSize(me->text)) {
-	HText_appendCharacter(me->text, '\r');
-    } else if (List_Nesting_Level >= 0) {
-	HText_NegateLineOne(me->text);
-    }
-    me->in_word = NO;
-    return;
-}
-
-/*
-**  This function resets paragraph alignments for block
-**  elements which do not have a defined style sheet. - FM
-*/
-PRIVATE void HTML_ResetParagraphAlignment ARGS1(
-	HTStructured *, me)
-{
-    if (!me)
-        return;
-
-    if (List_Nesting_Level >= 0 ||
-	((Division_Level < 0) &&
-	 (!strcmp(me->sp->style->name, "Normal") ||
-	  !strcmp(me->sp->style->name, "Preformatted")))) {
-	me->sp->style->alignment = HT_LEFT;
-    } else {
-	me->sp->style->alignment = current_default_alignment;
-    }
-    return;
-}
-
-/*
-**  If an HREF, itself or if resolved against a base,
-**  represents a file URL, and the host is defaulted,
-**  force in "//localhost".  We need this until
-**  all the other Lynx code which performs security
-**  checks based on the "localhost" string is changed
-**  to assume "//localhost" when a host field is not
-**  present in file URLs - FM
-*/
-PRIVATE void HTMLFillLocalFileURL ARGS2(
-	char **,	href,
-	char *,		base)
-{
-    char * temp = NULL;
-
-    if (*href == NULL || *(*href) == '\0')
-        return;
-
-    if (!strcmp(*href, "//") || !strncmp(*href, "///", 3)) {
-	if (base != NULL && !strncmp(base, "file:", 5)) {
-	    StrAllocCopy(temp, "file:");
-	    StrAllocCat(temp, *href);
-	    StrAllocCopy(*href, temp);
-	}
-    }
-    if (!strncmp(*href, "file:", 5)) {
-	if (*(*href+5) == '\0') {
-	    StrAllocCat(*href, "//localhost");
-	} else if (!strcmp(*href, "file://")) {
-	    StrAllocCat(*href, "localhost");
-	} else if (!strncmp(*href, "file:///", 8)) {
-	    StrAllocCopy(temp, (*href+7));
-	    StrAllocCopy(*href, "file://localhost");
-	    StrAllocCat(*href, temp);
-	} else if (!strncmp(*href, "file:/", 6) && *(*href+6) != '/') {
-	    StrAllocCopy(temp, (*href+5));
-	    StrAllocCopy(*href, "file://localhost");
-	    StrAllocCat(*href, temp);
-	}
-    }
-
-    /*
-     * No path in a file://localhost URL means a
-     * directory listing for the current default. - FM
-     */
-    if (!strcmp(*href, "file://localhost")) {
-#ifdef VMS
-	StrAllocCat(*href, HTVMS_wwwName(getenv("PATH")));
-#else
-	char curdir[DIRNAMESIZE];
-#ifdef NO_GETCWD
-	getwd (curdir);
-#else
-	getcwd (curdir, DIRNAMESIZE);
-#endif /* NO_GETCWD */
-	StrAllocCat(*href, curdir);
-#endif /* VMS */
-    }
-
-#ifdef VMS
-    /*
-     * On VMS, a file://localhost/ URL means
-     * a listing for the login directory. - FM
-     */
-    if (!strcmp(*href, "file://localhost/"))
-	StrAllocCat(*href, (HTVMS_wwwName((char *)Home_Dir())+1));
-#endif /* VMS */
-
-    FREE(temp);
-    return;
-}
-
-/*
-**  This function creates NAMEd Anchors of a non-zero-length NAME
-**  or ID attribute was present in the tag.
-*/
-PRIVATE void HTML_CheckForID ARGS4(
-	HTStructured *,		me,
-	CONST BOOL *,		present,
-	CONST char **,		value,
-	int,			attribute)
-{
-    HTChildAnchor *B_ID_A = NULL;
-    char *temp = NULL;
-
-    if (!(me && me->text))
-        return;
-
-    if (present && present[attribute]
-	&& value[attribute] && *value[attribute]) {
-	/*
-	 *  Translate any named or numeric character references. - FM
-	 */
-	StrAllocCopy(temp, value[attribute]);
-	LYUnEscapeToLatinOne(&temp, TRUE);
-
-	/*
-	 *  Create the link if we still have a non-zero-length string. - FM
-	 */
-	if ((temp[0] != '\0') &&
-	    (B_ID_A = HTAnchor_findChildAndLink(
-				me->node_anchor,	/* Parent */
-				temp,			/* Tag */
-				NULL,			/* Addresss */
-				(void *)0))) {		/* Type */
-	    HText_beginAnchor(me->text, B_ID_A);
-	    HText_endAnchor(me->text);
-	}
-	FREE(temp);
-    }
-
-    return;
-}
-
-/*
-**  This function creates a NAMEd Anchor for the ID string
-**  passed to it directly as an argument.  It assumes the
-**  does not need checking for character references. - FM
-*/
-PRIVATE void HTML_HandleID ARGS2(
-	HTStructured *,		me,
-	char *,			id)
-{
-    HTChildAnchor *B_ID_A = NULL;
-
-    if (!(me && me->text) ||
-        !(id && *id))
-        return;
-
-    /*
-     *  Create the link if we still have a non-zero-length string. - FM
-     */
-    if (B_ID_A = HTAnchor_findChildAndLink(
-				me->node_anchor,	/* Parent */
-				id,			/* Tag */
-				NULL,			/* Addresss */
-				(void *)0)) {		/* Type */
-	HText_beginAnchor(me->text, B_ID_A);
-	HText_endAnchor(me->text);
-    }
-
-    return;
-}
diff --git a/src/HTML.h b/src/HTML.h
index aada006f..23d89e17 100644
--- a/src/HTML.h
+++ b/src/HTML.h
@@ -1,9 +1,9 @@
-/*                                                     HTML to rich text converter for libwww
-                             THE HTML TO RTF OBJECT CONVERTER
-                                             
-   This interprets the HTML semantics.
-   
- */
+/*					HTML to rich text converter for libwww
+**
+**			THE HTML TO RTF OBJECT CONVERTER
+**
+**  This interprets the HTML semantics.
+*/
 #ifndef HTML_H
 #define HTML_H
 
@@ -20,22 +20,150 @@
 
 extern CONST HTStructuredClass HTMLPresentation;
 
+#ifdef Lynx_HTML_Handler
 /*
+**	This section is semi-private to HTML.c and it's helper modules. - FM
+**	--------------------------------------------------------------------
+*/
 
-HTConverter to present HTML
+typedef struct _stack_element {
+        HTStyle *	style;
+	int		tag_number;
+} stack_element;
+
+/*		HTML Object
+**		-----------
+*/
+#define MAX_NESTING 800		/* Should be checked by parser */
+
+struct _HTStructured {
+    CONST HTStructuredClass * 	isa;
+    HTParentAnchor * 		node_anchor;
+    HText * 			text;
+
+    HTStream*			target;			/* Output stream */
+    HTStreamClass		targetClass;		/* Output routines */
+
+    HTChildAnchor *		CurrentA;	/* current HTML_A anchor */
+    char *			base_href;	/* current HTML_BASE href */
+    char *			map_address;	/* current HTML_MAP address */
+
+    HTChunk 			title;		/* Grow by 128 */
+    HTChunk			object;		/* Grow by 128 */
+    BOOL			object_started;
+    BOOL			object_declare;
+    BOOL			object_shapes;
+    BOOL			object_ismap;
+    char *			object_usemap;
+    char *			object_id;
+    char *			object_title;
+    char *			object_data;
+    char *			object_type;
+    char *			object_classid;
+    char *			object_codebase;
+    char *			object_codetype;
+    char *			object_name;
+    HTChunk			option;		/* Grow by 128 */
+    char *			LastOptionValue;
+    BOOL			LastOptionChecked;
+    BOOL			select_disabled;
+    HTChunk			textarea;	/* Grow by 128 */
+    char *			textarea_name;
+    char *			textarea_cols;
+    int 			textarea_rows;
+    int				textarea_disabled;
+    char *			textarea_id;
+    HTChunk			math;		/* Grow by 128 */
+    HTChunk			style_block;	/* Grow by 128 */
+    HTChunk			script;		/* Grow by 128 */
+
+    /*
+     *  Used for nested lists. - FM
+     */
+    int		List_Nesting_Level;	/* counter for list nesting level */
+    int 	OL_Counter[7];		/* counter for ordered lists */
+    char 	OL_Type[7];		/* types for ordered lists */
+    int 	Last_OL_Count;		/* last count in ordered lists */
+    char 	Last_OL_Type;		/* last type in ordered lists */
+
+    int				Division_Level;
+    short			DivisionAlignments[MAX_NESTING];
+    int				Underline_Level;
+    int				Quote_Level;
+
+    BOOL			UsePlainSpace;
+    BOOL			HiddenValue;
+    int				lastraw;
+
+    char *			comment_start;	/* for literate programming */
+    char *			comment_end;
+
+    HTTag *			current_tag;
+    BOOL			style_change;
+    HTStyle *			new_style;
+    HTStyle *			old_style;
+    int				current_default_alignment;
+    BOOL			in_word;  /* Have just had a non-white char */
+    stack_element 	stack[MAX_NESTING];
+    stack_element 	*sp;		/* Style stack pointer */
+
+    /*
+    **  Track if we are in an anchor, paragraph, address, base, etc.
+    */
+    BOOL		inA;
+    BOOL		inAPPLET;
+    BOOL		inAPPLETwithP;
+    BOOL		inBadHTML;
+    BOOL		inBASE;
+    BOOL		inBoldA;
+    BOOL		inBoldH;
+    BOOL		inCAPTION;
+    BOOL		inCREDIT;
+    BOOL		inFIG;
+    BOOL		inFIGwithP;
+    BOOL		inFORM;
+    BOOL		inLABEL;
+    BOOL		inP;
+    BOOL		inPRE;
+    BOOL		inSELECT;
+    BOOL		inTABLE;
+    BOOL		inTEXTAREA;
+    BOOL		inUnderline;
+
+    BOOL		needBoldH;
+};
+
+struct _HTStream {
+    CONST HTStreamClass *	isa;
+    /* .... */
+};
 
+/*
+ *	Semi-Private functions. - FM
  */
-PUBLIC HTStream* HTMLToPlain PARAMS((
+extern void HTML_put_character PARAMS((HTStructured *me, char c));
+extern void HTML_put_string PARAMS((HTStructured *me, CONST char *s));
+extern void HTML_write PARAMS((HTStructured *me, CONST char *s, int l));
+extern void HTML_put_entity PARAMS((HTStructured *me, int entity_number));
+#endif /* Lynx_HTML_Handler */
+
+/*				P U B L I C
+*/
+
+/*
+**  HTConverter to present HTML
+*/
+extern HTStream* HTMLToPlain PARAMS((
         HTPresentation *        pres,
         HTParentAnchor *        anchor,
         HTStream *              sink));
 
-PUBLIC HTStream* HTMLToC PARAMS((
+extern HTStream* HTMLToC PARAMS((
         HTPresentation *        pres,
         HTParentAnchor *        anchor,
         HTStream *              sink));
 
-PUBLIC HTStream* HTMLPresent PARAMS((
+extern HTStream* HTMLPresent PARAMS((
         HTPresentation *        pres,
         HTParentAnchor *        anchor,
         HTStream *              sink));
@@ -45,7 +173,8 @@ extern HTStructured* HTML_new PARAMS((
         HTFormat        format_out,
         HTStream *      target));
 
-/*      Names for selected internal representations:
+/*
+**  Names for selected internal representations.
 */
 typedef enum _HTMLCharacterSet {
         HTML_ISO_LATIN1,
@@ -53,27 +182,24 @@ typedef enum _HTMLCharacterSet {
         HTML_PC_CP950
 } HTMLCharacterSet;
 
-
 /*
-
-Record error message as a hypertext object
-
-   The error message should be marked as an error so that it can be reloaded later. This
-   implementation just throws up an error message and leaves the document unloaded.
-   
- */
-/* On entry,
+**  Record error message as a hypertext object.
+**
+**  The error message should be marked as an error so that it can be
+**  reloaded later.  This implementation just throws up an error message
+**  and leaves the document unloaded.
+**
+**  On entry,
 **      sink    is a stream to the output device if any
 **      number  is the HTTP error number
 **      message is the human readable message.
-** On exit,
+**  On exit,
 **      a retrun code like HT_LOADED if object exists else 60; 0
 */
-
-PUBLIC int HTLoadError PARAMS((
-        HTStream *      sink,
-        int             number,
-        CONST char *    message));
+extern int HTLoadError PARAMS((
+	HTStream *	sink,
+	int		number,
+	CONST char *	message));
 
 #endif /* HTML_H */
 
diff --git a/src/LYBookmark.c b/src/LYBookmark.c
index 4ba29d0b..8f574bc1 100644
--- a/src/LYBookmark.c
+++ b/src/LYBookmark.c
@@ -10,6 +10,7 @@
 #include "LYKeymap.h"
 #include "LYCharUtils.h"
 #include "LYCurses.h"
+#include "GridText.h"
 
 #ifdef VMS
 #include "HTVMSUtils.h"
@@ -25,22 +26,29 @@ PRIVATE BOOLEAN is_mosaic_hotlist=FALSE;
 PRIVATE char * convert_mosaic_bookmark_file PARAMS((char *filename_buffer));
 
 /*
- *  Tries to open the bookmark file for reading.
- *  if successful the file is closed and the filename
- *  is returned and the URL is given in name.
- *
- *  Returns a zero-length pointer to flag a cancel,
- *  a space to flag an undefined selection, and
- *  NULL for a failure (processing error). - FM
+ *  Tries to open a bookmark file for reading, which may be
+ *  the default, or based on offering the user a choice from
+ *  the MBM_A_subbookmark[] array.  If successful the file is
+ *  closed, and the filename in system path specs is returned,
+ *  the URL is allocated into *URL, and the MBM_A_subbookmark[]
+ *  filepath is allocated into the BookmarkPage global.  Returns
+ *  a zero-length pointer to flag a cancel, or a space to flag
+ *  an undefined selection, without allocating into *URL or
+ *  BookmarkPage.  Returns NULL with allocating into BookmarkPage
+ *  but not *URL is the selection is valid but the file doesn't
+ *  yet exist. - FM
  */
 PUBLIC char * get_bookmark_filename ARGS1(
-	char **, URL)
+	char **,	URL)
 {
     char URL_buffer[256];
     static char filename_buffer[256];
     char string_buffer[256];
     FILE *fp;
     int MBM_tmp;
+#ifndef VMS
+    int len;
+#endif /* !VMS */
 
     /*
      *  Multi_Bookmarks support. - FMG & FM
@@ -49,7 +57,7 @@ PUBLIC char * get_bookmark_filename ARGS1(
     MBM_tmp = select_multi_bookmarks();
     if (MBM_tmp == -2)
         /*
-	 *  Zero-length pointer flags a cancel.
+	 *  Zero-length pointer flags a cancel. - FM
 	*/
         return("");
     if (MBM_tmp == -1) {
@@ -59,23 +67,28 @@ PUBLIC char * get_bookmark_filename ARGS1(
 	_statusline(string_buffer);
 	sleep(AlertSecs);
 	/*
-	 *  Space flags an undefined selection.
-	*/
+	 *  Space flags an undefined selection. - FMG
+	 */
 	return(" ");
     } else {
+        /*
+	 *  Save the filepath as a global.  The system path will be
+	 *  loaded into to the (static) filename_buffer as the return
+	 *  value, the URL will be allocated into *URL, and we also
+	 *  need the filepath available to calling functions.  This
+	 *  is all pitifully non-reentrant, a la the original Lynx,
+	 *  and should be redesigned someday. - FM
+	 */
 	StrAllocCopy(BookmarkPage, MBM_A_subbookmark[MBM_tmp]);
     }
 
     /*
-     *  Seek it in the home path.
+     *  Seek it in the home path. - FM
      */
-#ifdef VMS
-    LYVMS_HomePathAndFilename(filename_buffer,
-			      sizeof(filename_buffer),
-			      BookmarkPage);
-#else
-    sprintf(filename_buffer,"%s/%s", Home_Dir(), BookmarkPage);
-#endif /* VMS */
+    filename_buffer[255] = '\0';
+    LYAddPathToHome(filename_buffer,
+		    sizeof(filename_buffer),
+		    BookmarkPage);
     if (TRACE)
         fprintf(stderr, "\nget_bookmark_filename: SEEKING %s\n   AS %s\n\n",
 		BookmarkPage, filename_buffer);
@@ -124,8 +137,12 @@ success:
 
 } /* big end */
 
+/*
+ *  Converts a Mosaic hotlist file into an HTML
+ *  file for handling as a Lynx bookmark file. - FM
+ */
 PRIVATE char * convert_mosaic_bookmark_file ARGS1(
-	char *,	filename_buffer)
+	char *,		filename_buffer)
 {
     static char newfile[256];
     static BOOLEAN first = TRUE;
@@ -144,7 +161,7 @@ PRIVATE char * convert_mosaic_bookmark_file ARGS1(
     }
 
     if ((nfp = fopen(newfile, "w")) == NULL) {
-	_statusline(NO_TEMP_FOR_HOTLIST);
+        LYMBM_statusline(NO_TEMP_FOR_HOTLIST);
 	sleep(AlertSecs);
 	return ("");
     }
@@ -181,87 +198,130 @@ PRIVATE char * convert_mosaic_bookmark_file ARGS1(
     return(newfile);
 }
 
+/*
+ *  Adds a link to a bookmark file, creating the file
+ *  if it doesn't already exist, and making sure that
+ *  no_cache is set for a pre-existing, cached file,
+ *  so that the change will be evident on return to
+ *  to that file. - FM
+ */
 PUBLIC void save_bookmark_link ARGS2(
-	char *,	address,
-	char *,	title)
+	char *,		address,
+	char *,		title)
 {
     FILE *fp;
     BOOLEAN first_time = FALSE;
     char *filename;
     char *bookmark_URL = NULL;
     char filename_buffer[256];
+    char string_buffer[256];
     char *Address = NULL;
     char *Title = NULL;
+    int i, c;
+    DocAddress WWWDoc;
+    HTParentAnchor *tmpanchor;
+    HText *text;
 
+    /*
+     *  Make sure we were passed something to save. - FM
+     */
     if (!(address && *address)) {
         HTAlert(MALFORMED_ADDRESS);
 	return;
     }
 
+    /*
+     *  Offer a choice of bookmark files,
+     *  or get the default. - FMG
+     */
     filename = get_bookmark_filename(&bookmark_URL);
 
     /*
-     *  If filename is a space, invalid bookmark
-     *  file was selected.  If zero-length, user
-     *  cancelled.  Ignore request in both cases!
+     *  If filename is NULL, must create a new file.  If
+     *  filename is a space, an invalid bookmark file was
+     *  selected, or if zero-length, the user cancelled.
+     *  Ignore request in both cases.  Otherwise, make
+     *  a copy before anything might change the static
+     *  get_bookmark_filename() buffer. - FM
      */
-    if (filename)
-      if (*filename == '\0' || !strcmp(filename," "))
-	return;
+    if (filename == NULL) {
+        first_time = TRUE;
+	filename_buffer[0] = '\0';
+    } else {
+        if (*filename == '\0' || !strcmp(filename," ")) {
+	    FREE(bookmark_URL);
+	    return;
+	}
+	strcpy(filename_buffer, filename);
+    }
+
     /*
-     *  If BookmarkPage didn't get loaded, something
-     *  went wrong, so ignore the request.
+     *  If BookmarkPage is NULL, something went
+     *  wrong, so ignore the request. - FM
      */
-    if (!BookmarkPage)
+    if (BookmarkPage == NULL) {
+        FREE(bookmark_URL);
 	return;
+    }
 
-     /*
-      *  We don't need the full URL.
-      */
-    FREE(bookmark_URL);
+    /*
+     *  If the link will be added to the same
+     *  bookmark file, get confirmation. - FM
+     */
+    if (LYMultiBookmarks == TRUE &&
+        strstr(HTLoadedDocumentURL(),
+    	       (*BookmarkPage == '.' ?
+	            (BookmarkPage+1) : BookmarkPage)) != NULL) {
+	LYMBM_statusline(MULTIBOOKMARKS_SELF);
+	c = LYgetch();
+	if (TOUPPER(c) != 'L') {
+	    FREE(bookmark_URL);
+	    return;
+	}
+    }
 
     /*
      *  Allow user to change the title. - FM
      */
-    filename_buffer[255] = '\0';
-    LYstrncpy(filename_buffer, title, 255);
-    convert_to_spaces(filename_buffer);
-    _statusline(TITLE_PROMPT); 
-    LYgetstr(filename_buffer, VISIBLE, sizeof(filename_buffer), NORECALL);
-    if (*filename_buffer == '\0') {
-	_statusline(CANCELLED);
+    string_buffer[255] = '\0';
+    LYstrncpy(string_buffer, title, 255);
+    convert_to_spaces(string_buffer);
+    LYMBM_statusline(TITLE_PROMPT);
+    LYgetstr(string_buffer, VISIBLE, sizeof(string_buffer), NORECALL);
+    if (*string_buffer == '\0') {
+	LYMBM_statusline(CANCELLED);
 	sleep(MessageSecs);
+	FREE(bookmark_URL);
 	return;
     }
 
     /*
-     *  Create the Title with any left-angle-brackets converted to &lt;
-     *  entities and any ampersands converted to &amp; entities.  - FM
+     *  Create the Title with any left-angle-brackets
+     *  converted to &lt; entities and any ampersands
+     *  converted to &amp; entities.  - FM
      */
-    StrAllocCopy(Title, filename_buffer);
+    StrAllocCopy(Title, string_buffer);
     LYEntify(&Title, TRUE);
 
     /*
-     *  Open the bookmark file. - FM
+     *  Create the bookmark file, if it doesn't exist already,
+     *  Otherwise, open the pre-existing bookmark file. - FM
      */
-    if (filename == NULL)
-	first_time = TRUE;
-    /*
-     *  Try in the home directory.
-     */
-#ifdef VMS
-    LYVMS_HomePathAndFilename(filename_buffer,
-			      sizeof(filename_buffer),
-			      BookmarkPage);
-#else
-    sprintf(filename_buffer, "%s/%s", Home_Dir(), BookmarkPage);
-#endif /* VMS */
+    if (first_time) {
+        /*
+	 *  Seek it in the home path. - FM
+	 */
+	LYAddPathToHome(filename_buffer,
+			sizeof(filename_buffer),
+			BookmarkPage);
+    }
     if (TRACE)
         fprintf(stderr, "\nsave_bookmark_link: SEEKING %s\n   AS %s\n\n",
 		BookmarkPage, filename_buffer);
     if ((fp = fopen(filename_buffer, (first_time ? "w" : "a+"))) == NULL) {
-	_statusline(BOOKMARK_OPEN_FAILED);
+	LYMBM_statusline(BOOKMARK_OPEN_FAILED);
 	sleep(AlertSecs);
+	FREE(bookmark_URL);
 	return;
     }
 
@@ -300,15 +360,51 @@ PUBLIC void save_bookmark_link ARGS2(
     } else {
 	fprintf(fp,"<LI><a href=\"%s\">%s</a>\n", Address, Title);
     }
-
     fclose(fp);
+
+    /*
+     *  If this is a cached bookmark file, set nocache for
+     *  it so we'll see the new bookmark link when that
+     *  cache is retrieved. - FM
+     */
+    if (!first_time && nhist > 0 && bookmark_URL) {
+    	for (i = 0; i < nhist; i++) {
+	    if (history[i].bookmark &&
+	    	!strcmp(history[i].address, bookmark_URL)) {
+		WWWDoc.address = history[i].address;
+		WWWDoc.post_data = NULL;
+		WWWDoc.post_content_type = NULL;
+		WWWDoc.bookmark = history[i].bookmark;
+		WWWDoc.isHEAD = FALSE;
+		WWWDoc.safe = FALSE;
+		if (((tmpanchor = HTAnchor_parent(
+					HTAnchor_findAddress(&WWWDoc)
+				    		 )) != NULL) &&
+		    (text = (HText *)HTAnchor_document(tmpanchor)) != NULL) {
+		    HText_setNoCache(text);
+		}
+		break;
+	    }
+	}
+    }
+
+    /*
+     *  Clean up and report success.
+     */
     FREE(Title);
     FREE(Address);
-
-    _statusline(OPERATION_DONE);
+    FREE(bookmark_URL);
+    LYMBM_statusline(OPERATION_DONE);
     sleep(MessageSecs);
 }
 	
+/*
+ *  Remove a link from a bookmark file.  The calling
+ *  function is expected to have used get_filename_link(),
+ *  pass us the link number as cur, the MBM_A_subbookmark[]
+ *  string as cur_bookmark_page, and to have set up no_cache
+ *  itself. - FM
+ */
 PUBLIC void remove_bookmark_link ARGS2(
 	int,		cur,
 	char *,		cur_bookmark_page)
@@ -332,13 +428,9 @@ PUBLIC void remove_bookmark_link ARGS2(
 
     if (!cur_bookmark_page)
 	return;
-#ifdef VMS
-    LYVMS_HomePathAndFilename(filename_buffer,
-			      sizeof(filename_buffer),
-			      cur_bookmark_page);
-#else
-    sprintf(filename_buffer,"%s/%s", Home_Dir(), cur_bookmark_page);
-#endif /* VMS */
+    LYAddPathToHome(filename_buffer,
+		    sizeof(filename_buffer),
+		    cur_bookmark_page);
     if (TRACE)
         fprintf(stderr, "\nremove_bookmark_link: SEEKING %s\n   AS %s\n\n",
 		cur_bookmark_page, filename_buffer);
@@ -407,7 +499,7 @@ PUBLIC void remove_bookmark_link ARGS2(
 		seen++;
                 if (++n == cur) {
 		    if (seen != 1 || !LYstrstr(buf, "</a>") ||
-			LYstrstr(cp+1, "<a href=")) {
+			LYstrstr((cp + 1), "<a href=")) {
 			_statusline(BOOKMARK_LINK_NOT_ONE_LINE);
 			sleep(AlertSecs);
 			goto failure;
@@ -507,13 +599,7 @@ PUBLIC int select_multi_bookmarks NOARGS
      *  still show the screen and let them do it the "long" way.
      */
     if (LYMBMAdvanced && user_mode == ADVANCED_MODE) {
-	move(LYlines-1, 0);
-	clrtoeol();
-	start_reverse();
-	addstr("Select subbookmark, '=' for menu, or ^G to cancel: ");
-	stop_reverse();
-	refresh();
-
+	LYMBM_statusline(MULTIBOOKMARKS_SELECT);
 get_advanced_choice:
 	c = LYgetch();
 #ifdef VMS
@@ -581,6 +667,7 @@ PUBLIC int select_menu_multi_bookmarks NOARGS
     int c, MBM_counter, MBM_tmp_count, MBM_allow;
     int MBM_screens, MBM_from, MBM_to, MBM_current;
     char string_buffer[256];
+    char shead_buffer[256];
     char *cp, *cp1;
 
     /*
@@ -626,7 +713,7 @@ PUBLIC int select_menu_multi_bookmarks NOARGS
 	return (-2);
     }
     /*
-     *  Load the bad choice message.
+     *  Load the bad choice message buffer.
      */
     sprintf(string_buffer,
     	    BOOKMARK_FILE_NOT_DEFINED,
@@ -648,29 +735,36 @@ draw_bookmark_choices:
 	MBM_to = MBM_V_MAXFILES;
 
     /*
-     * Display menu of bookmarks.
+     *  Display menu of bookmarks.  NOTE that we avoid printw()'s
+     *  to increase the chances that any non-ASCII or multibyte/CJK
+     *  characters will be handled properly. - FM
      */
     clear();
     move(1, 5);
     if (bold_H1 || bold_headers)
 	start_bold();
-    if (MBM_screens > 1)
-	printw(" Select Bookmark (screen %d of %d)", MBM_current, MBM_screens);
-    else
-	printw("       Select Bookmark");
+    if (MBM_screens > 1) {
+        sprintf(shead_buffer,
+		MULTIBOOKMARKS_SHEAD_MASK, MBM_current, MBM_screens);
+	addstr(shead_buffer);
+    } else {
+        addstr(MULTIBOOKMARKS_SHEAD);
+    }
     if (bold_H1 || bold_headers)
 	stop_bold();
 
     MBM_tmp_count = 0;
     for (c = MBM_from; c <= MBM_to; c++) {
 	move(3+MBM_tmp_count, 5);
-	printw("%c : %s",(c+'A'),
-	       (!MBM_A_subdescript[c] ? "" : MBM_A_subdescript[c]));
-
+	addch((unsigned char)(c + 'A'));
+	addstr(" : ");
+	if (MBM_A_subdescript[c])
+	    addstr(MBM_A_subdescript[c]);
 	move(3+MBM_tmp_count,36);
-	printw("(%s)",
-	       (!MBM_A_subbookmark[c] ? "" : MBM_A_subbookmark[c]));
-
+	addch('(');
+	if (MBM_A_subbookmark[c])
+	    addstr(MBM_A_subbookmark[c]);
+	addch(')');
 	MBM_tmp_count++;
     }
 
@@ -679,16 +773,21 @@ draw_bookmark_choices:
      */
     if (MBM_screens > 1) {
 	move(LYlines-2, 0);
-	addstr(MULTIBOOKMARKS_MOVE);
+	addstr("'");
+	standout();
+	addstr("[");
+	standend();
+	addstr("' ");
+	addstr(PREVIOUS);
+	addstr(", '");
+	standout();
+	addstr("]");
+	standend();
+	addstr("' ");
+	addstr(NEXT_SCREEN);
     }
 
-    move(LYlines-1, 0);
-    clrtoeol();
-    start_reverse();
-    addstr(MULTIBOOKMARKS_SAVE);
-    stop_reverse();
-    refresh();
-
+    LYMBM_statusline(MULTIBOOKMARKS_SAVE);
 get_bookmark_choice:
     c = LYgetch();
 #ifdef VMS
@@ -749,19 +848,9 @@ get_bookmark_choice:
     if (c < 0 || c > MBM_V_MAXFILES) {
 	goto get_bookmark_choice;
     } else if (!MBM_A_subbookmark[c]) {
-	move(LYlines-1, 0);
-	clrtoeol();
-	start_reverse();
- 	addstr(string_buffer);
-	stop_reverse();
-	refresh();
+ 	LYMBM_statusline(string_buffer);
 	sleep(AlertSecs);
-	move(LYlines-1, 0);
-	clrtoeol();
-	start_reverse();
-	addstr(MULTIBOOKMARKS_SAVE);
-	stop_reverse();
-	refresh();
+	LYMBM_statusline(MULTIBOOKMARKS_SAVE);
 	goto get_bookmark_choice;
     } else {
 	return(c);
@@ -784,3 +873,23 @@ PUBLIC BOOLEAN LYHaveSubBookmarks NOARGS
 
     return(FALSE);
 }
+
+/*
+ *  This function passes a string to _statusline(), making
+ *  sure it is at the bottom of the screen if LYMultiBookmarks
+ *  is TRUE, otherwise, letting it go to the normal statusline
+ *  position based on the current user mode.  We want to use
+ *  _statusline() so that any multibyte/CJK characters in the
+ *  string will be handled properly. - FM
+ */
+ PUBLIC void LYMBM_statusline  ARGS1(
+ 	char *,		text)
+{
+    if (LYMultiBookmarks == TRUE && user_mode == NOVICE_MODE) {
+	LYStatusLine = (LYlines - 1);
+        _statusline(text);
+	LYStatusLine = -1;
+    } else {
+        _statusline(text);
+    }
+}
diff --git a/src/LYBookmark.h b/src/LYBookmark.h
index 41f54c6b..a776a81a 100644
--- a/src/LYBookmark.h
+++ b/src/LYBookmark.h
@@ -12,8 +12,7 @@ extern void remove_bookmark_link PARAMS((int cur, char *cur_bookmark_page));
 extern int select_multi_bookmarks NOPARAMS;
 extern int select_menu_multi_bookmarks NOPARAMS;
 extern BOOLEAN LYHaveSubBookmarks NOPARAMS;
-
-extern void edit_bookmarks NOPARAMS; /* in LYOptions.c */
+extern void LYMBM_statusline PARAMS((char *text));
 
 #define BOOKMARK_TITLE "Bookmark file"
 #define MOSAIC_BOOKMARK_TITLE "Converted Mosaic Hotlist"
diff --git a/src/LYCgi.c b/src/LYCgi.c
index 9a81fadb..de6293ec 100644
--- a/src/LYCgi.c
+++ b/src/LYCgi.c
@@ -296,14 +296,19 @@ PUBLIC int LYLoadCGI ARGS4(
 		char post_len[32];
 		int argv_cnt = 3; /* name, one arg and terminator */
 		char **cur_argv = NULL;
+		char buf[BUFSIZ];
 
 		/* Set up output pipe */
 		close(fd2[0]);
 		dup2(fd2[1], fileno(stdout)); /* Should check success code */
 		dup2(fd2[1], fileno(stderr));
 		close(fd2[1]);
-		
-		
+
+		sprintf(buf, "HTTP_ACCEPT_LANGUAGE=%.*s",
+			     (sizeof(buf) - 22), language);
+		buf[(sizeof(buf) - 1)] = '\0';
+		add_environment_value(buf);
+
 		if (anAnchor->post_data) { /* post script, read stdin */
 		    close(fd1[1]);
 		    dup2(fd1[0], fileno(stdin));
diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c
index 18aa65d0..5b6b94dd 100644
--- a/src/LYCharUtils.c
+++ b/src/LYCharUtils.c
@@ -1,22 +1,39 @@
 /*
-** Functions associated with LYCharSets.c and the Lynx version of HTML.c - FM
-** ==========================================================================
-**
-** These functions should be prototyped in the Lynx version of HTML.c.
+**  Functions associated with LYCharSets.c and the Lynx version of HTML.c - FM
+**  ==========================================================================
 */
 #include "HTUtils.h"
 #include "tcp.h"
 
+#define Lynx_HTML_Handler
+#include "HTChunk.h"
+#include "HText.h"
+#include "HTStyle.h"
 #include "HTML.h"
-#include "HTFont.h"
+
 #include "HTCJK.h"
+#include "HTAtom.h"
+#include "HTMLGen.h"
 #include "HTParse.h"
 
 #include "LYGlobalDefs.h"
-#include "LYCharSets.h"
 #include "LYCharUtils.h"
-#include "LYUtils.h"
+#include "LYCharSets.h"
+
+#include "HTAlert.h"
+#include "HTFont.h"
+#include "HTForms.h"
+#include "HTNestedList.h"
 #include "GridText.h"
+#include "LYSignal.h"
+#include "LYUtils.h"
+#include "LYMap.h"
+#include "LYBookmark.h"
+
+#ifdef VMS
+#include "LYCurses.h"
+#include "HTVMSUtils.h"
+#endif /* VMS */
 
 #include "LYexit.h"
 #include "LYLeaks.h"
@@ -30,6 +47,16 @@ extern BOOL HTPassHighCtrlNum;
 extern HTkcode kanji_code;
 extern HTCJKlang HTCJK;
 
+extern void LYSetCookie PARAMS((
+	CONST char *	header,
+	CONST char *	address));
+
+/*
+ *  Used for nested lists. - FM
+ */
+PUBLIC int OL_CONTINUE = -29999;     /* flag for whether CONTINUE is set */
+PUBLIC int OL_VOID = -29998;	     /* flag for whether a count is set */
+
 
 /*
 **  This function converts HTML named entities within a string
@@ -787,7 +814,6 @@ PUBLIC void LYUnEscapeToLatinOne ARGS2(
         StrAllocCopy(*str, url);
 	FREE(url);
     }
-    return;
 }
 
 /*
@@ -868,7 +894,6 @@ PUBLIC void LYExpandString ARGS1(
     }
     StrAllocCat(*str, q);
     free_and_clear(&p);
-    return;
 }
 
 /*
@@ -952,8 +977,6 @@ PUBLIC void LYEntify ARGS2(
 	}
     }
     StrAllocCopy(*str, cp);
-
-    return;
 }
 
 /*
@@ -977,8 +1000,6 @@ PUBLIC void LYTrimHead ARGS1(
 	}
 	str[j] = '\0';
     }
-    
-    return;
 }
 
 /*
@@ -1002,8 +1023,6 @@ PUBLIC void LYTrimTail ARGS1(
 	    break;
 	i--;
     }
-
-    return;
 }
 
 /*
@@ -1117,6 +1136,78 @@ PUBLIC char *LYFindEndOfComment ARGS1(
 }
 
 /*
+**  If an HREF, itself or if resolved against a base,
+**  represents a file URL, and the host is defaulted,
+**  force in "//localhost".  We need this until
+**  all the other Lynx code which performs security
+**  checks based on the "localhost" string is changed
+**  to assume "//localhost" when a host field is not
+**  present in file URLs - FM
+*/
+PUBLIC void LYFillLocalFileURL ARGS2(
+	char **,	href,
+	char *,		base)
+{
+    char * temp = NULL;
+
+    if (*href == NULL || *(*href) == '\0')
+        return;
+
+    if (!strcmp(*href, "//") || !strncmp(*href, "///", 3)) {
+	if (base != NULL && !strncmp(base, "file:", 5)) {
+	    StrAllocCopy(temp, "file:");
+	    StrAllocCat(temp, *href);
+	    StrAllocCopy(*href, temp);
+	}
+    }
+    if (!strncmp(*href, "file:", 5)) {
+	if (*(*href+5) == '\0') {
+	    StrAllocCat(*href, "//localhost");
+	} else if (!strcmp(*href, "file://")) {
+	    StrAllocCat(*href, "localhost");
+	} else if (!strncmp(*href, "file:///", 8)) {
+	    StrAllocCopy(temp, (*href+7));
+	    StrAllocCopy(*href, "file://localhost");
+	    StrAllocCat(*href, temp);
+	} else if (!strncmp(*href, "file:/", 6) && *(*href+6) != '/') {
+	    StrAllocCopy(temp, (*href+5));
+	    StrAllocCopy(*href, "file://localhost");
+	    StrAllocCat(*href, temp);
+	}
+    }
+
+    /*
+     * No path in a file://localhost URL means a
+     * directory listing for the current default. - FM
+     */
+    if (!strcmp(*href, "file://localhost")) {
+#ifdef VMS
+	StrAllocCat(*href, HTVMS_wwwName(getenv("PATH")));
+#else
+	char curdir[DIRNAMESIZE];
+#ifdef NO_GETCWD
+	getwd (curdir);
+#else
+	getcwd (curdir, DIRNAMESIZE);
+#endif /* NO_GETCWD */
+	StrAllocCat(*href, curdir);
+#endif /* VMS */
+    }
+
+#ifdef VMS
+    /*
+     * On VMS, a file://localhost/ URL means
+     * a listing for the login directory. - FM
+     */
+    if (!strcmp(*href, "file://localhost/"))
+	StrAllocCat(*href, (HTVMS_wwwName((char *)Home_Dir())+1));
+#endif /* VMS */
+
+    FREE(temp);
+    return;
+}
+
+/*
 ** This function returns OL TYPE="A" strings in
 ** the range of " A." (1) to "ZZZ." (18278). - FM
 */
@@ -1448,3 +1539,748 @@ PUBLIC char *LYLowercaseI_OL_String ARGS1(
     return OLstring;
 }
 
+/*
+**  This function initializes the Ordered List counter. - FM
+*/
+PUBLIC void LYZero_OL_Counter ARGS1(
+	HTStructured *, 	me)
+{
+    int i;
+
+    if (!me)
+        return;
+
+    for (i = 0; i < 7; i++) {
+        me->OL_Counter[i] = OL_VOID;
+	me->OL_Type[i] = '1';
+    }
+	
+    me->Last_OL_Count = 0;
+    me->Last_OL_Type = '1';
+    
+    return;
+}
+
+/*
+**  This function processes META tags in HTML streams. - FM
+*/
+PUBLIC void LYHandleMETA ARGS4(
+	HTStructured *, 	me,
+	CONST BOOL*,	 	present,
+	CONST char **,		value,
+	char **,		include)
+{
+    char *http_equiv = NULL, *name = NULL, *content = NULL;
+    char *href = NULL, *id_string = NULL, *temp = NULL;
+    char *cp, *cp0, *cp1;
+    int url_type = 0, i;
+
+    if (!me || !present)
+        return;
+
+    /*
+     *  Load the attributes for possible use by Lynx. - FM
+     */
+    if (present[HTML_META_HTTP_EQUIV] &&
+	value[HTML_META_HTTP_EQUIV] && *value[HTML_META_HTTP_EQUIV]) {
+	StrAllocCopy(http_equiv, value[HTML_META_HTTP_EQUIV]);
+	convert_to_spaces(http_equiv);
+	LYUnEscapeToLatinOne(&http_equiv, FALSE);
+	LYTrimHead(http_equiv);
+	LYTrimTail(http_equiv);
+	if (*http_equiv == '\0') {
+	    FREE(http_equiv);
+	}
+    }
+    if (present[HTML_META_NAME] &&
+	value[HTML_META_NAME] && *value[HTML_META_NAME]) {
+	StrAllocCopy(name, value[HTML_META_NAME]);
+	convert_to_spaces(name);
+	LYUnEscapeToLatinOne(&name, FALSE);
+	LYTrimHead(name);
+	LYTrimTail(name);
+	if (*name == '\0') {
+	    FREE(name);
+	}
+    }
+    if (present[HTML_META_CONTENT] &&
+	value[HTML_META_CONTENT] && *value[HTML_META_CONTENT]) {
+	/*
+	 *  Technically, we should be creating a comma-separated
+	 *  list, but META tags come one at a time, and we'll
+	 *  handle (or ignore) them as each is received.  Also,
+	 *  at this point, we only trim leading and trailing
+	 *  blanks from the CONTENT value, without translating
+	 *  any named entities or numeric character references,
+	 *  because how we should do that depends on what type
+	 *  of information it contains, and whether or not any
+	 *  of it might be sent to the screen. - FM
+	 */
+	StrAllocCopy(content, value[HTML_META_CONTENT]);
+	convert_to_spaces(content);
+	LYTrimHead(content);
+	LYTrimTail(content);
+	if (*content == '\0') {
+	    FREE(content);
+	}
+    }
+    if (TRACE) {
+	fprintf(stderr,
+	        "LYHandleMETA: HTTP-EQUIV=\"%s\" NAME=\"%s\" CONTENT=\"%s\"\n",
+		(http_equiv ? http_equiv : "NULL"),
+		(name ? name : "NULL"),
+		(content ? content : "NULL"));
+    }
+
+    /*
+     *  Make sure we have META name/value pairs to handle. - FM
+     */
+    if (!(http_equiv || name) || !content)
+        goto free_META_copies;
+		
+    /*
+     * Check for a no-cache Pragma
+     * or Cache-Control directive. - FM
+     */
+    if (!strcasecomp((name ? name : http_equiv), "Pragma") ||
+        !strcasecomp((name ? name : http_equiv), "Cache-Control")) {
+	LYUnEscapeToLatinOne(&content, FALSE);
+	LYTrimHead(content);
+	LYTrimTail(content);
+	if (!strcasecomp(content, "no-cache")) {
+	    me->node_anchor->no_cache = TRUE;
+	    HText_setNoCache(me->text);
+	}
+
+	/*
+	 *  If we didn't get a Cache-Control MIME header,
+	 *  and the META has one, convert to lowercase,
+	 *  store it in the anchor element, and if we
+	 *  haven't yet set no_cache, check whether we
+	 *  should. - FM
+	 */
+	if ((!me->node_anchor->cache_control) &&
+	    !strcasecomp((name ? name : http_equiv), "Cache-Control")) {
+	    for (i = 0; content[i]; i++)
+		 content[i] = TOLOWER(content[i]);
+	    StrAllocCopy(me->node_anchor->cache_control, content);
+	    if (me->node_anchor->no_cache == FALSE) {
+	        cp0 = content;
+		while ((cp = strstr(cp0, "no-cache")) != NULL) {
+		    cp += 8;
+		    while (*cp != '\0' && WHITE(*cp))
+			cp++;
+		    if (*cp == '\0' || *cp == ';') {
+			me->node_anchor->no_cache = TRUE;
+			HText_setNoCache(me->text);
+			break;
+		    }
+		    cp0 = cp;
+		}
+		if (me->node_anchor->no_cache == TRUE)
+		    goto free_META_copies;
+		cp0 = content;
+		while ((cp = strstr(cp0, "max-age")) != NULL) {
+		    cp += 7;
+		    while (*cp != '\0' && WHITE(*cp))
+			cp++;
+		    if (*cp == '=') {
+			cp++;
+			while (*cp != '\0' && WHITE(*cp))
+			    cp++;
+			if (isdigit((unsigned char)*cp)) {
+			    cp0 = cp;
+			    while (isdigit((unsigned char)*cp))
+				cp++;
+			    if (*cp0 == '0' && cp == (cp0 + 1)) {
+			        me->node_anchor->no_cache = TRUE;
+				HText_setNoCache(me->text);
+				break;
+			    }
+			}
+		    }
+		    cp0 = cp;
+		}
+	    }
+	}
+
+    /*
+     * Check for an Expires directive. - FM
+     */
+    } else if (!strcasecomp((name ? name : http_equiv), "Expires")) {
+	/*
+	 *  If we didn't get a Expires MIME header,
+	 *  store it in the anchor element, and if we
+	 *  haven't yet set no_cache, check whether we
+	 *  should. - FM
+	 */
+	LYUnEscapeToLatinOne(&content, FALSE);
+	LYTrimHead(content);
+	LYTrimTail(content);
+	StrAllocCopy(me->node_anchor->expires, content);
+	if (me->node_anchor->no_cache == FALSE) {
+	    if ((content[0] == '0' && content[1] == '\0') ||
+		LYmktime(content) <= 0) {
+		me->node_anchor->no_cache = TRUE;
+		HText_setNoCache(me->text);
+	    }
+	}
+
+    /*
+     *  Check for a text/html Content-Type with a
+     *  charset directive, if we didn't already set
+     *  the charset via a server's header. - AAC & FM
+     */
+    } else if (!(me->node_anchor->charset && *me->node_anchor->charset) && 
+	       !strcasecomp((name ? name : http_equiv), "Content-Type")) {
+	LYUnEscapeToLatinOne(&content, FALSE);
+	LYTrimHead(content);
+	LYTrimTail(content);
+	/*
+	 *  Force the Content-type value to all lower case. - FM
+	 */
+	for (cp = content; *cp; cp++)
+	    *cp = TOLOWER(*cp);
+
+	if ((cp = strstr(content, "text/html;")) != NULL &&
+	    (cp1 = strstr(content, "charset")) != NULL &&
+	    cp1 > cp) {
+	    cp1 += 7;
+	    while (*cp1 == ' ' || *cp1 == '=')
+	        cp1++;
+
+	    if (!strncmp(cp1, "us-ascii", 8) ||
+		!strncmp(cp1, "iso-8859-1", 10)) {
+		StrAllocCopy(me->node_anchor->charset, "iso-8859-1");
+		HTCJK = NOCJK;
+
+	    } else if (!strncmp(cp1, "iso-8859-2", 10) &&
+		       !strncmp(LYchar_set_names[current_char_set],
+				"ISO Latin 2", 11)) {
+		StrAllocCopy(me->node_anchor->charset, "iso-8859-2");
+		HTPassEightBitRaw = TRUE;
+
+	    } else if (!strncmp(cp1, "iso-8859-", 9) &&
+		       !strncmp(LYchar_set_names[current_char_set],
+				"Other ISO Latin", 15)) {
+		/*
+		 *  Hope it's a match, for now. - FM
+		 */
+		StrAllocCopy(me->node_anchor->charset, "iso-8859- ");
+		me->node_anchor->charset[9] = cp1[9];
+		HTPassEightBitRaw = TRUE;
+		HTAlert(me->node_anchor->charset);
+
+	    } else if (!strncmp(cp1, "koi8-r", 6) &&
+		       !strncmp(LYchar_set_names[current_char_set],
+				"KOI8-R character set", 20)) {
+		StrAllocCopy(me->node_anchor->charset, "koi8-r");
+		HTPassEightBitRaw = TRUE;
+
+	    } else if (!strncmp(cp1, "euc-jp", 6) && HTCJK == JAPANESE) {
+		StrAllocCopy(me->node_anchor->charset, "euc-jp");
+
+	    } else if (!strncmp(cp1, "shift_jis", 9) && HTCJK == JAPANESE) {
+		StrAllocCopy(me->node_anchor->charset, "shift_jis");
+
+	    } else if (!strncmp(cp1, "iso-2022-jp", 11) &&
+	    			HTCJK == JAPANESE) {
+		StrAllocCopy(me->node_anchor->charset, "iso-2022-jp");
+
+	    } else if (!strncmp(cp1, "iso-2022-jp-2", 13) &&
+	    			HTCJK == JAPANESE) {
+		StrAllocCopy(me->node_anchor->charset, "iso-2022-jp-2");
+
+	    } else if (!strncmp(cp1, "euc-kr", 6) && HTCJK == KOREAN) {
+		StrAllocCopy(me->node_anchor->charset, "euc-kr");
+
+	    } else if (!strncmp(cp1, "iso-2022-kr", 11) && HTCJK == KOREAN) {
+		StrAllocCopy(me->node_anchor->charset, "iso-2022-kr");
+
+	    } else if ((!strncmp(cp1, "big5", 4) ||
+			!strncmp(cp1, "cn-big5", 7)) &&
+		       HTCJK == TAIPEI) {
+		StrAllocCopy(me->node_anchor->charset, "big5");
+
+	    } else if (!strncmp(cp1, "euc-cn", 6) && HTCJK == CHINESE) {
+		StrAllocCopy(me->node_anchor->charset, "euc-cn");
+
+	    } else if ((!strncmp(cp1, "gb2312", 6) ||
+			!strncmp(cp1, "cn-gb", 5)) &&
+		       HTCJK == CHINESE) {
+		StrAllocCopy(me->node_anchor->charset, "gb2312");
+
+	    } else if (!strncmp(cp1, "iso-2022-cn", 11) && HTCJK == CHINESE) {
+		StrAllocCopy(me->node_anchor->charset, "iso-2022-cn");
+	    }
+
+	    if (TRACE && me->node_anchor->charset) {
+		fprintf(stderr,
+			"HTML: New charset: %s\n",
+			me->node_anchor->charset);
+	    }
+	}
+	/*
+	 *  Set the kcode element based on the charset. - FM
+	 */
+	HText_setKcode(me->text, me->node_anchor->charset);
+
+    /*
+     *  Check for a Refresh directive. - FM
+     */
+    } else if (!strcasecomp((name ? name : http_equiv), "Refresh")) {
+	char *Seconds = NULL;
+
+	/*
+	 *  Look for the Seconds field. - FM
+	 */
+	cp = content;
+	while (*cp && isspace((unsigned char)*cp))
+	    cp++;
+	if (*cp && isdigit(*cp)) {
+	    cp1 = cp;
+	    while (*cp1 && isdigit(*cp1))
+		cp1++;
+	    *cp1 = '\0';
+	    StrAllocCopy(Seconds, cp);
+	    cp1++;
+	}
+	if (Seconds) {
+	    /*
+	     *  We have the seconds field.
+	     *  Now look for a URL field - FM
+	     */
+	    while (*cp1) {
+		if (!strncasecomp(cp1, "URL", 3)) {
+		    cp = (cp1 + 3);
+		    while (*cp && (*cp == '=' || isspace((unsigned char)*cp)))
+			cp++;
+		    cp1 = cp;
+		    while (*cp1 && !isspace((unsigned char)*cp1))
+			cp1++;
+		    *cp1 = '\0';
+		    if (*cp)
+			StrAllocCopy(href, cp);
+		    break;
+		}
+		cp1++;
+	    }
+	    if (href) {
+		/*
+		 *  We found a URL field, so check it out. - FM
+		 */
+		if (!(url_type = LYLegitimizeHREF(me, (char**)&href, TRUE))) {
+		    /*
+		     *  The specs require a complete URL,
+		     *  but this is a Netscapism, so don't
+		     *  expect the author to know that. - FM
+		     */
+		    HTAlert(REFRESH_URL_NOT_ABSOLUTE);
+		    /*
+		     *  Use the document's address
+		     *  as the base. - FM
+		     */
+		    if (*href != '\0') {
+			temp = HTParse(href,
+				       me->node_anchor->address, PARSE_ALL);
+			StrAllocCopy(href, temp);
+			FREE(temp);
+		    } else {
+			StrAllocCopy(href, me->node_anchor->address);
+			HText_setNoCache(me->text);
+		    }
+		}
+		/*
+		 *  Check whether to fill in localhost. - FM
+		 */
+		LYFillLocalFileURL((char **)&href,
+				   (me->inBASE ?
+				 me->base_href : me->node_anchor->address));
+		/*
+		 *  Set the no_cache flag if the Refresh URL
+		 *  is the same as the document's address. - FM
+		 */
+		if (!strcmp(href, me->node_anchor->address)) {
+		    HText_setNoCache(me->text);
+		} 
+	    } else {
+		/*
+		 *  We didn't find a URL field, so use
+		 *  the document's own address and set
+		 *  the no_cache flag. - FM
+		 */
+		StrAllocCopy(href, me->node_anchor->address);
+		HText_setNoCache(me->text);
+	    }
+	    /*
+	     *  Check for an anchor in http or https URLs. - FM
+	     */
+	    if ((strncmp(href, "http", 4) == 0) &&
+		(cp = strrchr(href, '#')) != NULL) {
+		StrAllocCopy(id_string, cp);
+		*cp = '\0';
+	    }
+	    me->CurrentA = HTAnchor_findChildAndLink(
+				me->node_anchor,	/* Parent */
+				id_string,		/* Tag */
+				href,			/* Addresss */
+				(void *)0);		/* Type */
+	    if (id_string)
+		*cp = '#';
+	    FREE(id_string);
+	    LYEnsureSingleSpace(me);
+	    if (me->inUnderline == FALSE)
+		HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
+	    HTML_put_string(me, "REFRESH(");
+	    HTML_put_string(me, Seconds);
+	    HTML_put_string(me, " sec):");
+	    FREE(Seconds);
+	    if (me->inUnderline == FALSE)
+		HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    HTML_put_character(me, ' ');
+	    me->in_word = NO;
+	    HText_beginAnchor(me->text, me->CurrentA);
+	    if (me->inBoldH == FALSE)
+		HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+	    HTML_put_string(me, href);
+	    FREE(href);
+	    if (me->inBoldH == FALSE)
+		HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+	    HText_endAnchor(me->text);
+	    LYEnsureSingleSpace(me);
+	}
+
+    /*
+     *  Check for a suggested filename via a Content-Disposition with
+     *  file; filename=name.suffix in it, if we don't already have it
+     *  via a server header. - FM
+     */
+    } else if (!(me->node_anchor->SugFname && *me->node_anchor->SugFname) &&
+    	       !strcasecomp((name ?
+    			     name : http_equiv), "Content-Disposition")) {
+	cp = content;
+	while (*cp != '\0' && strncasecomp(cp, "file;", 5))
+	    cp++;
+	if (*cp != '\0') {
+	    cp += 5;
+	    while (*cp != '\0' && WHITE(*cp))
+	        cp++;
+	    if (*cp != '\0') {
+	        while (*cp != '\0' && strncasecomp(cp, "filename=", 9))
+		    cp++;
+		if (*cp != '\0') {
+		    StrAllocCopy(me->node_anchor->SugFname, (cp + 9));
+		    cp = me->node_anchor->SugFname;
+		    while (*cp != '\0' && !WHITE(*cp))
+			cp++;
+		    *cp = '\0';
+		    if (*me->node_anchor->SugFname == '\0')
+		        FREE(me->node_anchor->SugFname);
+		}
+	    }
+	}
+    /*
+     *  Check for a Set-Cookie directive. - AK
+     */
+    } else if (!strcasecomp((name ? name : http_equiv), "Set-Cookie")) {
+	/*
+	 *  We're using the Request-URI as the second argument,
+	 *  regardless of whether a Content-Base header or BASE
+	 *  tag are present.
+	 */
+	LYSetCookie(content, me->node_anchor->address);
+    }
+
+    /*
+     *  Free the copies. - FM
+     */
+free_META_copies:
+    FREE(http_equiv);
+    FREE(name);
+    FREE(content);
+}
+
+/*
+**  This function strips white characters and
+**  generally fixes up attribute values that
+**  were received from the SGML parser and
+**  are to be treated as partial or absolute
+**  URLs. - FM
+*/
+PUBLIC int LYLegitimizeHREF ARGS3(
+	HTStructured *, 	me,
+	char **,		href,
+	BOOL,			force_slash)
+{
+    int url_type = 0;
+
+    if (!me || !href || *href == NULL || *(*href) == '\0')
+        return(url_type);
+
+    collapse_spaces(*href);
+    LYUnEscapeToLatinOne(&(*href), TRUE);
+    url_type = is_url(*href);
+    if (!url_type && force_slash &&
+	(!strcmp(*href, ".") || !strcmp(*href, "..")) &&
+	 strncmp((me->inBASE ?
+	       me->base_href : me->node_anchor->address),
+		 "file:", 5)) {
+        /*
+	 *  The Fielding RFC/ID for resolving partial HREFs says
+	 *  that a slash should be on the end or the preceding
+	 *  symbolic element for "." and "..", but all tested
+	 *  browsers only do that for an explicit "./" or "../",
+	 *  so we'll respect the RFC/ID only if force_slash was
+	 *  TRUE and it's not a file URL. - FM
+	 */
+	StrAllocCat(*href, "/");
+    }
+    return(url_type); 
+}
+
+/*
+**  This function checks for a Content-Base header,
+**  and if not present, a Content-Location header
+**  which is an absolute URL, and sets the BASE
+**  accordingly.  If set, it will be replaced by
+**  any BASE tag in the HTML stream, itself. - FM
+*/
+PUBLIC void LYCheckForContentBase ARGS1(
+	HTStructured *,		me)
+{
+    char *cp = NULL;
+    BOOL present[HTML_BASE_ATTRIBUTES];
+    CONST char *value[HTML_BASE_ATTRIBUTES];
+    int i;
+
+    if (!(me && me->node_anchor))
+        return;
+
+    if (me->node_anchor->content_base != NULL) {
+        /*
+	 *  We have a Content-Base value.  Use it
+	 *  if it's non-zero length. - FM
+	 */
+        if (*me->node_anchor->content_base == '\0')
+	    return;
+	StrAllocCopy(cp, me->node_anchor->content_base);
+	collapse_spaces(cp);
+    } else if (me->node_anchor->content_location != NULL) {
+        /*
+	 *  We didn't have a Content-Base value, but do
+	 *  have a Content-Location value.  Use it if
+	 *  it's an absolute URL. - FM
+	 */
+        if (*me->node_anchor->content_location == '\0')
+	    return;
+	StrAllocCopy(cp, me->node_anchor->content_location);
+	collapse_spaces(cp);
+	if (!is_url(cp)) {
+	    FREE(cp);
+	    return;
+	}
+    } else {
+        /*
+	 *  We had neither a Content-Base nor
+	 *  Content-Location value. - FM
+	 */
+        return;
+    }
+
+    /*
+     *  If we collapsed to a zero-length value,
+     *  ignore it. - FM
+     */
+    if (*cp == '\0') {
+        FREE(cp);
+	return;
+    }
+
+    /*
+     *  Pass the value to HTML_start_element as
+     *  the HREF of a BASE tag. - FM
+     */
+    for (i = 0; i < HTML_BASE_ATTRIBUTES; i++)
+	 present[i] = NO;
+    present[HTML_BASE_HREF] = YES;
+    value[HTML_BASE_HREF] = (CONST char *)cp;
+    (*me->isa->start_element)(me, HTML_BASE, present, value, 0);
+    FREE(cp);
+}
+
+/*
+**  This function creates NAMEd Anchors if a non-zero-length NAME
+**  or ID attribute was present in the tag. - FM
+*/
+PUBLIC void LYCheckForID ARGS4(
+	HTStructured *,		me,
+	CONST BOOL *,		present,
+	CONST char **,		value,
+	int,			attribute)
+{
+    HTChildAnchor *ID_A = NULL;
+    char *temp = NULL;
+
+    if (!(me && me->text))
+        return;
+
+    if (present && present[attribute]
+	&& value[attribute] && *value[attribute]) {
+	/*
+	 *  Translate any named or numeric character references. - FM
+	 */
+	StrAllocCopy(temp, value[attribute]);
+	LYUnEscapeToLatinOne(&temp, TRUE);
+
+	/*
+	 *  Create the link if we still have a non-zero-length string. - FM
+	 */
+	if ((temp[0] != '\0') &&
+	    (ID_A = HTAnchor_findChildAndLink(
+				me->node_anchor,	/* Parent */
+				temp,			/* Tag */
+				NULL,			/* Addresss */
+				(void *)0))) {		/* Type */
+	    HText_beginAnchor(me->text, ID_A);
+	    HText_endAnchor(me->text);
+	}
+	FREE(temp);
+    }
+}
+
+/*
+**  This function creates a NAMEd Anchor for the ID string
+**  passed to it directly as an argument.  It assumes the
+**  does not need checking for character references. - FM
+*/
+PUBLIC void LYHandleID ARGS2(
+	HTStructured *,		me,
+	char *,			id)
+{
+    HTChildAnchor *ID_A = NULL;
+
+    if (!(me && me->text) ||
+        !(id && *id))
+        return;
+
+    /*
+     *  Create the link if we still have a non-zero-length string. - FM
+     */
+    if (ID_A = HTAnchor_findChildAndLink(
+				me->node_anchor,	/* Parent */
+				id,			/* Tag */
+				NULL,			/* Addresss */
+				(void *)0)) {		/* Type */
+	HText_beginAnchor(me->text, ID_A);
+	HText_endAnchor(me->text);
+    }
+}
+
+/*
+**  This function checks whether we want to overrride
+**  the current default alignment for parargraphs and
+**  instead use that specified in the element's style
+**  sheet. - FM
+*/
+PUBLIC BOOLEAN LYoverride_default_alignment ARGS1(
+	HTStructured *, me)
+{
+    if (!me)
+        return NO;
+
+    switch(me->sp[0].tag_number) {
+	case HTML_BLOCKQUOTE:
+	case HTML_BQ:
+	case HTML_NOTE:
+	case HTML_FN:
+        case HTML_ADDRESS:
+	    me->sp->style->alignment = HT_LEFT;
+	    return YES;
+	    break;
+
+	default:
+	    break;
+    }
+    return NO;
+}
+
+/*
+**  This function inserts newlines if needed to create double spacing,
+**  and sets the left margin for subsequent text to the second line
+**  indentation of the current style. - FM
+*/
+PUBLIC void LYEnsureDoubleSpace ARGS1(
+	HTStructured *, me)
+{
+    if (!me || !me->text)
+        return;
+
+    if (HText_LastLineSize(me->text)) {
+	HText_appendCharacter(me->text, '\r');
+	HText_appendCharacter(me->text, '\r');
+    } else if (HText_PreviousLineSize(me->text)) {
+	HText_appendCharacter(me->text, '\r');
+    } else if (me->List_Nesting_Level >= 0) {
+	HText_NegateLineOne(me->text);
+    }
+    me->in_word = NO;
+    return;
+}
+
+/*
+**  This function inserts a newline if needed to create single spacing,
+**  and sets the left margin for subsequent text to the second line
+**  indentation of the current style. - FM
+*/
+PUBLIC void LYEnsureSingleSpace ARGS1(
+	HTStructured *, me)
+{
+    if (!me || !me->text)
+        return;
+
+    if (HText_LastLineSize(me->text)) {
+	HText_appendCharacter(me->text, '\r');
+    } else if (me->List_Nesting_Level >= 0) {
+	HText_NegateLineOne(me->text);
+    }
+    me->in_word = NO;
+    return;
+}
+
+/*
+**  This function resets paragraph alignments for block
+**  elements which do not have a defined style sheet. - FM
+*/
+PUBLIC void LYResetParagraphAlignment ARGS1(
+	HTStructured *, me)
+{
+    if (!me)
+        return;
+
+    if (me->List_Nesting_Level >= 0 ||
+	((me->Division_Level < 0) &&
+	 (!strcmp(me->sp->style->name, "Normal") ||
+	  !strcmp(me->sp->style->name, "Preformatted")))) {
+	me->sp->style->alignment = HT_LEFT;
+    } else {
+	me->sp->style->alignment = me->current_default_alignment;
+    }
+    return;
+}
+
+PUBLIC BOOLEAN LYCheckForCSI ARGS2(
+	HTStructured *, 	me,
+	char **,		url)
+{
+    if (!(me && me->node_anchor && me->node_anchor->address))
+        return FALSE;
+
+    if (strncasecomp(me->node_anchor->address, "file:", 5))
+        return FALSE;
+
+    if (!LYisLocalHost(me->node_anchor->address))
+        return FALSE;
+     
+    StrAllocCopy(*url, me->node_anchor->address);
+    return TRUE;
+}
diff --git a/src/LYCharUtils.h b/src/LYCharUtils.h
index 880bd19a..94c5e1fd 100644
--- a/src/LYCharUtils.h
+++ b/src/LYCharUtils.h
@@ -6,20 +6,71 @@
 #include "HTUtils.h"
 #endif /* HTUTILS_H */
 
-extern char * LYUnEscapeEntities PARAMS((char *str,
-					 BOOLEAN plain_space,
-					 BOOLEAN hidden));
-extern void LYUnEscapeToLatinOne PARAMS((char **str,
-					 BOOLEAN isURL));
-extern void LYExpandString PARAMS((char **str));
-extern void LYEntify PARAMS((char **str,
-			     BOOLEAN isTITLE));
-extern void LYTrimHead PARAMS((char *str));
-extern void LYTrimTail PARAMS((char *str));
-extern char *LYFindEndOfComment PARAMS((char *str));
-extern char *LYUppercaseA_OL_String PARAMS((int seqnum));
-extern char *LYLowercaseA_OL_String PARAMS((int seqnum));
-extern char *LYUppercaseI_OL_String PARAMS((int seqnum));
-extern char *LYLowercaseI_OL_String PARAMS((int seqnum));
+extern char * LYUnEscapeEntities PARAMS((
+	char *		str,
+	BOOLEAN		plain_space,
+	BOOLEAN		hidden));
+extern void LYUnEscapeToLatinOne PARAMS((
+	char **		str,
+	BOOLEAN		isURL));
+extern void LYExpandString PARAMS((
+	char **		str));
+extern void LYEntify PARAMS((
+	char **		str,
+	BOOLEAN		isTITLE));
+extern void LYTrimHead PARAMS((
+	char *		str));
+extern void LYTrimTail PARAMS((
+	char *		str));
+extern char *LYFindEndOfComment PARAMS((
+	char *		str));
+extern void LYFillLocalFileURL PARAMS((
+	char **		href,
+	char *		base));
+
+#ifdef Lynx_HTML_Handler
+extern int OL_CONTINUE;		/* flag for whether CONTINUE is set */
+extern int OL_VOID;		/* flag for whether a count is set */
+extern void LYZero_OL_Counter PARAMS((
+	HTStructured *		me));
+extern char *LYUppercaseA_OL_String PARAMS((
+	int			seqnum));
+extern char *LYLowercaseA_OL_String PARAMS((
+	int			seqnum));
+extern char *LYUppercaseI_OL_String PARAMS((
+	int			seqnum));
+extern char *LYLowercaseI_OL_String PARAMS((
+	int			seqnum));
+extern void LYHandleMETA PARAMS((
+	HTStructured *		me,
+	CONST BOOL*	 	present,
+	CONST char **		value,
+	char **			include));
+extern int LYLegitimizeHREF PARAMS((
+	HTStructured *	 	me,
+	char **			href,
+	BOOL			force_slash));
+extern void LYCheckForContentBase PARAMS((
+	HTStructured *		me));
+extern void LYCheckForID PARAMS((
+	HTStructured *		me,
+	CONST BOOL *		present,
+	CONST char **		value,
+	int			attribute));
+extern void LYHandleID PARAMS((
+	HTStructured *		me,
+	char *			id));
+extern BOOLEAN LYoverride_default_alignment PARAMS((
+	HTStructured *		me));
+extern void LYEnsureDoubleSpace PARAMS((
+	HTStructured *		me));
+extern void LYEnsureSingleSpace PARAMS((
+	HTStructured *		me));
+extern void LYResetParagraphAlignment PARAMS((
+	HTStructured *		me));
+extern BOOLEAN LYCheckForCSI PARAMS((
+	HTStructured *		me,
+	char **			url));
+#endif /* Lynx_HTML_Handler */
 
 #endif /* LYCHARUTILS_H */
diff --git a/src/LYClean.c b/src/LYClean.c
index ed2238a8..2d97a386 100644
--- a/src/LYClean.c
+++ b/src/LYClean.c
@@ -11,40 +11,51 @@
 #include "LYexit.h"
 #include "LYLeaks.h"
 
+#define FREE(x) if (x) {free(x); x = NULL;}
+
 #ifdef VMS
 BOOLEAN HadVMSInterrupt = FALSE;
 #endif /* VMS */
 
 /*
- * Interrupt handler.  Stop curses and exit gracefully.
+ *  Interrupt handler.  Stop curses and exit gracefully.
  */
-PUBLIC void cleanup_sig ARGS1(int,sig)
+PUBLIC void cleanup_sig ARGS1(
+	int,		sig)
 {
 
 #ifdef IGNORE_CTRL_C
-	if(sig == SIGINT)	{
-            /* Need to rearm the signal */
-	    signal(SIGINT, cleanup_sig);
-	    sigint = TRUE;
-	    return;
-	}
+    if (sig == SIGINT)	{
+    /*
+     *  Need to rearm the signal.
+     */
+    signal(SIGINT, cleanup_sig);
+    sigint = TRUE;
+    return;
+    }
 #endif /* IGNORE_CTRL_C */
 
 #ifdef VMS
     if (!dump_output_immediately) {
         int c;
 
-	/* Reassert the AST  */
+	/*
+	 *  Reassert the AST.
+	 */
 	(void) signal(SIGINT, cleanup_sig);
 	HadVMSInterrupt = TRUE;
 	if (!LYCursesON)
 	    return;
 
-        /* Refresh screen to get rid of "cancel" message, then query */
+        /*
+	 *  Refresh screen to get rid of "cancel" message, then query.
+	 */
 	clearok(curscr, TRUE);
 	refresh();
 
-	/* Ask if exit is intended */
+	/*
+	 *  Ask if exit is intended.
+	 */
 	_statusline(REALLY_EXIT);
 	c = LYgetch();
 #ifdef QUIT_DEFAULT_YES
@@ -56,10 +67,15 @@ PUBLIC void cleanup_sig ARGS1(int,sig)
     }
 #endif /* VMS */
 
-    /* ignore further interrupts */     /*  mhc: 11/2/91 */
+    /*
+     *  Ignore further interrupts. - mhc: 11/2/91
+     */
     (void) signal(SIGHUP, SIG_IGN);
 
-#ifdef VMS  /* use ttclose() from cleanup() for VMS if not dumping */
+#ifdef VMS 
+    /*
+     *  Use ttclose() from cleanup() for VMS if not dumping.
+     */
     if (dump_output_immediately)
 #else /* Unix: */
     (void) signal(SIGINT, SIG_IGN);
@@ -67,18 +83,24 @@ PUBLIC void cleanup_sig ARGS1(int,sig)
 
     (void) signal(SIGTERM, SIG_IGN);
 
+    if (traversal)
+        dump_traversal_history();
+
     if (sig != SIGHUP) {
-	if (!dump_output_immediately)
-	    cleanup(); /* <==also calls cleanup_files() */
-	printf("\nExiting via interrupt: %d\n", sig);
-	fflush(stdout);
+	if (!dump_output_immediately) {
+	    /*
+	     *  cleanup() also calls cleanup_files().
+	     */
+	    cleanup();
+	}
+	if (sig != 0) {
+	    printf("\r\nExiting via interrupt: %d\r\n", sig);
+	    fflush(stdout);
+	}
     } else {
 	cleanup_files();
     }
 
-    if (traversal)
-        dump_traversal_history();
-
     (void) signal(SIGHUP, SIG_DFL);
     (void) signal(SIGTERM, SIG_DFL);
 #ifndef VMS
@@ -86,33 +108,38 @@ PUBLIC void cleanup_sig ARGS1(int,sig)
 #endif /* !VMS */
 #ifdef SIGTSTP
     if (no_suspend)
-	(void) signal(SIGTSTP,SIG_DFL);
+	(void) signal(SIGTSTP, SIG_DFL);
 #endif /* SIGTSTP */
-    exit(0);
+    if (sig != 0) {
+        exit(0);
+    }
 }
 
 /*
- * called by Interrupt handler or at quit time.  
- * Erases the temporary files that lynx created
- * temporary files are removed by tempname 
- * which created them
+ *  Called by Interrupt handler or at quit time.  
+ *  Erases the temporary files that lynx created
+ *  temporary files are removed by tempname 
+ *  which created them.
  */
 PUBLIC void cleanup_files NOARGS
 {
-    char filename[120];
+    char filename[256];
 
-	tempname(filename, REMOVE_FILES);
-	
+    tempname(filename, REMOVE_FILES);
+    FREE(lynx_temp_space);
 }
 
 PUBLIC void cleanup NOARGS
 {
+    int i;
 #ifdef VMS
     extern BOOLEAN DidCleanup;
 #endif /* VMS */
 
-    /* cleanup signals - just in case */
-    /* ignore further interrupts */     /*  mhc: 11/2/91 */
+    /*
+     *  Cleanup signals - just in case.
+     *  Ignore further interrupts. - mhc: 11/2/91
+     */
     (void) signal (SIGHUP, SIG_IGN);
     (void) signal (SIGTERM, SIG_IGN);
 
@@ -132,11 +159,18 @@ PUBLIC void cleanup NOARGS
         stop_curses();
     }
     cleanup_files();
+    for (i = 0; i < nhist; i++) {
+        FREE(history[i].title);
+        FREE(history[i].address);
+        FREE(history[i].post_data);
+        FREE(history[i].post_content_type);
+	FREE(history[i].bookmark);
+    }
+    nhist = 0;
 #ifdef VMS
     ttclose();
     DidCleanup = TRUE;
 #endif /* VMS */
 
-   fflush(stdout);
+    fflush(stdout);
 }
-
diff --git a/src/LYCookie.c b/src/LYCookie.c
new file mode 100644
index 00000000..957314bf
--- /dev/null
+++ b/src/LYCookie.c
@@ -0,0 +1,1262 @@
+/*	  		       Lynx Cookie Support	           LYCookies.c
+**			       ===================
+**
+**	Author:	AMK	A.M. Kuchling (amk@magnet.com)	12/25/96
+**
+**	Incorporated with mods by FM			01/16/97
+**
+**  Based on:
+**	http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-mgmt-05.txt
+**
+**  TO DO: (roughly in order of decreasing priority)
+      * host_matches() is only lightly tested in the Internet at large.
+      * Hex escaping isn't considered at all.  Any semi-colons, commas,
+        or spaces actually in cookie names or values (i.e., not serving
+	as punctuation for the overall Set-Cookie value) should be hex
+	escaped if not quoted, but presumeably the server is expecting
+	them to be hex escaped in our Cookie request header as well, so
+	in theory we need not unescape them.  We'll see how this works
+	out in practice.
+      * The prompt should show more information about the cookie being
+        set in Novice mode.
+      * The truncation heuristic in HTConfirmCookie should probably be 
+        smarter, smart enough to leave a really short name/value string 
+	alone.
+      * We protect against denial-of-service attacks (see section 6.3.1
+        of the draft) by limiting a domain to 50 cookies, limiting the
+	total number of cookies to 500, and limiting a processed cookie
+	to a maximum of 4096 bytes, but we count on the normal garbage
+	collections to bring us back down under the limits, rather than
+	actively removing cookies and/or domains based on age or frequency
+	of use.
+      * The comments in this file chould contain extracts from the -05
+        HTTP State Management draft (URL above).
+      * If the a cookie has the secure flag set, we presently treat only
+        SSL connections as secure.  This may need to be expanded for other
+        secure communication protocols that become standarized.
+      * Cookies could be optionally stored in a file from session to session.
+*/
+
+#include "HTUtils.h"
+#include "tcp.h"
+#include "HTAccess.h"
+#include "HTParse.h"
+#include "HTAlert.h"
+#include "LYCurses.h"
+#include "LYSignal.h"
+#include "LYUtils.h"
+#include "LYCharUtils.h"
+#include "LYClean.h"
+#include "LYGlobalDefs.h"
+#include "LYEdit.h"
+#include "LYStrings.h"
+#include "LYSystem.h"
+#include "GridText.h"
+#include "LYCookie.h"
+
+#define FREE(x) if (x) {free(x); x = NULL;}
+
+/*
+**  The first level of the cookie list is a list indexed by the domain
+**  string; cookies with the same domain will be placed in the same
+**  list.  Thus, finding the cookies that apply to a given URL is a
+**  two-level scan; first we check each domain to see if it applies,
+**  and if so, then we check the paths of all the cookies on that
+**  list.   We keep a running total of cookies as we add or delete
+**  them
+*/
+PRIVATE HTList *domain_list = NULL;
+PRIVATE HTList *cookie_list = NULL;
+PRIVATE int total_cookies = 0;
+
+struct _cookie {
+    char *lynx_id; /* Lynx cookie identifier */
+    char *name;    /* Name of this cookie */
+    char *value;   /* Value of this cookie */
+    int version;   /* Cookie protocol version (=1) */
+    char *comment; /* Comment to show to user */
+    char *domain;  /* Domain for which this cookie is valid */
+    int port;      /* Server port from which this cookie was given (usu. 80) */
+    char *path;    /* Path prefix for which this cookie is valid */
+    int pathlen;   /* Length of the path */
+    int flags;     /* Various flags */
+    time_t expires;   /* The time when this cookie expires */
+};
+typedef struct _cookie cookie;
+
+#define COOKIE_FLAG_SECURE 1	   /* If set, cookie requires secure links */
+#define COOKIE_FLAG_EXPIRES_SET 2  /* If set, an expiry date was set */
+
+struct _HTStream 
+{
+  HTStreamClass * isa;
+};
+
+PRIVATE void MemAllocCopy ARGS3(
+	char **,	dest,
+	CONST char *,	start,
+	CONST char *,	end)
+{
+    char *temp = (char *)calloc(1, ((end - start) + 1));
+
+    if (temp == NULL)
+        outofmem(__FILE__, "MemAllocCopy");
+
+    LYstrncpy(temp, (char *)start, (end - start));
+    HTSACopy(dest, temp);
+    FREE(temp);
+}
+
+PRIVATE cookie * newCookie NOARGS
+{
+    cookie *p = (cookie *)calloc(1, sizeof(cookie));
+    char lynx_id[64];
+
+    if (p == NULL)
+        outofmem(__FILE__, "newCookie");
+    sprintf(lynx_id, "%p", p);
+    StrAllocCopy(p->lynx_id, lynx_id);
+    p->port = 80; 
+    return p;
+}
+
+PRIVATE void freeCookie ARGS1(
+	cookie *,	co)
+{
+    if (co) {
+        FREE(co->lynx_id);
+	FREE(co->name); 
+	FREE(co->value);
+	FREE(co->comment);
+	FREE(co->domain);
+	FREE(co->path);
+	FREE(co);
+    }
+}
+
+PRIVATE void LYCookieJar_free NOARGS
+{
+    HTList *dl = domain_list;
+    domain_entry *de = NULL;
+    HTList *cl = NULL, *next = NULL;
+    cookie *co = NULL;
+
+    while (dl) {
+	if ((de = dl->object) != NULL) {
+	    cl = de->cookie_list;
+	    while (cl) {
+		next = cl->next;
+		if (co) {
+		    co = cl->object;
+		    HTList_removeObject(de->cookie_list, co);
+		    freeCookie(co);
+		    co = NULL;
+		}
+		cl = next;
+	    }
+	    FREE(de->domain);
+	    HTList_delete(de->cookie_list);
+	    de->cookie_list = NULL;
+	}
+	dl = dl->next;
+    }
+    cookie_list = NULL;
+    HTList_delete(domain_list);
+    domain_list = NULL;
+}
+
+/*
+**  Compare two hostnames as specified in Section 2 of:
+**    http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-mgmt-05.txt
+*/
+PRIVATE BOOLEAN host_matches ARGS2(
+	CONST char *,	A,
+	CONST char *,	B)
+{
+    /*
+     *  The following line will handle both numeric IP addresses and
+     *  FQDNs.  Do numeric addresses require special handling?
+     */
+    if (*B != '.' && !strcmp(A, B))
+	return YES;
+
+    /*
+     *  The following will pass a "dotted tail" match to "a.b.c.e"
+     *  as described in Section 2 of the -05 draft.
+     */
+    if (*B == '.') {
+	int diff = (strlen(A) - strlen(B));
+	if (diff > 0) {
+	    if (!strcmp((A + diff), B))
+		return YES;
+	}
+    }
+    return NO;
+}
+
+/*
+**  Store a cookie somewhere in the domain list.
+*/
+PRIVATE void store_cookie ARGS3(
+	cookie *,	co,
+	CONST char *,	hostname,
+	CONST char *,	path)
+{
+    HTList *hl, *next;
+    cookie *c2;
+    time_t now = time(NULL);
+    int pathlen, pos;
+    CONST char *ptr;
+    domain_entry *de = NULL;
+
+    if (co == NULL)
+        return;
+
+    /*
+     *  Apply sanity checks.
+     *
+     *  Section 4.3.2, condition 1: The value for the Path attribute is
+     *  not a prefix of the request-URI.
+     */
+    if (strncmp(co->path, path, co->pathlen) != 0)
+        return;
+    /*
+     *  The next 4 conditions do NOT apply if the domain is still 
+     *  the default of request-host.
+     */
+    if (strcmp(co->domain, hostname) != 0) {
+        /*
+	 *  The hostname does not contain a dot.
+	 */
+	if (strchr(hostname, '.') == NULL)
+	    return;
+
+	/*
+	 *  Section 4.3.2, condition 2: The value for the Domain attribute
+	 *  contains no embedded dots or does not start with a dot. 
+	 *  (A dot is embedded if it's neither the first nor last character.) 
+	 */
+	if (co->domain[0] != '.' || co->domain[1] == '\0')
+	    return;
+	ptr = strchr((co->domain + 1), '.');
+	if (ptr == NULL || ptr[1] == '\0')
+	    return;
+      
+        /*
+	 *  Section 4.3.2, condition 3: The value for the request-host does
+	 *  not domain-match the Domain attribute.
+	 */
+	if (!host_matches(hostname, co->domain))
+	    return;
+
+        /*
+	 *  Section 4.3.2, condition 4: The request-host is a FQDN (not IP
+	 *  address) and has the form HD, where D is the value of the Domain
+	 *  attribute, and H is a string that contains one or more dots.
+	 */
+	ptr = ((hostname + strlen(hostname)) - strlen(co->domain));
+	if (strchr(hostname, '.') < ptr)
+	    return;
+    }
+
+    /*
+     *  Ensure that the domain list exists.
+     */
+    if (domain_list == NULL) {
+        atexit(LYCookieJar_free);
+        domain_list = HTList_new();
+	total_cookies = 0;
+    }
+
+    /*
+     *  Look through domain_list to see if the cookie's domain
+     *  is already listed.
+     */
+    if (dump_output_immediately) { /* Non-interactive, can't respond */
+	if (cookie_list == NULL)
+	    cookie_list = HTList_new();
+    } else {
+	cookie_list = NULL;
+	for (hl = domain_list; hl != NULL; hl = hl->next) {
+	    de = (domain_entry *)hl->object;
+	    if ((de != NULL && de->domain != NULL) &&
+	    	!strcmp(co->domain, de->domain)) {
+	        cookie_list = de->cookie_list;
+		break;
+	    }
+	}
+	if (hl == NULL) {
+	    /*
+	     *  Domain not found; add a new entry for this domain.
+	     */
+	    de = (domain_entry *)calloc(1, sizeof(domain_entry));
+	    if (de == NULL)
+		outofmem(__FILE__, "store_cookie");
+	    de->bv = QUERY_USER;
+	    cookie_list = de->cookie_list = HTList_new();
+	    StrAllocCopy(de->domain, co->domain);
+	    HTList_addObject(domain_list, de);
+	}
+    }
+  
+    /*
+     *  Loop over the cookie list, deleting expired and matching cookies.
+     */
+    hl = cookie_list;
+    pos = 0;
+    while (hl) {
+	c2 = (cookie *)hl->object;
+	next = hl->next;
+	/*
+	 *  Check if this cookie has expired.
+	 */
+	if ((c2 != NULL) &&
+	    (c2->flags & COOKIE_FLAG_EXPIRES_SET) &&
+	    c2->expires < now) {
+	    HTList_removeObject(cookie_list, c2);
+	    freeCookie(c2);
+	    c2 = NULL;
+	    total_cookies--;
+
+	/*
+	 *  Check if this cookie matches the one we're inserting.
+	 */
+	} else if ((c2) && (co->port == c2->port) && 
+		   !strcmp(co->domain, c2->domain) &&
+		   !strcmp(co->path, c2->path) &&
+		   !strcmp(co->name, c2->name)) {
+	    HTList_removeObject(cookie_list, c2);
+	    freeCookie(c2);
+	    c2 = NULL;
+	    total_cookies--;
+
+	} else if ((c2) && (c2->pathlen) > (co->pathlen)) {
+	    pos++;
+	}
+	hl = next;
+    }
+
+    /*
+     *  Don't bother to add the cookie if it's already expired.
+     */
+    if ((co->flags & COOKIE_FLAG_EXPIRES_SET) && co->expires < now) {
+	freeCookie(co);
+	co = NULL;
+
+    /*
+     *  Don't add the cookie if we're over the domain's limit. - FM
+     */
+    } else if (HTList_count(cookie_list) > 50) {
+        if (TRACE)
+	    fprintf(stderr,
+	"store_cookie: Domain's cookie limit exceeded!  Rejecting cookie.\n");
+        freeCookie(co);
+	co = NULL;
+
+    /*
+     *  Don't add the cookie if we're over the total cookie limit. - FM
+     */
+    } else if (total_cookies > 500) {
+        if (TRACE)
+	    fprintf(stderr,
+	"store_cookie: Total cookie limit exceeded!  Rejecting cookie.\n");
+        freeCookie(co);
+	co = NULL;
+
+    /*
+     *  Get confirmation if we need it, and add cookie
+     *  if confirmed or 'allow' is set to always. - FM
+     */
+    } else if (HTConfirmCookie(de, hostname, 
+			       co->domain, co->path, co->name, co->value)) {
+	HTList_insertObjectAt(cookie_list, co, pos);
+	total_cookies++;
+    } else {
+        freeCookie(co);
+	co = NULL;
+    }
+}
+
+PRIVATE char * scan_cookie_sublist ARGS6(
+	CONST char *,	hostname,
+	CONST char *,	path,
+	int,		port,
+	HTList *,	sublist,
+	char *,		header,
+	BOOL,		secure)
+{
+    HTList *hl = sublist, *next = NULL;
+    cookie *co;
+    time_t now = time(NULL);
+
+    while (hl) {
+	co = (cookie *)hl->object;
+	next = hl->next;
+
+	if (TRACE && co) {
+	    fprintf(stderr, "Checking cookie %x %s=%s\n",
+		    	    hl,
+			    (co->name ? co->name : "(no name)"),
+			    (co->value ? co->value : "(no value)"));
+	    fprintf(stderr, "%s %s %i %s %s %i%s\n",
+	    		    hostname,
+			    (co->domain ? co->domain : "(no domain)"),
+			    host_matches(hostname, co->domain),
+			    path, co->path, ((co->pathlen > 0) ?
+			  strncmp(path, co->path, co->pathlen) : 0),
+			    ((co->flags & COOKIE_FLAG_SECURE) ?
+			    			   " secure" : ""));
+	}
+ 	/*
+	 *  Check if this cookie has expired, and if so, delete it.
+	 */
+	if (((co) && (co->flags & COOKIE_FLAG_EXPIRES_SET)) &&
+	    co->expires < now) {
+	    HTList_removeObject(sublist, co);
+	    freeCookie(co);
+	    co = NULL;
+	    total_cookies--;
+	}
+
+	/*
+	 *  Check if we have a unexpired match, and handle if we do.
+	 */
+	if (((co != NULL) &&
+	     co->port == port && host_matches(hostname, co->domain)) && 
+	    (co->pathlen == 0 || !strncmp(path, co->path, co->pathlen))) {
+	    /*
+	     *  Skip if the secure flag is set and we don't have
+	     *  a secure connection.  HTTP.c presently treats only
+	     *  SSL connections as secure. - FM
+	     */
+	    if ((co->flags & COOKIE_FLAG_SECURE) && secure == FALSE) {
+	        hl = next;
+		continue;
+	    }
+
+	    /*
+	     *  Start or append to the request header.
+	     */
+	    if (header == NULL) {
+	        if (co->version > 0) {
+		    /*
+		     *  For Version 1 (or greater) cookies,
+		     *  the version number goes before the
+		     *  first cookie.
+		     */
+		    char version[16];
+		    sprintf(version, "$Version=%i; ", co->version);
+		    StrAllocCopy(header, version);
+		}
+	    } else {
+		/*
+		 *  There's already cookie data there,
+		 *  so add a separator.
+		 */
+		StrAllocCat(header, "; ");
+	    }
+	    /*
+	     *  Include the cookie name=value pair.
+	     */
+	    StrAllocCat(header, co->name);
+	    StrAllocCat(header, "=");
+	    StrAllocCat(header, co->value);
+	    /*
+	     *  For Version 1 (or greater) cookies, add
+	     *  attributes for the cookie. - FM
+	     */
+	    if (co->version > 0) {
+		if (co->path) {
+		    /*
+		     *  Append the path attribute. - FM
+		     */
+		    StrAllocCat(header, "; $Path=");
+		    StrAllocCat(header, co->path);
+		}
+		if (co->domain) {
+		    /*
+		     *  Append the domain attribute. - FM
+		     */
+		    StrAllocCat(header, "; $Domain=");
+		    StrAllocCat(header, co->domain);
+		}
+	    }
+	}
+	hl = next;
+    }
+ 
+    return(header);
+}
+
+PUBLIC void LYSetCookie ARGS2(
+	CONST char *,	header,
+	CONST char *,	address)
+{
+    CONST char *p, *attr_start, *attr_end, *value_start, *value_end;
+    char *hostname = NULL, *path = NULL, *ptr;
+    cookie *cur_cookie = NULL;
+    int port = 80;
+    int length = 0;
+
+    /*
+     *  Get the hostname, port and path of the address, and report
+     *  the Set-Cookie request if trace mode is on, but set the cookie
+     *  only if LYSetCookies is TRUE. - FM
+     */
+    if (((hostname = HTParse(address, "", PARSE_HOST)) != NULL) &&
+	(ptr = strchr(hostname, ':')) != NULL)  {
+	/*
+	 *  Replace default port number.
+	 */
+	*ptr = '\0';
+	ptr++;
+        port = atoi(ptr);
+    } else if (!strncasecomp(address, "https:", 6)) {
+        port = 443;
+    } 
+    if (((path = HTParse(address, "",
+    			 PARSE_PATH|PARSE_PUNCTUATION)) != NULL) &&
+	(ptr = strrchr(path, '/')) != NULL) {
+	if (ptr == path)
+	    *(ptr+1) = '\0';	/* Leave a single '/' alone */
+	else
+	    *ptr = '\0'; 
+      }
+    if (TRACE) {
+	fprintf(stderr,
+    "LYSetCookie called with host '%s', path '%s',\n    and header '%s'%s\n",
+		(hostname ? hostname : ""),
+		(path ? path : ""),
+		(header ? header : ""),
+	     (LYSetCookies ? "" : "\n    Ignoring this Set-Cookie request."));
+    }
+    if (LYSetCookies == FALSE) {
+	FREE(hostname);
+	FREE(path);
+	return;
+    }
+
+    /*
+     *  Process the Set-Cookie header value.
+     */
+    p = (char *)header;
+    while (length <= 4096 && *p) {
+	attr_start = attr_end = value_start = value_end = NULL;
+#define SKIP_SPACES while (*p != '\0' && isspace((unsigned char)*p)) p++;
+        SKIP_SPACES;
+	/*
+	 *  Get the attribute name.
+	 */
+	attr_start = p;
+	while (*p != '\0' && !isspace((unsigned char)*p) &&
+	       *p != '=' && *p != ';' && *p != ',')
+	    p++;
+	attr_end = p;
+      
+	if (*p == '=') {
+	    /*
+	     *  Get the value string.
+	     */
+	    p++;
+	    SKIP_SPACES;
+	    /*
+	     *  Hack alert!  We must handle Netscape-style cookies with
+	     *		"Expires=Mon, 01-Jan-96 13:45:35 GMT" or
+	     *		"Expires=Mon,  1 Jan 1996 13:45:35 GMT".
+	     *  No quotes, but there are spaces.  Argh... 
+	     *  Anyway, we know it will have at least 3 space separators
+	     *  within it, and two dashes or two more spaces, so this code
+	     *  looks for a space after the 5th space separator or dash to
+	     *  mark the end of the value. - FM
+	     */
+	    if ((attr_end - attr_start) == 7 && 
+		!strncasecomp(attr_start, "Expires", 7)) {
+		int spaces = 6;
+		value_start = p;
+		while (*p != '\0' && *p != ';' && spaces) {
+		    p++;
+		    if (isspace((unsigned char)*p)) {
+		        while (isspace((unsigned char)*(p + 1)))
+			    p++;
+		        spaces--;
+		    } else if (*p == '-') {
+		        spaces--;
+		    }
+		}
+	        value_end = p;
+	    } else if (*p == '"') {
+	        /*
+		 *  It's a quoted string.
+		 */
+		p++;
+		value_start = p;
+		while (*p != '\0' && *p != '"')
+		    p++;
+		value_end = p;
+		if (*p == '"')
+		    p++;
+	    } else {
+		/*
+		 *   Otherwise, it's an unquoted string.
+		 */
+		SKIP_SPACES;
+		value_start = p;
+		while (*p != '\0' && !isspace((unsigned char)*p) && *p != ';')
+		    p++;
+		value_end = p;
+	    }
+	}
+
+	/*
+	 *  Check for a separator character, and skip it.
+	 */
+	if (*p == ';')
+	    p++;
+
+	/*
+	 *  Now, we can handle this attribute/value pair.
+	 */
+	if (attr_end != attr_start) {
+	    int len = (attr_end - attr_start);
+	    BOOLEAN known_attr = NO;
+	    char *value = NULL;
+
+	    if (value_end > value_start) {
+		int value_len = (value_end - value_start);
+
+		length += value_len;
+		if (length > 4096)
+		    break;
+		value = (char *)calloc(1, value_len + 1);
+		if (value == NULL)
+		    outofmem(__FILE__, "LYSetCookie");
+		LYstrncpy(value, (char *)value_start, value_len);
+	    }
+	    if (len == 6 && !strncasecomp(attr_start, "secure", 6)) {
+		known_attr = YES;
+		if (cur_cookie != NULL)
+		    cur_cookie->flags |= COOKIE_FLAG_SECURE;
+	    } else if (len == 7 && !strncasecomp(attr_start, "comment", 7)) {
+		known_attr = YES;
+		if (cur_cookie != NULL && value)
+		    StrAllocCopy(cur_cookie->comment, value);
+	    } else if (len == 6 && !strncasecomp(attr_start, "domain", 6)) {
+		known_attr = YES;
+		if (cur_cookie != NULL && value)
+		    StrAllocCopy(cur_cookie->domain, value);
+	    } else if (len == 4 && !strncasecomp(attr_start, "path", 4)) {
+		known_attr = YES;
+		if (cur_cookie != NULL && value) {
+		    StrAllocCopy(cur_cookie->path, value);
+		    cur_cookie->pathlen = strlen(cur_cookie->path);
+		}
+	    } else if (len == 7 && !strncasecomp(attr_start, "version", 7)) {
+		known_attr = YES;
+		if (cur_cookie != NULL && value) {
+		    int temp = strtol(value, NULL, 10);
+		    if (errno != -ERANGE)
+			cur_cookie->version = temp;
+		}
+	    } else if (len == 7 && !strncasecomp(attr_start, "max-age", 7)) {
+		known_attr = YES;
+		if (cur_cookie != NULL && value) {
+		    int temp = strtol(value, NULL, 10);
+		    cur_cookie->flags |= COOKIE_FLAG_EXPIRES_SET;
+		    if (errno == -ERANGE) {
+			cur_cookie->expires = (time_t)0;
+		    } else {
+			cur_cookie->expires = (time(NULL) + temp);
+			if (TRACE)
+			    fprintf(stderr,
+			    	    "LYSetCooke: expires %i, %s",
+				    cur_cookie->expires,
+				    ctime(&cur_cookie->expires));
+		    }
+		}
+	    } else if (len == 7 && !strncasecomp(attr_start, "expires", 7)) {
+	    	/*
+		 *  Convert an 'expires' attribute value for Version 0
+		 *  cookies to the equivalent of a Version 1 (or greater)
+		 *  'max-age' value added to 'time(NULL)'. - FM
+		 */
+		if (cur_cookie && cur_cookie->version < 1) {
+		    known_attr = YES;
+		    if (value) {
+			cur_cookie->flags |= COOKIE_FLAG_EXPIRES_SET;
+		        cur_cookie->expires = LYmktime(value);
+			if (cur_cookie->expires > 0) {
+			    if (TRACE)
+				fprintf(stderr,
+					"LYSetCooke: expires %i, %s",
+					cur_cookie->expires,
+					ctime(&cur_cookie->expires));
+			}
+		    }
+		}
+		/*
+		 *  If it's a version 1 (or greater) cookie, then you
+		 *  really can set a cookie named 'expires', so we don't
+		 *  set known_attr.
+		 */
+	    }
+
+	    /*
+	     *  If none of the above comparisions succeeded, then we have
+	     *  an unknown pair of the form 'foo=bar', which means it's
+	     *  time to create a new cookie.
+	     */
+	    if (!known_attr) {
+		store_cookie(cur_cookie, hostname, path);
+		cur_cookie = newCookie();
+		length += len;
+		if (length > 4096) {
+		    FREE(value);
+		    break;
+		}
+		StrAllocCopy(cur_cookie->domain, hostname);
+		StrAllocCopy(cur_cookie->path, path);
+		cur_cookie->pathlen = strlen(cur_cookie->path);
+		cur_cookie->port = port;
+		MemAllocCopy(&(cur_cookie->name), attr_start, attr_end);
+		MemAllocCopy(&(cur_cookie->value), value_start, value_end);
+	    }
+	    FREE(value);
+	}
+	if (TRACE) {
+	    fprintf(stderr, "LYSetCookie: attr=value pair: ");
+	    if (attr_start == attr_end)  {
+		fprintf(stderr, "[No attr]");
+	    } else {
+		CONST char *i;
+	      
+		for (i = attr_start; i < attr_end; i++)
+		    putc(*i, stderr);
+	    }
+	    fprintf(stderr, "=");
+	    if (value_start >= value_end) {
+		fprintf(stderr, "[No value]");
+	    } else {
+		CONST char *i;
+
+		for (i = value_start; i < value_end; i++)
+		    putc(*i, stderr);
+	    }
+	    fprintf(stderr, "\n");
+	}
+    }
+
+    /*
+     *  Store the final cookie if within length limit. - FM
+     */
+    if (length <= 4096) {
+        /*
+	 *  Force the secure flag on if it's not
+	 *  set but this is an https URL. - FM
+	 */
+        if (!strncasecomp(address, "https:", 6) &&
+	    !(cur_cookie->flags & COOKIE_FLAG_SECURE)) {
+	    cur_cookie->flags |= COOKIE_FLAG_SECURE;
+	    if (TRACE)
+	        fprintf(stderr, "LYSetCookie: Forced the 'secure' flag on.\n");
+	}
+        store_cookie(cur_cookie, hostname, path);
+    } else {
+	if (TRACE)
+	    fprintf(stderr, "LYSetCookie: Rejecting cookie due to length!\n");
+        freeCookie(cur_cookie);
+    }
+    FREE(hostname);
+    FREE(path);
+}
+
+PUBLIC char * LYCookie ARGS4(
+	CONST char *,	hostname,
+	CONST char *,	path,
+	int,		port,
+	BOOL,		secure)
+{
+    char *header = NULL;
+    HTList *hl = domain_list, *next = NULL;
+    domain_entry *de;
+
+    if (TRACE) {
+	fprintf(stderr,
+		"LYCookie: Searching for '%s:%i', '%s'.\n",
+		(hostname ? hostname : "(null)"),
+		port,
+		(path ? path : "(null)"));
+    }
+
+    /*
+     *  Search the cookie_list elements in the domain_list
+     *  for any cookies associated with the //hostname:port/path
+     */
+    while (hl) {
+	de = (domain_entry *)hl->object;
+	next = hl->next;
+
+	if (de != NULL) {
+	    if (!HTList_isEmpty(de->cookie_list)) {
+	        /*
+		 *  Scan the domain's cookie_list for
+		 *  any cookies we should include in
+		 *  our request header.
+		 */
+	        header = scan_cookie_sublist(hostname, path, port,
+					     de->cookie_list, header, secure);
+	    } else if (de->bv == QUERY_USER) {
+		/*
+		 *  No cookies in this domain, and no default
+		 *  accept/reject choice was set by the user,
+		 *  so delete the domain. - FM
+		 */
+		FREE(de->domain);
+		HTList_delete(de->cookie_list);
+		de->cookie_list = NULL;
+		HTList_removeObject(domain_list, de);
+		de = NULL;
+	    }
+	}
+        hl = next;
+    }
+    if (header)
+        return(header);
+
+    /*
+     *  If we set a header, perhaps all the cookies have
+     *  expired and we deleted the last of them above, so
+     *  check if we should delete and NULL the domain_list. - FM
+     */
+    if (domain_list) {
+	if (HTList_isEmpty(domain_list)) {
+	    HTList_delete(domain_list);
+	    domain_list = NULL;
+	}
+    }
+    return(NULL);
+}
+
+/* 	LYHandleCookies - F.Macrides (macrides@sci.wfeb.edu)
+**	---------------
+**
+**  Lists all cookies by domain, and allows deletions of
+**  individual cookies or entire domains, and changes of
+**  'allow' settings.  The list is invoked via the COOKIE_JAR
+**  command (Ctrl-K), and deletions or changes of 'allow'
+**  settings are done by activating links in that list.
+**  The procedure uses a LYNXCOOKIE: internal URL scheme.
+**
+**  Semantics:
+**	LYNXCOOKIE:/			Create and load the Cookie Jar Page.
+**	LYNXCOOKIE://domain		Manipulate the domain.
+**	LYNXCOOKIE://domain/lynx_id	Delete cookie with lynx_id in domain.
+**
+**	New functions can be added as extensions to the path, and/or by
+**	assigning meanings to ;parameters, a ?searchpart, and/or #fragments.
+*/
+PRIVATE int LYHandleCookies ARGS4 (
+	CONST char *, 		arg,
+	HTParentAnchor *,	anAnchor,
+	HTFormat,		format_out,
+	HTStream*,		sink)
+{
+    HTFormat format_in = WWW_HTML;
+    HTStream *target = NULL;
+    char buf[1024];
+    char *domain = NULL;
+    char *lynx_id = NULL;
+    HTList *dl, *cl, *next;
+    domain_entry *de;
+    cookie *co;
+    char *name = NULL, *value = NULL, *path = NULL, *comment = NULL;
+    int ch;
+#ifdef VMS
+    extern BOOLEAN HadVMSInterrupt;
+#endif /* VMS */
+
+    /*
+     *  Check whether we have something to do. - FM
+     */
+    if (domain_list == NULL) {
+	HTProgress(COOKIE_JAR_IS_EMPTY);
+	sleep(MessageSecs);
+	return(HT_NO_DATA);
+    }
+
+    /*
+     *  If there's a domain string in the "host" field of the
+     *  LYNXCOOKIE: URL, this is a request to delete something
+     *  or change and 'allow' setting. - FM
+     */
+    if ((domain = HTParse(arg, "", PARSE_HOST)) != NULL) {
+        if (*domain == '\0') {
+	    FREE(domain);
+	} else {
+	    /*
+	     *  If there is a path string (not just a slash) in the
+	     *  LYNXCOOKIE: URL, that's a cookie's lynx_id and this
+	     *  is a request to delete it from the Cookie Jar. - FM
+	     */ 
+	    if ((lynx_id = HTParse(arg, "", PARSE_PATH)) != NULL) {
+	        if (*lynx_id == '\0') {
+		    FREE(lynx_id);
+		}
+	    }
+	}
+    }
+    if (domain) {
+        /*
+	 *  Seek the domain in the domain_list structure. - FM
+	 */
+	for (dl = domain_list; dl != NULL; dl = dl->next) {
+	    de = dl->object;
+	    if (!(de && de->domain))
+	        /*
+		 *  First object in the list always is empty. - FM
+		 */
+		continue;
+	    if (!strcmp(domain, de->domain)) {
+	        /*
+		 *  We found the domain.  Check
+		 *  whether a lynx_id is present. - FM
+		 */
+	        if (lynx_id) {
+		    /*
+		     *  Seek and delete the cookie with this lynx_id
+		     *  in the domain's cookie list. - FM
+		     */
+		    for (cl = de->cookie_list; cl != NULL; cl = cl->next) {
+		        if ((co = (cookie *)cl->object) == NULL)
+			    /*
+			     *  First object is always empty. - FM
+			     */
+			    continue;
+			if (!strcmp(lynx_id, co->lynx_id)) {
+			    /*
+			     *  We found the cookie.
+			     *  Delete it if confirmed. - FM
+			     */
+			    if (HTConfirm(DELETE_COOKIE_CONFIRMATION) == FALSE)
+			        return(HT_NO_DATA);
+			    HTList_removeObject(de->cookie_list, co);
+			    freeCookie(co);
+			    co = NULL;
+			    total_cookies--;
+			    if ((de->bv == QUERY_USER &&
+			         HTList_isEmpty(de->cookie_list)) &&
+				HTConfirm(DELETE_EMPTY_DOMAIN_CONFIRMATION)) {
+			        /*
+				 *  No more cookies in this domain, no
+				 *  default accept/reject choice was set
+				 *  by the user, and got confirmation on
+				 *  deleting the domain, so do it. - FM
+				 */
+				FREE(de->domain);
+				HTList_delete(de->cookie_list);
+				de->cookie_list = NULL;
+				HTList_removeObject(domain_list, de);
+				de = NULL;
+				HTProgress(DOMAIN_EATEN);
+			    } else {
+			        HTProgress(COOKIE_EATEN);
+			    }
+			    sleep(MessageSecs);
+			    break;
+			}
+		    }
+		} else {
+		    /*
+		     *  Prompt whether to delete all of the cookies in
+		     *  this domain, or the domain if no cookies in it,
+		     *  or to change its 'allow' setting, or to cancel,
+		     *  and then act on the user's response. - FM
+		     */
+		    if (HTList_isEmpty(de->cookie_list)) {
+			_statusline(DELETE_DOMAIN_SET_ALLOW_OR_CANCEL);
+		    } else {
+			_statusline(DELETE_COOKIES_SET_ALLOW_OR_CANCEL);
+		    }
+		    while (1) {
+			ch = LYgetch();
+#ifdef VMS
+			if (HadVMSInterrupt) {
+			    HadVMSInterrupt = FALSE;
+			    ch = 'C';
+			}
+#endif /* VMS */
+			switch(TOUPPER(ch)) {
+			    case 'A':
+			        /*
+				 *  Set to accept all cookies 
+				 *  from this domain. - FM
+				 */
+				de->bv = QUERY_USER;
+				_user_message(ALWAYS_ALLOWING_COOKIES,
+					      de->domain);
+				sleep(MessageSecs);
+				return(HT_NO_DATA);
+
+			    case 'C':
+			    case 7:	/* Ctrl-G */
+			    case 3:	/* Ctrl-C */
+			        /*
+				 *  Cancelled. - FM
+				 */
+				_statusline(CANCELLED);
+				sleep(MessageSecs);
+				return(HT_NO_DATA);
+
+			    case 'D':
+			        if (HTList_isEmpty(de->cookie_list)) {
+				    /*
+				     *  We had an empty domain, so we
+				     *  were asked to delete it. - FM
+				     */
+				    FREE(de->domain);
+				    HTList_delete(de->cookie_list);
+				    de->cookie_list = NULL;
+				    HTList_removeObject(domain_list, de);
+				    de = NULL;
+				    HTProgress(DOMAIN_EATEN);
+				    sleep(MessageSecs);
+				    break;
+				}
+Delete_all_cookies_in_domain:
+				/*
+				 *  Delete all cookies in this domain. - FM
+				 */
+				cl = de->cookie_list;
+				while (cl) {
+				    next = cl->next;
+				    co = cl->object;
+				    if (co) {
+				        HTList_removeObject(de->cookie_list,
+							    co);
+					freeCookie(co);
+					co = NULL;
+					total_cookies--;
+				    }
+				    cl = next;
+				}
+				HTProgress(DOMAIN_COOKIES_EATEN);
+				sleep(MessageSecs);
+				/*
+				 *  If a default accept/reject
+				 *  choice is set, we're done. - FM
+				 */
+				if (de->bv != QUERY_USER)
+				    return(HT_NO_DATA);
+				/*
+				 *  Check whether to delete
+				 *  the empty domain. - FM
+				 */
+				if(HTConfirm(
+				    	DELETE_EMPTY_DOMAIN_CONFIRMATION)) {
+				    FREE(de->domain);
+				    HTList_delete(de->cookie_list);
+				    de->cookie_list = NULL;
+				    HTList_removeObject(domain_list, de);
+				    de = NULL;
+				    HTProgress(DOMAIN_EATEN);
+				    sleep(MessageSecs);
+				}
+				break;
+
+			    case 'P':
+			        /*
+				 *  Set to prompt for cookie acceptence
+				 *  from this domain. - FM
+				 */
+				de->bv = QUERY_USER;
+				_user_message(PROMTING_TO_ALLOW_COOKIES,
+					      de->domain);
+				sleep(MessageSecs);
+				return(HT_NO_DATA);
+
+		    	    case 'V':
+			        /*
+				 *  Set to reject all cookies
+				 *  from this domain. - FM
+				 */
+				de->bv = REJECT_ALWAYS;
+				_user_message(NEVER_ALLOWING_COOKIES,
+					      de->domain);
+				sleep(MessageSecs);
+				if ((!HTList_isEmpty(de->cookie_list)) &&
+				    HTConfirm(DELETE_ALL_COOKIES_IN_DOMAIN))
+				    goto Delete_all_cookies_in_domain;
+				return(HT_NO_DATA);
+
+			    default:
+			        continue;
+			}
+			break;
+		    }
+		}
+		break;
+	    }
+	}
+	if (HTList_isEmpty(domain_list)) {
+	    /*
+	     *  There are no more domains left,
+	     *  so delete the domain_list. - FM
+	     */
+	    HTList_delete(domain_list);
+	    domain_list = NULL;
+	    HTProgress(ALL_COOKIES_EATEN);
+	    sleep(MessageSecs);
+	}
+	return(HT_NO_DATA);
+    }
+
+    /*
+     *  If we get to here, it was a LYNXCOOKIE:/ URL
+     *  for creating and displaying the Cookie Jar Page,
+     *  or we didn't find the domain or cookie in a
+     *  deletion request.  Set up an HTML stream and
+     *  return an updated Cookie Jar Page. - FM
+     */
+    target = HTStreamStack(format_in, 
+			   format_out,
+			   sink, anAnchor);
+    if (!target || target == NULL) {
+	sprintf(buf, CANNOT_CONVERT_I_TO_O,
+		HTAtom_name(format_in), HTAtom_name(format_out));
+	HTAlert(buf);
+	return(HT_NOT_LOADED);
+    }
+
+    /*
+     *  Load HTML strings into buf and pass buf
+     *  to the target for parsing and rendering. - FM
+     */
+    sprintf(buf, "<HEAD>\n<TITLE>%s</title>\n</HEAD>\n<BODY>\n",
+		 COOKIE_JAR_TITLE);
+    (*target->isa->put_block)(target, buf, strlen(buf));
+
+    sprintf(buf, "<H1>%s</H1>\n", REACHED_COOKIE_JAR_PAGE);
+    (*target->isa->put_block)(target, buf, strlen(buf));
+    sprintf(buf, "<H2>%s Version %s</H2>\n", LYNX_NAME, LYNX_VERSION);
+    (*target->isa->put_block)(target, buf, strlen(buf));
+
+    sprintf(buf, "<NOTE>%s\n", ACTIVATE_TO_GOBBLE);
+    (*target->isa->put_block)(target, buf, strlen(buf));
+    sprintf(buf, "%s</NOTE>\n", OR_CHANGE_ALLOW);
+    (*target->isa->put_block)(target, buf, strlen(buf));
+
+    sprintf(buf, "<DL COMPACT>\n");
+    (*target->isa->put_block)(target, buf, strlen(buf));
+    for (dl = domain_list; dl != NULL; dl = dl->next) {
+	de = dl->object;
+	if (de == NULL)
+	    /*
+	     *  First object always is NULL. - FM
+	     */
+	    continue;
+
+	/*
+	 *  Show the domain link and 'allow' setting. - FM
+	 */
+	sprintf(buf, "<DT><A HREF=\"LYNXCOOKIE://%s/\">Domain=%s</A>\n",
+		      de->domain, de->domain);
+	(*target->isa->put_block)(target, buf, strlen(buf));
+	switch (de->bv) {
+	    case (ACCEPT_ALWAYS):
+		sprintf(buf, COOKIES_ALWAYS_ALLOWED);
+		break;
+	    case (REJECT_ALWAYS):
+		sprintf(buf, COOKIES_NEVER_ALLOWED);
+		break;
+	    case (QUERY_USER):
+		sprintf(buf, COOKIES_ALLOWED_VIA_PROMPT);
+	    break;
+	}
+	(*target->isa->put_block)(target, buf, strlen(buf));
+
+	/*
+	 *  Show the domain's cookies. - FM
+	 */
+	for (cl = de->cookie_list; cl != NULL; cl = cl->next) {
+	    if ((co = (cookie *)cl->object) == NULL)
+		/*
+		 *  First object is always NULL. - FM
+		 */
+	        continue;
+
+	    /*
+	     *  Show the name=value pair. - FM
+	     */
+	    if (co->name) {
+	        StrAllocCopy(name, co->name);
+		LYEntify(&name, TRUE);
+	    } else {
+	        StrAllocCopy(name, NO_NAME);
+	    }
+	    if (co->value) {
+	        StrAllocCopy(value, co->value);
+		LYEntify(&value, TRUE);
+	    } else {
+	        StrAllocCopy(value, NO_VALUE);
+	    }
+	    sprintf(buf, "<DD><A HREF=\"LYNXCOOKIE://%s/%s\">%s=%s</A>\n",
+			 de->domain, co->lynx_id, name, value);
+	    FREE(name);
+	    FREE(value);
+	    (*target->isa->put_block)(target, buf, strlen(buf));
+
+	    /*
+	     *  Show the path, port, and secure setting. - FM
+	     */
+ 	    if (co->path) {
+	        StrAllocCopy(path, co->path);
+		LYEntify(&path, TRUE);
+	    } else {
+	        StrAllocCopy(path, "/");
+	    }
+	    sprintf(buf, "<DD>Path=%s\n<DD>Port: %i Secure: %s\n",
+			 path, co->port,
+			 ((co->flags & COOKIE_FLAG_SECURE) ? "YES" : "NO"));
+	    FREE(path);
+	    (*target->isa->put_block)(target, buf, strlen(buf));
+
+	    /*
+	     *  Show the Maximum Gobble Date. - FM
+	     */
+	    sprintf(buf, "<DD><EM>Maximum Gobble Date:</EM> %s%s",
+	    		 ((co->expires > 0) ?
+			ctime(&co->expires) : END_OF_SESSION),
+			 ((co->expires > 0) ?
+				 	 "" : "\n"));
+	    (*target->isa->put_block)(target, buf, strlen(buf));
+
+	    /*
+	     *  Show the comment, if we have one. - FM
+	     */
+ 	    if (co->comment) {
+	        StrAllocCopy(comment, co->comment);
+		LYEntify(&comment, TRUE);
+		sprintf(buf, "<DD><EM>Comment:</EM> %s\n", comment);
+		FREE(comment);
+		(*target->isa->put_block)(target, buf, strlen(buf));
+	    }
+	}
+	sprintf(buf, "</DT>\n");
+	(*target->isa->put_block)(target, buf, strlen(buf));
+    }
+    sprintf(buf, "</DL>\n</BODY>\n");
+    (*target->isa->put_block)(target, buf, strlen(buf));
+
+    /*
+     *  Free the target to complete loading of the
+     *  Cookie Jar Page, and report a successful load. - FM
+     */
+    (*target->isa->_free)(target);
+    return(HT_LOADED);
+}
+
+#ifdef GLOBALDEF_IS_MACRO
+#define _LYCOOKIE_C_GLOBALDEF_1_INIT { "LYNXCOOKIE",LYHandleCookies,0}
+GLOBALDEF (HTProtocol,LYLynxCookies,_LYCOOKIE_C_GLOBALDEF_1_INIT);
+#else
+GLOBALDEF PUBLIC HTProtocol LYLynxCookies = {"LYNXCOOKIE",LYHandleCookies,0};
+#endif /* GLOBALDEF_IS_MACRO */
diff --git a/src/LYCookie.h b/src/LYCookie.h
new file mode 100644
index 00000000..abc8a018
--- /dev/null
+++ b/src/LYCookie.h
@@ -0,0 +1,23 @@
+
+#ifndef LYCOOKIES_H
+#define LYCOOKIES_H
+
+extern void LYSetCookie PARAMS((
+	CONST char *	header,
+	CONST char *	address));
+extern char *LYCookie PARAMS((
+	CONST char *	hostname,
+	CONST char *	partialpath,
+	int		port,
+	BOOL		secure));
+
+typedef enum {ACCEPT_ALWAYS, REJECT_ALWAYS, QUERY_USER} behaviour;
+
+struct _domain_entry {
+    char *	domain;  /* Domain for which these cookies are valid */
+    behaviour	bv;
+    HTList *	cookie_list;
+};
+typedef struct _domain_entry domain_entry;
+
+#endif /* LYCOOKIES_H */
diff --git a/src/LYCurses.c b/src/LYCurses.c
index 52402448..8ec8b4d2 100644
--- a/src/LYCurses.c
+++ b/src/LYCurses.c
@@ -5,6 +5,7 @@
 #include "LYGlobalDefs.h"
 #include "LYSignal.h"
 #include "LYClean.h"
+#include "LYStrings.h"
 #ifdef USE_SLANG
 #include "LYCharSets.h"
 #endif /* USE_SLANG */
@@ -12,6 +13,8 @@
 #include "LYexit.h"
 #include "LYLeaks.h"
 
+#define FREE(x) if (x) {free(x); x = NULL;}
+
 #ifdef VMS
 #define DISPLAY "DECW$DISPLAY"
 #else
@@ -29,9 +32,8 @@ extern int _NOSHARE(COLS);
 #endif /* VMS && __GNUC__ */
 
 /*
- * These are routines to start and stop curses and to cleanup
- * the screen at the end
- *
+ *  These are routines to start and stop curses and to cleanup
+ *  the screen at the end.
  */
 
 PRIVATE int dumbterm PARAMS((char *terminal));
@@ -63,13 +65,15 @@ PUBLIC void VTHome NOARGS
 }
 #endif /* VMS */
 
-PUBLIC void sl_add_attr ARGS1(int, a)
+PUBLIC void sl_add_attr ARGS1(
+	int,		a)
 {
     Current_Attr |= a;
     SLsmg_set_color(Current_Attr);
 }
 
-PUBLIC void sl_sub_attr ARGS1(int, a)
+PUBLIC void sl_sub_attr ARGS1(
+	int,		a)
 {
     Current_Attr &= ~a;
     SLsmg_set_color(Current_Attr);
@@ -81,13 +85,17 @@ PUBLIC void lynx_setup_colors NOARGS
     SLtt_set_color(1, NULL, "blue", "white");	 /* bold */
     SLtt_set_color(2, NULL, "yellow", "blue");	 /* reverse */
     SLtt_set_color(4, NULL, "magenta", "white"); /* underline */
-    /* The other objects are '|'ed together to get rest */
+    /*
+     *  The other objects are '|'ed together to get rest.
+     */
     SLtt_set_color(3, NULL, "green", "white");	 /* bold-reverse */
     SLtt_set_color(5, NULL, "blue", "white");    /* bold-underline */
     SLtt_set_color(6, NULL, "red", "white");	 /* reverse-underline */
     SLtt_set_color(7, NULL, "magenta", "cyan");	 /* reverse-underline-bold */
 
-    /* Now set monchrome attributes */
+    /*
+     *  Now set monchrome attributes.
+     */
     SLtt_set_mono(1, NULL, SLTT_BOLD_MASK);
     SLtt_set_mono(2, NULL, SLTT_REV_MASK);
     SLtt_set_mono(3, NULL, SLTT_REV_MASK | SLTT_BOLD_MASK);
@@ -97,7 +105,8 @@ PUBLIC void lynx_setup_colors NOARGS
     SLtt_set_mono(7, NULL, SLTT_ULINE_MASK | SLTT_BOLD_MASK | SLTT_REV_MASK);
 }
 
-PRIVATE void sl_suspend ARGS1(int, sig)
+PRIVATE void sl_suspend ARGS1(
+	int,		sig)
 {
 #ifndef VMS
 #ifdef SIGSTOP
@@ -116,7 +125,9 @@ PRIVATE void sl_suspend ARGS1(int, sig)
     SLtty_set_suspend_state(1);
     if (sig == SIGTSTP)
         SLsmg_resume_smg();
-    /* Get new window size in case it changed. */
+    /*
+     *  Get new window size in case it changed.
+     */
     r = SLtt_Screen_Rows;
     c = SLtt_Screen_Cols;
     size_change(0);
@@ -147,8 +158,8 @@ PUBLIC void start_curses NOARGS
 	SLtt_add_color_attribute(4, SLTT_ULINE_MASK);
 	SLtt_add_color_attribute(5, SLTT_ULINE_MASK);
 	/*
-	 * If set, the blink escape sequence will turn on high
-	 * intensity background (rxvt and maybe Linux console).
+	 *  If set, the blink escape sequence will turn on high
+	 *  intensity background (rxvt and maybe Linux console).
 	 */
 	if (Lynx_Color_Flags & SL_LYNX_USE_BLINK)
 	    SLtt_Blink_Mode = 1;	       
@@ -262,7 +273,8 @@ PUBLIC void stop_curses NOARGS
 /*
  *  Check terminal type, start curses & setup terminal.
  */
-PUBLIC BOOLEAN setup ARGS1(char *,terminal)
+PUBLIC BOOLEAN setup ARGS1(
+	char *,		terminal)
 {
     int c;
     int status;
@@ -333,9 +345,10 @@ PUBLIC BOOLEAN setup ARGS1(char *,terminal)
 #else	/* Not VMS: */
 
 /*
- * check terminal type, start curses & setup terminal
+ *  Check terminal type, start curses & setup terminal.
  */
-PUBLIC BOOLEAN setup ARGS1(char *,terminal)
+PUBLIC BOOLEAN setup ARGS1(
+	char *,		terminal)
 {
     static char term_putenv[120];
     char buffer[120];
@@ -352,7 +365,9 @@ PUBLIC BOOLEAN setup ARGS1(char *,terminal)
 	(void) putenv(term_putenv);
     }
 
-	/* query the terminal type */
+    /*
+     *  Query the terminal type.
+     */
     if (dumbterm(getenv("TERM"))) {
 	char *s;
 
@@ -367,7 +382,7 @@ PUBLIC BOOLEAN setup ARGS1(char *,terminal)
 	    strcpy(buffer,"vt100"); 
 	
 	sprintf(term_putenv,"TERM=%s", buffer);
-	putenv(term_putenv);  /* */
+	putenv(term_putenv);
 	printf("\nTERMINAL TYPE IS SET TO %s\n",getenv("TERM"));
 	sleep(MESSAGESECS);
     }
@@ -389,7 +404,8 @@ PUBLIC BOOLEAN setup ARGS1(char *,terminal)
     return(1);
 }
 
-PRIVATE int dumbterm ARGS1(char *,terminal)
+PRIVATE int dumbterm ARGS1(
+	char *,		terminal)
 {
     int dumb = FALSE;
 
@@ -491,7 +507,9 @@ static	short	trap_flag = FALSE;	/* TRUE if AST is set		*/
 BOOLEAN DidCleanup = FALSE;		/* Exit handler flag		*/
 static char VersionVMS[20];		/* Version of VMS		*/
 
-PUBLIC int VMSVersion ARGS2(char *,VerString, int,VerLen)
+PUBLIC int VMSVersion ARGS2(
+	char *,		VerString,
+	int,		VerLen)
 {
      unsigned long status, itm_cod = SYI$_VERSION;
      int i, verlen = 0;
@@ -507,8 +525,10 @@ PUBLIC int VMSVersion ARGS2(char *,VerString, int,VerLen)
      if (!(status&1) || verlen == 0)
 	  return 0;
 
-     /* Cut out trailing spaces */
-     for (m=VerString+verlen, i=verlen-1; i > 0 && VerString[i] == ' '; --i)
+     /*
+      *  Cut out trailing spaces
+      */
+     for (m = VerString+verlen, i = verlen-1; i > 0 && VerString[i] == ' '; --i)
 	  *(--m) = '\0';
 
      return strlen(VerString)+1;	/* Transmit ending 0 too */
@@ -517,28 +537,37 @@ PUBLIC int VMSVersion ARGS2(char *,VerString, int,VerLen)
 PUBLIC void VMSexit NOARGS
 {
     /*
-     * If we get here and DidCleanup is not set, it was via an
-     *  ACCVIO, so make *sure* we attempt a cleanup and reset
-     *  the terminal.
+     *  If we get here and DidCleanup is not set, it was via an
+     *  ACCVIO, or outofmemory forced exit, so make *sure* we
+     *  attempt a cleanup and reset the terminal.
      */
-     if (!DidCleanup) {
-          fprintf(stderr,
+    if (!DidCleanup) {
+        if (LYOutOfMemory == FALSE) {
+            fprintf(stderr,
 "\nA Fatal error has occured in %s Ver. %s\n", LYNX_NAME, LYNX_VERSION);
-	  fprintf(stderr,
+	    fprintf(stderr,
 "\nPlease notify your system administrator to confirm a bug, and if\n");
-	  fprintf(stderr,
+	    fprintf(stderr,
 "confirmed, to notify the lynx-dev list.  Bug reports should have concise\n");
-	  fprintf(stderr,
+	    fprintf(stderr,
 "descriptions of the command and/or URL which causes the problem, the\n");
-	  fprintf(stderr,
+	    fprintf(stderr,
 "operating system name with version number, the TCPIP implementation, the\n");
-	  fprintf(stderr,
+	    fprintf(stderr,
 "TRACEBACK if it can be captured, and any other relevant information.\n");
 
-          fprintf(stderr,"\nPress RETURN to clean up: ");
-	  (void) getchar();
-          cleanup();
-     }
+            fprintf(stderr,"\nPress RETURN to clean up: ");
+	    (void) getchar();
+	} else if (LYCursesON) {
+	    _statusline(MEMORY_EXHAUSTED_ABORT);
+	    sleep(AlertSecs);
+	}
+        cleanup();
+    }
+    if (LYOutOfMemory == TRUE) {
+	printf("\r\n%s\r\n\r\n", MEMORY_EXHAUSTED_ABORT);
+	fflush(stdout);
+    }
 }
 
 /*
@@ -549,7 +578,6 @@ PUBLIC void VMSexit NOARGS
  *		to EDIT, and sets up the Ctrl-C and Ctrl-Y interrupt
  *		handling.
  */
-
 PUBLIC int ttopen NOARGS
 {
 	extern	void cleanup_sig();
@@ -589,7 +617,9 @@ PUBLIC int ttopen NOARGS
 	if( status != SS$_NORMAL )
 		exit( status );
 
-	/* declare the exit handler block */
+	/*
+	 *  Declare the exit handler block.
+	 */
 	exit_handler_block.forward   = 0;
 	exit_handler_block.address   = (unsigned long) &VMSexit;
 	exit_handler_block.zero      = 0;
@@ -598,7 +628,9 @@ PUBLIC int ttopen NOARGS
 	if (status != SS$_NORMAL)
 		exit( status );
 
-	/* set the AST */
+	/*
+	 *  Set the AST.
+	 */
 	lib$disable_ctrl(&mask, &old_msk);
 	trap_flag = TRUE;
 	status = sys$qiow ( EFN, iochan,
@@ -610,9 +642,13 @@ PUBLIC int ttopen NOARGS
 		exit ( status );
 	}
 
-	/* Get the version of VMS */
+	/*
+	 *  Get the version of VMS.
+	 */
 	if (VMSVersion(VersionVMS, 20) < 3)
-		/* Load zeros on error */
+		/*
+		 *  Load zeros on error.
+		 */
 		strcpy(VersionVMS, "V0.0-0");
 
 	return(0);
@@ -624,7 +660,6 @@ PUBLIC int ttopen NOARGS
  *		to the command interpreter.  It puts the terminal back
  *		in a reasonable state.
  */
-
 PUBLIC int ttclose NOARGS
 {
 	int	status;
@@ -648,30 +683,31 @@ PUBLIC int ttclose NOARGS
  *	TTGETC --
  *		Read a character from the terminal, with NOECHO and NOFILTR.
  */
-
 PUBLIC int ttgetc NOARGS
 {
-     int status;
-     unsigned short iosb[4];
-     
-     if (in_pos < in_len)
-          return(buffer[in_pos++]);
-
-     status = sys$qiow (EFN, iochan,
-     			IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
-     			&iosb, 0, 0,
-			&buffer, 1, 0, 0, 0, 0);
-     if ((status&1) == 1)
-          status = iosb[0];
-     if (status == SS$_PARTESCAPE) {
-	  /* escape sequence in progress, fake a successful read */
-	  status = 1;
-     }
-     if ((status&1) != 1)
-          exit(status);
-     in_pos = 1;
-     in_len = iosb[1] + iosb[3];
-     return (buffer[0]);
+    int status;
+    unsigned short iosb[4];
+
+    if (in_pos < in_len)
+        return(buffer[in_pos++]);
+
+    status = sys$qiow(EFN, iochan,
+		      IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
+		      &iosb, 0, 0,
+		      &buffer, 1, 0, 0, 0, 0);
+    if ((status&1) == 1)
+        status = iosb[0];
+    if (status == SS$_PARTESCAPE) {
+	/*
+	 *  Escape sequence in progress.  Fake a successful read.
+	 */
+	status = 1;
+    }
+    if ((status&1) != 1 && status != SS$_DATAOVERUN)
+        exit(status);
+    in_pos = 1;
+    in_len = iosb[1] + iosb[3];
+    return(buffer[0]);
 }
 
 /*
@@ -679,35 +715,36 @@ PUBLIC int ttgetc NOARGS
  *		Check whether a keystroke has been entered, and return
  *		 it, or -1 if none was entered.
  */
-
 PUBLIC int typeahead NOARGS
 {
-     int status;
-     unsigned short iosb[4];
-     
-     if (dump_output_immediately)
-         return -1;
+    int status;
+    unsigned short iosb[4];
 
-     if (in_pos < in_len)
-          return(buffer[in_pos++]);
+    if (dump_output_immediately)
+        return -1;
+
+    if (in_pos < in_len)
+        return(buffer[in_pos++]);
 
 again:
-     status = sys$qiow (EFN, iochan,
-     			IO$_READVBLK|IO$M_TIMED|IO$M_NOECHO|IO$M_NOFILTR,
-     			&iosb, 0, 0,
-			&buffer, 1, 0, 0, 0, 0);
-     if ((status&1) == 1)
-          status = iosb[0];
-     if (status == SS$_PARTESCAPE) {
-	  /* escape sequence in progress, finish reading it */
-	  goto again;
-     }
-
-     in_pos = 1;
-     in_len = iosb[1] + iosb[3];
-     if (status == SS$_TIMEOUT)
-         return(-1);
-     return (buffer[0]);
+    status = sys$qiow (EFN, iochan,
+		       IO$_READVBLK|IO$M_TIMED|IO$M_NOECHO|IO$M_NOFILTR,
+		       &iosb, 0, 0,
+		       &buffer, 1, 0, 0, 0, 0);
+    if ((status&1) == 1)
+        status = iosb[0];
+    if (status == SS$_PARTESCAPE) {
+	/*
+	 *  Escape sequence in progress, finish reading it.
+	 */
+	goto again;
+    }
+
+    in_pos = 1;
+    in_len = iosb[1] + iosb[3];
+    if (status == SS$_TIMEOUT || status == SS$_DATAOVERUN)
+        return(-1);
+    return (buffer[0]);
 }
 
 /*
@@ -735,32 +772,42 @@ void (*func)();
 	short iosb[4];
 	static int SIG_IGN_flag;
 
-	/* Pass all signals other than SIGINT to signal() */
-	/* Also pass SIGINT to signal() if we're dumping  */
+	/*
+	 *  Pass all signals other than SIGINT to signal().
+	 *  Also pass SIGINT to signal() if we're dumping.
+	 */
 	if (sig != SIGINT || dump_output_immediately) {
 	    signal(sig, func);
 	    return;
 	}
 
-	/* If func is SIG_DFL, treat it as ttclose() */
+	/*
+	 *  If func is SIG_DFL, treat it as ttclose().
+	 */
 	if (func == SIG_DFL) {
 	    ttclose();
 	    return;
 	}
 
-	/* Clear any previous AST */
+	/*
+	 *  Clear any previous AST.
+	 */
 	if (trap_flag) {
 	    status = sys$dassgn (iochan);
 	    status = lib$enable_ctrl(&old_msk);
 	    trap_flag = FALSE;
 	}
 
-	/* If func is SIG_IGN, leave the TT channel closed and the  */
-	/* system response to interrupts enabled for system() calls */
+	/*
+	 *  If func is SIG_IGN, leave the TT channel closed and the
+	 *  system response to interrupts enabled for system() calls.
+	 */
 	if (func == SIG_IGN)
 	    return;
 
-	/* If we get to here, we have a LYNX func, so set the AST */
+	/*
+	 *  If we get to here, we have a LYNX func, so set the AST.
+	 */
 	lib$disable_ctrl(&mask, &old_msk);
 	trap_flag = TRUE;
 	status = sys$assign (&term_nam_dsc, &iochan, 0, 0 );
@@ -781,12 +828,15 @@ void (*func)();
  *	to Lynx instead of breaking out to DCL if a user issues interrupts
  *	or generates an ACCVIO during spawns.
  */
-
 #ifdef __DECC
-PRIVATE unsigned int DCLspawn_exception ARGS2(void *,sigarr, void *,mecharr)
+PRIVATE unsigned int DCLspawn_exception ARGS2(
+	void *,		sigarr,
+	void *,		mecharr)
 {
 #else
-PRIVATE int DCLspawn_exception ARGS2(void *,sigarr, void *,mecharr)
+PRIVATE int DCLspawn_exception ARGS2(
+	void *,		sigarr,
+	void *,		mecharr)
 {
 #endif /* __DECC */
      int status;
@@ -795,11 +845,14 @@ PRIVATE int DCLspawn_exception ARGS2(void *,sigarr, void *,mecharr)
      return(SS$_UNWIND);
 }
 
-PRIVATE int spawn_DCLprocess ARGS1(char *,command)
+PRIVATE int spawn_DCLprocess ARGS1(
+	char *,		command)
 {
      int status;
      unsigned long Status = 0;
-     /** Keep DECC from complaining **/
+     /*
+      *  Keep DECC from complaining.
+      */
      struct dsc$descriptor_s  command_desc;
      command_desc.dsc$w_length  = strlen(command);
      command_desc.dsc$b_class   = DSC$K_CLASS_S;
@@ -815,25 +868,34 @@ PRIVATE int spawn_DCLprocess ARGS1(char *,command)
 #else
      if (VersionVMS[1] >= '6') {
 #endif /* __ALPHA */
-	 /** Include TRUSTED flag **/
+	 /*
+	  *  Include TRUSTED flag.
+	  */
 	 unsigned long trusted = CLI$M_TRUSTED;
          status = lib$spawn(&command_desc,0,0,&trusted,
 	 		    0,0,&Status);
-	 /** If it was invalid, try again without the flag **/
+	 /*
+	  *  If it was invalid, try again without the flag.
+	  */
          if (status == LIB$_INVARG)
             status = lib$spawn(&command_desc,0,0,0,
 	    		       0,0,&Status );
      } else
 	 status = lib$spawn(&command_desc,0,0,0,
 	 		    0,0,&Status);
-     /** Return -1 on error. **/
+     /*
+      *  Return -1 on error.
+      */
      if ((status&1) != 1 || (Status&1) != 1)
          return(-1);
-     /** Return 0 on success. **/
+     /*
+      *  Return 0 on success.
+      */
      return(0);
 }
 
-PUBLIC int DCLsystem ARGS1(char *,command)
+PUBLIC int DCLsystem ARGS1(
+	char *,		command)
 {
      int status;
      extern void controlc();
@@ -841,7 +903,9 @@ PUBLIC int DCLsystem ARGS1(char *,command)
      VMSsignal(SIGINT, SIG_IGN);
      status = spawn_DCLprocess(command);
      VMSsignal(SIGINT, cleanup_sig);
-     /** Returns 0 on success, -1 any error. **/
+     /*
+      *  Returns 0 on success, -1 any error.
+      */
      return(status);
 }
 
@@ -851,9 +915,9 @@ PUBLIC int DCLsystem ARGS1(char *,command)
 **  Pass it the window, it's height, and it's width. - FM
 */
 PUBLIC void VMSbox ARGS3(
-    WINDOW *,	win,
-    int,	height,
-    int,	width)
+	WINDOW *,	win,
+	int,		height,
+	int,		width)
 {
     int i;
 
@@ -876,4 +940,3 @@ PUBLIC void VMSbox ARGS3(
 }
 #endif /* !USE_SLANG */
 #endif /* VMS */
-
diff --git a/src/LYForms.c b/src/LYForms.c
index b7cd64ee..8474dc12 100644
--- a/src/LYForms.c
+++ b/src/LYForms.c
@@ -181,6 +181,7 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
 	    break;
 
 	case F_SUBMIT_TYPE:
+	case F_IMAGE_SUBMIT_TYPE:
 	    if (form->disabled == YES)
 	        break;
 	    if (form->no_cache &&
diff --git a/src/LYGetFile.c b/src/LYGetFile.c
index cd8ef577..fa6b0c3e 100644
--- a/src/LYGetFile.c
+++ b/src/LYGetFile.c
@@ -50,7 +50,8 @@ extern BOOLEAN LYDidRename;
 
 
 #ifdef DIRED_SUPPORT
-PRIVATE char * LYSanctify ARGS1(char *, href) 
+PRIVATE char * LYSanctify ARGS1(
+	char *,		href) 
 {
     int i;
     char *p, *cp, *tp;
@@ -81,34 +82,44 @@ PRIVATE char * LYSanctify ARGS1(char *, href)
 #endif /* DIRED_SUPPORT */
 
 
-PUBLIC BOOLEAN getfile ARGS1(document *,doc)
+PUBLIC BOOLEAN getfile ARGS1(
+	document *,	doc)
 {
-        int url_type;
-	char *cp;
+        int url_type = 0;
+	char *cp = NULL;
+	char *temp = NULL;
 	DocAddress WWWDoc;  /* a WWW absolute doc address struct */
 
 Try_Redirected_URL:
-	/* load the WWWDoc struct in case we need to use it */
+	/*
+	 *  Load the WWWDoc struct in case we need to use it.
+	 */
 	WWWDoc.address = doc->address;
         WWWDoc.post_data = doc->post_data;
         WWWDoc.post_content_type = doc->post_content_type;
         WWWDoc.bookmark = doc->bookmark;
 	WWWDoc.isHEAD = doc->isHEAD;
+	WWWDoc.safe = doc->safe;
 
-	/* reset WWW_Download_File just in case */
+	/*
+	 *  Reset WWW_Download_File just in case.
+	 */
 	FREE(WWW_Download_File);
 
-	/* reset redirect_post_content just in case */
+	/*
+	 *  Reset redirect_post_content just in case.
+	 */
 	redirect_post_content = FALSE;
 
 	if (TRACE) {
 	    fprintf(stderr,"LYGetFile: getting %s\n\n",doc->address);
 	}
 
-	/* check to see if this is a universal document ID
-	 * that lib WWW wants to handle
+	/*
+	 *  Check to see if this is a universal document ID
+	 *  that lib WWW wants to handle.
  	 *
-	 * some special URL's we handle ourselves :)
+	 *  Some special URL's we handle ourselves. :)
 	 */
 	if ((url_type = is_url(doc->address)) != 0) {
 		if (LYValidate && !LYPermitURL) {
@@ -117,6 +128,7 @@ Try_Redirected_URL:
 			  url_type == LYNXHIST_URL_TYPE ||
 		    	  url_type == LYNXKEYMAP_URL_TYPE ||
 			  url_type == LYNXIMGMAP_URL_TYPE ||
+			  url_type == LYNXCOOKIE_URL_TYPE ||
 			  0==strncasecomp(WWWDoc.address, helpfilepath,
 					  strlen(helpfilepath)) ||
 			  0==strncasecomp(WWWDoc.address, aboutfilepath,
@@ -124,6 +136,9 @@ Try_Redirected_URL:
 			  (lynxlistfile != NULL &&
 			   0==strncasecomp(WWWDoc.address, lynxlistfile,
 			  		  strlen(lynxlistfile))) ||
+			  (lynxlinksfile != NULL &&
+			   0==strncasecomp(WWWDoc.address, lynxlinksfile,
+			  		  strlen(lynxlinksfile))) ||
 			  (lynxjumpfile != NULL &&
 			   0==strncasecomp(WWWDoc.address, lynxjumpfile,
 			  		  strlen(lynxjumpfile))))) {
@@ -133,7 +148,9 @@ Try_Redirected_URL:
 		    }
 		}
 		if (traversal) {
-		    /* only traverse http URLs */
+		    /*
+		     *  Only traverse http URLs.
+		     */
 		    if (url_type != HTTP_URL_TYPE &&
 		        url_type != LYNXIMGMAP_URL_TYPE)
 		        return(NULLFILE);
@@ -143,6 +160,7 @@ Try_Redirected_URL:
 			  url_type == LYNXHIST_URL_TYPE ||
 		    	  url_type == LYNXKEYMAP_URL_TYPE ||
 			  url_type == LYNXIMGMAP_URL_TYPE ||
+			  url_type == LYNXCOOKIE_URL_TYPE ||
 			  url_type == LYNXPRINT_URL_TYPE ||
 			  url_type == LYNXDOWNLOAD_URL_TYPE ||
 			  url_type == MAILTO_URL_TYPE ||
@@ -152,6 +170,8 @@ Try_Redirected_URL:
 			   (url_type == LYNXEXEC_URL_TYPE ||
 			    url_type == LYNXPROG_URL_TYPE ||
 			    url_type == LYNXCGI_URL_TYPE)) ||
+			  (WWWDoc.bookmark != NULL &&
+			   *WWWDoc.bookmark != '\0') ||
 			  0==strncasecomp(WWWDoc.address, helpfilepath,
 					  strlen(helpfilepath)) ||
 			  0==strncasecomp(WWWDoc.address, aboutfilepath,
@@ -159,9 +179,6 @@ Try_Redirected_URL:
 			  (lynxlistfile != NULL &&
 			   0==strncasecomp(WWWDoc.address, lynxlistfile,
 			  		  strlen(lynxlistfile))) ||
-			  (lynxbookfile != NULL &&
-			   0==strncasecomp(WWWDoc.address, lynxbookfile,
-			  		  strlen(lynxbookfile))) ||
 			  (lynxjumpfile != NULL &&
 			   0==strncasecomp(WWWDoc.address, lynxjumpfile,
 			  		  strlen(lynxjumpfile))))) {
@@ -215,10 +232,10 @@ Try_Redirected_URL:
 #ifdef VMS
 		    if (LYDidRename) {
 		        /*
-			 * The temporary file was saved to disk via a
-			 * rename(), so we can't access the temporary
-			 * file again via the download menu.  Clear the
-			 * flag, and return NULLFILE to pop. - FM
+			 *  The temporary file was saved to disk via a
+			 *  rename(), so we can't access the temporary
+			 *  file again via the download menu.  Clear the
+			 *  flag, and return NULLFILE to pop. - FM
 			 */
 		        LYDidRename = FALSE;
 		        return(NULLFILE);
@@ -241,6 +258,7 @@ Try_Redirected_URL:
         	       WWWDoc.post_content_type = doc->post_content_type;
 		       WWWDoc.bookmark = doc->bookmark;
 		       WWWDoc.isHEAD = doc->isHEAD;
+		       WWWDoc.safe = doc->safe;
 
 		       if (!HTLoadAbsolute(&WWWDoc))
 		           return(NOT_FOUND);
@@ -255,12 +273,14 @@ Try_Redirected_URL:
 		} else if (url_type == LYNXHIST_URL_TYPE) {
 		    /*
 		     *  'doc' will change to the new file
-		     *  if we had a successful pop. - FM
+		     *  if we had a successful LYpop_num(),
+		     *  and the return value will be FALSE
+		     *  if we had a cancel. - FM
 		     */
-		    historytarget(doc);
-		    if (!doc || !doc->address) {
-		        HTMLSetCharacterHandling(current_char_set);
-		        return(NOT_FOUND);
+		    if ((historytarget(doc) == FALSE) ||
+		        !doc || !doc->address) {
+			HTMLSetCharacterHandling(current_char_set);
+			return(NOT_FOUND);
 		    }
 
 		    /*
@@ -271,6 +291,7 @@ Try_Redirected_URL:
         	    WWWDoc.post_content_type = doc->post_content_type;
 		    WWWDoc.bookmark = doc->bookmark;
 		    WWWDoc.isHEAD = doc->isHEAD;
+		    WWWDoc.safe = doc->safe;
 
 		    if (!HTLoadAbsolute(&WWWDoc)) {
 		        HTMLSetCharacterHandling(current_char_set);
@@ -297,13 +318,17 @@ Try_Redirected_URL:
 
 			char *p, addressbuf[1024];
 
-			/* Bug puts slash on end if none is in the string */
+			/*
+			 *  Bug puts slash on end if none is in the string.
+			 */
 			char *last_slash = strrchr(doc->address,'/');
 			if (last_slash-doc->address==strlen(doc->address)-1)
 			    doc->address[strlen(doc->address)-1] = '\0';
 
 			p = doc->address;
-			/** Convert '~' to $HOME **/
+			/*
+			 *  Convert '~' to $HOME.
+			 */
 			if ((cp = strchr(doc->address, '~'))) {
 			    strncpy(addressbuf, doc->address, cp-doc->address);
 			    addressbuf[cp - doc->address] = '\0';
@@ -316,17 +341,23 @@ Try_Redirected_URL:
 			    strcat(addressbuf, cp+1);
 			    p = addressbuf;
 			}
-			/* Show URL before executing it */
+			/*
+			 *  Show URL before executing it.
+			 */
 			statusline(doc->address);
 			sleep(InfoSecs);
 			stop_curses();
-			/* run the command */
+			/*
+			 *  Run the command.
+			 */
 			if (strstr(p,"//") == p+9)
 			    system(p+11);
 			else
 			    system(p+9);
 			if (url_type != LYNXPROG_URL_TYPE) {
-			    /* Make sure user gets to see screen output */
+			    /*
+			     *  Make sure user gets to see screen output.
+			     */
 #ifndef VMS
 			    signal(SIGINT, SIG_IGN);
 #endif /* !VMS */
@@ -341,6 +372,7 @@ Try_Redirected_URL:
 #endif /* VMS */
 			}
 			start_curses();
+			LYAddVisitedLink(doc);
 			
            	     } else {
 			char buf[512];
@@ -382,13 +414,15 @@ Try_Redirected_URL:
 		    }
 		    return(NULLFILE);
 		
-		  /* from here on we could have a remote host,
-		   * so check if that's allowed.
-		   */
+		/*
+		 *  From here on we could have a remote host,
+		 *  so check if that's allowed.
+		 */
 		} else if (local_host_only &&
 			   url_type != NEWS_URL_TYPE &&
 			   url_type != LYNXKEYMAP_URL_TYPE &&
 			   url_type != LYNXIMGMAP_URL_TYPE &&
+			   url_type != LYNXCOOKIE_URL_TYPE &&
 			   url_type != LYNXCGI_URL_TYPE &&
 			   !(LYisLocalHost(doc->address) ||
 			     LYisLocalAlias(doc->address))) {
@@ -396,11 +430,12 @@ Try_Redirected_URL:
 		    sleep(MessageSecs);
 		    return(NULLFILE);
 
-		  /* disable www telnet access if not telnet_ok */
+		/*
+		 *  Disable www telnet access if not telnet_ok.
+		 */
 		} else if (url_type == TELNET_URL_TYPE || 
 			   url_type == TN3270_URL_TYPE ||
 			   url_type == TELNET_GOPHER_URL_TYPE) {
-
 		    if (!telnet_ok) {
 		    	_statusline(TELNET_DISABLED);
 		    	sleep(MessageSecs);
@@ -412,19 +447,19 @@ Try_Redirected_URL:
                         HTLoadAbsolute(&WWWDoc);
 			start_curses();
                         fflush(stdout);
-
+			LYAddVisitedLink(doc);
 		    }
-
 		    return(NULLFILE);
 
-  		/* disable www news access if not news_ok */
+  		/*
+		 *  Disable www news access if not news_ok.
+		 */
                 } else if (url_type == NEWS_URL_TYPE && !news_ok) {
                     _statusline(NEWS_DISABLED);
                     sleep(MessageSecs);
                     return(NULLFILE);
 
 		} else if (url_type == RLOGIN_URL_TYPE) {
-
 		    if (!rlogin_ok) {
 			statusline(RLOGIN_DISABLED);
 			sleep(MessageSecs);
@@ -433,13 +468,14 @@ Try_Redirected_URL:
 			HTLoadAbsolute(&WWWDoc);
 			fflush(stdout);
 			start_curses();
+			LYAddVisitedLink(doc);
 		    }
 		    return(NULLFILE);
 
 		/*
 		 *  If its a gopher index type and there isn't a search
 		 *  term already attached then do this.  Otherwise
-   		 *   just load it!
+   		 *  just load it!
 		 */
 		} else if (url_type == INDEX_GOPHER_URL_TYPE &&
 					strchr(doc->address,'?') == NULL) {
@@ -450,7 +486,6 @@ Try_Redirected_URL:
 		     *  the search term. - FM
 		     */
 		    if ((cp = strstr(doc->address, "%09")) != NULL) {
-		        char *temp = NULL;
 		        *cp = '\0';
 			StrAllocCopy(temp, doc->address);
 			cp += 3;
@@ -480,6 +515,7 @@ Try_Redirected_URL:
 			WWWDoc.post_content_type = doc->post_content_type;
 			WWWDoc.bookmark = doc->bookmark;
 			WWWDoc.isHEAD = doc->isHEAD;
+			WWWDoc.safe = doc->safe;
 		        status = HTLoadAbsolute(&WWWDoc);
 		    }
 		    return(status); 
@@ -495,7 +531,7 @@ Try_Redirected_URL:
 		    if (url_type == HTML_GOPHER_URL_TYPE) {
 		        char *tmp=NULL;
 		       /*
-		        * If tuple's Path=GET%20/... convert to an http URL
+		        *  If tuple's Path=GET%20/... convert to an http URL.
 		        */ 
 		        if ((cp=strchr(doc->address+9, '/')) != NULL &&
 		           0==strncmp(++cp, "hGET%20/", 8)) {
@@ -507,7 +543,7 @@ Try_Redirected_URL:
 			    *cp = '\0';
 			    StrAllocCat(tmp, doc->address+9);
 			   /*
-			    * If the port is defaulted, it should stay 70
+			    *  If the port is defaulted, it should stay 70.
 			    */
 			    if (strchr(tmp+6, ':') == NULL) {
 			        StrAllocCat(tmp, "70/");
@@ -538,7 +574,6 @@ Try_Redirected_URL:
 #else
 		    if (url_type == FILE_URL_TYPE &&
 		        (cp=strstr(doc->address, "/~")) != NULL) {
-			char *temp=NULL;
 			*cp = '\0';
 			cp += 2;
 			StrAllocCopy(temp, doc->address);
@@ -556,7 +591,7 @@ Try_Redirected_URL:
 #endif /* DIRED_SUPPORT */
 		    if (TRACE)
 		        sleep(MessageSecs);
-		    user_message(WWW_WAIT_MESSAGE,doc->address);
+		    user_message(WWW_WAIT_MESSAGE, doc->address);
 #ifdef NOTDEFINED
 		    sleep(InfoSecs);
 #endif /* NOTDEFINED */
@@ -593,21 +628,22 @@ Try_Redirected_URL:
 				 *  the RIGHT thing and returning an invalid
 				 *  address message. - FM
 				 */
-			        char *temp = HTParse(use_this_url_instead,
-						     WWWDoc.address,
-						     PARSE_ALL);
+				HTAlert(LOCATION_NOT_ABSOLUTE);
+			        temp = HTParse(use_this_url_instead,
+					       WWWDoc.address,
+					       PARSE_ALL);
 				if (temp && *temp) {
 				    StrAllocCopy(use_this_url_instead, temp);
 				}
 				FREE(temp);
 			    }
 			    HTMLSetCharacterHandling(current_char_set);
-			    if(TRACE)
+			    if (TRACE)
 			        sleep(MessageSecs);
 			    _user_message("Using %s", use_this_url_instead);
 			    sleep(InfoSecs);
 			    if (TRACE)
-			        fprintf(stderr,"\n");
+			        fprintf(stderr, "\n");
 			    StrAllocCopy(doc->address,
 					use_this_url_instead);
 			    FREE(use_this_url_instead);
@@ -632,13 +668,14 @@ Try_Redirected_URL:
 
 		    lynx_mode = NORMAL_LYNX_MODE;
 
-		    /* some URL's don't actually return a document
-		     * compare doc->address with the document that is 
-		     * actually loaded and return NULL if not
-		     * loaded.  If www_search_result is not -1
-		     * then this is a reference to a named anchor
-		     * within the same document.  Do NOT return
-		     * NULL
+		    /*
+		     *  Some URL's don't actually return a document
+		     *  compare doc->address with the document that is 
+		     *  actually loaded and return NULL if not
+		     *  loaded.  If www_search_result is not -1
+		     *  then this is a reference to a named anchor
+		     *  within the same document.  Do NOT return
+		     *  NULL.
 		     */
                     {
                         char *pound;
@@ -674,6 +711,7 @@ Try_Redirected_URL:
 				FREE(fname);
 				return(NOT_FOUND);
 			    }
+			    LYAddVisitedLink(doc);
 			    StrAllocCopy(doc->address, fname);
 			    FREE(fname);
 		    	    WWWDoc.address = doc->address;
@@ -681,6 +719,7 @@ Try_Redirected_URL:
 		    	    FREE(WWWDoc.post_content_type);
 			    WWWDoc.bookmark = doc->bookmark;
 			    WWWDoc.isHEAD = FALSE;
+			    WWWDoc.safe = doc->safe;
 			    HTOutputFormat = WWW_PRESENT;
 			    if (!HTLoadAbsolute(&WWWDoc)) 
                         	return(NOT_FOUND);
@@ -689,27 +728,28 @@ Try_Redirected_URL:
 
 			} else if (pound == NULL &&
 				   /*
-				    * HTAnchor hash-table searches are now
-				    * case-sensitive (hopefully, without
-				    * anchor deletion problems), so this
-				    * is too. - FM
+				    *  HTAnchor hash-table searches are now
+				    *  case-sensitive (hopefully, without
+				    *  anchor deletion problems), so this
+				    *  is too. - FM
 				    */
 				   (strcmp(doc->address,
 				  	   HTLoadedDocumentURL()) ||
 				   /*
-				    * Also check the post_data elements. - FM
+				    *  Also check the post_data elements. - FM
 				    */
 				   strcmp((doc->post_data ?
 				   	   doc->post_data : ""),
 				    	  HTLoadedDocumentPost_data()) ||
 				   /*
-				    * Also check the isHEAD element. - FM
+				    *  Also check the isHEAD element. - FM
 				    */
 				   doc->isHEAD != HTLoadedDocumentIsHEAD())) {
 			    HTMLSetCharacterHandling(current_char_set);
 			    /*
 			     *  Nothing needed to be shown.
 			     */
+			    LYAddVisitedLink(doc);
 			    return(NULLFILE);
 
                         } else {
@@ -734,16 +774,20 @@ Try_Redirected_URL:
 	  }
 }
 
-/* the user wants to select a link by number
- * if follow_link_number returns DO_LINK_STUFF do_link will be
- * run immeditely following its execution.
- * if follow_link_number returns PRINT_ERROR an error message will
- * be given to the user, if follow_link_number returns DO_FORMS_STUFF
- * some forms stuff will be done, and if follow_link_number returns
- * DO_NOTHING nothing special will run after it.
+/*
+ *  The user wants to select a link by number.
+ *  If follow_link_number returns DO_LINK_STUFF do_link
+ *   will be run immeditely following its execution.
+ *  If follow_link_number returns PRINT_ERROR an error message
+ *   will be given to the user.
+ *  If follow_link_number returns DO_FORMS_STUFF some forms stuff
+ *   will be done.
+ *  If follow_link_number returns DO_NOTHING nothing special
+ *   will run after it.
  */
-
-PUBLIC int follow_link_number ARGS2(int,c, int,cur)
+PUBLIC int follow_link_number ARGS2(
+	int,		c,
+	int,		cur)
 {
     char temp[120];
     int link_number;
@@ -751,7 +795,9 @@ PUBLIC int follow_link_number ARGS2(int,c, int,cur)
     temp[0] = c;
     temp[1] = '\0';
     _statusline(FOLLOW_LINK_NUMBER);
-    /* get the number from the user */
+    /*
+     *  Get the number from the user.
+     */
     if (LYgetstr(temp, VISIBLE, sizeof(temp), NORECALL) < 0 || *temp == 0) {
         _statusline(CANCELLED);
         sleep(InfoSecs);
@@ -760,28 +806,26 @@ PUBLIC int follow_link_number ARGS2(int,c, int,cur)
 
     link_number = atoi(temp);
 
-    if (link_number > 0)  {
-              /* get the lname, and hightext,
-               * direct from
-               * www structures and add it to the cur link
-               * so that we can pass it transparently on to
-               * get_file()
-               * this is done so that you may select a link
-               * anywhere in the document, whether it is displayed
-               * on the screen or not!
-               */
-	       if (HTGetLinkInfo(link_number, &links[cur].hightext, 
-					 &links[cur].lname)) {
-                   links[cur].type = WWW_LINK_TYPE;
-
-		   return(DO_LINK_STUFF);
-       		} else {
-		   return(PRINT_ERROR);
-		}
+    if (link_number > 0) {
+        /*
+	 *  Get the lname, and hightext, direct from
+	 *  www structures and add it to the cur link
+	 *  so that we can pass it transparently on to
+	 *  get_file().  This is done so that you may select a link
+	 * anywhere in the document, whether it is displayed
+	 * on the screen or not!
+	 */
+	if (HTGetLinkInfo(link_number,
+			  &links[cur].hightext, 
+			  &links[cur].lname)) {
+	    links[cur].type = WWW_LINK_TYPE;
+	    return(DO_LINK_STUFF);
+	} else {
+	    return(PRINT_ERROR);
+	}
     } else {
-            return(PRINT_ERROR);
+        return(PRINT_ERROR);
     }
-
 }
 
 #if defined(EXEC_LINKS) || defined(LYNXCGI_LINKS)
@@ -848,7 +892,9 @@ PRIVATE void LYTrusted_free NOARGS
     return;
 }
 
-PUBLIC void add_trusted ARGS2 (char *,str, int,type)
+PUBLIC void add_trusted ARGS2(
+	char *,		str,
+	int,		type)
 {
     struct trust *tp;
     char *path;
@@ -899,17 +945,26 @@ PUBLIC void add_trusted ARGS2 (char *,str, int,type)
 }
 
 /*
- * Check to see if the supplied paths is allowed to be executed.
+ *  Check to see if the supplied paths is allowed to be executed.
  */
-PUBLIC BOOLEAN exec_ok ARGS3(CONST char *,source, CONST char *,link, int, type)
+PUBLIC BOOLEAN exec_ok ARGS3(
+	CONST char *,	source,
+	CONST char *,	link,
+	int,		type)
 {
     struct trust *tp;
-    char CONST *cp;
+    CONST char *cp;
     int Type = type;
 
+    /*
+     *  Always OK if it is a jump file shortcut.
+     */
     if (LYJumpFileURL)
 	return TRUE;
 
+    /*
+     *  Choose the trust structure based on the type.
+     */
     if (Type == EXEC_PATH) {
 	tp = trusted_exec;
     } else if (Type == ALWAYS_EXEC_PATH) {
@@ -920,8 +975,36 @@ PUBLIC BOOLEAN exec_ok ARGS3(CONST char *,source, CONST char *,link, int, type)
         HTAlert(MALFORMED_EXEC_REQUEST);
 	return FALSE;
     }
-#ifndef VMS
-    /* security: reject on strange character */
+
+#ifdef VMS
+    /*
+     *  Security: reject on relative path.
+     */
+    if ((cp = strchr(link, '[')) != NULL) {
+        char *cp1;
+        if (((cp1 = strchr(cp, '-')) != NULL) &&
+	    strchr(cp1, ']') != NULL) {
+	    while (cp1[1] == '-')
+	        cp1++;
+	    if (cp1[1] == ']' ||
+		cp1[1] == '.') {
+		HTAlert(RELPATH_IN_EXEC_LINK);
+		return FALSE;
+	    }
+	}
+    }
+#else
+    /*
+     *  Security: reject on relative path.
+     */
+    if (strstr(link, "../") != NULL) {
+        HTAlert(RELPATH_IN_EXEC_LINK);
+	return FALSE;
+    }
+
+    /*
+     *  Security: reject on strange character.
+     */
     for (cp = link; *cp != '\0'; cp++) {
 	if (!isalnum(*cp) && *cp != '_' && *cp != '-' &&
 	   *cp != ' ' && *cp != ':' && *cp != '.' &&
@@ -936,7 +1019,7 @@ PUBLIC BOOLEAN exec_ok ARGS3(CONST char *,source, CONST char *,link, int, type)
 	    return FALSE;
 	}
     }
-#endif /* !VMS */
+#endif /* VMS */
 
 check_tp_for_entry:
     while (tp) {
@@ -969,11 +1052,14 @@ check_tp_for_entry:
 }
 #endif /* EXEC_LINKS || LYNXCGI_LINKS */
 
-PRIVATE int fix_http_urls ARGS1(document *,doc)
+PRIVATE int fix_http_urls ARGS1(
+	document *,	doc)
 {
     char *slash;
 
-    /* if it's an ftp URL with a trailing slash, trim it off */
+    /*
+     *  If it's an ftp URL with a trailing slash, trim it off.
+     */
     if (!strncmp(doc->address, "ftp", 3) &&
         doc->address[strlen(doc->address)-1] == '/') {
 	char *path = HTParse(doc->address, "", PARSE_PATH|PARSE_PUNCTUATION);
@@ -993,7 +1079,9 @@ PRIVATE int fix_http_urls ARGS1(document *,doc)
 	}
     }
 
-    /* if there isn't a slash besides the two at the beginning, append one */
+    /*
+     *  If there isn't a slash besides the two at the beginning, append one.
+     */
     if ((slash = strrchr(doc->address, '/')) != NULL) {
 	if (*(slash-1) != '/' || *(slash-2) != ':') {
 	    return(0);
diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h
index 5f2577c5..bff9785e 100644
--- a/src/LYGlobalDefs.h
+++ b/src/LYGlobalDefs.h
@@ -44,6 +44,10 @@ extern char *no_proxy_putenv_cmd;
 extern char *list_format;
 #endif /* !VMS */
 
+#ifdef VMS
+extern char *LYCSwingPath;
+#endif /* VMS */
+
 #ifdef DIRED_SUPPORT
 extern BOOLEAN lynx_edit_mode;
 extern BOOLEAN no_dired_support;
@@ -88,7 +92,7 @@ extern char star_string[MAX_LINE + 1]; /* from GridText.c */
 extern BOOLEAN LYShowCursor;   /* show the cursor or hide it */
 extern BOOLEAN LYCursesON;  /* start_curses()->TRUE, stop_curses()->FALSE */
 extern BOOLEAN LYUserSpecifiedURL;  /* URL from a goto or document? */
-extern BOOLEAN LYJumpFileURL;   /* URL from the jump file shorcuts? */
+extern BOOLEAN LYJumpFileURL;   /* URL from the jump file shortcuts? */
 extern BOOLEAN jump_buffer;     /* TRUE if offering default shortcut */
 extern BOOLEAN goto_buffer;     /* TRUE if offering default goto URL */
 extern char *LYRequestTitle;    /* newdoc.title in calls to getfile() */
@@ -101,13 +105,14 @@ extern char *unchecked_box;  /* form boxes */
 extern char *checked_radio;  /* form radio buttons */
 extern char *unchecked_radio;  /* form radio buttons */
 extern char *empty_string;
+extern char *LynxHome;
 extern char *startfile;
 extern char *helpfile;
 extern char *helpfilepath;
 extern char *aboutfilepath;
 extern char *lynxjumpfile;
 extern char *lynxlistfile;
-extern char *lynxbookfile;
+extern char *lynxlinksfile;
 extern char *display;
 extern char *language;
 extern char *pref_charset; /* Lynx's preferred character set - MM */
@@ -256,5 +261,8 @@ extern BOOLEAN LYUseDefSelPop;		/* Command line -popup toggle    */
 extern int LYMultiBookmarks;    	/* Multi bookmark support on?	 */
 extern BOOLEAN LYMBMBlocked;		/* Force MBM support off?	 */
 extern BOOLEAN LYMBMAdvanced;		/* MBM statusline for ADVANCED?	 */
+extern int LYStatusLine;		/* Line for statusline() or -1   */
+extern BOOLEAN LYCollapseBRs;		/* Collapse serial BRs?		 */
+extern BOOLEAN LYSetCookies;		/* Process Set-Cookie headers?	 */
 
 #endif /* LYGLOBALDEFS_H */
diff --git a/src/LYHistory.c b/src/LYHistory.c
index 8ad69cb3..eb57db8e 100644
--- a/src/LYHistory.c
+++ b/src/LYHistory.c
@@ -2,11 +2,14 @@
 #include "tcp.h"
 #include "HTAlert.h"
 #include "HText.h"
+#include "LYGlobalDefs.h"
 #include "LYUtils.h"
 #include "LYHistory.h"
 #include "LYPrint.h"
 #include "LYDownload.h"
-#include "LYGlobalDefs.h"
+#include "LYKeymap.h"
+#include "LYList.h"
+#include "LYShowInfo.h"
 #include "LYSignal.h"
 #include "LYStrings.h"
 #include "LYCharUtils.h"
@@ -21,49 +24,178 @@
  
 #define FREE(x) if (x) {free(x); x = NULL;}
 
-/*
- *  Push the current filename, link and line number onto the history list.
+PUBLIC  HTList * Visited_Links = NULL;  /* List of safe popped docs. */
+
+/* 
+ *  Utility for freeing the list of visited links. - FM
  */
-PUBLIC void LYpush ARGS1(document *,doc)
+PRIVATE void Visited_Links_free NOARGS
 {
+    VisitedLink *vl;
+    HTList *cur = Visited_Links;
 
-    if( *doc->address == '\0')  /* dont push null file names */
-	return;
+    if (!cur)
+        return;
 
-    /* don't push the history, download, or printer lists */
-    if(!strcmp(doc->title, HISTORY_PAGE_TITLE) ||
-		!strcmp(doc->title, PRINT_OPTIONS_TITLE) ||
-		!strcmp(doc->title, DOWNLOAD_OPTIONS_TITLE) ) {
-	if (!LYforce_no_cache)
-	    LYoverride_no_cache = TRUE;
-	return;
+    while (NULL != (vl = (VisitedLink *)HTList_nextObject(cur))) {
+	FREE(vl->address);
+	FREE(vl->title);
+	FREE(vl);
     }
+    HTList_delete(Visited_Links);
+    Visited_Links = NULL;
+    return;
+}
+
+/* 
+ *  Utility for listing visited links, making any repeated
+ *  links the most current in the list. - FM
+ */
+PUBLIC void LYAddVisitedLink ARGS1(
+	document *,	doc)
+{
+    VisitedLink *new;
+    VisitedLink *old;
+    HTList *cur;
+
+    if (!(doc->address && *doc->address))
+        return;
 
+    /*
+     *  Exclude POST or HEAD replies, and bookmark, menu
+     *  or list files. - FM
+     */
+    if (doc->post_data || doc->isHEAD || doc->bookmark ||
+	!strcmp((doc->title ? doc->title : ""), HISTORY_PAGE_TITLE) ||
+	!strcmp((doc->title ? doc->title : ""), PRINT_OPTIONS_TITLE) ||
+	!strcmp((doc->title ? doc->title : ""), DOWNLOAD_OPTIONS_TITLE) ||
 #ifdef DIRED_SUPPORT
-    if(!strcmp(doc->title, DIRED_MENU_TITLE) ||
-		!strcmp(doc->title, UPLOAD_OPTIONS_TITLE) ||
-                !strcmp(doc->title, PERMIT_OPTIONS_TITLE)) {
-	if (!LYforce_no_cache)
-	    LYoverride_no_cache = TRUE;
+	!strcmp((doc->title ? doc->title : ""), DIRED_MENU_TITLE) ||
+	!strcmp((doc->title ? doc->title : ""), UPLOAD_OPTIONS_TITLE) ||
+	!strcmp((doc->title ? doc->title : ""), PERMIT_OPTIONS_TITLE) ||
+#endif /* DIRED_SUPPORT */
+	!strcmp((doc->title ? doc->title : ""), CURRENT_KEYMAP_TITLE) ||
+	!strcmp((doc->title ? doc->title : ""), LIST_PAGE_TITLE) ||
+	!strcmp((doc->title ? doc->title : ""), SHOWINFO_TITLE) ||
+	!strcmp((doc->title ? doc->title : ""), COOKIE_JAR_TITLE) ||
+	!strcmp((doc->title ? doc->title : ""), VISITED_LINKS_TITLE)) {
+	return;
+    }
+
+    if ((new = (VisitedLink *)calloc(1, sizeof(*new))) == NULL)
+    	outofmem(__FILE__, "HTAddVisitedLink");
+    StrAllocCopy(new->address, doc->address);
+    StrAllocCopy(new->title, (doc->title ? doc->title : "(no title)"));
+
+    if (!Visited_Links) {
+        Visited_Links = HTList_new();
+	atexit(Visited_Links_free);
+	HTList_addObject(Visited_Links, new);
 	return;
     }
+
+    cur = Visited_Links;
+    while (NULL != (old = (VisitedLink *)HTList_nextObject(cur))) {
+	if (!strcmp((old->address ? old->address : ""),
+		    (new->address ? new->address : "")) &&
+	    !strcmp((old->title ? new->title : ""),
+	    	    (new->title ? new->title : ""))) {
+	    FREE(old->address);
+	    FREE(old->title);
+	    HTList_removeObject(Visited_Links, old);
+	    FREE(old);
+	    break;
+	}
+    }
+    HTList_addObject(Visited_Links, new);
+
+    return;
+}
+
+/*
+ *  Push the current filename, link and line number onto the history list.
+ */
+PUBLIC void LYpush ARGS2(
+	document *,	doc,
+	BOOLEAN,	force_push)
+{
+    /*
+     *  Don't push NULL file names.
+     */
+    if (*doc->address == '\0')
+	return;
+
+    /*
+     *  Check whether this is a document we
+     *  don't push unless forced. - FM
+     */
+    if (!force_push) {
+	/*
+	 *  Don't push the history, printer, or download lists.
+	 */
+	if (!strcmp(doc->title, HISTORY_PAGE_TITLE) ||
+	    !strcmp(doc->title, PRINT_OPTIONS_TITLE) ||
+	    !strcmp(doc->title, DOWNLOAD_OPTIONS_TITLE)) {
+	    if (!LYforce_no_cache)
+		LYoverride_no_cache = TRUE;
+	    return;
+	}
+
+#ifdef DIRED_SUPPORT
+	/*
+	 *  Don't push DIRED menu, upload or permit lists.
+	 */
+	if (!strcmp(doc->title, DIRED_MENU_TITLE) ||
+	    !strcmp(doc->title, UPLOAD_OPTIONS_TITLE) ||
+	    !strcmp(doc->title, PERMIT_OPTIONS_TITLE)) {
+	    if (!LYforce_no_cache)
+		LYoverride_no_cache = TRUE;
+	    return;
+	}
 #endif /* DIRED_SUPPORT */
+    }
+
+    /*
+     *  If file is identical to one before it, don't push it.
+     */
+    if (nhist> 1 &&
+        STREQ(history[nhist-1].address, doc->address) &&
+        !strcmp(history[nhist-1].post_data ?
+		history[nhist-1].post_data : "",
+                doc->post_data ?
+		doc->post_data : "") &&
+        !strcmp(history[nhist-1].bookmark ?
+		history[nhist-1].bookmark : "",
+                doc->bookmark ?
+		doc->bookmark : "") &&
+	history[nhist-1].isHEAD == doc->isHEAD) 
+        return;
 
-    if(nhist>1 && STREQ(history[nhist-1].address, doc->address) &&
-       !strcmp(history[nhist-1].post_data ? history[nhist-1].post_data : "",
-               doc->post_data ? doc->post_data : "") &&
-	       history[nhist-1].isHEAD == doc->isHEAD) 
-        return;  /* file is identical to one before it don't push it */
-
-    if(nhist>2 && STREQ(history[nhist-2].address, doc->address) &&
-       !strcmp(history[nhist-2].post_data ? history[nhist-2].post_data : "",
-               doc->post_data ? doc->post_data : "") &&
-	       history[nhist-2].isHEAD == doc->isHEAD) {
-	  nhist--; /* pop one off the stack */
-          return;  /* file is identical to one two before it don't push it */
+    /*
+     *  If file is identical to one two before it, don't push it.
+     */
+    if (nhist > 2 &&
+        STREQ(history[nhist-2].address, doc->address) &&
+        !strcmp(history[nhist-2].post_data ?
+		history[nhist-2].post_data : "",
+                doc->post_data ?
+		doc->post_data : "") &&
+        !strcmp(history[nhist-2].bookmark ?
+		history[nhist-2].bookmark : "",
+                doc->bookmark ?
+		doc->bookmark : "") &&
+	history[nhist-2].isHEAD == doc->isHEAD) {
+	/*
+	 *  Pop one off the stack.
+	 */
+	nhist--;
+        return;
     }
 
-    if (nhist<MAXHIST)  {
+    /*
+     *  OK, push it if we have stack space.
+     */
+    if (nhist < MAXHIST)  {
 	history[nhist].link = doc->link;
 	history[nhist].page = doc->line;
 	history[nhist].title = NULL;
@@ -77,40 +209,53 @@ PUBLIC void LYpush ARGS1(document *,doc)
 	history[nhist].bookmark = NULL;
 	StrAllocCopy(history[nhist].bookmark, doc->bookmark);
 	history[nhist].isHEAD = doc->isHEAD;
+	history[nhist].safe = doc->safe;
 	nhist++;
-
-        if(TRACE)
-    	    fprintf(stderr,"\nLYpush: address:%s\n        title:%s\n",
-						doc->address,doc->title);
+   	if (TRACE) {
+    	    fprintf(stderr,
+		    "\nLYpush: address:%s\n        title:%s\n",
+		    doc->address, doc->title);
+	}
+    } else {
+        if (LYCursesON) {
+	    _statusline(MAXHIST_REACHED);
+	    sleep(AlertSecs);
+	} 
+        if (TRACE) {
+    	    fprintf(stderr,
+     "\nLYpush: MAXHIST reached for:\n        address:%s\n        title:%s\n",
+		    doc->address, doc->title);
+	}
     }
 }
 
 /*
  *  Pop the previous filename, link and line number from the history list.
  */
-PUBLIC void LYpop ARGS1(document *,doc)
+PUBLIC void LYpop ARGS1(
+	document *,	doc)
 {
- 
-    if (nhist>0) {
+    if (nhist > 0) {
 	nhist--;
 	doc->link = history[nhist].link;
 	doc->line = history[nhist].page;
 	FREE(doc->title);
-	doc->title = history[nhist].title;    /* will be freed later */
+	doc->title = history[nhist].title;	 /* will be freed later */
 	FREE(doc->address);
-	doc->address = history[nhist].address;  /* will be freed later */
+	doc->address = history[nhist].address;   /* will be freed later */
 	FREE(doc->post_data);
 	doc->post_data = history[nhist].post_data;
 	FREE(doc->post_content_type);
 	doc->post_content_type = history[nhist].post_content_type;
 	FREE(doc->bookmark);
-	doc->bookmark = history[nhist].bookmark;
+	doc->bookmark = history[nhist].bookmark; /* will be freed later */
 	doc->isHEAD = history[nhist].isHEAD;
-
-        if(TRACE)
-	    fprintf(stderr,"LYpop: address:%s\n     title:%s\n",
-						doc->address,doc->title);
-
+	doc->safe = history[nhist].safe;
+        if (TRACE) {
+	    fprintf(stderr,
+	    	    "LYpop: address:%s\n     title:%s\n",
+		    doc->address, doc->title);
+	}
     }
 }
 
@@ -119,7 +264,9 @@ PUBLIC void LYpop ARGS1(document *,doc)
  *  list but don't actually remove the entry, just return it.
  *  (This procedure is badly named :)
  */
-PUBLIC void LYpop_num ARGS2(int,number, document *,doc)
+PUBLIC void LYpop_num ARGS2(
+	int,		number,
+	document *,	doc)
 {
     if (number >= 0 && nhist >= number) {
 	doc->link = history[number].link;
@@ -130,14 +277,15 @@ PUBLIC void LYpop_num ARGS2(int,number, document *,doc)
 	StrAllocCopy(doc->post_content_type, history[number].post_content_type);
 	StrAllocCopy(doc->bookmark, history[number].bookmark);
 	doc->isHEAD = history[number].isHEAD;
+	doc->safe = history[number].safe;
     }
 }
 
 /*
  *  This procedure outputs the history buffer into a temporary file.
- *  
  */
-PUBLIC int showhistory ARGS1(char **,newfile)
+PUBLIC int showhistory ARGS1(
+	char **,	newfile)
 {
     static char tempfile[256];
     static BOOLEAN first = TRUE;
@@ -155,7 +303,7 @@ PUBLIC int showhistory ARGS1(char **,newfile)
 #endif /* VMS */
     }
 
-    if ((fp0 = fopen(tempfile,"w")) == NULL) {
+    if ((fp0 = fopen(tempfile, "w")) == NULL) {
 	HTAlert(CANNOT_OPEN_TEMP);
 	return(-1);
     }
@@ -181,7 +329,7 @@ PUBLIC int showhistory ARGS1(char **,newfile)
     for (x = nhist-1; x >= 0; x--) {
 	/*
 	 *  The number of the document in the hist stack,
-	 *  its name in a link, and its address. - FM
+	 *  its title in a link, and its address. - FM
 	 */
 	if (history[x].title != NULL) {
 	    StrAllocCopy(Title, history[x].title);
@@ -210,53 +358,155 @@ PUBLIC int showhistory ARGS1(char **,newfile)
 }
 
 /* 
- *  This is a kludge to make the history page seem like any other type of
- *  file since more info is needed than can be provided by the normal link
- *  structure.  I saved out the history number to a special URL.  The info
- *  looks like:  LYNXHIST:#
+ *  This function makes the history page seem like any other type of
+ *  file since more info is needed than can be provided by the normal
+ *  link structure.  We saved out the history number to a special URL.
+ *  The info looks like:  LYNXHIST:#
  */
-PUBLIC void historytarget ARGS1(document *,newdoc)
+PUBLIC BOOLEAN historytarget ARGS1(
+	document *,	newdoc)
 {
     int number, c;
     DocAddress WWWDoc;
+    HTParentAnchor *tmpanchor;
+    HText *text;
 
     if ((!newdoc || !newdoc->address) ||
         strlen(newdoc->address) < 10 || !isdigit(*(newdoc->address+9)))
-	return;
+	return(FALSE);
 
     if ((number = atoi(newdoc->address+9)) > nhist || number < 0)
-        return;
+        return(FALSE);
 
     LYpop_num(number, newdoc);
 
     /*
-     *  If we have POST content, aren't forcing no_cache,
-     *  and still have the text cached, ask the user whether
-     *  to resubmit the form. - FM
+     *  If we have POST content, and have LYresubmit_posts set
+     *  or have no_cache set or do not still have the text cached,
+     *  ask the user whether to resubmit the form. - FM
      */
-    if (newdoc->post_data != NULL && LYforce_no_cache == FALSE) {
-        if (LYresubmit_posts == TRUE) {
+    if (newdoc->post_data != NULL) {
+	WWWDoc.address = newdoc->address;
+        WWWDoc.post_data = newdoc->post_data;
+        WWWDoc.post_content_type = newdoc->post_content_type;
+        WWWDoc.bookmark = newdoc->bookmark;
+	WWWDoc.isHEAD = newdoc->isHEAD;
+	WWWDoc.safe = newdoc->safe;
+	tmpanchor = HTAnchor_parent(HTAnchor_findAddress(&WWWDoc));
+	text = (HText *)HTAnchor_document(tmpanchor);
+        if (((LYresubmit_posts == TRUE) ||
+	     (LYforce_no_cache == TRUE &&
+	      LYoverride_no_cache == FALSE) ||
+	     text == NULL) &&
+	    HTConfirm(CONFIRM_POST_RESUBMISSION) == TRUE) {
+	    LYforce_no_cache == TRUE;
 	    LYoverride_no_cache = FALSE;
+	} else if (text != NULL) {
+	    LYforce_no_cache == FALSE;
+	    LYoverride_no_cache = TRUE;
 	} else {
-	    WWWDoc.address = newdoc->address;
-            WWWDoc.post_data = newdoc->post_data;
-            WWWDoc.post_content_type = newdoc->post_content_type;
-            WWWDoc.bookmark = newdoc->bookmark;
-	    WWWDoc.isHEAD = newdoc->isHEAD;
-	    if ((HText *)HTAnchor_document(
-				HTAnchor_parent(HTAnchor_findAddress(&WWWDoc))
-					  )) {
-		LYoverride_no_cache = TRUE;
-		_statusline(
-		   "Document from Form with POST content.  Resubmit? (y/n) ");
-		c = LYgetch();
-		if (TOUPPER(c) == 'Y') {
-		    LYoverride_no_cache = FALSE;
-		}
-	    }
+	    _statusline(CANCELLED);
+	    sleep(InfoSecs);
+	    return(FALSE);
 	}
     }
 
     if (number != 0)
 	StrAllocCat(newdoc->title," (From History)");
+    return(TRUE);
+}
+
+/*
+ *  This procedure outputs the Visited Links
+ *  list into a temporary file. - FM
+ */
+PUBLIC int LYShowVisitedLinks ARGS1(
+	char **,	newfile)
+{
+    static char tempfile[256];
+    static BOOLEAN first = TRUE;
+    static char vl_filename[256];
+    char *Title = NULL;
+    char *Address = NULL;
+    int x;
+    FILE *fp0;
+    VisitedLink *vl;
+    HTList *cur = Visited_Links;
+
+    if (!cur)
+        return(-1);
+
+    if (first) {
+	tempname(tempfile, NEW_FILE);
+	first = FALSE;
+#ifdef VMS
+    } else {
+	remove(tempfile);  /* Remove duplicates on VMS. */
+#endif /* VMS */
+    }
+
+    if ((fp0 = fopen(tempfile, "w")) == NULL) {
+	HTAlert(CANNOT_OPEN_TEMP);
+	return(-1);
+    }
+
+    /*
+     *  Make the file a URL now.
+     */
+#ifdef VMS
+    sprintf(vl_filename,"file://localhost/%s", tempfile);
+#else
+    sprintf(vl_filename,"file://localhost%s", tempfile);
+#endif /* VMS */
+    StrAllocCopy(*newfile, vl_filename);
+    LYforce_HTML_mode = TRUE;	/* force this file to be HTML */
+    LYforce_no_cache = TRUE;	/* force this file to be new */
+
+    fprintf(fp0, "<head>\n<title>%s</title>\n</head>\n<body>\n",
+		 VISITED_LINKS_TITLE);
+
+    fprintf(fp0, "<h1>You have reached the Visited Links Page</h1>\n");
+    fprintf(fp0, "<h2>%s Version %s</h2>\n<pre>", LYNX_NAME, LYNX_VERSION);
+    fprintf(fp0, 
+  "<em>You visited (POSTs, bookmark, menu and list files excluded):</em>\n");
+    x = HTList_count(Visited_Links);
+    while (NULL != (vl = (VisitedLink *)HTList_nextObject(cur))) {
+	/*
+	 *  The number of the document (most recent highest),
+	 *  its title in a link, and its address. - FM
+	 */
+	x--;
+	if (vl->title != NULL && *vl->title != '\0') {
+	    StrAllocCopy(Title, vl->title);
+	    LYEntify(&Title, TRUE);
+	} else {
+	    StrAllocCopy(Title , "(no title)");
+	}
+	if (vl->address != NULL && *vl->address != '\0') {
+	    StrAllocCopy(Address, vl->address);
+	    LYEntify(&Address, FALSE);
+	    fprintf(fp0,
+		    "%s<em>%d</em>. <tab id=t%d><a href=\"%s\">%s</a>\n",
+		    (x > 99 ? "" : x < 9 ? "  " : " "),
+		    x, x, Address, Title);
+	} else {
+	    fprintf(fp0,
+		    "%s<em>%d</em>. <tab id=t%d><em>%s</em>\n",
+		    (x > 99 ? "" : x < 9 ? "  " : " "),
+		    x, x, Title);
+	}
+	if (Address != NULL) {
+	    StrAllocCopy(Address, vl->address);
+	    LYEntify(&Address, TRUE);
+	}
+	fprintf(fp0, "<tab to=t%d>%s\n", x,
+		     ((Address != NULL) ? Address : "(no address)"));
+    }
+
+    fprintf(fp0,"</pre>\n</body>\n");
+
+    fclose(fp0);
+    FREE(Title);
+    FREE(Address);
+    return(0);
 }
diff --git a/src/LYHistory.h b/src/LYHistory.h
index 1271259b..caac9605 100644
--- a/src/LYHistory.h
+++ b/src/LYHistory.h
@@ -6,12 +6,15 @@
 #include "LYStructs.h"
 #endif /* LYSTRUCTS_H */
 
-extern void LYpush PARAMS((document *doc));
+extern void LYAddVisitedLink PARAMS((document *doc));
+extern void LYpush PARAMS((document *doc, BOOLEAN force_push));
 extern void LYpop PARAMS((document *doc));
 extern void LYpop_num PARAMS((int number, document *doc));
 extern int showhistory PARAMS((char **newfile));
-extern void historytarget PARAMS((document *newdoc));
+extern BOOLEAN historytarget PARAMS((document *newdoc));
+extern int LYShowVisitedLinks PARAMS((char **newfile));
 
 #define HISTORY_PAGE_TITLE  "Lynx History Page"
+#define VISITED_LINKS_TITLE  "Lynx Visited Links Page"
 
 #endif /* LYHISTORY_H */
diff --git a/src/LYKeymap.c b/src/LYKeymap.c
index 5ba5f6a1..2545f6a6 100644
--- a/src/LYKeymap.c
+++ b/src/LYKeymap.c
@@ -30,7 +30,7 @@ char keymap[] = {
 LYK_ABORT,          LYK_END,        LYK_NEXT_PAGE,     0,
 /* ^D */            /* ^E */        /* ^F */       /* ^G */
 
-LYK_HISTORY,      LYK_NEXT_LINK,    LYK_ACTIVATE,      0,
+LYK_HISTORY,      LYK_NEXT_LINK,    LYK_ACTIVATE,  LYK_COOKIE_JAR,
 /* bs */            /* ht */        /* nl */       /* ^K */
 
 LYK_REFRESH,      LYK_ACTIVATE,     LYK_DOWN_TWO,      0,
@@ -82,11 +82,11 @@ LYK_RAW_TOGGLE,  LYK_ADD_BOOKMARK, LYK_PREV_PAGE,   LYK_COMMENT,
 LYK_DOWNLOAD,        LYK_EDIT,             
 /* D */              /* E */         
 
-#ifdef DIRED_SUPPORT
+#if defined(DIRED_SUPPORT) || defined(VMS)
 LYK_DIRED_MENU,
 #else
 0,          
-#endif /* DIRED_SUPPORT */
+#endif /* DIRED_SUPPORT || VMS */
 /* F */        
 
 LYK_GOTO,
@@ -108,7 +108,7 @@ LYK_TAG_LINK,
 #endif /* DIRED_SUPPORT */
 /* T */
 
- 	          LYK_PREV_DOC,   LYK_VIEW_BOOKMARK,   0,
+ 	          LYK_PREV_DOC,    LYK_VLINKS,         0,
                      /* U */         /* V */        /* W */
 
 #ifdef NOT_USED
@@ -127,11 +127,11 @@ LYK_MINIMAL,   LYK_ADD_BOOKMARK,  LYK_PREV_PAGE,    LYK_COMMENT,
 LYK_DOWNLOAD,        LYK_EDIT,             
 /* d */              /* e */         
 
-#ifdef DIRED_SUPPORT
+#if defined(DIRED_SUPPORT) || defined(VMS)
 LYK_DIRED_MENU,
 #else
 0,          
-#endif /* DIRED_SUPPORT */
+#endif /* DIRED_SUPPORT || VMS */
 /* f */        
 
 LYK_GOTO,
@@ -436,6 +436,7 @@ PRIVATE struct rmap revmap[] = {
 { "ADD_BOOKMARK",	"add to your personal bookmark list" },
 { "DEL_BOOKMARK",	"delete from your personal bookmark list" },
 { "VIEW_BOOKMARK",	"view your personal bookmark list" },
+{ "VLINKS",		"list links visited during the current Lynx session" },
 { "SHELL",		"escape from the browser to the system" },
 { "DOWNLOAD",		"download the current link to your computer" },
 { "TRACE_TOGGLE",	"toggle tracing of browser operations" },
@@ -446,21 +447,26 @@ PRIVATE struct rmap revmap[] = {
 { "TOGGLE_HELP",	"show other commands in the novice help menu" },
 { "JUMP",		"go directly to a target document or action" },
 { "KEYMAP",		"display the current key map" },
-{ "LIST",		"list references (links) in the current document" },
+{ "LIST",		"list the references (links) in the current document" },
 { "TOOLBAR",		"go to Toolbar or Banner in the current document" },
 { "HISTORICAL",		"toggle historical vs. valid/minimal comment parsing" },
 { "MINIMAL",		"toggle minimal vs. valid comment parsing" },
 { "SOFT_DQUOTES",	"toggle valid vs. soft double-quote parsing" },
 { "RAW_TOGGLE",		"toggle raw 8-bit translations or CJK mode ON or OFF" },
+{ "COOKIE_JAR",		"Examine the Cookie Jar" },
+#ifdef VMS
+{ "DIRED_MENU",		"invoke File/Directory Manager, if available" },
+#else
 #ifdef DIRED_SUPPORT
+{ "DIRED_MENU",		"display a full menu of file operations" },
 { "CREATE",		"create a new file or directory" },
 { "REMOVE",		"remove a file or directory" },
 { "MODIFY",		"modify the name or location of a file or directory" },
 { "TAG_LINK",		"tag a file or directory for later action" },
-{ "DIRED_MENU",		"display a full menu of file operations" },
 { "UPLOAD",		"upload from your computer to the current directory" },
 { "INSTALL",		"install file or tagged files into a system area" },
 #endif /* DIRED_SUPPORT */
+#endif /* VMS */
 #ifdef NOT_USED
 { "VERSION",		"report version of lynx"},
 { "FORM_UP",		"toggle a checkbox" },
@@ -512,9 +518,6 @@ PRIVATE char *pretty ARGS1 (int, c)
 	return buf;
 }
 
-
-#define KEYTITLE "Current Key Map"
-
 PRIVATE void print_binding ARGS3(HTStream *, target, char *, buf, int, i)
 {
 #if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
@@ -556,11 +559,12 @@ PRIVATE int LYLoadKeymap ARGS4 (
 	return(HT_NOT_LOADED);
     }
 
-    sprintf(buf, "<head>\n<title>%s</title>\n</head>\n<body>\n", KEYTITLE);
+    sprintf(buf, "<head>\n<title>%s</title>\n</head>\n<body>\n",
+    		  CURRENT_KEYMAP_TITLE);
     (*target->isa->put_block)(target, buf, strlen(buf));
 	
     sprintf(buf, "<h1>%s (%s Version %s)</h1>\n<pre>",
-		 KEYTITLE, LYNX_NAME, LYNX_VERSION);
+		 CURRENT_KEYMAP_TITLE, LYNX_NAME, LYNX_VERSION);
     (*target->isa->put_block)(target, buf, strlen(buf));
 
     for (i = 'a'+1; i <= 'z'+1; i++) {
diff --git a/src/LYKeymap.h b/src/LYKeymap.h
index 99c38fd2..1ed08cf2 100644
--- a/src/LYKeymap.h
+++ b/src/LYKeymap.h
@@ -20,6 +20,8 @@ extern char keymap[]; /* main keymap matrix */
 extern char override[];
 #endif
 
+#define CURRENT_KEYMAP_TITLE "Current Key Map"
+
 #define       LYK_1     	1
 #define       LYK_2     	2
 #define       LYK_3     	3
@@ -69,36 +71,41 @@ extern char override[];
 #define       LYK_ADD_BOOKMARK  47
 #define       LYK_DEL_BOOKMARK  48
 #define       LYK_VIEW_BOOKMARK 49
-#define       LYK_SHELL 	50
-#define       LYK_DOWNLOAD      51
-#define       LYK_TRACE_TOGGLE  52
-#define       LYK_IMAGE_TOGGLE  53
-#define       LYK_INLINE_TOGGLE 54
-#define       LYK_HEAD          55
-#define       LYK_DO_NOTHING    56
-#define       LYK_TOGGLE_HELP	57
-#define       LYK_JUMP		58
-#define       LYK_KEYMAP	59
-#define       LYK_LIST		60
-#define       LYK_TOOLBAR	61
-#define       LYK_HISTORICAL	62
-#define       LYK_MINIMAL	63
-#define       LYK_SOFT_DQUOTES	64
-#define       LYK_RAW_TOGGLE	65
+#define       LYK_VLINKS	50
+#define       LYK_SHELL 	51
+#define       LYK_DOWNLOAD      52
+#define       LYK_TRACE_TOGGLE  53
+#define       LYK_IMAGE_TOGGLE  54
+#define       LYK_INLINE_TOGGLE 55
+#define       LYK_HEAD          56
+#define       LYK_DO_NOTHING    57
+#define       LYK_TOGGLE_HELP	58
+#define       LYK_JUMP		59
+#define       LYK_KEYMAP	60
+#define       LYK_LIST		61
+#define       LYK_TOOLBAR	62
+#define       LYK_HISTORICAL	63
+#define       LYK_MINIMAL	64
+#define       LYK_SOFT_DQUOTES	65
+#define       LYK_RAW_TOGGLE	66
+#define       LYK_COOKIE_JAR    67
 
+#ifdef VMS
+#define       LYK_DIRED_MENU    68
+#endif /* VMS */
 #ifdef DIRED_SUPPORT
-#define       LYK_CREATE        66
-#define       LYK_REMOVE        67
-#define       LYK_MODIFY        68
-#define       LYK_TAG_LINK      69
-#define       LYK_DIRED_MENU    70
-#define       LYK_UPLOAD        71
-#define       LYK_INSTALL       72
+#define       LYK_DIRED_MENU    68
+#define       LYK_CREATE        69
+#define       LYK_REMOVE        70
+#define       LYK_MODIFY        71
+#define       LYK_TAG_LINK      72
+#define       LYK_UPLOAD        73
+#define       LYK_INSTALL       74
 #endif /* DIRED_SUPPORT */
 #ifdef NOT_USED
-#define       LYK_VERSION	73
-#define       LYK_FORM_UP       74
-#define       LYK_FORM_DOWN     75
+#define       LYK_VERSION	75
+#define       LYK_FORM_UP       76
+#define       LYK_FORM_DOWN     77
 #endif /* NOT_USED */
 
 #endif /* LYKEYMAP_H */
diff --git a/src/LYLocal.c b/src/LYLocal.c
index 95a49abc..d7d36052 100644
--- a/src/LYLocal.c
+++ b/src/LYLocal.c
@@ -25,6 +25,7 @@
 #include "LYGlobalDefs.h"
 #include "LYUtils.h"
 #include "LYStrings.h"
+#include "LYCharUtils.h"
 #include "LYStructs.h"
 #include "LYGetFile.h"
 #include "LYHistory.h"
@@ -105,6 +106,9 @@ struct dired_menu {
 #if defined(OK_TAR) && defined(OK_GZIP) && !defined(ARCHIVE_ONLY)
 { DE_FILE,     ".tar.gz", "Expand",
    "(current selection)", "LYNXDIRED://UNTAR_GZ%p",		NULL },
+
+{ DE_FILE,        ".tgz", "Expand",
+   "(current selection)", "LYNXDIRED://UNTAR_GZ%p",		NULL },
 #endif /* OK_TAR && OK_GZIP && !ARCHIVE_ONLY */
 
 #ifndef ARCHIVE_ONLY
@@ -161,6 +165,9 @@ struct dired_menu {
 { DE_TAG,	      "", "Remove all tagged files and directories.",
 		      "", "LYNXDIRED://REMOVE_TAGGED",		NULL },
 
+{ DE_TAG,	      "", "Untag all tagged files and directories.",
+		      "", "LYNXDIRED://CLEAR_TAGGED",		NULL },
+
 { 0,		    NULL, NULL,
 		    NULL, NULL,					NULL }
 };
@@ -214,7 +221,7 @@ PRIVATE BOOLEAN remove_tagged NOARGS
 	    sprintf(tmpbuf, "remove %s", testpath);
 	    if (my_spawn(RM_PATH, args, tmpbuf) <= 0) {
 		FREE(testpath);
-		return count;
+		return ((count == 0) ? -1 : count);
 	    }
 	    ++count;
 	 }
@@ -379,8 +386,11 @@ PRIVATE BOOLEAN modify_tagged ARGS1(
 	       args[1] = srcpath;
 	       args[2] = savepath;
 	       args[3] = (char *) 0;
-	       if (my_spawn(MV_PATH, args, tmpbuf) <= 0)
+	       if (my_spawn(MV_PATH, args, tmpbuf) <= 0) {
+		  if (count == 0)
+		      count = -1;
 		  break;
+	       }
 	       ++count;
 	    }
 	    FREE(srcpath);
@@ -466,7 +476,7 @@ PRIVATE BOOLEAN modify_name ARGS1(
 	       args[2] = newpath;
 	       args[3] = (char *) 0;
 	       if (my_spawn(MV_PATH, args, tmpbuf) <= 0)
-		  return 0;
+		  return (-1);
 	       return 1; 
 	    }
 	 } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
@@ -587,7 +597,7 @@ PRIVATE BOOLEAN modify_location ARGS1(
 	 args[2] = newpath;
 	 args[3] = (char *) 0;
 	 if (my_spawn(MV_PATH, args, tmpbuf) <= 0)
-	    return 0;
+	    return (-1);
 	 return 1;
       } else {
 	 _statusline("Destination has different owner! Request denied. ");
@@ -719,7 +729,7 @@ PRIVATE BOOLEAN create_file ARGS1(
 	 args[1] = testpath;
 	 args[2] = (char *) 0;
 	 if (my_spawn(TOUCH_PATH, args, tmpbuf) <= 0)
-	    return 0;
+	    return (-1);
 	 return 1;
       } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
 	 _statusline(
@@ -782,7 +792,7 @@ PRIVATE BOOLEAN create_directory ARGS1(
 	 args[1] = testpath;
 	 args[2] = (char *) 0;
 	 if (my_spawn(MKDIR_PATH, args, tmpbuf) <= 0)
-	    return 0;
+	    return (-1);
 	 return 1;
       } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
 	 _statusline(
@@ -888,7 +898,7 @@ PRIVATE BOOLEAN remove_single ARGS1(
       args[2] = testpath;
       args[3] = (char *) 0;
       if (my_spawn(RM_PATH, args, tmpbuf) <= 0)
-	  return 0;
+	  return (-1);
       return 1;
    }
    return 0;
@@ -1178,7 +1188,7 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	args[2] = destpath;
 	args[3] = (char *) 0;
 	if (my_spawn(CHMOD_PATH, args, tmpbuf) <= 0) {
-	    return 0;
+	    return (-1);
 	}
 	++LYforce_no_cache;         /* Force update of dired listing */
 	return 1;
@@ -1259,16 +1269,6 @@ PUBLIC void showtags ARGS1(
    }
 }
 
-PUBLIC char * strip_trailing_slash ARGS1(
-	char *,		dirname)
-{
-   int i;
-
-   i = strlen(dirname) - 1;
-   while (i && dirname[i] == '/') dirname[i--] = '\0';
-   return dirname;
-}
-
 /*
 **  Perform file management operations for LYNXDIRED URL's.
 **  Attempt to be consistent.  These are (pseudo) URLs - i.e. they should
@@ -1301,9 +1301,11 @@ PUBLIC int local_dired ARGS1(
     */
    tp = NULL;
    if (!strncmp(line,"LYNXDIRED://NEW_FILE",20)) {
-      if (create_file(&line[20])) ++LYforce_no_cache;
+      if (create_file(&line[20]) > 0)
+          ++LYforce_no_cache;
    } else if (!strncmp(line,"LYNXDIRED://NEW_FOLDER",22)) {
-      if (create_directory(&line[22])) ++LYforce_no_cache;
+      if (create_directory(&line[22]) > 0)
+          ++LYforce_no_cache;
    } else if (!strncmp(line,"LYNXDIRED://INSTALL_SRC",23)) {
       local_install(NULL, &line[23], &tp);
       StrAllocCopy(doc->address, tp);
@@ -1313,11 +1315,14 @@ PUBLIC int local_dired ARGS1(
       local_install(&line[24], NULL, &tp);
       LYpop(doc);
    } else if (!strncmp(line,"LYNXDIRED://MODIFY_NAME",23)) {
-      if (modify_name(&line[23])) ++LYforce_no_cache;
+      if (modify_name(&line[23]) > 0)
+          ++LYforce_no_cache;
    } else if (!strncmp(line,"LYNXDIRED://MODIFY_LOCATION",27)) {
-      if (modify_location(&line[27])) ++LYforce_no_cache;
+      if (modify_location(&line[27]) > 0)
+          ++LYforce_no_cache;
    } else if (!strncmp(line,"LYNXDIRED://MOVE_TAGGED",23)) {
-      if (modify_tagged(&line_url[23])) ++LYforce_no_cache;
+      if (modify_tagged(&line_url[23]) > 0)
+          ++LYforce_no_cache;
 #ifdef OK_PERMIT
    } else if (!strncmp(line,"LYNXDIRED://PERMIT_SRC",22)) {
       permit_location(NULL, &line[22], &tp);
@@ -1329,9 +1334,12 @@ PUBLIC int local_dired ARGS1(
        permit_location(&line_url[27], NULL, &tp);
 #endif /* OK_PERMIT */
    } else if (!strncmp(line,"LYNXDIRED://REMOVE_SINGLE",25)) {
-      if (remove_single(&line[25])) ++LYforce_no_cache;
+      if (remove_single(&line[25]) > 0)
+          ++LYforce_no_cache;
    } else if (!strncmp(line,"LYNXDIRED://REMOVE_TAGGED",25)) {
       if (remove_tagged()) ++LYforce_no_cache;
+   } else if (!strncmp(line,"LYNXDIRED://CLEAR_TAGGED",24)) {
+      clear_tags();
    } else if (!strncmp(line,"LYNXDIRED://UPLOAD",18)) {
       /*
        *  They're written by LYUpload_options() HTUnEscaped,
@@ -1549,11 +1557,11 @@ PUBLIC int dired_options ARGS2(
 	 cp += 5;
        strcpy(path,cp);
        StrAllocCopy(path_url,cp);
-       if (path_url[strlen(path_url)-1] == '/')
+       if (*path_url && path_url[1] && path_url[strlen(path_url)-1] == '/')
 	   path_url[strlen(path_url)-1] = '\0';
        HTUnEscape(path);
-       if (path[strlen(path)-1] == '/')
-	  path[strlen(path)-1] = '\0';
+       if (*path && path[1] && path[strlen(path)-1] == '/')
+	   path[strlen(path)-1] = '\0';
 
        if (lstat(path,&dir_info) == -1 && stat(path,&dir_info) == -1) {
 	  sprintf(tmpbuf,"Unable to get status of %s ",path);
@@ -1588,8 +1596,35 @@ PUBLIC int dired_options ARGS2(
           fprintf(fp0,"Current selection is %s <p>\n",path);
        else
           fprintf(fp0,"Nothing currently selected. <p>\n");
-    else 
-       fprintf(fp0,"Current selection is all tagged items. <p>\n");
+    else {    /* write out number of tagged items, and names of first
+	      few of them relative to current (in the DIRED sense) directory */
+	int n = HTList_count(tagged);
+	char * cp1 = NULL;
+	char * cd = NULL;
+	int i, m;
+#define NUM_TAGS_TO_WRITE 10
+	fprintf(fp0,"Current selection is %d tagged item%s",
+		n, (n==1 ? ":" : "s:"));
+	StrAllocCopy(cd, doc->address);
+	HTUnEscapeSome(cd, "/");
+	if (*cd && cd[strlen(cd)-1] != '/')
+	    StrAllocCat(cd, "/");
+	m = (n < NUM_TAGS_TO_WRITE) ? n : NUM_TAGS_TO_WRITE;
+	for (i=1; i <= m; i++) {
+		cp1 = HTRelative(HTList_objectAt(tagged, i-1),
+		             (*cd ? cd : "file://localhost"));
+		HTUnEscape(cp1);
+		LYEntify(&cp1, TRUE); /* _should_ do this everywhere... */
+		fprintf(fp0,"%s <br>\n &nbsp;&nbsp;&nbsp;%s",
+			(i==1 ? "" : " ,"), cp1);
+		FREE(cp1);
+	}
+        if (n > m) {
+	    fprintf(fp0," , ...");
+	}
+	fprintf(fp0, " <p>\n");
+	FREE(cd);
+    }
 
     /*
      * if menu_head is NULL then use defaults and link them together now
@@ -1674,7 +1709,7 @@ PRIVATE int my_spawn ARGS3(
 	waitpid(pid, &wstatus, 0); /* wait for child */
 #endif /* NeXT || AIX4 || sony_news */
 	if (WEXITSTATUS(wstatus) != 0 ||
-	    WTERMSIG(wstatus) != 0)  { /* error return */
+	    WTERMSIG(wstatus) > 0)  { /* error return */
 	    sprintf(tmpbuf, "Probable failure to %s due to system error!",
 		    msg);
 	    rc = 0;
@@ -1805,7 +1840,7 @@ PUBLIC BOOLEAN local_install ARGS3(
    if (HTList_isEmpty(tagged)) {
          args[1] = savepath;
 	 if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0)
-	     return count;
+	     return (-1);
 	 count++;
    } else {
        char * name;
@@ -1815,7 +1850,7 @@ PUBLIC BOOLEAN local_install ARGS3(
 	       args[1] = name + 16;
 
 	   if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0)
-	       return count;
+	       return ((count == 0) ? -1 : count);
 	   count++;
        }	
        clear_tags();
diff --git a/src/LYLocal.h b/src/LYLocal.h
index 66dbff4d..6a042e60 100644
--- a/src/LYLocal.h
+++ b/src/LYLocal.h
@@ -33,7 +33,7 @@
 #endif /* !S_ISUID */
 
 /* Special return code for LYMainLoop.c */
-#define PERMIT_FORM_RESULT 2
+#define PERMIT_FORM_RESULT (-99)
 
 extern BOOLEAN local_create PARAMS((document *doc));
 extern BOOLEAN local_modify PARAMS((document *doc, char **newpath));
@@ -56,7 +56,6 @@ extern BOOLEAN is_a_file PARAMS((char *testname));
 */
 extern void tagflag PARAMS((int flag, int cur)); 
 extern void showtags PARAMS((HTList *tag));
-extern char * strip_trailing_slash PARAMS((char * dirname));
 extern int local_dired PARAMS((document *doc));
 extern int dired_options PARAMS ((document *doc, char ** newfile));
 
diff --git a/src/LYMail.c b/src/LYMail.c
index 094e6da8..a0855064 100644
--- a/src/LYMail.c
+++ b/src/LYMail.c
@@ -30,9 +30,12 @@ PUBLIC void mailform ARGS4(
 {
     FILE *fd;
     char *address = NULL;
-    char cmd[512], *cp, *cp0, *cp1;
-    int len, i, ch, recall;
+    char *searchpart = NULL;
+    char *cp = NULL, *cp0 = NULL, *cp1 = NULL;
     char subject[80];
+    char self[80];
+    char cmd[512];
+    int len, i, ch;
 #ifdef VMS
     char tmpfile[256];
     char *address_ptr1, *address_ptr2;
@@ -43,30 +46,77 @@ PUBLIC void mailform ARGS4(
 	HTAlert(BAD_FORM_MAILTO);
 	return;
     }
+    subject[0] = '\0';
+    self[0] = '\0';
 
     if ((cp = (char *)strchr(mailto_address,'\n')) != NULL)
 	*cp = '\0';
     StrAllocCopy(address, mailto_address);
 
     /*
-     *  Check for a ?searchpart with subject=foo. - FM
+     *  Check for a ?searchpart. - FM
      */
-    subject[0] = '\0';
     if ((cp = strchr(address, '?')) != NULL) {
-	*cp++ = '\0';
-	while (*cp != '\0' && strncasecomp(cp, "subject=", 8))
-	    cp++;
-	cp0 = (cp - 1);
-	if ((*cp != '\0') &&
-	    (*cp0 == '\0' || *cp0 == '&' || *cp0 == ';')) {
-	    if ((cp1 = strchr(cp, '&')) != NULL) {
-	        *cp1 = '\0';
-	    } else if ((cp1 = strchr(cp, ';')) != NULL) {
-	        *cp1 = '\0';
+	StrAllocCopy(searchpart, cp);
+        *cp = '\0';
+	cp = (searchpart + 1);
+	if (*cp != '\0') {
+	    /*
+	     *  Seek and handle a subject=foo. - FM
+	     */
+	    while (*cp != '\0') {
+	        if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "subject=", 8))
+		    break;
+	        cp++;
+	    }
+	    if (*cp) {
+		cp += 8;
+		if ((cp1 = strchr(cp, '&')) != NULL) {
+		    *cp1 = '\0';
+		}
+		if (*cp) {
+		    strncpy(subject, cp, 70);
+		    subject[70] = '\0';
+		    HTUnEscape(subject);
+		}
+		if (cp1) {
+		    *cp1 = '&';
+		    cp1 = NULL;
+		}
+	    }
+
+	    /*
+	     *  Seek and handle cc=foo fields.  Excludes Bcc=foo
+	     *  and appends to address, so we can use our own cc
+	     *  field for the actual mailing. - FM
+	     */
+	    cp = (searchpart + 1);
+	    while (*cp != '\0') {
+	        if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "cc=", 3)) {
+		    cp += 3;
+		    if ((cp1 = strchr(cp, '&')) != NULL) {
+		        *cp1 = '\0';
+		    }
+		    while (*cp == ',')
+		        cp++;
+		    if (*cp) {
+			StrAllocCat(address, ",");
+			StrAllocCat(address, cp);
+		    }
+		    if (cp1) {
+		        *cp1 = '&';
+			cp = cp1;
+			cp1 = NULL;
+		    } else {
+		        break;
+		    }
+		}
+	        cp++;
 	    }
-	    strncpy(subject, cp, 70);
-	    subject[70] = '\0';
-	    HTUnEscape(subject);
+
+	    FREE(searchpart);
 	}
     }
 
@@ -90,7 +140,8 @@ PUBLIC void mailform ARGS4(
     }
 
     /*
-     *  Allow user to edit the default Subject. - FM
+     *  Allow user to edit the default Subject
+     *   and enter a cc to self. - FM
      */
     if (subject[0] == '\0') {
         if (mailto_subject && *mailto_subject) {
@@ -101,9 +152,21 @@ PUBLIC void mailform ARGS4(
 	}
 	subject[70] = '\0';
     }
-    recall = 0;
     _statusline(SUBJECT_PROMPT);
-    if ((ch = LYgetstr(subject, VISIBLE, 71, recall)) < 0) {
+    if ((ch = LYgetstr(subject, VISIBLE, 71, NORECALL)) < 0) {
+	/*
+	 * User cancelled via ^G. - FM
+	 */
+	_statusline(FORM_MAILTO_CANCELLED);
+	sleep(InfoSecs);
+	FREE(address);
+	return;
+    }
+    sprintf(self,"%.79s", (personal_mail_address ? 
+			   personal_mail_address : ""));
+    self[79] = '\0';
+    _statusline("Cc: ");
+    if ((ch = LYgetstr(self, VISIBLE, sizeof(self), NORECALL)) < 0) {
 	/*
 	 * User cancelled via ^G. - FM
 	 */
@@ -113,7 +176,32 @@ PUBLIC void mailform ARGS4(
 	return;
     }
 
-#ifdef UNIX
+#ifdef VMS
+    sprintf(tmpfile, "%s%s", lynx_temp_space, "temp_mail.txt");
+    if ((fd = fopen(tmpfile,"w")) == NULL) {
+	HTAlert(FORM_MAILTO_FAILED);
+	FREE(address);
+	return;
+    }
+    if (*self) {
+        cp = self;
+	while (*cp == ' ' || *cp == ',')
+	    cp++;
+	if (*cp) {
+	    StrAllocCat(address, ",");
+	    StrAllocCat(address, cp);
+	}
+    }
+    if (mailto_type &&
+        !strncasecomp(mailto_type, "multipart/form-data", 19)) {
+	/*
+	 *  Ugh!  There's no good way to include headers while
+	 *  we're still using "generic" VMS MAIL, so we'll put
+	 *  this in the body of the message. - FM
+	 */
+	fprintf(fd, "X-Content-Type: %s\n\n", mailto_type);
+    }
+#else
 #ifdef MMDF
     sprintf(cmd, "%s -mlruxto,cc\\*",system_mail);
 #else
@@ -133,25 +221,11 @@ PUBLIC void mailform ARGS4(
     fprintf(fd,"To: %s\n", address);
     if (personal_mail_address && *personal_mail_address)
 	fprintf(fd,"From: %s\n", personal_mail_address);
+    remove_tildes(self);
+    if (*self)
+	fprintf(fd,"Cc: %s\n", self);
     fprintf(fd,"Subject: %.70s\n\n", subject);
     _statusline(SENDING_FORM_CONTENT);
-#endif /* UNIX */
-#ifdef VMS
-    sprintf(tmpfile,"%s%s",lynx_temp_space, "temp_mail.txt");
-    if ((fd = fopen(tmpfile,"w")) == NULL) {
-	HTAlert(FORM_MAILTO_FAILED);
-	FREE(address);
-	return;
-    }
-    if (mailto_type &&
-        !strncasecomp(mailto_type, "multipart/form-data", 19)) {
-	/*
-	 *  Ugh!  There's no good way to include headers while
-	 *  we're still using "generic" VMS MAIL, so we'll put
-	 *  this in the body of the message. - FM
-	 */
-	fprintf(fd, "X-Content-Type: %s\n\n", mailto_type);
-    }
 #endif /* VMS */
 
     /*
@@ -192,7 +266,10 @@ PUBLIC void mailform ARGS4(
 #endif /* UNIX */
 #ifdef VMS
     fclose(fd);
-    sprintf(cmd, "%s /subject=\"%.70s\" %s ",system_mail, subject,tmpfile);
+    sprintf(cmd, "%s %s/subject=\"%.70s\" %s ",
+    		 system_mail,
+		 (strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"),
+		 subject, tmpfile);
 
     address_ptr1 = address;
     do {
@@ -204,7 +281,7 @@ PUBLIC void mailform ARGS4(
 
 	if (strlen(address) > 3) {
 	    if (!first)
-		strcat(cmd, ", ");  /* add a comma and a space */
+		strcat(cmd, ",");  /* add a comma */
 	    sprintf( &cmd[strlen(cmd)], mail_adrs, address_ptr1);
 	    first = FALSE;
 	}
@@ -248,7 +325,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
     /*
      *  Check for a ?searchpart and trim it. - FM
      */
-    if ((cp = strchr(address, '?')) != NULL && strchr(cp+1, '=') != NULL)
+    if ((cp = strchr(address, '?')) != NULL)
 	*cp = '\0';
 
     /*
@@ -324,7 +401,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
 
 	if (strlen(address) > 3) {
 	    if (!first)
-		strcat(cmd, ", ");  /* add a comma and a space */
+		strcat(cmd, ",");  /* add a comma */
 	    sprintf(&cmd[strlen(cmd)], mail_adrs, address_ptr1);
 	    first = FALSE;
 	}
@@ -375,8 +452,12 @@ PUBLIC void reply_by_mail ARGS3(
 {
     char user_input[1000];
     FILE *fd;
-    char *address = NULL, *cp, *cp0, *cp1;
-    int i;
+    char *address = NULL;
+    char *searchpart = NULL;
+    char *body = NULL;
+    char *cp = NULL, *cp0 = NULL, *cp1 = NULL;
+    char *temp = NULL;
+    int i, len;
     int c = 0;  /* user input */
     char tmpfile[256], cmd[512];
     static char *personal_name = NULL;
@@ -413,26 +494,139 @@ PUBLIC void reply_by_mail ARGS3(
 	HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
 	return;
     }
+    subject[0] = '\0';
 
     /*
-     *  Check for a ?searchpart with subject=foo. - FM
+     *  Check for a ?searchpart. - FM
      */
-    subject[0] = '\0';
     if ((cp = strchr(address, '?')) != NULL) {
-	*cp++ = '\0';
-	while (*cp != '\0' && strncasecomp(cp, "subject=", 8))
-	    cp++;
-	cp0 = (cp - 1);
-	if ((*cp != '\0') &&
-	    (*cp0 == '\0' || *cp0 == '&' || *cp0 == ';')) {
-	    if ((cp1 = strchr(cp, '&')) != NULL) {
-	        *cp1 = '\0';
-	    } else if ((cp1 = strchr(cp, ';')) != NULL) {
-	        *cp1 = '\0';
+	StrAllocCopy(searchpart, cp);
+	*cp = '\0';
+	cp = (searchpart + 1);
+	if (*cp != '\0') {
+	    /*
+	     *  Seek and handle a subject=foo. - FM
+	     */
+	    while (*cp != '\0') {
+	        if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "subject=", 8))
+		    break;
+	        cp++;
+	    }
+	    if (*cp) {
+		cp += 8;
+		if ((cp1 = strchr(cp, '&')) != NULL) {
+		    *cp1 = '\0';
+		}
+		if (*cp) {
+		    strncpy(subject, cp, 70);
+		    subject[70] = '\0';
+		    HTUnEscape(subject);
+		}
+		if (cp1) {
+		    *cp1 = '&';
+		    cp1 = NULL;
+		}
 	    }
-	    strncpy(subject, cp, 70);
-	    subject[70] = '\0';
-	    HTUnEscape(subject);
+
+	    /*
+	     *  Seek and handle cc=foo fields.  Excludes Bcc=foo
+	     *  and appends to address, so we can use our own cc
+	     *  field for the actual mailing. - FM
+	     */
+	    cp = (searchpart + 1);
+	    while (*cp != '\0') {
+	        if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "cc=", 3)) {
+		    cp += 3;
+		    if ((cp1 = strchr(cp, '&')) != NULL) {
+		        *cp1 = '\0';
+		    }
+		    while (*cp == ',')
+		        cp++;
+		    if (*cp) {
+		        StrAllocCat(address, ",");
+			StrAllocCat(address, cp);
+		    }
+		    if (cp1) {
+		        *cp1 = '&';
+			cp = cp1;
+			cp1 = NULL;
+		    } else {
+		        break;
+		    }
+		}
+	        cp++;
+	    }
+
+	    /*
+	     *  Seek and handle body=foo fields. - FM
+	     */
+	    cp = (searchpart + 1);
+	    while (*cp != '\0') {
+	        if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
+		    !strncasecomp(cp, "body=", 5)) {
+		    cp += 5;
+		    if ((cp1 = strchr(cp, '&')) != NULL) {
+		        *cp1 = '\0';
+		    }
+		    if (*cp) {
+			/*
+			 *  Break up the value into lines with
+			 *  a maximimum length of 78. - FM
+			 */
+		        StrAllocCopy(temp, cp);
+			HTUnEscape(temp);
+			cp0 = temp;
+			while((cp = strchr(cp0, '\n')) != NULL) {
+			    *cp = '\0';
+			    if (cp > cp0) {
+			        if (*(cp - 1) == '\r') {
+				    *(cp - 1) = '\0';
+				}
+			    }
+			    i = 0;
+			    len = strlen(cp0);
+			    while (len > 78) {
+				strncpy(cmd, (char *)&cp0[i], 78);
+				cmd[78] = '\0';
+				strcat(cmd, "\n");
+				StrAllocCat(body, cmd);
+				i += 78;
+				len = strlen((char *)&cp0[i]);
+			    }
+			    sprintf(cmd, "%s\n", (char *)&cp0[i]);
+			    StrAllocCat(body, cmd);
+			    cp0 = (cp + 1);
+			}
+			i = 0;
+			len = strlen(cp0);
+			while (len > 78) {
+			    strncpy(cmd, (char *)&cp0[i], 78);
+			    cmd[78] = '\0';
+			    strcat(cmd, "\n");
+			    StrAllocCat(body, cmd);
+			    i += 78;
+			    len = strlen((char *)&cp0[i]);
+			}
+			if (len) {
+			    sprintf(cmd, "%s\n", (char *)&cp0[i]);
+			    StrAllocCat(body, cmd);
+			}
+			FREE(temp);
+		    }
+		    if (cp1) {
+		        *cp1 = '&';
+			cp = cp1;
+			cp1 = NULL;
+		    } else {
+		        break;
+		    }
+		}
+	        cp++;
+	    }
+
+	    FREE(searchpart);
 	}
     }
     if (subject[0] == '\0' && title && *title) {
@@ -458,8 +652,11 @@ PUBLIC void reply_by_mail ARGS3(
 	}
 	cp = cp1;
     }
+    if (address[(strlen(address) - 1)] == ',')
+        address[(strlen(address) - 1)] == '\0';
     if (*address == '\0') {
         FREE(address);
+	FREE(body);
 	fclose(fd);		/* Close the tmpfile.  */
 	remove(tmpfile);	/* Delete the tmpfile. */
 	HTAlert(NO_ADDRESS_IN_MAILTO_URL);
@@ -474,16 +671,18 @@ PUBLIC void reply_by_mail ARGS3(
 
     
 #ifdef VMS
-    /*
-     *  Put the X-URL and X-Mailer lines in the tmpfile.
-     */
-    fprintf(fd, "X-URL: %s%s\n",
-    		(filename && *filename) ? filename : "mailto:",
-		(filename && *filename) ? "" : address);
-    fprintf(fd,"X-Mailer: Lynx, Version %s\n",LYNX_VERSION);
+    if (!body) {
+	/*
+	 *  Put the X-URL and X-Mailer lines in the tmpfile.
+	 */
+	fprintf(fd, "X-URL: %s%s\n",
+		    (filename && *filename) ? filename : "mailto:",
+		    (filename && *filename) ? "" : address);
+	fprintf(fd,"X-Mailer: Lynx, Version %s\n",LYNX_VERSION);
 #ifdef NO_ANONYMOUS_MAIL
-    fprintf(fd,"\n");
+	fprintf(fd,"\n");
 #endif /* NO_ANONYMOUS_MAIL */
+    }
 #else /* Unix: */
     /*
      *  Put the To: line in the header.
@@ -502,26 +701,43 @@ PUBLIC void reply_by_mail ARGS3(
 #endif /* VMS */
 
     /*
-     *  Cear the screen and inform the user.
+     *  Clear the screen and inform the user.
      */
     clear();
     move(2,0);
-    scrollok(stdscr,TRUE);	/* Enable scrolling. */
-    addstr("You are now sending a comment to:");
-    addstr("\n	");
-    addstr(address);
-    addstr("\n\nUse Ctrl-G to cancel if you do not want to send a message\n");
+    scrollok(stdscr, TRUE);	/* Enable scrolling. */
+    if (body)
+	addstr(SENDING_MESSAGE_WITH_BODY_TO);
+    else
+	addstr(SENDING_COMMENT_TO);
+    cp = address;
+    while ((cp1 = strchr(cp, ',')) != NULL) {
+        *cp1 = '\0';
+	while (*cp == ' ')
+	    cp++;
+	if (*cp) {
+	    addstr(cp);
+	    addstr(",\n  ");
+	}
+	*cp1 = ',';
+	cp = (cp1 + 1);
+    }
+    if (*cp)
+        addstr(cp);
+    addstr(CTRL_G_TO_CANCEL_SEND);
 
+#ifdef VMS
+    if (!body) {
+#endif /* VMS */
 #ifndef NO_ANONYMOUS_EMAIL
     /*
      *  Get the user's personal name.
      */
-    addstr("\n Please enter your name, ");
-    addstr("or leave it blank if you wish to remain anonymous\n");
+    addstr(ENTER_NAME_OR_BLANK);
     if (personal_name == NULL)
 	*user_input = '\0';
     else {
-	addstr(" Use Control-U to erase the default.\n");
+	addstr(CTRL_U_TO_ERASE);
 	strcpy(user_input, personal_name);
     }
 #ifdef VMS
@@ -554,10 +770,10 @@ PUBLIC void reply_by_mail ARGS3(
     /*
      *  Get the user's return address.
      */
-    addstr("\n Please enter a mail address or some other\n");
-    addstr(" means to contact you, if you desire a response.\n");
+    addstr(ENTER_MAIL_ADDRESS_OR_OTHER);
+    addstr(MEANS_TO_CONTACT_FOR_RESPONSE);
     if (personal_mail_address)
-	addstr(" Use Control-U to erase the default.\n");
+	addstr(CTRL_U_TO_ERASE);
 #ifdef VMS
     addstr("X-From: ");
 #else
@@ -587,12 +803,15 @@ PUBLIC void reply_by_mail ARGS3(
     StrAllocCat(header, buf);
 #endif /* VMS */
 #endif /* !NO_ANONYMOUS_EMAIL */
+#ifdef VMS
+    }
+#endif /* VMS */
 
     /*
      *  Get the subject line.
      */
-    addstr("\n Please enter a subject line.\n");
-    addstr(" Use Control-U to erase the default.\n");
+    addstr(ENTER_SUBJECT_LINE);
+    addstr(CTRL_U_TO_ERASE);
     addstr("Subject: ");
     /* Add the default subject. */
     sprintf(user_input, "%.70s%.63s",
@@ -622,14 +841,13 @@ PUBLIC void reply_by_mail ARGS3(
     StrAllocCat(header, buf);
 #endif /* VMS */
 
-#ifndef VMS
     /*
      *  Offer a CC line.
      */
-    addstr("\n Enter a mail address for a CC of your message.\n");
+    addstr(ENTER_ADDRESS_FOR_CC);
     if (personal_mail_address)
-	addstr(" Use Control-U to erase the default.\n");
-    addstr(" (Leave blank if you don't want a copy.)\n");
+	addstr(CTRL_U_TO_ERASE);
+    addstr(BLANK_FOR_NO_COPY);
     addstr("Cc: ");
     /* Add the mail address if there is one. */
     sprintf(user_input,"%s", (personal_mail_address ? 
@@ -645,6 +863,17 @@ PUBLIC void reply_by_mail ARGS3(
     }
     addstr("\n");
     remove_tildes(user_input);
+#ifdef VMS
+    if (*user_input) {
+        cp = user_input;
+	while (*cp == ' ' || *cp == ',')
+	    cp++;
+	if (*cp) {
+	    StrAllocCat(address, ",");
+	    StrAllocCat(address, cp);
+	}
+    }
+#else
     if (*user_input) {
 	sprintf(buf,"Cc: %s\n",user_input);
 	StrAllocCat(header, buf);
@@ -655,7 +884,7 @@ PUBLIC void reply_by_mail ARGS3(
      */
     sprintf(buf,"\n");
     StrAllocCat(header, buf);
-#endif /* !VMS */
+#endif /* VMS */
 
     if (!no_editor && editor && *editor != '\0') {
         /*
@@ -663,7 +892,14 @@ PUBLIC void reply_by_mail ARGS3(
 	 */
 	char *editor_arg = "";
 
-	if (strcmp(HTLoadedDocumentURL(),"")) {
+	if (body) {
+	    cp1 = body;
+	    while((cp = strchr(cp1, '\n')) != NULL) {
+	        *cp++ = '\0';
+		fprintf(fd, "%s\n", cp1);
+		cp1 = cp;
+	    }
+	} else if (strcmp(HTLoadedDocumentURL(), "")) {
             /*
 	     *  Ask if the user wants to include the original message.
 	     */
@@ -674,7 +910,7 @@ PUBLIC void reply_by_mail ARGS3(
                 c = LYgetch();
             if (TOUPPER(c) == 'Y') {
                 /* the 1 will add the reply ">" in front of every line */
-                print_wwwfile_to_fd(fd,1);
+                print_wwwfile_to_fd(fd, 1);
 	    }
         }
 	fclose(fd);		/* Close the tmpfile. */
@@ -700,13 +936,53 @@ PUBLIC void reply_by_mail ARGS3(
 	    start_curses();
 	}
 
+    } else if (body) {
+	/*
+	 *  Let user review the body. - FM
+	 */
+	clear();
+	move(0,0);
+	addstr(REVIEW_MESSAGE_BODY);
+	refresh();
+	cp1 = body;
+	i = (LYlines - 5);
+	while((cp = strchr(cp1, '\n')) != NULL) {
+	    if (i <= 0) {
+	        addstr(RETURN_TO_CONTINUE);
+		refresh();
+		c = LYgetch();
+		addstr("\n");
+		if (term_letter || c == 7 || c == 3) {
+		    addstr(CANCELLED);
+		    sleep(InfoSecs);
+		    fclose(fd);			/* Close the tmpfile. */
+		    scrollok(stdscr, FALSE);	/* Stop scrolling.    */
+		    goto cleanup;
+		}
+		i = (LYlines - 2);
+	    }
+	    *cp++ = '\0';
+	    sprintf(cmd, "%s\n", cp1);
+	    fprintf(fd, cmd);
+	    addstr(cmd);
+	    cp1 = cp;
+	    i--;
+	}
+	while (i >= 0) {
+	    addstr("\n");
+	    i--;
+	}
+	refresh();
+	fclose(fd);		/* Close the tmpfile.	  */
+	scrollok(stdscr,FALSE);	/* Stop scrolling.	  */
+
     } else {
         /*
 	 *  Use the internal line editor for the message.
 	 */
-	addstr("\n Please enter your message below.");
-	addstr("\n When you are done, press enter and put a single period (.)");
-	addstr("\n on a line and press enter again.");
+	addstr(ENTER_MESSAGE_BELOW);
+	addstr(ENTER_PERIOD_WHEN_DONE_A);
+	addstr(ENTER_PERIOD_WHEN_DONE_B);
 	addstr("\n\n");
 	refresh();
     	*user_input = '\0';
@@ -745,7 +1021,12 @@ PUBLIC void reply_by_mail ARGS3(
      */
     signal(SIGINT, SIG_IGN);
 #endif /* !VMS */
-    _statusline(SEND_COMMENT_PROMPT);
+    LYStatusLine = (LYlines - 1);
+    if (body)
+        _statusline(SEND_MESSAGE_PROMPT);
+    else
+        _statusline(SEND_COMMENT_PROMPT);
+    LYStatusLine = -1;
     c = 0;
     while (TOUPPER(c) != 'Y' && TOUPPER(c) != 'N' &&
 	   !term_letter && c != 7   && c != 3)
@@ -764,7 +1045,10 @@ PUBLIC void reply_by_mail ARGS3(
     /*
      *  Set the mail command.
      */
-    sprintf(cmd, "%s /subject=\"%s\" %s ", system_mail, subject, tmpfile);
+    sprintf(cmd, "%s %s/subject=\"%s\" %s ",
+    		 system_mail,
+		 (strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"),
+		 subject, tmpfile);
 
     /*
      *  Now add all the people in the address field.
@@ -784,7 +1068,7 @@ PUBLIC void reply_by_mail ARGS3(
 	 */
 	if (strlen(address_ptr1) > 3) {	
 	    if (!first)
-		strcat(cmd, ", ");  /* add a comma and a space */
+		strcat(cmd, ",");  /* add a comma */
 	    sprintf( &cmd[strlen(cmd)], mail_adrs, address_ptr1);
 	    first = FALSE;
 	}
@@ -847,6 +1131,7 @@ cleandown:
     term_letter = FALSE;
     remove(tmpfile);	/* Delete the tmpfile. */
     FREE(address);
+    FREE(body);
     return;
 }
 
diff --git a/src/LYMain.c b/src/LYMain.c
index 963a528a..6c45c54d 100644
--- a/src/LYMain.c
+++ b/src/LYMain.c
@@ -81,6 +81,10 @@ PUBLIC char *syslog_txt = NULL;		/* syslog arb text for session */
 #endif /* SYSLOG_REQUESTED_URLS */
 #endif /* !VMS */
 
+#ifdef VMS
+PUBLIC char *LYCSwingPath = NULL;
+#endif /* VMS */
+
 #ifdef DIRED_SUPPORT
 PUBLIC BOOLEAN lynx_edit_mode = FALSE;
 PUBLIC BOOLEAN no_dired_support = FALSE;
@@ -225,13 +229,14 @@ PUBLIC char *jumpfile = NULL;	/* the name of the default jumps file */
 PUBLIC char *jumpprompt = NULL;	/* the default jumps prompt */
 PUBLIC char *bookmark_page = NULL; /* the name of the default bookmark page */
 PUBLIC char *BookmarkPage = NULL;  /* the name of the current bookmark page */
+PUBLIC char *LynxHome = NULL;	/* the default Home HREF. */
 PUBLIC char *startfile = NULL;	/* the first file */
 PUBLIC char *helpfile = NULL; 	/* the main help file */
 PUBLIC char *helpfilepath = NULL;   /* the path to the help file set */
 PUBLIC char *aboutfilepath = NULL;  /* the path to the about lynx file */
 PUBLIC char *lynxjumpfile = NULL;   /* the current jump file URL */
 PUBLIC char *lynxlistfile = NULL;   /* the current list file URL */
-PUBLIC char *lynxbookfile = NULL;   /* the current bookmark file URL */
+PUBLIC char *lynxlinksfile = NULL;  /* the current visited links file URL */
 PUBLIC char *startrealm = NULL;     /* the startfile realm */
 PUBLIC char *indexfile = NULL;	    /* an index file if there is one */
 PUBLIC char *personal_mail_address = NULL; /* the users mail address */
@@ -296,7 +301,10 @@ PUBLIC BOOLEAN LYSelectPopups = USE_SELECT_POPUPS;
 PUBLIC BOOLEAN LYUseDefSelPop = TRUE;	/* Command line -popup toggle */
 PUBLIC int LYMultiBookmarks = MULTI_BOOKMARK_SUPPORT;
 PUBLIC BOOLEAN LYMBMBlocked = BLOCK_MULTI_BOOKMARKS;
-PUBLIC BOOLEAN LYMBMAdvanced = ADVANCED_MULTI_BOOKMARKS;
+PUBLIC BOOLEAN LYMBMAdvanced = TRUE;
+PUBLIC int LYStatusLine = -1;		 /* Line for statusline() if > -1 */
+PUBLIC BOOLEAN LYCollapseBRs = COLLAPSE_BR_TAGS;  /* Collapse serial BRs? */
+PUBLIC BOOLEAN LYSetCookies = SET_COOKIES; /* Process Set-Cookie headers? */
 
 /* These are declared in cutil.h for current freeWAIS libraries. - FM */
 #ifdef DECLARE_WAIS_LOGFILES
@@ -310,12 +318,11 @@ extern int HTNewsMaxChunk;  /* Max news articles before chunking (HTNews.c) */
 
 extern int mainloop NOPARAMS;
 
-
-PRIVATE BOOLEAN anon_restrictions_set=FALSE;
-PRIVATE BOOLEAN stack_dump=FALSE;
-PRIVATE char *terminal=NULL;
+PRIVATE BOOLEAN anon_restrictions_set = FALSE;
+PRIVATE BOOLEAN stack_dump = FALSE;
+PRIVATE char *terminal = NULL;
 PRIVATE char *pgm;
-PRIVATE BOOLEAN number_links=FALSE;
+PRIVATE BOOLEAN number_links = FALSE;
 
 PRIVATE void parse_arg PARAMS((char **arg, int *i, int argc));
 #ifndef VMS
@@ -349,8 +356,10 @@ PRIVATE void free_lynx_globals NOARGS
 #ifdef VMS
     Define_VMSLogical("LYNX_VERSION", "");
     FREE(mail_adrs);
+    FREE(LYCSwingPath);
 #endif /* VMS */
 
+    FREE(LynxHome);
     FREE(startfile);
     FREE(helpfile);
     FREE(jumpprompt);
@@ -366,7 +375,6 @@ PRIVATE void free_lynx_globals NOARGS
     FREE(pref_charset);
     FREE(inews_path);
     FREE(system_mail);
-    FREE(lynx_temp_space);
     FREE(LYUserAgent);
     FREE(LYUserAgentDefault);
     FREE(LYHostName);
@@ -389,28 +397,26 @@ PRIVATE void free_lynx_globals NOARGS
     FREE(personal_mail_address);
     FREE(URLDomainPrefixes);
     FREE(URLDomainSuffixes);
-    for (i = 0; i < MAXLINKS; i++) {
+    for (i = 0; i < nlinks; i++) {
         FREE(links[i].lname);
     }
-    for (i = 0; i < nhist; i++) {
-        FREE(history[i].title);
-        FREE(history[i].address);
-        FREE(history[i].post_data);
-        FREE(history[i].post_content_type);
-    }
+    nlinks = 0;
 
     return;
 }
 
-
 /*
  * Wow!  Someone wants to start up Lynx.
  */
-PUBLIC int main ARGS2(int,argc, char **,argv)
+PUBLIC int main ARGS2(
+	int,		argc,
+	char **,	argv)
 {
-    int  i;	/* indexing variable */
-    int status=0;	/* exit status */
-    char *lynx_cfg_file=NULL;
+    int  i;		/* indexing variable */
+    int status = 0;	/* exit status */
+    int len;
+    char *lynx_cfg_file = NULL;
+    char *temp = NULL;
     char *cp;
     FILE *fp;
 
@@ -477,7 +483,7 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
 #ifdef JUMPFILE
     StrAllocCopy(jumpfile, JUMPFILE);
     {
-        char *temp = (char *)malloc(strlen(jumpfile) + 10);
+        temp = (char *)malloc(strlen(jumpfile) + 10);
 	if (!temp) {
 	    outofmem(__FILE__, "main");
 	} else {
@@ -499,16 +505,14 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
     StrAllocCopy(pref_charset, PREFERRED_CHARSET);
     StrAllocCopy(inews_path, INEWS);
     StrAllocCopy(system_mail, SYSTEM_MAIL);
-    if ((cp=getenv("LYNX_TEMP_SPACE")) != NULL)
+    if ((cp = getenv("LYNX_TEMP_SPACE")) != NULL)
         StrAllocCopy(lynx_temp_space, cp);
     else
         StrAllocCopy(lynx_temp_space, TEMP_SPACE);
     if ((cp = strchr(lynx_temp_space, '~'))) {
-	char *temp = NULL;
-	int len;
 	*(cp++) = '\0';
 	StrAllocCopy(temp, lynx_temp_space);
-	if ((len=strlen(temp)) > 0 && temp[len-1] == '/')
+	if (((len = strlen(temp)) > 0) && temp[len-1] == '/')
 	    temp[len-1] = '\0';
 #ifdef VMS
 	StrAllocCat(temp, HTVMS_wwwName((char *)Home_Dir()));
@@ -523,7 +527,7 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
     StrAllocCat(LYUserAgent, "/");
     StrAllocCat(LYUserAgent, LYNX_VERSION);
     if (HTLibraryVersion) {
-        StrAllocCat(LYUserAgent, "  libwww-FM/");
+        StrAllocCat(LYUserAgent, " libwww-FM/");
 	StrAllocCat(LYUserAgent, HTLibraryVersion);
     }
     StrAllocCopy(LYUserAgentDefault, LYUserAgent);
@@ -538,10 +542,7 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
     for (i = 0; lynx_temp_space[i]; i++)
         lynx_temp_space[i] = TOLOWER(lynx_temp_space[i]);
     if (strchr(lynx_temp_space, '/') != NULL) {
-        char *temp = NULL;
-	int len = strlen(lynx_temp_space);
-
-	if (len == 1) {
+	if ((len = strlen(lynx_temp_space)) == 1) {
 	    StrAllocCopy(lynx_temp_space, "sys$scratch:");
 	} else {
 	    if (lynx_temp_space[len-1] != '/')
@@ -557,14 +558,18 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
     }
 #else
     {
-        int len = strlen(lynx_temp_space);
-	if (len > 1 && lynx_temp_space[len-1] != '/') {
+        len;
+	if (((len = strlen(lynx_temp_space)) > 1) &&
+	    lynx_temp_space[len-1] != '/') {
 	    StrAllocCat(lynx_temp_space, "/");
 	}
     }
 #endif /* VMS */
 #ifdef VMS
     StrAllocCopy(mail_adrs, MAIL_ADRS);
+#ifdef CSWING_PATH
+    StrAllocCopy(LYCSwingPath, CSWING_PATH);
+#endif /* CSWING_PATH */
 #endif /* VMS */
 #ifdef LYNX_HOST_NAME
     StrAllocCopy(LYHostName, LYNX_HOST_NAME);
@@ -665,12 +670,9 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
      *  Convert a '~' in the configuration file path to $HOME.
      */
     if ((cp = strchr(lynx_cfg_file, '~'))) {
-	char *temp = NULL;
-	int len;
-
 	*(cp++) = '\0';
 	StrAllocCopy(temp, lynx_cfg_file);
-	if ((len=strlen(temp)) > 0 && temp[len-1] == '/')
+	if (((len = strlen(temp)) > 0) && temp[len-1] == '/')
 	    temp[len-1] = '\0';
 #ifdef VMS
 	StrAllocCat(temp, HTVMS_wwwName((char *)Home_Dir()));
@@ -730,12 +732,9 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
     }
     if (lynx_save_space) {
         if ((cp = strchr(lynx_save_space, '~')) != NULL) {
-	    char *temp = NULL;
-	    int len;
-
 	    *(cp++) = '\0';
 	    StrAllocCopy(temp, lynx_save_space);
-	    if ((len=strlen(temp)) > 0 && temp[len-1] == '/')
+	    if (((len = strlen(temp)) > 0) && temp[len-1] == '/')
 	        temp[len-1] = '\0';
 #ifdef VMS
 	    StrAllocCat(temp, HTVMS_wwwName((char *)Home_Dir()));
@@ -750,11 +749,8 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
         for (i = 0; lynx_save_space[i]; i++)
             lynx_save_space[i] = TOLOWER(lynx_save_space[i]);
         if (strchr(lynx_save_space, '/') != NULL) {
-            char *temp = NULL;
-	    int len = strlen(lynx_save_space);
-
-	    if (len == 1) {
-	        StrAllocCopy(lynx_save_space, "sys$scratch:");
+	    if ((len = strlen(lynx_save_space)) == 1) {
+	        StrAllocCopy(lynx_save_space, "sys$login:");
 	    } else {
 	        if (lynx_save_space[len-1] != '/')
 	            StrAllocCat(lynx_save_space, "/");
@@ -769,9 +765,8 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
 	}
 #else
     {
-        int len = strlen(lynx_save_space);
-
-	if (len > 1 && lynx_save_space[len-1] != '/') {
+	if (((len = strlen(lynx_save_space)) > 1) &&
+	    lynx_save_space[len-1] != '/') {
 	    StrAllocCat(lynx_save_space, "/");
 	}
     }
@@ -795,6 +790,15 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
 	StrAllocCopy(startfile, cp);
 
     /*
+     *  Set the LynxHome URL.  If it's a file URL and the
+     *  host is defaulted, force in "//localhost", and if
+     *  it's not an absolute URL, make it one. - FM
+     */
+    StrAllocCopy(LynxHome, startfile);
+    LYFillLocalFileURL((char **)&LynxHome, "file://localhost");
+    LYEnsureAbsoluteURL((char **)&LynxHome, "LynxHome");
+
+    /*
      *  Process arguments - with none, look for the database in STARTDIR,
      *  starting with STARTFILE.
      *
@@ -823,7 +827,7 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
 	    parse_arg(argv, NULL, -1);
 	}
     } else {
-	for (i=1; i<argc; i++) {
+	for (i = 1; i < argc; i++) {
 	    parse_arg(&argv[i], &i, argc);
 	}
     }
@@ -933,136 +937,32 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
 
     /*
      *  If startfile is a file URL and the host is defaulted,
-     *  force in "//localhost".  We need this until all the
-     *  other Lynx code which performs security checks based
-     *  on the "localhost" string is changed to assume
-     *  "//localhost" when a host field is not present in file
-     *  URLs - FM
-     */
-    if (!strncmp(startfile, "file:", 5)) {
-	char *temp=NULL;
-        if (startfile[5] == '\0') {
-            StrAllocCat(startfile, "//localhost");
-        } else if (!strcmp(startfile, "file://")) {
-            StrAllocCat(startfile, "localhost");
-        } else if (!strncmp(startfile, "file:///", 8)) {
-	    StrAllocCopy(temp, (startfile+7));
-	    StrAllocCopy(startfile, "file://localhost");
-	    StrAllocCat(startfile, temp);
-	    FREE(temp);
-        } else if (!strncmp(startfile, "file:/", 6) && startfile[6] != '/') {
-	    StrAllocCopy(temp, (startfile+5));
-	    StrAllocCopy(startfile, "file://localhost");
-	    StrAllocCat(startfile, temp);
-	    FREE(temp);
-	}
-    }
-
-    /*
-     *  No path in a file://localhost URL for startfile means
-     *  a directory listing for the current default. - FM
-     */
-    if (!strcmp(startfile, "file://localhost")) {
-#ifdef VMS
-	StrAllocCat(startfile, HTVMS_wwwName(getenv("PATH")));
-#else
-        char curdir[DIRNAMESIZE];
-#ifdef NO_GETCWD
-      	getwd (curdir);
-#else
-    	getcwd (curdir, DIRNAMESIZE);
-#endif /* NO_GETCWD */
-	StrAllocCat(startfile, curdir);
-#endif /* VMS */
-    }
-
-#ifdef VMS
-    /*
-     *  On VMS, a file://localhost/ URL for startfile
-     *  means a listing for the login directory. - FM
-     */
-    if (!strcmp(startfile, "file://localhost/"))
-	StrAllocCat(startfile, (HTVMS_wwwName((char *)Home_Dir())+1));
-#endif /* VMS */
-
-    /*
-     *  If it is not a URL then make it one.
-     */
-    if (!is_url(startfile)) {
-	if (TRACE)
-	    fprintf(stderr, "STARTFILE '%s' is not a URL\n", startfile);
-        LYConvertToURL(&startfile);
-    }
-
-    /*
-     *  If homepage is a file URL and the host is defaulted,
-     *  force in "//localhost".  We need this until all the
-     *  other Lynx code which performs security checks based
-     *  on the "localhost" string is changed to assume
-     *  "//localhost" when a host field is not present in file
-     *  URLs - FM
-     */
-    if (homepage && !strncmp(homepage, "file:", 5)) {
-	char *temp=NULL;
-        if (homepage[5] == '\0') {
-            StrAllocCat(homepage, "//localhost");
-        } else if (!strcmp(homepage, "file://")) {
-            StrAllocCat(homepage, "localhost");
-        } else if (!strncmp(homepage, "file:///", 8)) {
-	    StrAllocCopy(temp, (homepage+7));
-	    StrAllocCopy(homepage, "file://localhost");
-	    StrAllocCat(homepage, temp);
-	    FREE(temp);
-        } else if (!strncmp(homepage, "file:/", 6) && homepage[6] != '/') {
-	    StrAllocCopy(temp, (homepage+5));
-	    StrAllocCopy(homepage, "file://localhost");
-	    StrAllocCat(homepage, temp);
-	    FREE(temp);
-	}
-    }
-
-    /*
-     *  No path in a file://localhost URL for homepage means
-     *  a directory listing for the current default. - FM
-     */
-    if (homepage && !strcmp(homepage, "file://localhost")) {
-#ifdef VMS
-	StrAllocCat(homepage, HTVMS_wwwName(getenv("PATH")));
-#else
-        char curdir[DIRNAMESIZE];
-#ifdef NO_GETCWD
-      	getwd (curdir);
-#else
-    	getcwd (curdir, DIRNAMESIZE);
-#endif /* NO_GETCWD */
-	StrAllocCat(homepage, curdir);
-#endif /* VMS */
-    }
-
-#ifdef VMS
-    /*
-     *  On VMS, a file://localhost/ URL for homepage
-     *  means a listing for the login directory. - FM
+     *  force in "//localhost", and if it's not an absolute URL,
+     *  make it one. - FM
      */
-    if (homepage && !strcmp(homepage, "file://localhost/"))
-	StrAllocCat(homepage, (HTVMS_wwwName((char *)Home_Dir())+1));
-#endif /* VMS */
+    LYFillLocalFileURL((char **)&startfile, "file://localhost");
+    LYEnsureAbsoluteURL((char **)&startfile, "STARTFILE");
 
     /*
-     *  If it is not a URL then make it one.
+     *  If homepage was specified and is a file URL with the
+     *  host defaulted, force in "//localhost", and if it's
+     *  not an absolute URL, make it one. - FM
      */
-    if (homepage && !is_url(homepage)) {
-	if (TRACE)
-	    fprintf(stderr, "HOMEPAGE '%s' is not a URL\n", homepage);
-        LYConvertToURL(&homepage);
+    if (homepage) {
+        LYFillLocalFileURL((char **)&homepage, "file://localhost");
+	LYEnsureAbsoluteURL((char **)&homepage, "HOMEPAGE");
     }
 
     /*
      *  If we don't have a homepage specified,
-     *  set it to startfile.
+     *  set it to startfile.  Otherwise, reset
+     *  LynxHome. - FM
      */
-    if (!homepage)
+    if (!(homepage && *homepage)) {
 	StrAllocCopy(homepage, startfile);
+    } else {
+        StrAllocCopy(LynxHome, homepage);
+    }
 
     /*
      *  Set up the inside/outside domain restriction flags. - FM
@@ -1233,16 +1133,18 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
 /*
  *  Called by HTAccessInit to register any protocols supported by lynx.
  *  Protocols added by lynx:
- *    LYNXKEYMAP, lynxcgi, LYNXIMGMAP
+ *    LYNXKEYMAP, lynxcgi, LYNXIMGMAP, LYNXCOOKIE
  */
 #ifdef GLOBALREF_IS_MACRO
 extern GLOBALREF (HTProtocol,LYLynxKeymap);
 extern GLOBALREF (HTProtocol,LYLynxCGI);
 extern GLOBALREF (HTProtocol,LYLynxIMGmap);
+extern GLOBALREF (HTProtocol,LYLynxCookies);
 #else
 GLOBALREF  HTProtocol LYLynxKeymap;
 GLOBALREF  HTProtocol LYLynxCGI;
 GLOBALREF  HTProtocol LYLynxIMGmap;
+GLOBALREF  HTProtocol LYLynxCookies;
 #endif /* GLOBALREF_IS_MACRO */
 
 PUBLIC void LYRegisterLynxProtocols NOARGS
@@ -1250,6 +1152,7 @@ PUBLIC void LYRegisterLynxProtocols NOARGS
     HTRegisterProtocol(&LYLynxKeymap);
     HTRegisterProtocol(&LYLynxCGI);
     HTRegisterProtocol(&LYLynxIMGmap);
+    HTRegisterProtocol(&LYLynxCookies);
 }
 
 /*
@@ -1257,7 +1160,9 @@ PUBLIC void LYRegisterLynxProtocols NOARGS
  *  appropriate).
  */
 
-PRIVATE char * scan3D ARGS2(char **,argv, int *,i)
+PRIVATE char * scan3D ARGS2(
+	char **,	argv,
+	int *,		i)
 {
     char *result;
 
@@ -1268,7 +1173,10 @@ PRIVATE char * scan3D ARGS2(char **,argv, int *,i)
     return argv[1];
 }
 
-PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc)
+PRIVATE void parse_arg ARGS3(
+	char **,	argv,
+	int *,		i,
+	int,		argc)
 {
     char *cp;
 #ifndef VMS
@@ -1276,6 +1184,17 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc)
 #endif /* !VMS */
 #define nextarg ((cp=scan3D(&argv[0], i))!=NULL)
 
+    /*
+     *  Check for a command line startfile. - FM
+     */
+    if (argv[0][0] != '-') {
+	StrAllocCopy(startfile, argv[0]);
+	return;
+    }
+
+    switch (TOLOWER(argv[0][1])) {
+
+    case 'a':
     if (strncmp(argv[0], "-anonymous", 10) == 0) {
         /*
 	 *  Should already have been set, so we don't
@@ -1285,7 +1204,454 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc)
 	if (!anon_restrictions_set)
 	    parse_restrictions("default");
 	    anon_restrictions_set = TRUE;
+
+    } else if (strncmp(argv[0], "-auth", 5) == 0) {
+        /*
+	 *  Authentication information for protected forms.
+	 */
+	char *auth_info = NULL;
 	
+	if (nextarg) {
+	    StrAllocCopy(auth_info, cp);
+	    memset(cp, ' ', strlen(cp));/* Let's not show too much */
+	}
+        if (auth_info != NULL)  {
+	    if ((cp = strchr(auth_info, ':')) != NULL) { /* Pw */
+		*cp++ = '\0';	/* Terminate ID */
+		if (*cp) {
+		    HTUnEscape(cp);
+		    StrAllocCopy(authentication_info[1], cp);
+		}
+	    }
+	    if (*auth_info) { /* Id */
+	        HTUnEscape(auth_info);
+		StrAllocCopy(authentication_info[0], auth_info);
+	    }
+	    FREE(auth_info);
+	}
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'b':
+    if (strcmp(argv[0], "-book") == 0) {
+        /*
+	 *  Use bookmarks as startfile.
+	 */
+	bookmark_start = TRUE;
+
+    } else if (strcmp(argv[0], "-buried_news") == 0) {
+        /*
+	 *  Toggle scans for buried news references.
+	 */
+        if (scan_for_buried_news_references)
+	    scan_for_buried_news_references = FALSE;
+	else
+	    scan_for_buried_news_references = TRUE;
+
+#ifdef USE_SLANG
+    } else if (strncmp(argv[0], "-blink", 6) == 0) {
+        Lynx_Color_Flags |= SL_LYNX_USE_BLINK;
+#endif /* USE_SLANG */
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'c':
+    if (strncmp(argv[0], "-cache", 6) == 0) {
+	if (nextarg)
+	    HTCacheSize = atoi(cp);
+	/*
+	 *  Limit size.
+	 */
+	if (HTCacheSize < 2) HTCacheSize = 2;
+
+    } else if (strncmp(argv[0], "-case", 5) == 0) {
+	case_sensitive = TRUE;
+
+    } else if (strncmp(argv[0], "-cfg", 4) == 0) {
+	/*
+	 *  Already read the alternate configuration file 
+	 *  so just check whether we need to increment i
+	 */
+	if (nextarg)
+	    ; /* do nothing */
+
+    } else if (strncmp(argv[0], "-child", 6) == 0) {
+	child_lynx = TRUE;
+	no_disk_save = TRUE;
+
+#ifdef USE_SLANG
+    } else if (strncmp(argv[0], "-color", 6) == 0) {
+        Lynx_Color_Flags |= SL_LYNX_USE_COLOR;
+#endif /* USE_SLANG */
+
+    } else if (strncmp(argv[0], "-crawl", 6) == 0) {
+	crawl = TRUE;
+	LYcols = 80;
+
+    } else if (strncmp(argv[0], "-cookies", 8) == 0) {
+        if (LYSetCookies)
+	    LYSetCookies = FALSE;
+	else
+	    LYSetCookies = TRUE;
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'd':
+    if (strncmp(argv[0], "-display", 8) == 0) {
+	if (nextarg) {
+#ifdef VMS
+	    int j;
+	    for (j = 0; cp[j]; j++)
+	        cp[j] = TOUPPER(cp[j]);
+	    Define_VMSLogical(DISPLAY, cp ? cp : "");
+#else
+	    sprintf(display_putenv_command, "DISPLAY=%s", cp ? cp : "");
+	    putenv(display_putenv_command);
+#endif /* VMS */
+	    if ((cp = getenv(DISPLAY)) != NULL && *cp != '\0') {
+		display = cp;
+	    }
+	}
+
+    } else if (strncmp(argv[0], "-dump", 5) == 0) {
+	dump_output_immediately = TRUE;
+	LYcols=80;
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'e':
+    if (strncmp(argv[0], "-editor", 7) == 0) {
+	if (nextarg)
+	    StrAllocCopy(editor,cp);
+	system_editor = TRUE;
+
+    } else if (strncmp(argv[0], "-emacskeys", 10) == 0) {
+	emacs_keys = TRUE;
+
+    } else if (strncmp(argv[0], "-enable_scrollback", 18) == 0) {
+        if (enable_scrollback)
+	    enable_scrollback = FALSE;
+	else
+	    enable_scrollback = TRUE;
+
+    } else if (strncmp(argv[0], "-error_file", 11) == 0) {
+        /*
+	 *  Output return (success/failure) code
+	 *  of an HTTP transaction.
+	 */
+	if (nextarg)
+	    http_error_file = cp;
+
+#if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS)
+    } else if (strncmp(argv[0], "-exec", 5) == 0) {
+#ifndef NEVER_ALLOW_REMOTE_EXEC
+	local_exec = TRUE;
+#else
+	local_exec_on_local_files = TRUE;
+#endif /* NEVER_ALLOW_REMOTE_EXEC */
+#endif /* EXEC_LINKS || EXEC_SCRIPTS */
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'f':
+    if (strncmp(argv[0], "-force_html", 11) == 0) {
+	LYforce_HTML_mode = TRUE;
+
+    } else if (strncmp(argv[0], "-fileversions", 13) == 0) {
+#ifdef VMS
+	HTVMSFileVersions = TRUE;
+#else
+	break;;
+#endif /* VMS */
+	
+    } else if (strncmp(argv[0], "-ftp", 4) == 0) {
+	ftp_ok = FALSE;
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'g':
+    if (strcmp(argv[0], "-get_data") == 0) {
+        /*
+	 *  User data for GET form.
+	 */
+	char **get_data;
+	char buf[1024];
+
+        /*
+	 *  On Unix, conflicts with curses when interactive
+         *  so let's force a dump.  - CL
+	 *
+	 *  On VMS, mods have been made in LYCurses.c to deal with
+	 *  potential conflicts, so don't force the dump here. - FM
+         */
+#ifndef VMS
+	dump_output_immediately = TRUE;
+        LYcols = 80;
+#endif /* VMS */
+
+	StrAllocCopy(form_get_data, "?");   /* Prime the pump */
+	get_data = &form_get_data;
+
+	/*
+	 *  Build GET data for later.  Stop reading when we see a line
+	 *  with "---" as its first three characters.
+	 */
+	while (fgets(buf, sizeof(buf), stdin) &&
+	       strncmp(buf, "---", 3) != 0) {
+	    int j;
+
+	    for (j = strlen(buf) - 1; j >= 0 && /* Strip line terminators */
+		(buf[j] == CR || buf[j] == LF); j--) {
+		buf[j] = '\0';
+	    }
+	    StrAllocCat(*get_data, buf);
+	}
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'h':
+    if (strcmp(argv[0], "-help") == 0) {
+        goto Output_Help_List;
+
+    } else if (strcmp(argv[0], "-head") == 0) {
+        /*
+	 *  Return mime headers.
+	 */
+	HEAD_request = TRUE;
+
+    } else if (strncmp(argv[0], "-historical", 11) == 0) {
+        if (historical_comments)
+	    historical_comments = FALSE;
+	else
+	    historical_comments = TRUE;
+
+    } else if (strncmp(argv[0], "-homepage", 9) == 0) {
+	if (nextarg)
+	    StrAllocCopy(homepage,cp);
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'i':
+    if (strncmp(argv[0], "-image_links", 12) == 0) {
+	if (clickable_images)
+	    clickable_images = FALSE;
+	else
+	    clickable_images = TRUE;
+
+    } else if (strncmp(argv[0], "-index", 6) == 0) {
+	if (nextarg)
+	    StrAllocCopy(indexfile, cp);
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'l':
+    if (strncmp(argv[0], "-link", 5) == 0) {
+        if (nextarg)
+	    ccount = atoi(cp);
+
+    } else if (strncmp(argv[0], "-localhost", 10) == 0) {
+	local_host_only = TRUE;
+
+#if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS)
+    } else if (strncmp(argv[0], "-locexec", 8) == 0) {
+	local_exec_on_local_files = TRUE;
+#endif /* EXEC_LINKS || EXEC_SCRIPTS */
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'm':
+    if (strcmp(argv[0], "-mime_header") == 0) {
+        /*
+	 *  Include mime headers and force source dump.
+	 */
+	keep_mime_headers = TRUE;
+	dump_output_immediately = TRUE;
+	HTOutputFormat = HTAtom_for("www/dump");
+	LYcols=999;
+
+    } else if (strncmp(argv[0], "-minimal", 11) == 0) {
+        if (minimal_comments)
+	    minimal_comments = FALSE;
+	else
+	    minimal_comments = TRUE;
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'n':
+    if (strncmp(argv[0], "-newschunksize", 14) == 0) {
+        if (nextarg) {
+	    HTNewsChunkSize = atoi(cp);
+	    /*
+	     * If the new HTNewsChunkSize exceeds the maximum,
+	     * increase HTNewsMaxChunk to this size. - FM
+	     */
+	    if (HTNewsChunkSize > HTNewsMaxChunk) {
+	        HTNewsMaxChunk = HTNewsChunkSize; 
+	    }
+	}
+
+    } else if (strncmp(argv[0], "-newsmaxchunk", 13) == 0) {
+        if (nextarg) {
+	    HTNewsMaxChunk = atoi(cp);
+	    /*
+	     * If HTNewsChunkSize exceeds the new maximum,
+	     * reduce HTNewsChunkSize to this maximum. - FM
+	     */
+	    if (HTNewsChunkSize > HTNewsMaxChunk) {
+	        HTNewsChunkSize = HTNewsMaxChunk;
+	    }
+	}
+
+    } else if (strncmp(argv[0], "-nobrowse", 9) == 0) {
+	HTDirAccess = HT_DIR_FORBID;
+
+#if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS)
+    } else if (strncmp(argv[0], "-noexec", 7) == 0) {
+	local_exec = FALSE;
+#endif /* EXEC_LINKS || EXEC_SCRIPTS */
+
+    } else if (strncmp(argv[0], "-nofilereferer", 14) == 0) {
+	no_filereferer = TRUE;
+
+    } else if (strncmp(argv[0], "-nofrom", 7) == 0) {
+	LYNoFromHeader = TRUE;
+
+    } else if (strncmp(argv[0], "-nolist", 7) == 0) {
+	nolist = TRUE;
+
+    } else if (strncmp(argv[0], "-nolog", 6) == 0) {
+	error_logging = FALSE;
+
+    } else if (strcmp(argv[0], "-nopause") == 0) { /* No statusline pauses */
+        InfoSecs = 0;
+	MessageSecs = 0;
+	AlertSecs = 0;
+
+    } else if (strncmp(argv[0], "-noprint", 8) == 0) {
+	no_print = TRUE;
+
+    } else if (strcmp(argv[0], "-noredir") == 0) {
+        /*
+	 *  Don't follow URL redirections.
+	 */
+	no_url_redirection = TRUE;
+
+    } else if (strncmp(argv[0], "-noreferer", 10) == 0) {
+	LYNoRefererHeader = TRUE;
+
+#ifdef SOCKS	
+    } else if (strncmp(argv[0], "-nosocks", 8) == 0) {
+	socks_flag = FALSE;
+#endif /* SOCKS */
+
+    } else if (strncmp(argv[0], "-nostatus", 9) == 0)	{
+	no_statusline = TRUE;
+
+    } else if (strncmp(argv[0], "-number_links", 9) == 0) {
+        number_links = TRUE;
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'p':
+    if (strncmp(argv[0], "-popup", 6) == 0) {
+	LYUseDefSelPop = FALSE;
+
+    } else if (strcmp(argv[0], "-post_data") == 0) {
+        /*
+	 *  User data for POST form.
+	 */
+	char **post_data;
+	char buf[1024];
+
+        /*
+	 *  On Unix, conflicts with curses when interactive
+         *  so let's force a dump.  - CL
+	 *
+	 *  On VMS, mods have been made in LYCurses.c to deal with
+	 *  potential conflicts, so don't force a dump here. - FM
+         */
+#ifndef VMS
+	dump_output_immediately = TRUE;
+        LYcols = 80;
+#endif /* VMS */
+
+	post_data = &form_post_data;
+
+	/*
+	 *  Build post data for later.  Stop reading when we see a line
+	 *  with "---" as its first three characters.
+	 */
+	while (fgets(buf, sizeof(buf), stdin) &&
+	       strncmp(buf, "---", 3) != 0) {
+	    int j;
+
+	    for (j = strlen(buf) - 1; j >= 0 && /* Strip line terminators */
+		(buf[j] == CR || buf[j] == LF); j--) {
+		buf[j] = '\0';
+	    }
+	    StrAllocCat(*post_data, buf);
+	}
+
+    } else if (strncmp(argv[0], "-print", 6) == 0) {
+	no_print=FALSE;
+
+    } else if (strncmp(argv[0], "-pseudo_inlines", 15) == 0) {
+	if (pseudo_inline_alts)
+	    pseudo_inline_alts = FALSE;
+	else
+	    pseudo_inline_alts = TRUE;
+
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'r':
+    if (strncmp(argv[0], "-raw", 4) == 0) {
+        LYUseDefaultRawMode = FALSE;
+
+    } else if (strncmp(argv[0], "-realm", 6) == 0) {
+	check_realm = TRUE;
+
+    } else if (strncmp(argv[0], "-reload", 7) == 0) {
+        reloading = TRUE;
+
     } else if (strncmp(argv[0], "-restrictions", 13) == 0) {
 	if ((cp=strchr(argv[0],'=')) != NULL)
 	    parse_restrictions(cp+1);
@@ -1378,110 +1744,29 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc)
 		exit(0);
 	    }
 
-    } else if (strncmp(argv[0], "-homepage", 9) == 0) {
-	if (nextarg)
-	    StrAllocCopy(homepage,cp);
-	
-    } else if (strncmp(argv[0], "-editor", 7) == 0) {
-	if (nextarg)
-	    StrAllocCopy(editor,cp);
-	system_editor = TRUE;
-	
-#ifndef VMS
-#ifdef SYSLOG_REQUESTED_URLS
-    } else if (strncmp(argv[0], "-syslog", 7) == 0) {
-	if (nextarg) 
-	    StrAllocCopy(syslog_txt, cp);
-#endif /* SYSLOG_REQUESTED_URLS */
-#endif /* !VMS */
-	
-    } else if (strncmp(argv[0], "-display", 8) == 0) {
-	if (nextarg) {
-#ifdef VMS
-	    int j;
-	    for (j = 0; cp[j]; j++)
-	        cp[j] = TOUPPER(cp[j]);
-	    Define_VMSLogical(DISPLAY, cp ? cp : "");
-#else
-	    sprintf(display_putenv_command, "DISPLAY=%s", cp ? cp : "");
-	    putenv(display_putenv_command);
-#endif /* VMS */
-	    if ((cp = getenv(DISPLAY)) != NULL && *cp != '\0') {
-		display = cp;
-	    }
-	}
-	
-    } else if (strncmp(argv[0], "-index", 6) == 0) {
-	if (nextarg)
-	    StrAllocCopy(indexfile, cp);
-	
-    } else if (strncmp(argv[0], "-cfg", 4) == 0) {
-	/*
-	 *  Already read the alternate configuration file 
-	 *  so just check whether we need to increment i
-	 */
-	if (nextarg)
-	    ; /* do nothing */
-	
-    } else if (strncmp(argv[0], "-stack_dump", 11) == 0) {
-	stack_dump = TRUE;
-	
-    } else if (strncmp(argv[0], "-cache", 6) == 0) {
-	if (nextarg)
-	    HTCacheSize = atoi(cp);
-	
-	/* limit size */
-	if (HTCacheSize < 2) HTCacheSize = 2;
-	
-    } else if (strncmp(argv[0], "-vikeys", 7) == 0) {
-	vi_keys = TRUE;
-	
-    } else if (strncmp(argv[0], "-emacskeys", 10) == 0) {
-	emacs_keys = TRUE;
-	
-    } else if (strncmp(argv[0], "-version", 8) == 0) {
-	printf("\n%s Version %s\n(c)1996 GNU General Public License\n\
-<URL:http://lynx.browser.org/>\n\n",
-		LYNX_NAME, LYNX_VERSION);
-	exit(0);
-	
-    } else if (strncmp(argv[0], "-case", 5) == 0) {
-	case_sensitive = TRUE;
-	
-    } else if (strncmp(argv[0], "-dump", 5) == 0) {
-	dump_output_immediately = TRUE;
-	LYcols=80;
-	
-    } else if (strncmp(argv[0], "-nofrom", 7) == 0) {
-	LYNoFromHeader = TRUE;
-	
-    } else if (strncmp(argv[0], "-nofilereferer", 14) == 0) {
-	no_filereferer = TRUE;
-	
-    } else if (strncmp(argv[0], "-nolist", 7) == 0) {
-	nolist = TRUE;
-	
-    } else if (strncmp(argv[0], "-noreferer", 10) == 0) {
-	LYNoRefererHeader = TRUE;
-	
-    } else if (strncmp(argv[0], "-popup", 6) == 0) {
-	LYUseDefSelPop = FALSE;
+    } else if (strncmp(argv[0], "-resubmit_posts", 14) == 0) {
+	if (LYresubmit_posts)
+	    LYresubmit_posts = FALSE;
+	else
+	    LYresubmit_posts = TRUE;
 
-    } else if (strncmp(argv[0], "-crawl", 6) == 0) {
-	crawl = TRUE;
-	LYcols=80;
+    } else if (strncmp(argv[0], "-rlogin", 7) == 0) {
+	rlogin_ok = FALSE;
 
-    } else if (strncmp(argv[0], "-historical", 11) == 0) {
-        if (historical_comments)
-	    historical_comments = FALSE;
-	else
-	    historical_comments = TRUE;
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
 
-    } else if (strncmp(argv[0], "-minimal", 11) == 0) {
-        if (minimal_comments)
-	    minimal_comments = FALSE;
+    case 's':
+    if (strncmp(argv[0], "-selective", 10) == 0) {
+	HTDirAccess = HT_DIR_SELECTIVE;
+
+    } else if (strncmp(argv[0], "-show_cursor", 12) == 0) {
+	if (LYShowCursor)
+	    LYShowCursor = FALSE;
 	else
-	    minimal_comments = TRUE;
+	    LYShowCursor = TRUE;
 
     } else if (strncmp(argv[0], "-soft_dquotes", 13) == 0) {
         if (soft_dquotes)
@@ -1489,425 +1774,277 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc)
 	else
 	    soft_dquotes = TRUE;
 
-    } else if (strncmp(argv[0], "-enable_scrollback", 18) == 0) {
-        if (enable_scrollback)
-	    enable_scrollback = FALSE;
-	else
-	    enable_scrollback = TRUE;
-
-    } else if (strncmp(argv[0], "-link", 5) == 0) {
-        if (nextarg)
-	    ccount = atoi(cp);
-
-    } else if (strncmp(argv[0], "-traversal", 10) == 0) {
-	traversal = TRUE;
-#ifdef USE_SLANG
-	LYcols=80;
-#else
-	LYcols=999;
-#endif /* USE_SLANG */
-
-    } else if (strncmp(argv[0], "-realm", 6) == 0) {
-	check_realm = TRUE;
-
     } else if (strncmp(argv[0], "-source", 7) == 0) {
 	dump_output_immediately = TRUE;
 	HTOutputFormat = HTAtom_for("www/dump");
 	LYcols=999;
-	
-    } else if (strncmp(argv[0], "-reload", 7) == 0) {
-        reloading = TRUE;
 
-    } else if (strncmp(argv[0], "-force_html", 11) == 0) {
-	LYforce_HTML_mode = TRUE;
-	
-#ifdef SOCKS	
-    } else if (strncmp(argv[0], "-nosocks", 8) == 0) {
-	socks_flag = FALSE;
-#endif /* SOCKS */
+    } else if (strncmp(argv[0], "-stack_dump", 11) == 0) {
+	stack_dump = TRUE;
 
-    } else if (strncmp(argv[0], "-trace", 6) == 0) {
-	WWW_TraceFlag = TRUE;
-	
-    } else if (strncmp(argv[0], "-number_links", 9) == 0) {
-        number_links = TRUE;
-	
-    } else if (strncmp(argv[0], "-image_links", 12) == 0) {
-	if (clickable_images)
-	    clickable_images = FALSE;
-	else
-	    clickable_images = TRUE;
+    } else if (strncmp(argv[0], "-startfile_ok", 13) == 0) {
+        startfile_ok = TRUE;
 
-    } else if (strncmp(argv[0], "-pseudo_inlines", 15) == 0) {
-	if (pseudo_inline_alts)
-	    pseudo_inline_alts = FALSE;
-	else
-	    pseudo_inline_alts = TRUE;
+#ifndef VMS
+#ifdef SYSLOG_REQUESTED_URLS
+    } else if (strncmp(argv[0], "-syslog", 7) == 0) {
+	if (nextarg) 
+	    StrAllocCopy(syslog_txt, cp);
+#endif /* SYSLOG_REQUESTED_URLS */
+#endif /* !VMS */
 
-    } else if (strncmp(argv[0], "-resubmit_posts", 14) == 0) {
-	if (LYresubmit_posts)
-	    LYresubmit_posts = FALSE;
-	else
-	    LYresubmit_posts = TRUE;
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
 
-    } else if (strncmp(argv[0], "-underscore", 15) == 0) {
-	if (use_underscore)
-	    use_underscore = FALSE;
-	else
-	    use_underscore = TRUE;
+    case 't':
+    if (strncmp(argv[0], "-telnet", 7) == 0) {
+	telnet_ok = FALSE;
 
-    } else if (strncmp(argv[0], "-localhost", 10) == 0) {
-	local_host_only = TRUE;
-	
-    } else if (strncmp(argv[0], "-nobrowse", 9) == 0) {
-	HTDirAccess = HT_DIR_FORBID;
-	
-    } else if (strncmp(argv[0], "-selective", 10) == 0) {
-	HTDirAccess = HT_DIR_SELECTIVE;
-	
-    } else if (strncmp(argv[0], "-noprint", 8) == 0) {
-	no_print=TRUE;
-	
-    } else if (strncmp(argv[0], "-print", 6) == 0) {
-	no_print=FALSE;
-	
-#if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS)
-    } else if (strncmp(argv[0], "-exec", 5) == 0) {
-#ifndef NEVER_ALLOW_REMOTE_EXEC
-	local_exec=TRUE;
-#else
-	local_exec_on_local_files=TRUE;
-#endif /* NEVER_ALLOW_REMOTE_EXEC */
-	
-    } else if (strncmp(argv[0], "-locexec", 8) == 0) {
-	local_exec_on_local_files=TRUE;
-	
-    } else if (strncmp(argv[0], "-noexec", 7) == 0) {
-	local_exec=FALSE;
-#endif /* EXEC_LINKS || EXEC_SCRIPTS */
-	
-    } else if (strncmp(argv[0], "-child", 6) == 0) {
-	child_lynx=TRUE;
-	no_disk_save=TRUE;
-	
-    } else if (strncmp(argv[0], "-nolog", 6) == 0) {
-	error_logging=FALSE;
-	
-    } else if (strncmp(argv[0], "-nostatus", 9) == 0)	{
-	no_statusline = TRUE;
-	
-    } else if (strncmp(argv[0], "-show_cursor", 12) == 0) {
-	LYShowCursor = TRUE;
-	
     } else if (strncmp(argv[0], "-term", 5) == 0) {
 	if (nextarg)
 	    terminal = cp;
-	
-    } else if (strncmp(argv[0], "-telnet", 7) == 0) {
-	telnet_ok=FALSE;
-	
-    } else if (strncmp(argv[0], "-ftp", 4) == 0) {
-	ftp_ok=FALSE;
-	
-    } else if (strncmp(argv[0], "-rlogin", 7) == 0) {
-	rlogin_ok=FALSE;
-	
-#ifdef USE_SLANG
-    } else if (strncmp(argv[0], "-color", 6) == 0) {
-        Lynx_Color_Flags |= SL_LYNX_USE_COLOR;
 
-    } else if (strncmp(argv[0], "-blink", 6) == 0) {
-        Lynx_Color_Flags |= SL_LYNX_USE_BLINK;
-#endif /* USE_SLANG */
+    } else if (strncmp(argv[0], "-trace", 6) == 0) {
+	WWW_TraceFlag = TRUE;
 
-    } else if (strncmp(argv[0], "-fileversions", 13) == 0) {
-#ifdef VMS
-	HTVMSFileVersions=TRUE;
+    } else if (strncmp(argv[0], "-traversal", 10) == 0) {
+	traversal = TRUE;
+#ifdef USE_SLANG
+	LYcols=80;
 #else
-	return;
-#endif /* VMS */
-	
-    } else if (strcmp(argv[0], "-post_data") == 0 ||
- 	       strcmp(argv[0], "-get_data") == 0) { 	/* User data for post
- 							   or get form. */
-	char **post_data;
-	char buf[1024];
+	LYcols=999;
+#endif /* USE_SLANG */
 
-        /* -post_data and -get_data conflict with curses when interactive
-         * so let's force them to dump.  - CL
-	 *
-	 * On VMS, mods have been made in LYCurses.c to deal with
-	 * potential conflicts, so don't force them to dump here. - FM
-         */
-#ifndef VMS
-	dump_output_immediately = TRUE;
-        LYcols = 80;
-#endif /* VMS */
-        
-	if (strcmp(argv[0], "-get_data") == 0) {
-	    StrAllocCopy(form_get_data, "?");   /* Prime the pump */
-	    post_data = &form_get_data;
-	} else {
-	    post_data = &form_post_data;
-	}
-	
-	/* Build post data for later. Stop reading when we see a line with
-	 * "---" as its first three characters.
-	 */
-	while (fgets(buf, sizeof(buf), stdin) && strncmp(buf, "---", 3) != 0) {
-	    int j;
-	    
-	    for (j = strlen(buf) - 1; j >= 0 && /* Strip line terminators */
-		(buf[j] == CR || buf[j] == LF); j--) {
-		buf[j] = '\0';
-	    }
-	    StrAllocCat(*post_data, buf);
-	}
-	
-    } else if (strcmp(argv[0], "-head") == 0) {/* Return mime headers */
-	HEAD_request = TRUE;
-	
-    } else if (strcmp(argv[0], "-book") == 0) {/* Use bookmarks as startfile */
-	bookmark_start = TRUE;
-	
-    } else if (strcmp(argv[0], "-buried_news") == 0) {
-        /* Toggle scans for buried news references */
-        if (scan_for_buried_news_references)
-	    scan_for_buried_news_references = FALSE;
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
+
+    case 'u':
+    if (strncmp(argv[0], "-underscore", 15) == 0) {
+	if (use_underscore)
+	    use_underscore = FALSE;
 	else
-	    scan_for_buried_news_references = TRUE;
-	
-    } else if (strcmp(argv[0], "-mime_header") == 0) {
-        /* Include mime headers and force source dump */
-	keep_mime_headers = TRUE;
-	dump_output_immediately = TRUE;
-	HTOutputFormat = HTAtom_for("www/dump");
-	LYcols=999;
+	    use_underscore = TRUE;
 
-    } else if (strncmp(argv[0], "-error_file", 11) == 0) { /* Output return
-							      (success/failure)
-							      code of an HTTP
-							      transaction */
-	if (nextarg)
-	    http_error_file = cp;
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
 
-	
-    } else if (strncmp(argv[0], "-auth", 5) == 0) { /* Authentication
-						       information for
-						       protected forms */
-	char *auth_info = NULL;
-	
-	if (nextarg) {
-	    StrAllocCopy(auth_info, cp);
-	    memset(cp, ' ', strlen(cp));/* Let's not show too much */
-	}
-        if (auth_info != NULL)  {
-	    if ((cp = strchr(auth_info, ':')) != NULL) { /* Pw */
-		*cp++ = '\0';	/* Terminate ID */
-		if (*cp) {
-		    HTUnEscape(cp);
-		    StrAllocCopy(authentication_info[1], cp);
-		}
-	    }
-	    if (*auth_info) { /* Id */
-	        HTUnEscape(auth_info);
-		StrAllocCopy(authentication_info[0], auth_info);
-	    }
-	    FREE(auth_info);
-	}
-	
-    } else if (strcmp(argv[0], "-noredir") == 0) { /* Don't follow URL
-						      Redirections */
-	no_url_redirection = TRUE;
-	 
-    } else if (strcmp(argv[0], "-validate") == 0) { /* Follow only http URLs */
+    case 'v':
+    if (strcmp(argv[0], "-validate") == 0) {
+        /*
+	 *  Follow only http URLs.
+	 */
 	LYValidate = TRUE;
 	parse_restrictions("all");
 
-    } else if (strncmp(argv[0], "-raw", 4) == 0) {
-        LYUseDefaultRawMode = FALSE;
-
-    } else if (strncmp(argv[0], "-newschunksize", 14) == 0) {
-        if (nextarg) {
-	    HTNewsChunkSize = atoi(cp);
-	    /*
-	     * If the new HTNewsChunkSize exceeds the maximum,
-	     * increase HTNewsMaxChunk to this size. - FM
-	     */
-	    if (HTNewsChunkSize > HTNewsMaxChunk) {
-	        HTNewsMaxChunk = HTNewsChunkSize; 
-	    }
-	}
+    } else if (strncmp(argv[0], "-version", 8) == 0) {
+	printf("\n%s Version %s\n(c)1996 GNU General Public License\n\
+<URL:http://lynx.browser.org/>\n\n",
+		LYNX_NAME, LYNX_VERSION);
+	exit(0);
 
-    } else if (strncmp(argv[0], "-newsmaxchunk", 13) == 0) {
-        if (nextarg) {
-	    HTNewsMaxChunk = atoi(cp);
-	    /*
-	     * If HTNewsChunkSize exceeds the new maximum,
-	     * reduce HTNewsChunkSize to this maximum. - FM
-	     */
-	    if (HTNewsChunkSize > HTNewsMaxChunk) {
-	        HTNewsChunkSize = HTNewsMaxChunk;
-	    }
-	}
+    } else if (strncmp(argv[0], "-vikeys", 7) == 0) {
+	vi_keys = TRUE;
 
-    } else if (strncmp(argv[0], "-startfile_ok", 13) == 0) {
-        startfile_ok = TRUE;
+    } else {
+        goto Output_Error_and_Help_List;
+    }
+    break;
 
-    } else if (strncmp(argv[0], "-", 1) == 0) {
-	if (strncmp(argv[0], "-help", 5) != 0) 
+    default:
+Output_Error_and_Help_List:
+#ifdef VMS
+    printf(" LYNX: Invalid Option: %s\n", argv[0]);
+#else
+    printf("%s: Invalid Option: %s\n", pgm, argv[0]);
+#endif /* VMS */
+Output_Help_List:
 #ifdef VMS
-	    printf(" LYNX: Invalid Option: %s\n", argv[0]);
-	printf("USAGE: lynx [options] [file]\n");
+    printf("USAGE: lynx [options] [file]\n");
 #else
-	    printf("%s: Invalid Option: %s\n", pgm, argv[0]);
-	printf("USAGE: %s [options] [file]\n",pgm);
+    printf("USAGE: %s [options] [file]\n",pgm);
 #endif /* VMS */
-	printf("Options are:\n");
-	printf("    -                receive the arguments from stdin (enclose\n");
-	printf("                     in double-quotes (\"-\") on VMS)\n");
-	printf("    -anonymous       used to specify the anonymous account\n");
- 	printf("    -auth=id:pw      authentication information for protected forms\n");
- 	printf("    -book            use the bookmark page as the startfile\n");
- 	printf("    -buried_news     toggles scanning of news articles for buried references\n");
-	printf("    -cache=NUMBER    NUMBER of documents cached in memory (default is %d)\n",DEFAULT_CACHE_SIZE);
-	printf("    -case            enable case sensitive user searching\n");
-	printf("    -cfg=FILENAME    specifies a lynx.cfg file other than the default\n");
-	printf("    -child           exit on left-arrow in startfile, and disable save to disk\n");
+    printf("Options are:\n");
+    printf("    -                receive the arguments from stdin (enclose\n");
+    printf("                     in double-quotes (\"-\") on VMS)\n");
+    printf("    -anonymous       used to specify the anonymous account\n");
+    printf("    -auth=id:pw      authentication information for protected forms\n");
+    printf("    -book            use the bookmark page as the startfile\n");
+    printf("    -buried_news     toggles scanning of news articles for buried references\n");
+    printf("    -cache=NUMBER    NUMBER of documents cached in memory (default is %d)\n",DEFAULT_CACHE_SIZE);
+    printf("    -case            enable case sensitive user searching\n");
+    printf("    -cfg=FILENAME    specifies a lynx.cfg file other than the default\n");
+    printf("    -child           exit on left-arrow in startfile, and disable save to disk\n");
 #ifdef USE_SLANG
-	printf("    -color           force color mode on with standard bg colors\n");
-	printf("    -blink           force color mode on with high intensity bg colors\n");
+    printf("    -color           force color mode on with standard bg colors\n");
+    printf("    -blink           force color mode on with high intensity bg colors\n");
 #endif /* USE_SLANG */
-	printf("    -crawl           with -traversal, output each page to a file\n");
-	printf("                     with -dump, format output as with -traversal, but to stdout\n");
-	printf("    -display=DISPLAY set the display variable for X execed programs\n");
-	printf("    -dump            dump the first file to stdout and exit\n");
-	printf("    -editor=EDITOR   enable edit mode with specified editor\n");
-	printf("    -emacskeys       enable emacs-like key movement\n");
-	printf("    -enable_scrollback  toggle compatibility with comm programs' scrollback\n");
-	printf("                        keys (may be incompatible with some curses packages)\n");
- 	printf("    -error_file=FILE write the HTTP status code here\n");
+    printf("    -cookies         toggles handling of Set-Cookie headers\n");
+    printf("    -crawl           with -traversal, output each page to a file\n");
+    printf("                     with -dump, format output as with -traversal, but to stdout\n");
+    printf("    -display=DISPLAY set the display variable for X execed programs\n");
+    printf("    -dump            dump the first file to stdout and exit\n");
+    printf("    -editor=EDITOR   enable edit mode with specified editor\n");
+    printf("    -emacskeys       enable emacs-like key movement\n");
+    printf("    -enable_scrollback  toggles compatibility with comm programs' scrollback\n");
+    printf("                        keys (may be incompatible with some curses packages)\n");
+     printf("    -error_file=FILE write the HTTP status code here\n");
 #if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS)
 #ifndef NEVER_ALLOW_REMOTE_EXEC
-	printf("    -exec            enable local program execution\n");
+    printf("    -exec            enable local program execution\n");
 #endif /* !NEVER_ALLOW_REMOTE_EXEC */
-	printf("    -locexec         enable local program execution from local files only\n");
-	printf("    -noexec          disable local program execution (DEFAULT)\n");
+    printf("    -locexec         enable local program execution from local files only\n");
+    printf("    -noexec          disable local program execution (DEFAULT)\n");
 #endif /* EXEC_LINKS || EXEC_SCRIPTS */
-	printf("    -fileversions    include all versions of files in local VMS directory\n");
-	printf("                     listings\n");
-	printf("    -force_html      forces the first document to be interpreted as HTML\n");
-	printf("    -ftp             disable ftp access\n");
- 	printf("    -get_data        user data for get forms, read from stdin,\n");
-        printf("                     terminated by '---' on a line\n");
- 	printf("    -head            send a HEAD request\n");
-	printf("    -help            print this usage message\n");
-	printf("    -historical      toggles use of '>' or '-->' as a terminator for comments\n");
-	printf("    -homepage=URL    set homepage separate from start page\n");
-	printf("    -image_links     toggles inclusion of links for all images\n");
-	printf("    -index=URL       set the default index file to URL\n");
-	printf("    -link=NUMBER     starting count for lnk#.dat files produced by -crawl\n");
-	printf("    -localhost       disable URLs that point to remote hosts\n");
- 	printf("    -mime_header     include mime headers and force source dump\n");
-	printf("    -minimal         toggles minimal versus valid comment parsing\n");
- 	printf("    -newschunksize=NUMBER  number of articles in chunked news listings\n");
- 	printf("    -newsmaxchunk=NUMBER   maximum news articles in listings before chunking\n");
-	printf("    -nobrowse        disable directory browsing\n");
-	printf("    -nofilereferer   disable transmissions of Referer headers for file URLs\n");
-	printf("    -nofrom          disable transmissions of From headers\n");
-	printf("    -nolist          disable the link list feature in dumps\n");
-	printf("    -nolog           disable mailing of error messages to document owners\n");
-	printf("    -noprint         disable print functions\n");
- 	printf("    -noredir         don't follow Location: redirection\n");
-	printf("    -noreferer       disable transmissions of Referer headers\n");
+    printf("    -fileversions    include all versions of files in local VMS directory\n");
+    printf("                     listings\n");
+    printf("    -force_html      forces the first document to be interpreted as HTML\n");
+    printf("    -ftp             disable ftp access\n");
+    printf("    -get_data        user data for get forms, read from stdin,\n");
+    printf("                     terminated by '---' on a line\n");
+    printf("    -head            send a HEAD request\n");
+    printf("    -help            print this usage message\n");
+    printf("    -historical      toggles use of '>' or '-->' as a terminator for comments\n");
+    printf("    -homepage=URL    set homepage separate from start page\n");
+    printf("    -image_links     toggles inclusion of links for all images\n");
+    printf("    -index=URL       set the default index file to URL\n");
+    printf("    -link=NUMBER     starting count for lnk#.dat files produced by -crawl\n");
+    printf("    -localhost       disable URLs that point to remote hosts\n");
+    printf("    -mime_header     include mime headers and force source dump\n");
+    printf("    -minimal         toggles minimal versus valid comment parsing\n");
+    printf("    -newschunksize=NUMBER  number of articles in chunked news listings\n");
+    printf("    -newsmaxchunk=NUMBER   maximum news articles in listings before chunking\n");
+    printf("    -nobrowse        disable directory browsing\n");
+    printf("    -nofilereferer   disable transmissions of Referer headers for file URLs\n");
+    printf("    -nofrom          disable transmissions of From headers\n");
+    printf("    -nolist          disable the link list feature in dumps\n");
+    printf("    -nolog           disable mailing of error messages to document owners\n");
+    printf("    -nopause         disable forced pauses for statusline messages\n");
+    printf("    -noprint         disable print functions\n");
+    printf("    -noredir         don't follow Location: redirection\n");
+    printf("    -noreferer       disable transmissions of Referer headers\n");
 #ifdef SOCKS
-	printf("    -nosocks         don't use SOCKS proxy for this session\n");
+    printf("    -nosocks         don't use SOCKS proxy for this session\n");
 #endif /* SOCKS */
-	printf("    -nostatus        disable the miscellaneous information messages\n");
-	printf("    -number_links    force numbering of links\n");
-	printf("    -popup           toggles handling of single-choice SELECT options via\n");
-        printf("                     popup windows or as lists of radio buttons\n");
- 	printf("    -post_data       user data for post forms, read from stdin,\n");
-        printf("                     terminated by '---' on a line\n");
-	printf("    -print           enable print functions (DEFAULT)\n");
-	printf("    -pseudo_inlines  toggles pseudo-ALTs for inlines with no ALT string\n");
-	printf("    -raw             toggles default setting of 8-bit character translations\n");
-	printf("                     or CJK mode for the startup character set\n");
-	printf("    -realm           restricts access to URLs in the starting realm\n");
-	printf("    -reload          flushes the cache on a proxy server\n");
-	printf("                     (only the first document affected)\n");
-	printf("    -restrictions=[options]  use -restrictions to see list\n");
-	printf("    -resubmit_posts  toggles forced resubmissions (no-cache) of forms with\n");
-	printf("                     method POST when the documents they returned are sought\n");
-	printf("                     with the PREV_DOC command or from the History List\n");
-	printf("    -rlogin          disable rlogins\n");
-	printf("    -selective       require .www_browsable files to browse directories\n");
-	printf("    -show_cursor     don't hide the curser in the lower right corner\n");
-	printf("    -soft_dquotes    toggles emulation of the old Netscape and Mosaic bug which\n");
-	printf("                     treated '>' as a co-terminator for double-quotes and tags\n");
-	printf("    -source          dump the source of the first file to stdout and exit\n");
-	printf("    -startfile_ok    allow non-http startfile and homepage with -validate\n");
+    printf("    -nostatus        disable the miscellaneous information messages\n");
+    printf("    -number_links    force numbering of links\n");
+    printf("    -popup           toggles handling of single-choice SELECT options via\n");
+    printf("                     popup windows or as lists of radio buttons\n");
+    printf("    -post_data       user data for post forms, read from stdin,\n");
+    printf("                     terminated by '---' on a line\n");
+    printf("    -print           enable print functions (DEFAULT)\n");
+    printf("    -pseudo_inlines  toggles pseudo-ALTs for inlines with no ALT string\n");
+    printf("    -raw             toggles default setting of 8-bit character translations\n");
+    printf("                     or CJK mode for the startup character set\n");
+    printf("    -realm           restricts access to URLs in the starting realm\n");
+    printf("    -reload          flushes the cache on a proxy server\n");
+    printf("                     (only the first document affected)\n");
+    printf("    -restrictions=[options]  use -restrictions to see list\n");
+    printf("    -resubmit_posts  toggles forced resubmissions (no-cache) of forms with\n");
+    printf("                     method POST when the documents they returned are sought\n");
+    printf("                     with the PREV_DOC command or from the History List\n");
+    printf("    -rlogin          disable rlogins\n");
+    printf("    -selective       require .www_browsable files to browse directories\n");
+    printf("    -show_cursor     toggles hiding of the curser in the lower right corner\n");
+    printf("    -soft_dquotes    toggles emulation of the old Netscape and Mosaic bug which\n");
+    printf("                     treated '>' as a co-terminator for double-quotes and tags\n");
+    printf("    -source          dump the source of the first file to stdout and exit\n");
+    printf("    -startfile_ok    allow non-http startfile and homepage with -validate\n");
 #ifndef VMS
 #ifdef SYSLOG_REQUESTED_URLS
-	printf("    -syslog=text     information for syslog call\n");
+    printf("    -syslog=text     information for syslog call\n");
 #endif /* SYSLOG_REQUESTED_URLS */
 #endif /* !VMS */
-	printf("    -telnet          disable telnets\n");
-	printf("    -term=TERM       set terminal type to TERM\n");
-	printf("    -trace           turns on WWW trace mode\n");
-	printf("    -traversal       traverse all http links derived from startfile\n");
-	printf("    -underscore      toggles use of _underline_ format in dumps\n");
-	printf("    -validate        accept only http URLs (for validation)\n");
-	printf("    -version         print Lynx version information\n");
-	printf("    -vikeys          enable vi-like key movement\n");
-	if (strncmp(argv[0], "-help", 5) != 0)
-	    exit(-1);
-	exit(0);
-    } else {	/* alternate database path */
-	
-	StrAllocCopy(startfile, argv[0]);
-    }
+    printf("    -telnet          disable telnets\n");
+    printf("    -term=TERM       set terminal type to TERM\n");
+    printf("    -trace           turns on WWW trace mode\n");
+    printf("    -traversal       traverse all http links derived from startfile\n");
+    printf("    -underscore      toggles use of _underline_ format in dumps\n");
+    printf("    -validate        accept only http URLs (for validation)\n");
+    printf("    -version         print Lynx version information\n");
+    printf("    -vikeys          enable vi-like key movement\n");
+    if (strncmp(argv[0], "-help", 5) != 0)
+	exit(-1);
+    exit(0);
+    break;
+
+    } /* end of switch. */
 }
 
 #ifndef VMS
-static void FatalProblem ARGS1(int,sig)
+PRIVATE void FatalProblem ARGS1(
+	int,		sig)
 {
-    fprintf (stderr, "\r\n\
+    /*
+     *  Ignore further interrupts. - mhc: 11/2/91
+     */
+    (void) signal (SIGHUP, SIG_IGN);
+    (void) signal (SIGTERM, SIG_IGN);
+    (void) signal (SIGINT, SIG_IGN);
+#ifndef __linux__
+    (void) signal(SIGBUS, SIG_IGN);
+#endif /* !__linux__ */
+    (void) signal(SIGSEGV, SIG_IGN);
+    (void) signal(SIGILL, SIG_IGN);
+
+    /*
+     *  Flush all messages. - FM
+     */
+    fflush(stderr);
+    fflush(stdout);
+
+    /*
+     *  Deal with curses, if on, and clean up. - FM
+     */
+    if (LYOutOfMemory && LYCursesON) {
+	sleep(AlertSecs);
+    }
+    cleanup_sig(0);
+#ifndef __linux__
+    signal(SIGBUS, SIG_DFL);
+#endif /* !__linux__ */
+    signal(SIGSEGV, SIG_DFL);
+    signal(SIGILL, SIG_DFL);
+
+    /*
+     *  Issue appropriate messages and abort or exit. - FM
+     */
+    if (LYOutOfMemory == FALSE) {
+        fprintf (stderr, "\r\n\
 A Fatal error has occurred in %s Ver. %s\r\n", LYNX_NAME, LYNX_VERSION);
 
-    fprintf(stderr, "\r\n\
+        fprintf(stderr, "\r\n\
 Please notify your system administrator to confirm a bug, and\r\n\
 if confirmed, to notify the lynx-dev list.  Bug reports should\r\n\
 have concise descriptions of the command and/or URL which causes\r\n\
 the problem, the operating system name with version number, the\r\n\
 TCPIP implementation, and any other relevant information.\r\n");
 
-    fprintf(stderr, "\r\n\
+        fprintf(stderr, "\r\n\
 Do NOT mail the core file if one was generated.\r\n");
 
-    fprintf(stderr, "\r\n\
+        fprintf(stderr, "\r\n\
 Lynx now exiting with signal:  %d\r\n\r\n", sig);
 
-    /* ignore further interrupts */     /*  mhc: 11/2/91 */
-    (void) signal (SIGHUP, SIG_IGN);
-    (void) signal (SIGTERM, SIG_IGN);
-#ifndef VMS  /* use ttclose() from cleanup() for VMS */
-    (void) signal (SIGINT, SIG_IGN);
-#endif /* !VMS */
-#ifndef __linux__
-     (void) signal(SIGBUS, SIG_IGN);
-#endif /* !__linux__ */
-     (void) signal(SIGSEGV, SIG_IGN);
-     (void) signal(SIGILL, SIG_IGN);
+	/*
+	 *  Exit and dump core.
+	 */
+	abort();
 
-  if (LYCursesON)
-      sleep(AlertSecs);
-  cleanup_sig(0);
-#ifndef __linux__
-  signal(SIGBUS, 0);
-#endif /* !__linux__ */
-  signal(SIGSEGV, 0);
-  signal(SIGILL, 0);
-  abort();  /* exit and dump core */
+    } else {
+	LYOutOfMemory = FALSE;
+	printf("\r\n%s\r\n\r\n", MEMORY_EXHAUSTED_ABORT);
+	fflush(stdout);
+
+	/*
+	 *  Exit without dumping core.
+	 */
+	exit(0);
+    }
 }
 #endif /* !VMS */
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index 83567743..bce1652c 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -4,6 +4,7 @@
 #include "HTParse.h"
 #include "HTList.h"
 #include "HTFTP.h"
+#include "HTFile.h"
 #include "HTTP.h"
 #include "LYCurses.h"
 #include "LYGlobalDefs.h"
@@ -32,6 +33,7 @@
 #include "LYTraversal.h"
 #include "LYCharSets.h"
 #include "LYCharUtils.h"
+#include "LYCookie.h"
 
 #ifdef VMS
 #include "HTVMSUtils.h"
@@ -53,7 +55,10 @@ PUBLIC void HTAddGotoURL PARAMS((char *url));
 
 #define FASTTAB
 #ifdef FASTTAB
-PRIVATE int sametext ARGS2(char *,een, char *,twee) {
+PRIVATE int sametext ARGS2(
+	char *,		een,
+	char *,		twee)
+{
     if (een && twee)
         return (strcmp(een, twee) == 0);
     return TRUE;
@@ -98,25 +103,26 @@ PRIVATE void free_mainloop_variables NOARGS
 }
 
 /*
- * Here's where we do all the work.
- * mainloop is basically just a big switch dependent on the users input.
- * I have tried to offload most of the work done here to procedures to
- * make it more modular, but this procedure still does a lot of variable
- * manipulation.  This needs some work to make it neater. - Lou Moutilli
+ *  Here's where we do all the work.
+ *  mainloop is basically just a big switch dependent on the users input.
+ *  I have tried to offload most of the work done here to procedures to
+ *  make it more modular, but this procedure still does a lot of variable
+ *  manipulation.  This needs some work to make it neater. - Lou Moutilli
  *					(memoir from the original Lynx - FM)
  */
 
 int mainloop NOARGS
 {
-    int  c=0, real_c=0, old_c=0, cmd, arrowup=FALSE, show_help=FALSE;
-    int lines_in_file= -1;
-    int newline=0;
+    int c = 0, real_c = 0, old_c = 0, cmd;
+    int arrowup = FALSE, show_help = FALSE;
+    int lines_in_file = -1;
+    int Newline = 0;
     char prev_target[512];
     char user_input_buffer[1024];
-    char *owner_address=NULL;  /* holds the responsible owner's address     */
-    char *ownerS_address=NULL; /* holds owner's address during source fetch */
-    BOOLEAN first_file=TRUE;
-    BOOLEAN refresh_screen=FALSE;
+    char *owner_address = NULL;  /* Holds the responsible owner's address     */
+    char *ownerS_address = NULL; /* Holds owner's address during source fetch */
+    BOOLEAN first_file = TRUE;
+    BOOLEAN refresh_screen = FALSE;
     BOOLEAN force_load = FALSE;
     BOOLEAN crawl_ok = FALSE;
     BOOLEAN rlink_exists;
@@ -124,6 +130,7 @@ int mainloop NOARGS
     BOOLEAN vi_keys_flag = vi_keys;
     BOOLEAN emacs_keys_flag = emacs_keys;
     BOOLEAN keypad_mode_flag = keypad_mode;
+    BOOLEAN user_mode_flag = user_mode;
     BOOLEAN HTfileSortMethod_flag = HTfileSortMethod;
     int CurrentCharSet_flag = current_char_set;
     BOOLEAN show_dotfiles_flag = show_dotfiles;
@@ -140,6 +147,8 @@ int mainloop NOARGS
     int URLNum;
     BOOLEAN FirstURLRecall = TRUE;
     char *temp = NULL;
+    BOOLEAN ForcePush = FALSE;
+    int i, len;
 
 #ifdef DIRED_SUPPORT
     char *tp;
@@ -148,12 +157,12 @@ int mainloop NOARGS
 #endif /* DIRED_SUPPORT */
 
 /*
- *  curdoc.address contains the name of the file that is currently open
+ *  curdoc.address contains the name of the file that is currently open.
  *  newdoc.address contains the name of the file that will soon be 
- *		   opened if it exits
- *  prev_target contains the last search string the user searched for
- *  newdoc.title contains the link name that the user last chose to get into
- *		   the current link (file)
+ *		     opened if it exits.
+ *  prev_target    contains the last search string the user searched for.
+ *  newdoc.title   contains the link name that the user last chose to get
+ *		     into the current link (file).
  */
     /* initalize some variables*/
     newdoc.address = NULL;
@@ -166,22 +175,21 @@ int mainloop NOARGS
     curdoc.post_data = NULL;
     curdoc.post_content_type = NULL;
     curdoc.bookmark = NULL;
+    nhist = 0;
+    user_input_buffer[(sizeof(user_input_buffer) - 1)] = '\0';
+    *prev_target = '\0';
+    *user_input_buffer = '\0';
+    StrAllocCopy(CurrentUserAgent, (LYUserAgent ?
+    				    LYUserAgent : ""));
     atexit(free_mainloop_variables);
-    if (startfile && homepage && strcmp(startfile, homepage))
-        HTAddGotoURL(homepage);
-    HTAddGotoURL(startfile);
 initialize:
-    nhist = 0;
     StrAllocCopy(newdoc.address, startfile);
     StrAllocCopy(startrealm, startfile);
     StrAllocCopy(newdoc.title, "Entry into main screen");
-    newdoc.isHEAD=FALSE;
-    newdoc.line=1;
-    newdoc.link=0;
-    *prev_target='\0';
-    *user_input_buffer='\0';
-    StrAllocCopy(CurrentUserAgent, (LYUserAgent ?
-    				    LYUserAgent : ""));
+    newdoc.isHEAD = FALSE;
+    newdoc.safe = FALSE;
+    newdoc.line = 1;
+    newdoc.link = 0;
 
 #ifdef USE_SLANG
     if (TRACE && LYCursesON) {
@@ -220,13 +228,13 @@ initialize:
 	     */
 	    if ((cp = get_bookmark_filename(&newdoc.address)) != NULL &&
 	         *cp != '\0' && strcmp(cp, " ")) {
-		LYforce_HTML_mode = TRUE;  /* force HTML */
 		StrAllocCopy(newdoc.title, BOOKMARK_TITLE);
 		StrAllocCopy(newdoc.bookmark, BookmarkPage);
 		StrAllocCopy(startrealm, newdoc.address);
 		FREE(newdoc.post_data);
 		FREE(newdoc.post_content_type);
 		newdoc.isHEAD = FALSE;
+		newdoc.safe = FALSE;
 		if (TRACE)
 		    fprintf(stderr, "Using bookmarks=%s\n", newdoc.address);
 	    } else {
@@ -238,20 +246,18 @@ initialize:
 	}
     }
 
-    if (form_post_data) {
-	FREE(form_post_data);
-    } else if (form_get_data) {
-	FREE(form_get_data);
-    }
+    FREE(form_post_data);
+    FREE(form_get_data);
 
-    if (user_mode==NOVICE_MODE)
+    if (user_mode == NOVICE_MODE)
         display_lines = LYlines-4;
     else
         display_lines = LYlines-2;
 
     while (TRUE) {
-	/* if newdoc.address is different then curdoc.address then we need 
-	 * to go out and find and load newdoc.address
+	/*
+	 *  If newdoc.address is different then curdoc.address then
+	 *  we need to go out and find and load newdoc.address.
 	 */
 	if (LYforce_no_cache || force_load ||
 	    are_different(&curdoc, &newdoc)) {
@@ -266,17 +272,21 @@ initialize:
 		}
 try_again:
 		/*
-		 * Push the old file onto the history stack.
+		 *  Push the old file onto the history stack.
 	 	 */
 		if (curdoc.address && newdoc.address) {
-		    LYpush(&curdoc);
+		    LYpush(&curdoc, ForcePush);
 
 		} else if (!newdoc.address) {
 		    /*
-		     * If newdoc.address is empty then pop a file and load it.
+		     *  If newdoc.address is empty then pop a file
+		     *  and load it.  Force a no_cache override unless
+		     *  it's a bookmark file or it has POST content
+		     *  and LYresubmit_posts is set. - FM
 		     */
                     LYpop(&newdoc);
-		    if (newdoc.post_data != NULL && LYresubmit_posts) {
+		    if ((newdoc.bookmark != NULL) ||
+		        (newdoc.post_data != NULL && LYresubmit_posts)) {
 		        LYoverride_no_cache = FALSE;
 		    } else {
 		        LYoverride_no_cache = TRUE;
@@ -350,15 +360,15 @@ try_again:
 		    /*
 		     *  Fall through to do the NULL stuff and reload the
 		     *  old file, unless the first file wasn't found or
-		     *  has gone missing
+		     *  has gone missing.
 		     */
 		    if (!nhist) { 
 			/* 
-			 * If nhist = 0 then it must be the first file.
+			 *  If nhist = 0 then it must be the first file.
 			 */
 			if (!dump_output_immediately)
 			    cleanup();
-		        printf("\nlynx: Can't access start file %s\n",
+		        printf("\nlynx: Can't access startfile %s\n",
 			       startfile);
 			if (!dump_output_immediately) {
 			    (void) signal(SIGHUP, SIG_DFL);
@@ -377,7 +387,7 @@ try_again:
 
 		case NULLFILE:
 		    /*
-		     * Not supposed to return any file.
+		     *  Not supposed to return any file.
 		     */
 		    LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
 		    FREE(newdoc.address); /* to pop last doc */
@@ -386,13 +396,14 @@ try_again:
 		    reloading = FALSE;
 		    LYPermitURL = FALSE;
 		    LYCancelledFetch = FALSE;
+		    ForcePush = FALSE;
 		    if (traversal) {
 		        crawl_ok = FALSE;
 			if (traversal_link_to_add) {
 			    /*
-			     * It's a binary file, or the fetch attempt
-			     * failed.  Add it to TRAVERSE_REJECT_FILE
-			     * so we don't try again in this run.
+			     *  It's a binary file, or the fetch attempt
+			     *  failed.  Add it to TRAVERSE_REJECT_FILE
+			     *  so we don't try again in this run.
 			     */
 			    if (!lookup_reject(traversal_link_to_add)) {
 			        add_to_reject_list(traversal_link_to_add);
@@ -401,12 +412,12 @@ try_again:
 			}
 		    }
 		   /*
-		    * Make sure the first file was found and
-		    * has not gone missing.
+		    *  Make sure the first file was found and
+		    *  has not gone missing.
 		    */
 		   if (!nhist) { 
 		       /*
-		        * If nhist = 0 then it must be the first file.
+		        *  If nhist = 0 then it must be the first file.
 			*/
 		       if (first_file && homepage &&
 #ifdef VMS
@@ -416,14 +427,14 @@ try_again:
 #endif /* VMS */
 			{
 			   /* 
-			    * Couldn't return to the first file but there is a
-			    * homepage we can use instead. Useful for when the
-			    * first URL causes a program to be invoked. - GL
+			    *  Couldn't return to the first file but there is a
+			    *  homepage we can use instead. Useful for when the
+			    *  first URL causes a program to be invoked. - GL
 			    * 
-			    * But first make sure homepage is different from
-			    * startfile (above), then make it the same (below)
-			    * so we don't enter an infinite getfile() loop on
-			    * on failures to find the files. - FM
+			    *  But first make sure homepage is different from
+			    *  startfile (above), then make it the same (below)
+			    *  so we don't enter an infinite getfile() loop on
+			    *  on failures to find the files. - FM
 			    */
 			   StrAllocCopy(newdoc.address, homepage);
 			   FREE(newdoc.post_data);
@@ -431,6 +442,7 @@ try_again:
 			   FREE(newdoc.bookmark);
 			   StrAllocCopy(startfile, homepage);
 			   newdoc.isHEAD = FALSE;
+			   newdoc.safe = FALSE;
 		       } else {
 		           if (!dump_output_immediately)
 			       cleanup();
@@ -458,11 +470,111 @@ try_again:
 
 		case NORMAL:
 		    /*
-		     * Marvelously, we got the document!
+		     *  Marvelously, we got the document!
 		     */
 		    LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
 		    *prev_target = '\0';    /* Reset for this document. - FM */
 
+		    /*
+		     *  If it's the first file and we're interactive,
+		     *  check whether it's a bookmark file which was
+		     *  not accessed via the -book switch. - FM
+		     */
+		    if (((first_file == TRUE) &&
+		         (dump_output_immediately == FALSE) &&
+		         !(newdoc.bookmark && *newdoc.bookmark)) &&
+			((LYisLocalFile(newdoc.address) == TRUE) &&
+			 !(strcmp((HText_getTitle() ? HText_getTitle() : ""),
+				  BOOKMARK_TITLE))) &&
+			(temp = HTParse(newdoc.address, "",
+		    		     PARSE_PATH+PARSE_PUNCTUATION)) != NULL) {
+#ifdef VMS
+			cp = HTVMS_wwwName((char *)Home_Dir());
+#else
+			cp = (char *)Home_Dir();
+#endif /* VMS */
+			len = strlen(cp);
+#ifdef VMS
+			if (!strncasecomp(temp, cp, len) &&
+#else
+			if (!strncmp(temp, cp, len) &&
+#endif /* VMS */
+			    strlen(temp) > len) {
+			    /*
+			     *  We're interactive and this might be a
+			     *  bookmark file entered as a startfile
+			     *  rather than invoked via -book.  Check
+			     *  if it's in our bookmark file list, and
+			     *  if so, reload if with the relevant
+			     *  bookmark elements set. - FM
+			     */
+			    if ((cp = (char *)calloc(1,
+				  (strlen((char *)&temp[len]) + 2))) == NULL)
+				outofmem(__FILE__, "mainloop");
+			    if (temp[len] == '/')
+				sprintf(cp, ".%s", (char *)&temp[len]);
+			    else
+				strcpy(cp, (char *)&temp[len]);
+			    for (i = 0; i <= MBM_V_MAXFILES; i++) {
+				if (MBM_A_subbookmark[i] &&
+#ifdef VMS
+				    !strcasecomp(cp, MBM_A_subbookmark[i]))
+#else
+				    !strcmp(cp, MBM_A_subbookmark[i]))
+#endif /* VMS */
+				{
+				    StrAllocCopy(BookmarkPage,
+						 MBM_A_subbookmark[i]);
+				    break;
+				}
+			    }
+			    FREE(cp);
+			    if (i <= MBM_V_MAXFILES) {
+				FREE(temp);
+				if (LYValidate) {
+				    _statusline(BOOKMARKS_DISABLED);
+				    sleep(AlertSecs);
+				    return(-1);
+				}
+				if (temp = HTParse(newdoc.address, "",
+				 PARSE_ACCESS+PARSE_HOST+PARSE_PUNCTUATION)) {
+				    StrAllocCopy(newdoc.address, temp);
+				    HTuncache_current_document();
+				    FREE(curdoc.address);
+#ifdef VMS
+				    StrAllocCat(newdoc.address,
+			    		    HTVMS_wwwName((char *)Home_Dir()));
+#else
+				    StrAllocCat(newdoc.address, Home_Dir());
+#endif /* VMS */
+				    StrAllocCat(newdoc.address, "/");
+				    StrAllocCat(newdoc.address,
+			    		(strncmp(BookmarkPage, "./", 2) ?
+							   BookmarkPage :
+							(BookmarkPage + 2)));
+				    StrAllocCopy(newdoc.title, BOOKMARK_TITLE);
+				    StrAllocCopy(newdoc.bookmark, BookmarkPage);
+				    StrAllocCopy(startrealm, newdoc.address);
+				    FREE(newdoc.post_data);
+				    FREE(newdoc.post_content_type);
+				    newdoc.isHEAD = FALSE;
+				    newdoc.safe = FALSE;
+				    FREE(temp);
+				    if (!strcmp(homepage, startfile))
+				        StrAllocCopy(homepage, newdoc.address);
+				    StrAllocCopy(startfile, newdoc.address);
+				    if (TRACE)
+				        fprintf(stderr,
+						"Reloading as bookmarks=%s\n",
+						newdoc.address);
+				    goto try_again;
+				}
+			    }
+		        }
+		        cp = NULL;
+		    }
+		    FREE(temp);
+
 		    if (traversal) {
 		        /*
 			 *  During traversal build up lists of all links
@@ -470,14 +582,18 @@ try_again:
 			 *  feature for traversing http links in the web.
 			 */
 			if (traversal_link_to_add) {
-			    /* Add the address we sought to TRAVERSE_FILE */
+			    /*
+			     *  Add the address we sought to TRAVERSE_FILE.
+			     */
 			    if (!lookup(traversal_link_to_add))
 			        add_to_table(traversal_link_to_add);
 			    FREE(traversal_link_to_add);
 			}
 			if (curdoc.address && curdoc.title &&
 			    strncasecomp(curdoc.address, "LYNXIMGMAP:", 11))
-			    /* Add the address we got to TRAVERSE_FOUND_FILE */
+			    /*
+			     *  Add the address we got to TRAVERSE_FOUND_FILE.
+			     */
 			    add_to_traverse_list(curdoc.address, curdoc.title);
 		    }
 
@@ -497,48 +613,67 @@ try_again:
 		    }
 
 		    /*
-            	     * Set newline to the saved line.  It contains the
-		     * line the user was on if s/he has been in the file
-		     * before, or it is 1 if this is a new file.
+            	     *  Set Newline to the saved line.  It contains the
+		     *  line the user was on if s/he has been in the file
+		     *  before, or it is 1 if this is a new file.
 		     */
-                    newline = newdoc.line;
+                    Newline = newdoc.line;
 
 		    /* 
-		     * If we are going to a target line,
-		     * override any www_search line result.
+		     *  If we are going to a target line,
+		     *  override any www_search line result.
 		     */
-		    if (newline > 1)	
+		    if (Newline > 1)	
 			 www_search_result = -1;
 
 		    /*
-		     * Make sure curdoc.line will not be equal
-		     * to newline, so we get a redraw.
+		     *  Make sure curdoc.line will not be equal
+		     *  to Newline, so we get a redraw.
 		     */
 		    curdoc.line = -1;
 
 	  	    break;	
 		}  /* end switch */
 
-	   if (TRACE)
-	      sleep(AlertSecs); /* allow me to look at the results */
+	    if (TRACE)
+	        sleep(AlertSecs); /* allow me to look at the results */
+
+	    /*
+	     *  Set the files the same.
+	     */
+	    StrAllocCopy(curdoc.address, newdoc.address);
+	    StrAllocCopy(curdoc.post_data, newdoc.post_data);
+	    StrAllocCopy(curdoc.post_content_type, newdoc.post_content_type);
+	    StrAllocCopy(curdoc.bookmark, newdoc.bookmark);
+	    curdoc.isHEAD = newdoc.isHEAD;
+
+	    /*
+	     *  Set the remaining document elements and add to
+	     *  the visitied links list. - FM
+	     */
+	    if (ownerS_address != NULL) {
+	        if (HTOutputFormat == WWW_SOURCE && !HText_getOwner())
+	            HText_setMainTextOwner(ownerS_address);
+	        FREE(ownerS_address);
+	    }
+            if (HText_getTitle()) {
+	        StrAllocCopy(curdoc.title, HText_getTitle());
+	    } else if (!dump_output_immediately) {
+	        StrAllocCopy(curdoc.title, newdoc.title);
+	    }
+	    owner_address = HText_getOwner();
+	    curdoc.safe = HTLoadedDocumentIsSafe();
+	    if (!dump_output_immediately) {
+	        LYAddVisitedLink(&curdoc);
+	    }
 
-	   /* set the files the same */
-	   StrAllocCopy(curdoc.address, newdoc.address);
-	   StrAllocCopy(curdoc.post_data, newdoc.post_data);
-	   StrAllocCopy(curdoc.post_content_type, newdoc.post_content_type);
-	   StrAllocCopy(curdoc.bookmark, newdoc.bookmark);
-	   curdoc.isHEAD = newdoc.isHEAD;
 
 	   /*
 	    *  Reset WWW present mode so that if we were getting
 	    *  the source, we get rendered HTML from now on.
 	    */
-	   if (ownerS_address != NULL) {
-	       if (HTOutputFormat == WWW_SOURCE && !HText_getOwner())
-	           HText_setMainTextOwner(ownerS_address);
-	       FREE(ownerS_address);
-	   }
 	   HTOutputFormat = WWW_PRESENT;
+
 	   /*
 	    *  Reset all of the other relevant flags. - FM
 	    */
@@ -548,28 +683,28 @@ try_again:
 	   reloading = FALSE;		/* only set for RELOAD and RESUBMIT */
 	   HEAD_request = FALSE;	/* only set for HEAD requests */
 	   LYPermitURL = FALSE;		/* only set for LYValidate */
+	   ForcePush = FALSE;		/* only set for some PRINT requests. */
 
-  	} /* end if (STREQ(newdoc.address,curdoc.address) */
+  	} /* end if (STREQ(newdoc.address, curdoc.address) */
 
         if (dump_output_immediately) {
 	    if (crawl) {
-                if (HText_getTitle())
-	            StrAllocCopy(curdoc.title, HText_getTitle());
-                print_crawl_to_fd(stdout,curdoc.address,curdoc.title);
+                print_crawl_to_fd(stdout, curdoc.address, curdoc.title);
 	    } else {
                 print_wwwfile_to_fd(stdout,0);
 	    }
 	    return(0);
 	}
 
-	/* if the resent_sizechange variable is set to true
-	   then the window size changed recently. 
-	*/
+	/*
+	 *  If the resent_sizechange variable is set to TRUE
+	 *  then the window size changed recently. 
+	 */
 	if (recent_sizechange) {
 		stop_curses();
 		start_curses(); 
 		clear();
-		refresh_screen = TRUE; /*to force a redraw */
+		refresh_screen = TRUE; /* to force a redraw */
 		recent_sizechange=FALSE;
 		if (user_mode==NOVICE_MODE) {
 		    display_lines = LYlines-4;
@@ -579,17 +714,18 @@ try_again:
 	}
 
         if (www_search_result != -1) {
-             /* This was a WWW search, set the line
-              * to the result of the search
+             /*
+	      *  This was a WWW search, set the line
+              *  to the result of the search.
               */
-             newline = www_search_result;
+             Newline = www_search_result;
              www_search_result = -1;  /* reset */
 	     more = HText_canScrollDown();
         }
 
 	if (first_file == TRUE) {
 	    /*
-	     * We can never again have the first file.
+	     *  We can never again have the first file.
 	     */
 	    first_file = FALSE; 
 
@@ -618,7 +754,7 @@ try_again:
 	    }
 	    if (traversal) {
 	        /*
-		 * Set up the crawl output stuff.
+		 *  Set up the crawl output stuff.
 		 */
 		if (curdoc.address && !lookup(curdoc.address)) {
 		    if (strncasecomp(curdoc.address, "LYNXIMGMAP:", 11))
@@ -626,7 +762,7 @@ try_again:
 		    add_to_table(curdoc.address);
 		}
 		/*
-		 * Set up the traversal_host comparison string.
+		 *  Set up the traversal_host comparison string.
 		 */
 		if (strncmp((curdoc.address ? curdoc.address : "NULL"),
 			    "http", 4)) {
@@ -651,65 +787,81 @@ try_again:
 		    	    "Traversal host is '%s'\n\n", traversal_host);
 		}
 	    }
+	    if (startfile) {
+	        if (homepage && strcmp(startfile, homepage))
+		    HTAddGotoURL(homepage);
+	    if (strcmp(startfile, newdoc.address) ||
+	        newdoc.post_data == NULL);
+		HTAddGotoURL(startfile);
+	    }
 	    if (TRACE) {
 		refresh_screen = TRUE;
 		sleep(AlertSecs);
 	    }
 	}
 
-	/* if the curdoc.line is different than newline then there must
-	 * have been a change since last update. Run showpage.
-	 * showpage will put a fresh screen of text out.
-	 * If this is a WWW document then use the 
-	 * WWW routine HText_pageDisplay to put the page on
-	 * the screen
+	/*
+	 *  If the curdoc.line is different than Newline then there
+	 *  must have been a change since last update.  Run showpage.
+	 *  showpage will put a fresh screen of text out.  If this is
+	 *  a WWW document then use the WWW routine HText_pageDisplay
+	 *  to put the page on the screen.
          */
-	if (curdoc.line != newline) {
+	if (curdoc.line != Newline) {
 	
    	    refresh_screen = FALSE;
 
-	    HText_pageDisplay(newline, prev_target);
+	    HText_pageDisplay(Newline, prev_target);
 
 #ifdef DIRED_SUPPORT
 	    if (lynx_edit_mode && nlinks > 0 && !HTList_isEmpty(tagged))
 	      showtags(tagged);
 #endif /* DIRED_SUPPORT */
-	    /* if more equals true then there is more
-	     * info below this page 
+	    /*
+	     *  If more equals TRUE, then there is more
+	     *  info below this page .
 	     */
 	    more = HText_canScrollDown();
-	    curdoc.line = newline = HText_getTopOfScreen()+1;
+	    curdoc.line = Newline = HText_getTopOfScreen()+1;
             lines_in_file = HText_getNumOfLines();
 
-            if (HText_getTitle()) {
-	        StrAllocCopy(curdoc.title, HText_getTitle());
-	    } else {
-	        StrAllocCopy(curdoc.title, newdoc.title);
+	    if (curdoc.title == NULL) {
+	        /*
+		 *  If we don't yet have a title, try to get it,
+		 *  or set to that for newdoc.title. - FM
+		 */
+	        if (HText_getTitle()) {
+		    StrAllocCopy(curdoc.title, HText_getTitle());
+		} else {
+		    StrAllocCopy(curdoc.title, newdoc.title);
+		}
 	    }
-	   owner_address = HText_getOwner();
 
-	   if (arrowup) { 
-		/* arrow up is set if we just came up from
-		 * a page below 
+	    if (arrowup) { 
+		/*
+		 *  arrowup is set if we just came up from
+		 *  a page below.
 		 */
 	        curdoc.link = nlinks - 1;
 	        arrowup = FALSE;
-	   } else {
+	    } else {
 	        curdoc.link = newdoc.link;
 		if (curdoc.link >= nlinks)
 	            curdoc.link = nlinks - 1;
-	   }
+	    }
 
-	   show_help = FALSE; /* reset */
-	   newdoc.line = 1;
-	   newdoc.link = 0;
-	   curdoc.line = newline; /* set */
+	    show_help = FALSE; /* reset */
+	    newdoc.line = 1;
+	    newdoc.link = 0;
+	    curdoc.line = Newline; /* set */
 	}
 
-	/* refesh the screen if neccessary */
+	/*
+	 *  Refesh the screen if neccessary.
+	 */
 	if (refresh_screen) {
 	    clear();
-	    HText_pageDisplay(newline, prev_target);
+	    HText_pageDisplay(Newline, prev_target);
 
 #ifdef DIRED_SUPPORT
 	    if (lynx_edit_mode && nlinks > 0 && !HTList_isEmpty(tagged))
@@ -721,25 +873,33 @@ try_again:
 
 	}
 
-	/* report unread or new mail, if appropriate */
+	/*
+	 *  Report unread or new mail, if appropriate.
+	 */
 	if (check_mail && !no_mail && LYCheckMail())
 	    sleep(MessageSecs);
 
-	/* if help is not on the screen 
-	 * then put a message on the screen
-	 * to tell the user other misc info
+	/*
+	 *  If help is not on the screen,
+	 *  then put a message on the screen
+	 *  to tell the user other misc info.
 	 */
 	if (!show_help) {
-	    /* make sure form novice lines are replaced */
+	    /*
+	     *  Make sure form novice lines are replaced.
+	     */
 	    if (user_mode == NOVICE_MODE) {
 		noviceline(more);
 	    }
 
-	    /* if we are in forms mode then explicitly
-	     * tell the user what each kind of link is
+	    /*
+	     *  If we are in forms mode then explicitly
+	     *  tell the user what each kind of link is.
 	     */
 	    if (HTisDocumentSource()) {
-		/* currently displaying HTML source */
+		/*
+		 *  Currently displaying HTML source.
+		 */
 		_statusline(SOURCE_HELP);
 
 #ifdef INDICATE_FORMS_MODE_FOR_ALL_LINKS_ON_PAGE
@@ -797,6 +957,7 @@ try_again:
 			}
 		        break;
                     case F_SUBMIT_TYPE:
+                    case F_IMAGE_SUBMIT_TYPE:
 		  	if (links[curdoc.link].form->disabled == YES) {
 			    statusline(FORM_LINK_SUBMIT_DIS_MSG);
 			} else if (links[curdoc.link].form->submit_method ==
@@ -829,7 +990,9 @@ try_again:
 		else
 	            statusline(NORMAL_LINK_MESSAGE);
 
-		/* let them know if it's an index -- very rare*/
+		/*
+		 *  Let them know if it's an index -- very rare.
+		 */
 		if (is_www_index) {
 		    move(LYlines-1,LYcols-8);
 		    start_reverse();
@@ -838,7 +1001,9 @@ try_again:
 		}
 			
 	    } else if (user_mode == ADVANCED_MODE && nlinks > 0) {
-		/* show the URL */
+		/*
+		 *  Show the URL.
+		 */
 		if (more)
 		    if (is_www_index)
 		        _user_message("-more- -index- %s",
@@ -880,8 +1045,8 @@ try_again:
 
 	if (traversal) {
 	    /*
-	     * Don't go interactively into forms,
-	     * or accept keystrokes from the user
+	     *  Don't go interactively into forms,
+	     *  or accept keystrokes from the user
 	     */
             if (crawl && crawl_ok) {
 	        crawl_ok = FALSE;
@@ -912,7 +1077,7 @@ try_again:
 	    }
 	} else {
 	    /*
-	     * Normal, non-traversal handling
+	     *  Normal, non-traversal handling.
 	     */
 	    if (nlinks > 0 &&
 	    	links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
@@ -921,7 +1086,7 @@ try_again:
 		 links[curdoc.link].form->type == F_PASSWORD_TYPE ||
 		 links[curdoc.link].form->type == F_TEXTAREA_TYPE)) {
 	        /*
-		 * Replace novice lines if in NOVICE_MODE
+		 *  Replace novice lines if in NOVICE_MODE.
 		 */
     	        if (user_mode==NOVICE_MODE) {
 		    move(LYlines-2,0); clrtoeol();
@@ -937,25 +1102,28 @@ try_again:
 	        if (c == '\n' || c == '\r')
 #ifdef FASTTAB
 		    /*
-		     * Make return act like downarrow
+		     *  Make return act like down-arrow.
 		     */
 		    c = DNARROW;
 #else
 		    /*
-		     * Make return act like tab
+		     *  Make return act like tab.
 		     */
 		    c = '\t';
 #endif /* FASTTAB */
 	    } else {
-	        /* Get a keystroke from the user
-	         * Save the last keystroke to avoid redundant
-		 * error reporting.
+get_keyboard_input:
+	        /*
+		 *  Get a keystroke from the user.
+	         *  Save the last keystroke to avoid
+		 *  redundant error reporting.
 	         */
 	        real_c = c = LYgetch();	/* get user input */
 #ifndef VMS
 		if (c == 3) {		/* ^C */
-		    /* This shouldn't happen.  We'll try to
-		     * deal with whatever bug caused it. - FM
+		    /*
+		     *  This shouldn't happen.  We'll try to
+		     *  deal with whatever bug caused it. - FM
 		     */
 		    signal(SIGINT, cleanup_sig);
 		    old_c = 0;
@@ -982,16 +1150,17 @@ try_again:
 #endif /* VMS */
 
 new_keyboard_input:
-	/* a goto point for new input without going
-         * back through the getch() loop
+	/*
+	 *  A goto point for new input without going
+         *  back through the getch() loop.
          */
 	if (traversal) {
 	    /*
-	     * This is a special feature to traverse every http link
-	     * derived from startfile and check for errors or create
-	     * crawl ouput files.  Only URL's that begin with
-	     * "traversal_host" are searched - this keeps the search
-	     * from crossing to other servers (a feature, not a bug!)
+	     *  This is a special feature to traverse every http link
+	     *  derived from startfile and check for errors or create
+	     *  crawl ouput files.  Only URL's that begin with
+	     *  "traversal_host" are searched - this keeps the search
+	     *  from crossing to other servers (a feature, not a bug!).
 	     */
 	    rlink_exists = (nlinks > 0 && links[curdoc.link].lname != NULL);
 	    if (rlink_exists) {
@@ -1048,8 +1217,8 @@ new_keyboard_input:
  		    c=DNARROW;
 		else {
 		    /*
-		     * curdoc.title doesn't always work, so
-		     * bail out if the history list is empty.
+		     *  curdoc.title doesn't always work, so
+		     *  bail out if the history list is empty.
 		     */
 		    if (STREQ(curdoc.title,"Entry into main screen") ||
 	                (nhist <= 0 )) {
@@ -1080,8 +1249,9 @@ new_keyboard_input:
 	  cmd = override[c+1];
 #endif /* DIRED_SUPPORT && OK_OVERRIDE */
 
-new_cmd:  /* a goto point for new input without going
-           * back through the getch() loop
+new_cmd:  /*
+	   *  A goto point for new input without going
+           *  back through the getch() loop.
            */
 
 	switch(cmd) {
@@ -1093,12 +1263,17 @@ new_cmd:  /* a goto point for new input without going
                 _statusline(HELP);
             show_help = TRUE;
 
-            if (TRACE)
-                printw("%d", c);  /* show the user input */
+            if (TRACE) {
+	        sprintf(cfile, "%d", c);
+                addstr(cfile);  /* show the user input */
+		cfile[0] = '\0';
+	    }
             break;
 
 	case LYK_INTERRUPT:
-	    /* No network transmission to interrupt - 'til we multithread */
+	    /*
+	     *  No network transmission to interrupt - 'til we multithread.
+	     */
 	    break;
 
 	case LYK_1:
@@ -1110,23 +1285,28 @@ new_cmd:  /* a goto point for new input without going
 	case LYK_7:
 	case LYK_8:
 	case LYK_9:
-	    /* get a number from the user and follow that link number */
+	    /*
+	     *  Get a number from the user and follow that link number.
+	     */
 	    switch(follow_link_number(c, ((nlinks > 0) ? curdoc.link : 0))) {
 	    case DO_LINK_STUFF:
-                /* follow a normal link */
+                /*
+		 *  Follow a normal link.
+		 */
 		if (nlinks > 0)
                     StrAllocCopy(newdoc.address, links[curdoc.link].lname);
 		else
 		    StrAllocCopy(newdoc.address, links[0].lname);
 		/*
-		 * Might be an anchor in the same doc from a POST
-		 * form.  If so, don't free the content. -- FM
+		 *  Might be an anchor in the same doc from a POST
+		 *  form.  If so, don't free the content. -- FM
 		 */
 		if (are_different(&curdoc, &newdoc)) {
 		    FREE(newdoc.post_data);
 		    FREE(newdoc.post_content_type);
 		    FREE(newdoc.bookmark);
 		    newdoc.isHEAD = FALSE;
+		    newdoc.safe = FALSE;
 		}
 		force_load = TRUE;  /* force MainLoop to reload */
 		break;
@@ -1142,6 +1322,18 @@ new_cmd:  /* a goto point for new input without going
 	    break;
 
 	case LYK_SOURCE:  /* toggle view source mode */
+	    /*
+	     *  Check if this is a reply from a POST, and if so,
+	     *  seek confirmation if the safe element is not set. - FM
+	     */
+	    if ((curdoc.post_data != NULL &&
+	         curdoc.safe != TRUE) &&
+		HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
+		_statusline(CANCELLED);
+		sleep(InfoSecs);
+		break;
+	    } 
+
 	    if (HTisDocumentSource()) {
 	        HTOutputFormat = WWW_PRESENT;
 	    } else {
@@ -1155,7 +1347,19 @@ new_cmd:  /* a goto point for new input without going
 
 	case LYK_RELOAD:  /* control-R to reload and refresh */
 	    /*
-	     * Check to see if should reload source, or load html
+	     *  Check if this is a reply from a POST, and if so,
+	     *  seek confirmation if the safe element is not set. - FM
+	     */
+	    if ((curdoc.post_data != NULL &&
+	         curdoc.safe != TRUE) &&
+		HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
+		_statusline(CANCELLED);
+		sleep(InfoSecs);
+		break;
+	    } 
+
+	    /*
+	     *  Check to see if should reload source, or load html
 	     */
 	    if (HTisDocumentSource()) {
 		HTOutputFormat = WWW_SOURCE;
@@ -1164,22 +1368,22 @@ new_cmd:  /* a goto point for new input without going
 	    HTuncache_current_document();
 #ifdef NO_ASSUME_SAME_DOC
 	    /*
-	     * Don't assume the reloaded document will be the same. - FM
+	     *  Don't assume the reloaded document will be the same. - FM
 	     */
 	    newdoc.line=1;
 	    newdoc.link=0;
 #else
 	    /*
-	     * Do assume the reloaded document will be the same. - FM
-	     * (I don't remember all the reasons why we couldn't assume
-	     *  this.  As the problems show up, we'll try to fix them,
-	     *  or add warnings.  - FM)
+	     *  Do assume the reloaded document will be the same. - FM
+	     *  (I don't remember all the reasons why we couldn't assume
+	     *   this.  As the problems show up, we'll try to fix them,
+	     *   or add warnings.  - FM)
 	     */
 	    if (lynx_mode == FORMS_LYNX_MODE) {
 	        /*
-		 * Note that if there are no form links on the current
-		 * page, lynx_mode won't have this setting and we won't
-		 * know that this warning should be issued. - FM
+		 *  Note that if there are no form links on the current
+		 *  page, lynx_mode won't have this setting and we won't
+		 *  know that this warning should be issued. - FM
 		 */
 		_statusline(RELOADING_FORM);
 		sleep(AlertSecs);
@@ -1192,16 +1396,28 @@ new_cmd:  /* a goto point for new input without going
 	    clearok(curscr, TRUE);
 #endif /* VMS */
 	    /*
-	     * Reload should force a cache refresh on a proxy
+	     *  Reload should force a cache refresh on a proxy.
 	     *        -- Ari L. <luotonen@dxcern.cern.ch>
 	     */
             reloading = TRUE;
 	    break;
 
 	case LYK_HISTORICAL:  
-	    HTuncache_current_document();
-	    StrAllocCopy(newdoc.address, curdoc.address);
-	    FREE(curdoc.address);
+	    /*
+	     *  Check if this is a reply from a POST, and if so,
+	     *  seek confirmation of reload if the safe element
+	     *  is not set. - FM
+	     */
+	    if ((curdoc.post_data != NULL &&
+	         curdoc.safe != TRUE) &&
+		HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
+		_statusline(WILL_NOT_RELOAD_DOC);
+		sleep(InfoSecs);
+	    } else {
+	        HTuncache_current_document();
+		StrAllocCopy(newdoc.address, curdoc.address);
+		FREE(curdoc.address);
+	    }
 	    if (historical_comments)
 	        historical_comments = FALSE;
 	    else
@@ -1218,9 +1434,21 @@ new_cmd:  /* a goto point for new input without going
 
 	case LYK_MINIMAL:  
 	    if (!historical_comments) {
-	        HTuncache_current_document();
-	        StrAllocCopy(newdoc.address, curdoc.address);
-	        FREE(curdoc.address);
+	        /*
+		 *  Check if this is a reply from a POST, and if so,
+		 *  seek confirmation of reload if the safe element
+		 *  is not set. - FM
+		 */
+		if ((curdoc.post_data != NULL &&
+		     curdoc.safe != TRUE) &&
+		    HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
+		    _statusline(WILL_NOT_RELOAD_DOC);
+		    sleep(InfoSecs);
+		} else {
+		    HTuncache_current_document();
+		    StrAllocCopy(newdoc.address, curdoc.address);
+		    FREE(curdoc.address);
+		}
 	    }
 	    if (minimal_comments)
 	        minimal_comments = FALSE;
@@ -1237,9 +1465,21 @@ new_cmd:  /* a goto point for new input without going
 	    break;
 
 	case LYK_SOFT_DQUOTES:  
-	    HTuncache_current_document();
-	    StrAllocCopy(newdoc.address, curdoc.address);
-	    FREE(curdoc.address);
+	    /*
+	     *  Check if this is a reply from a POST, and if so,
+	     *  seek confirmation of reload if the safe element
+	     *  is not set. - FM
+	     */
+	    if ((curdoc.post_data != NULL &&
+	         curdoc.safe != TRUE) &&
+		HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
+		_statusline(WILL_NOT_RELOAD_DOC);
+		sleep(InfoSecs);
+	    } else {
+	        HTuncache_current_document();
+		StrAllocCopy(newdoc.address, curdoc.address);
+		FREE(curdoc.address);
+	    }
 	    if (soft_dquotes)
 	        soft_dquotes = FALSE;
 	    else
@@ -1270,13 +1510,13 @@ new_cmd:  /* a goto point for new input without going
 	    }
 	    break;
 	
-	case LYK_ABORT:
-	    return(0);  /* dont ask the user about quitting */
+	case LYK_ABORT:		/* don't ask the user about quitting */
+	    return(0);
 	    break;
 
 	case LYK_NEXT_PAGE:	/* next page */
 	    if (more) {
-	        newline += display_lines;
+	        Newline += display_lines;
 	    } else if (curdoc.link < nlinks-1) {
 		highlight(OFF,curdoc.link);
 		curdoc.link = nlinks-1;  /* put on last link */
@@ -1288,8 +1528,8 @@ new_cmd:  /* a goto point for new input without going
 	    break;
 
 	case LYK_PREV_PAGE:  /* page up */
-	    if (newline > 1) {
-		newline -= display_lines;
+	    if (Newline > 1) {
+		Newline -= display_lines;
 	    } else if (curdoc.link > 0) {
 		highlight(OFF,curdoc.link);
 		curdoc.link = 0;  /* put on last link */
@@ -1301,13 +1541,13 @@ new_cmd:  /* a goto point for new input without going
 	    break;
 
 	case  LYK_UP_TWO:
-	    if (newline > 1) {
-	        newline -= 2;
+	    if (Newline > 1) {
+	        Newline -= 2;
 		if (nlinks > 0 && curdoc.link > -1) {
 		    if (links[curdoc.link].ly <= (display_lines - 2)) {
 		        newdoc.link = curdoc.link +
 				      HText_LinksInLines(HTMainText,
-				      			 newline, 2);
+				      			 Newline, 2);
 		    } else {
 		        arrowup = TRUE;
 		    }
@@ -1321,10 +1561,9 @@ new_cmd:  /* a goto point for new input without going
 
 	case  LYK_DOWN_TWO:
 	    if (more) {
-	        newline += 2;
+	        Newline += 2;
 		if (nlinks > 0 && curdoc.link > -1 &&
 		    links[curdoc.link].ly > 2) {
-		    int i;
 		    newdoc.link = curdoc.link;
 		    for (i = 0; links[i].ly <= 2; i++)
 		        --newdoc.link;
@@ -1337,13 +1576,13 @@ new_cmd:  /* a goto point for new input without going
 	    break;
 
 	case  LYK_UP_HALF:
-	    if (newline > 1) {
-	        newline -= display_lines/2;
+	    if (Newline > 1) {
+	        Newline -= display_lines/2;
 		if (nlinks > 0 && curdoc.link > -1) {
 		    if (links[curdoc.link].ly <= (display_lines/2)) {
 		        newdoc.link = curdoc.link +
 				      HText_LinksInLines(HTMainText,
-				      			 newline,
+				      			 Newline,
 							 (display_lines/2));
 		    } else {
 		        arrowup = TRUE;
@@ -1358,10 +1597,9 @@ new_cmd:  /* a goto point for new input without going
 
 	case  LYK_DOWN_HALF:
 	    if (more) {
-	        newline += (display_lines/2);
+	        Newline += (display_lines/2);
 		if (nlinks > 0 && curdoc.link > -1 &&
 		    links[curdoc.link].ly > display_lines/2) {
-		    int i;
 		    newdoc.link = curdoc.link;
 		    for (i = 0; links[i].ly <= (display_lines/2); i++)
 		        --newdoc.link;
@@ -1382,7 +1620,7 @@ new_cmd:  /* a goto point for new input without going
 
 	case LYK_HOME:
 	    if (curdoc.line > 1)
-	        newline = 1;
+	        Newline = 1;
 	    else {
 		cmd = LYK_PREV_PAGE;
 		goto new_cmd;
@@ -1391,8 +1629,8 @@ new_cmd:  /* a goto point for new input without going
 
 	case LYK_END:
 	    if (more) {
-	       newline = MAXINT; /* go to end of file */
-	       arrowup = TRUE;  /* position on last link */
+	       Newline = MAXINT; /* go to end of file */
+	       arrowup = TRUE;	 /* position on last link */
 	    } else {
 		cmd = LYK_NEXT_PAGE;
 		goto new_cmd;
@@ -1400,21 +1638,25 @@ new_cmd:  /* a goto point for new input without going
 	    break;
 
 	case LYK_PREV_LINK:
-	    if (curdoc.link > 0) {		/* previous link */
-		highlight(OFF, curdoc.link);   /* unhighlight the current link */
+	    if (curdoc.link > 0) {	     /* previous link */
+		highlight(OFF, curdoc.link); /* unhighlight the current link */
 		curdoc.link--;
 
-	    } else if (!more && curdoc.link==0 && newline==1) { /* at the top of list */ 
-		/* if there is only one page of data and the user
-		 * goes off the top, then just move the cursor to
-		 * last link on the page
+	    } else if (!more &&
+	    	       curdoc.link==0 && Newline==1) { /* at the top of list */ 
+		/*
+		 *  If there is only one page of data and the user
+		 *  goes off the top, then just move the cursor to
+		 *  last link on the page.
 		 */
 		highlight(OFF,curdoc.link); /* unhighlight the current link */
 		curdoc.link = nlinks-1;  /* the last link */
 
 	    } else if (curdoc.line > 1) {	/* previous page */
-		/* go back to the previous page */
-		newline -= (display_lines);
+		/*
+		 *  Go back to the previous page.
+		 */
+		Newline -= (display_lines);
 		arrowup = TRUE;
 
 	    } else if (old_c != real_c) {
@@ -1429,7 +1671,7 @@ new_cmd:  /* a goto point for new input without going
 		highlight(OFF, curdoc.link);
 #ifdef FASTTAB
 		/*
-		 * Move to different textarea if TAB in textarea.
+		 *  Move to different textarea if TAB in textarea.
 		 */
 		if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
                     links[curdoc.link].form->type == F_TEXTAREA_TYPE &&
@@ -1450,15 +1692,15 @@ new_cmd:  /* a goto point for new input without going
 		curdoc.link++;
 #endif /* FASTTAB */
 	    /*
-	     * At the bottom of list and there is only one page. 
-	     * Move to the top link on the page.
+	     *  At the bottom of list and there is only one page. 
+	     *  Move to the top link on the page.
 	     */
-	    } else if (!more && newline == 1 && curdoc.link == nlinks-1) {
+	    } else if (!more && Newline == 1 && curdoc.link == nlinks-1) {
 		highlight(OFF,curdoc.link); 
 		curdoc.link = 0;
 
             } else if (more) {  /* next page */
-                 newline += (display_lines);
+                 Newline += (display_lines);
 
 	    } else if (old_c != real_c) {
 		old_c = real_c;
@@ -1469,7 +1711,7 @@ new_cmd:  /* a goto point for new input without going
 
         case LYK_UP_LINK:
             if (curdoc.link > 0) {  /* more links above? */
-                int i, newlink = -1;
+                int newlink = -1;
                 for (i = curdoc.link; i >= 0; i--) {
                     if (links[i].ly < links[curdoc.link].ly) {
                         newlink = i;
@@ -1480,11 +1722,11 @@ new_cmd:  /* a goto point for new input without going
                     highlight(OFF, curdoc.link);
                     curdoc.link = newlink;
 #ifdef NOTDEFINED
-                } else if (!more && newline == 1 && curdoc.link == 0) {
+                } else if (!more && Newline == 1 && curdoc.link == 0) {
                     highlight(OFF, curdoc.link);
                     curdoc.link = (nlinks-1);
                 } else if (more) {  /* next page */
-                        newline += (display_lines);
+                        Newline += (display_lines);
                 }
 #else
 		} else if (old_c != real_c) {
@@ -1495,16 +1737,17 @@ new_cmd:  /* a goto point for new input without going
 #endif /* NOTDEFINED */
 
 #ifdef NOTDEFINED
-            /* at the bottom of list and there is only one page
-             * move to the top link on the page
+            /*
+	     *  At the bottom of list and there is only one page.
+             *  Move to the top link on the page.
              */
-            } else if (!more && newline == 1 && curdoc.link == (nlinks-1)) {
+            } else if (!more && Newline == 1 && curdoc.link == (nlinks-1)) {
                 highlight(OFF, curdoc.link);
                 curdoc.link = 0;
 #endif /* NOTDEFINED */
 
-            } else if (curdoc.line > 1 && newline > 1) {  /* previous page */
-                    newline -= (display_lines);
+            } else if (curdoc.line > 1 && Newline > 1) {  /* previous page */
+                    Newline -= (display_lines);
 		    arrowup = TRUE;
 
 	    } else if (old_c != real_c) {
@@ -1516,7 +1759,7 @@ new_cmd:  /* a goto point for new input without going
 
 	case LYK_DOWN_LINK:
 	    if (curdoc.link < (nlinks-1)) {	/* more links? */
-		int i, newlink = -1;
+		int newlink = -1;
 		for (i = curdoc.link; i < nlinks; i++)
 		   if (links[i].ly > links[curdoc.link].ly) {
 			newlink = i;
@@ -1528,12 +1771,12 @@ new_cmd:  /* a goto point for new input without going
                     curdoc.link = newlink;
 #ifdef NOTDEFINED
 		} else if (!more &&
-			   newline == 1 && curdoc.link == (nlinks-1)) {
+			   Newline == 1 && curdoc.link == (nlinks-1)) {
                     highlight(OFF, curdoc.link);
                     curdoc.link = 0;
 #endif /* NOTDEFINED */
                 } else if (more) {  /* next page */
-                        newline += (display_lines);
+                        Newline += (display_lines);
 		} else if (old_c != real_c) {
 		    old_c = real_c;
 		    _statusline(NO_LINKS_BELOW);
@@ -1541,15 +1784,16 @@ new_cmd:  /* a goto point for new input without going
 		    break;
 		}
 #ifdef NOTDEFINED
-            /* at the bottom of list and there is only one page
-             * move to the top link on the page
+            /*
+	     *  At the bottom of list and there is only one page.
+             *  Move to the top link on the page.
              */
-            } else if (!more && newline == 1 && curdoc.link == (nlinks-1)) {
+            } else if (!more && Newline == 1 && curdoc.link == (nlinks-1)) {
                 highlight(OFF, curdoc.link);
                 curdoc.link = 0;
 #endif /* NOTDEFINED */
             } else if (more) {  /* next page */
-                    newline += (display_lines);
+                    Newline += (display_lines);
 
 	    } else if (old_c != real_c) {
 		old_c = real_c;
@@ -1574,6 +1818,30 @@ new_cmd:  /* a goto point for new input without going
 	    }
 	    break;
 
+        case LYK_COOKIE_JAR:       /* show the cookie jar */
+	    /*
+	     *  Don't do if already viewing the cookie jar.
+	     */	
+	    if (strcmp(curdoc.title, COOKIE_JAR_TITLE)) {
+	        StrAllocCopy(newdoc.address, "LYNXCOOKIE:/");
+		FREE(newdoc.post_data);
+		FREE(newdoc.post_content_type);
+		FREE(newdoc.bookmark);
+		newdoc.isHEAD = FALSE;
+		newdoc.safe = FALSE;
+		LYforce_no_cache = TRUE;
+		if (LYValidate || check_realm) {
+		    LYPermitURL = TRUE;
+	        }
+            } else {
+		/*
+		 *  If already in the cookie jar, get out.
+		 */
+		cmd = LYK_PREV_DOC;
+		goto new_cmd;
+	    }
+	    break;
+
 	case LYK_HISTORY: 	/* show the history page */
 	    if (curdoc.title && strcmp(curdoc.title, HISTORY_PAGE_TITLE)) {
 		/*
@@ -1590,22 +1858,23 @@ new_cmd:  /* a goto point for new input without going
 #endif /* USE_SLANG */
 		    refresh();
 		}
-                LYpush(&curdoc);
+                LYpush(&curdoc, ForcePush);
 
 		/*
 		 *  Print history options to file.
 		 */
-	    	if (showhistory(&newdoc.address) < 0)
+	    	if (showhistory(&newdoc.address) < 0) {
+		    LYpop(&curdoc);
 		    break;
- 		FREE(curdoc.address);  /* so it doesn't get pushed */
+		}
 		FREE(newdoc.post_data);
 		FREE(newdoc.post_content_type);
 		FREE(newdoc.bookmark);
 		newdoc.isHEAD = FALSE;
+		newdoc.safe = FALSE;
+ 		FREE(curdoc.address);  /* so it doesn't get pushed */
 
-                LYpop(&curdoc);
-
-		refresh_screen=TRUE;
+		refresh_screen = TRUE;
 		if (LYValidate || check_realm) {
 		    LYPermitURL = TRUE;
 		}
@@ -1619,6 +1888,54 @@ new_cmd:  /* a goto point for new input without going
 
 	case LYK_PREV_DOC:			 /* back up a level */
 	    if (nhist > 0) {  /* if there is anything to go back to */
+	        /*
+		 *  Check if the previous document is a reply from a POST,
+		 *  and if so, seek confirmation of resubmission if the safe
+		 *  element is not set and the document is not still in the
+		 *  cache or LYresubmit_posts is set. If not confirmed and
+		 *  it is not the startfile, pop it so we go to the yet
+		 *  previous document, until we're OK or reach the startfile.
+		 *  If we reach the startfile and its not OK or we don't get
+		 *  confirmation, cancel. - FM
+		 */
+		DocAddress WWWDoc;
+		HTParentAnchor *tmpanchor;
+
+		while (nhist > 0) {
+		    if (history[(nhist - 1)].post_data == NULL) {
+			break;
+		    }
+		    WWWDoc.address = history[(nhist - 1)].address;
+		    WWWDoc.post_data = history[(nhist - 1)].post_data;
+		    WWWDoc.post_content_type =
+		    		       history[(nhist - 1)].post_content_type;
+		    WWWDoc.bookmark = history[(nhist - 1)].bookmark;
+		    WWWDoc.isHEAD = history[(nhist - 1)].isHEAD;
+		    WWWDoc.safe = history[(nhist - 1)].safe;
+		    tmpanchor = HTAnchor_parent(HTAnchor_findAddress(&WWWDoc));
+		    if (HTAnchor_safe(tmpanchor)) {
+			break;
+		    }
+		    if ((LYresubmit_posts ||
+		         (HText *)HTAnchor_document(tmpanchor) == NULL) &&
+			HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
+			if (nhist == 1) {
+			    _statusline(CANCELLED);
+			    sleep(InfoSecs);
+			    old_c = 0;
+			    cmd = LYK_DO_NOTHING;
+			    goto new_cmd;
+			} else {
+			    _user_message(WWW_SKIP_MESSAGE, WWWDoc.address);
+			    sleep(MessageSecs);
+			    LYpop(&curdoc);
+			    continue;
+			}
+		    } else {
+			break;
+		    }
+		}
+
 		/*
 		 *  Set newdoc.address to empty to pop a file.
 		 */
@@ -1640,7 +1957,8 @@ new_cmd:  /* a goto point for new input without going
 	case LYK_NOCACHE: /* Force submission of form or link with no-cache */
 	    if (nlinks > 0) {
 	        if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-	            links[curdoc.link].form->type != F_SUBMIT_TYPE) {
+	            links[curdoc.link].form->type != F_SUBMIT_TYPE &&
+		    links[curdoc.link].form->type != F_IMAGE_SUBMIT_TYPE) {
 		    if (old_c == real_c)
 		        break;
 		    old_c = real_c;
@@ -1656,89 +1974,111 @@ new_cmd:  /* a goto point for new input without going
 	case LYK_ACTIVATE:			/* follow a link */
 	    if (nlinks > 0) {
 	        if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
-		        /*
-			 * Don't try to submit forms with bad actions. - FM
+		    /*
+		     *  Don't try to submit forms with bad actions. - FM
+		     */
+		    if (links[curdoc.link].form->type == F_SUBMIT_TYPE ||
+		        links[curdoc.link].form->type == F_IMAGE_SUBMIT_TYPE ||
+			links[curdoc.link].form->type ==
+			   			    F_TEXT_SUBMIT_TYPE) {
+			/*
+			 *  Do nothing if it's disabled. - FM
 			 */
-			if (links[curdoc.link].form->type == F_SUBMIT_TYPE ||
-			   links[curdoc.link].form->type ==
-			   			       F_TEXT_SUBMIT_TYPE) {
-			   /*
-			    * Do nothing if it's disabled. - FM
-			    */
-			   if (links[curdoc.link].form->disabled == YES) {
-			       HTOutputFormat = WWW_PRESENT;
-			       LYforce_no_cache = FALSE;
-			       break;
-			   }
-			   /*
-			    * Make sure we have an action. - FM
-			    */
-			   if (!links[curdoc.link].form->submit_action ||
-			       *links[curdoc.link].form->submit_action
+			if (links[curdoc.link].form->disabled == YES) {
+			    HTOutputFormat = WWW_PRESENT;
+			    LYforce_no_cache = FALSE;
+			    break;
+			}
+			/*
+			 *  Make sure we have an action. - FM
+			 */
+			if (!links[curdoc.link].form->submit_action ||
+			    *links[curdoc.link].form->submit_action
 			       					== '\0') {
-			       _statusline(NO_FORM_ACTION);
-			       sleep(MessageSecs);
-			       HTOutputFormat = WWW_PRESENT;
-			       LYforce_no_cache = FALSE;
-			       break;
-			    }
-		            /*
-			     * Check for no_mail if the form action
-			     * is a mailto URL. - FM
-			     */
-			    if (links[curdoc.link].form->submit_method
+			    _statusline(NO_FORM_ACTION);
+			    sleep(MessageSecs);
+			    HTOutputFormat = WWW_PRESENT;
+			    LYforce_no_cache = FALSE;
+			    break;
+			}
+	    		/*
+			 *  Check for no_mail if the form action
+			 *  is a mailto URL. - FM
+			 */
+			if (links[curdoc.link].form->submit_method
 			             == URL_MAIL_METHOD && no_mail) {
-			        HTAlert(FORM_MAILTO_DISALLOWED);
-				HTOutputFormat = WWW_PRESENT;
-				LYforce_no_cache = FALSE;
-			        break;
-			    }
-			    /*
-			     *  Make sure this isn't a spoof in an account
-			     *  with restrictions on file URLs. - FM
-			     */
-			    if (no_file_url &&
-			        !strncasecomp(
+			    HTAlert(FORM_MAILTO_DISALLOWED);
+			    HTOutputFormat = WWW_PRESENT;
+			    LYforce_no_cache = FALSE;
+			    break;
+			}
+			/*
+			 *  Make sure this isn't a spoof in an account
+			 *  with restrictions on file URLs. - FM
+			 */
+			if (no_file_url &&
+			    !strncasecomp(
 				    links[curdoc.link].form->submit_action,
-				    "file:", 5)) {
-				HTAlert(FILE_ACTIONS_DISALLOWED);
+					  "file:", 5)) {
+			    HTAlert(FILE_ACTIONS_DISALLOWED);
+			    HTOutputFormat = WWW_PRESENT;
+			    LYforce_no_cache = FALSE;
+			    break;
+			}
+#ifdef NOTDEFINED /* We're disabling form inputs instead of using this. - FM */
+		        /*
+			 *  Check for enctype and let user know we
+			 *  don't yet support multipart/form-data - FM
+			 */
+			if (links[curdoc.link].form->submit_enctype) {
+			    if (!strcmp(
+				     links[curdoc.link].form->submit_enctype,
+				        "multipart/form-data")) {
+				HTAlert(
+	"Enctype multipart/form-data not yet supported!  Cannot submit.");
 				HTOutputFormat = WWW_PRESENT;
 				LYforce_no_cache = FALSE;
 				break;
-			    }
-#ifdef NOTDEFINED /* We're disabling form inputs instead of using this. - FM */
-		            /*
-			     *  Check for enctype and let user know we
-			     *  don't yet support multipart/form-data - FM
-			     */
-			    if (links[curdoc.link].form->submit_enctype) {
-			        if (!strcmp(
-				      links[curdoc.link].form->submit_enctype,
-				      "multipart/form-data")) {
-				    HTAlert(
-	"Enctype multipart/form-data not yet supported!  Cannot submit.");
-				    HTOutputFormat = WWW_PRESENT;
-				    LYforce_no_cache = FALSE;
-				    break;
-				}
-			    }
+	    		    }
+			}
 #endif /* NOTDEFINED */
-			    if (check_realm) {
-			        LYPermitURL = TRUE;
-			    }
-			    if (no_filereferer == TRUE &&
-			        !strncasecomp(curdoc.address, "file:", 5)) {
-				LYNoRefererForThis = TRUE;
-			    }
+			if (check_realm) {
+			    LYPermitURL = TRUE;
 			}
-		        c = change_form_link(&links[curdoc.link],
-					     FORM_UP, &newdoc, &refresh_screen,
-					     links[curdoc.link].form->name,
-					     links[curdoc.link].form->value);
-			goto new_keyboard_input;
-
-	        } else {   /* Not a forms link */
+			if (no_filereferer == TRUE &&
+			    !strncasecomp(curdoc.address, "file:", 5)) {
+			    LYNoRefererForThis = TRUE;
+			}
+		    }
+		    c = change_form_link(&links[curdoc.link],
+					 FORM_UP, &newdoc, &refresh_screen,
+					 links[curdoc.link].form->name,
+					 links[curdoc.link].form->value);
+		    if (HTOutputFormat == HTAtom_for("www/download") &&
+		        newdoc.post_data != NULL &&
+			newdoc.safe == FALSE) {
+			if ((HText_POSTReplyLoaded(&newdoc) == TRUE) &&
+			    HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
+			    _statusline(CANCELLED);
+			    sleep(InfoSecs);
+			    HTOutputFormat = WWW_PRESENT;
+			    LYforce_no_cache = FALSE;
+			    StrAllocCopy(newdoc.address, curdoc.address);
+			    StrAllocCopy(newdoc.title, curdoc.title);
+			    StrAllocCopy(newdoc.post_data, curdoc.post_data);
+			    StrAllocCopy(newdoc.post_content_type,
+			    		 curdoc.post_content_type);
+			    StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
+			    newdoc.isHEAD = curdoc.isHEAD;
+			    newdoc.safe = curdoc.safe;
+			    break;
+			}
+		    }
+		    goto new_keyboard_input;
+	        } else {
 		    /*
+		     *  Not a forms link.
+		     *
 		     *  Make sure this isn't a spoof in an account
 		     *  with restrictions on file URLs. - FM
 		     */
@@ -1758,8 +2098,8 @@ new_cmd:  /* a goto point for new input without going
 		    StrAllocCopy(newdoc.address, links[curdoc.link].lname);
 		    StrAllocCopy(newdoc.title, links[curdoc.link].hightext);
 		    /*
-		     * Might be an anchor in the same doc from a POST
-		     * form.  If so, dont't free the content. -- FM
+		     *  Might be an anchor in the same doc from a POST
+		     *  form.  If so, dont't free the content. -- FM
 		     */
 		    if (are_different(&curdoc, &newdoc)) {
 		        FREE(newdoc.post_data);
@@ -1785,7 +2125,8 @@ new_cmd:  /* a goto point for new input without going
 #ifdef DIRED_SUPPORT
 		    if (lynx_edit_mode) {
 			  HTuncache_current_document();
-			  /*  Unescaping any slash chars in the URL,
+			  /*
+			   *  Unescaping any slash chars in the URL,
 			   *  but avoid double unescaping and too-early
 			   *  unescaping of other chars. - KW
 			   */
@@ -1793,12 +2134,14 @@ new_cmd:  /* a goto point for new input without going
 			  strip_trailing_slash(newdoc.address);
 		    }
 #endif /* DIRED_SUPPORT */
+		    if (!strncasecomp(curdoc.address, "LYNXCOOKIE:", 11)) {
+		        HTuncache_current_document();
+		    }
 		}
 	    }
 	    break;
 
 	case LYK_GOTO:   /* 'g' to goto a random URL  */
-	 
 	    if (no_goto && !LYValidate) {
 	        if (old_c != real_c) {
 	   	    old_c = real_c;
@@ -1824,14 +2167,14 @@ new_cmd:  /* a goto point for new input without going
 	    }
 
 	    /*
-	     * Ask the user.
+	     *  Ask the user.
 	     */
 	    _statusline(URL_TO_OPEN);
 	    if ((ch = LYgetstr(user_input_buffer, VISIBLE,
 	    		       sizeof(user_input_buffer), recall)) < 0 ) {
 		/*
-		 * User cancelled the Goto via ^G.
-		 * Restore user_input_buffer and break. - FM
+		 *  User cancelled the Goto via ^G.
+		 *  Restore user_input_buffer and break. - FM
 		 */
 		strcpy(user_input_buffer, temp);
 		FREE(temp);
@@ -1842,7 +2185,7 @@ new_cmd:  /* a goto point for new input without going
 
 check_recall:
 	    /*
-	     * Get rid of leading spaces (and any other spaces).
+	     *  Get rid of leading spaces (and any other spaces).
 	     */
 	    collapse_spaces(user_input_buffer);
 	    if (*user_input_buffer == '\0' &&
@@ -1856,19 +2199,19 @@ check_recall:
 	    if (recall && ch == UPARROW) {
 	        if (FirstURLRecall) {
 		    /*
-		     * Use last URL in the list. - FM
+		     *  Use last URL in the list. - FM
 		     */
 		    FirstURLRecall = FALSE;
 		    URLNum = 0;
 		} else {
 		    /*
-		     * Go back to the previous URL in the list. - FM
+		     *  Go back to the previous URL in the list. - FM
 		     */
 		    URLNum++;
 		}
 		if (URLNum >= URLTotal)
 		    /*
-		     * Roll around to the last URL in the list. - FM
+		     *  Roll around to the last URL in the list. - FM
 		     */
 		    URLNum = 0;
 		if ((cp = (char *)HTList_objectAt(Goto_URLs,
@@ -1887,8 +2230,8 @@ check_recall:
 				      sizeof(user_input_buffer),
 				      recall)) < 0) {
 			/*
-			 * User cancelled the Goto via ^G.
-			 * Restore user_input_buffer and break. - FM
+			 *  User cancelled the Goto via ^G.
+			 *  Restore user_input_buffer and break. - FM
 			 */
 			strcpy(user_input_buffer, temp);
 			FREE(temp);
@@ -1901,19 +2244,19 @@ check_recall:
 	    } else if (recall && ch == DNARROW) {
 	        if (FirstURLRecall) {
 		    /*
-		     * Use the first URL in the list. - FM
+		     *  Use the first URL in the list. - FM
 		     */
 		    FirstURLRecall = FALSE;
 		    URLNum = URLTotal - 1;
 		} else {
 		    /*
-		     * Advance to the next URL in the list. - FM
+		     *  Advance to the next URL in the list. - FM
 		     */
 		    URLNum--;
 		}
 		if (URLNum < 0)
 		    /*
-		     * Roll around to the first URL in the list. - FM
+		     *  Roll around to the first URL in the list. - FM
 		     */
 		    URLNum = URLTotal - 1;
 		if ((cp=(char *)HTList_objectAt(Goto_URLs,
@@ -1932,8 +2275,8 @@ check_recall:
 				       sizeof(user_input_buffer),
 				       recall)) < 0) {
 			/*
-			 * User cancelled the Goto via ^G.
-			 * Restore user_input_buffer and break. - FM
+			 *  User cancelled the Goto via ^G.
+			 *  Restore user_input_buffer and break. - FM
 			 */
 			strcpy(user_input_buffer, temp);
 			FREE(temp);
@@ -1946,18 +2289,14 @@ check_recall:
 	    }
 
 	    /*
-	     * If its not a URL then make it one.
+	     *  If its not a URL then make it one.
 	     */
-	    if (!is_url(user_input_buffer)) {
-	        char *user_input_string = NULL;
-	        if (TRACE)
-		    fprintf(stderr, "\n'%s' is not a URL\n",
-		    			user_input_buffer);
-		StrAllocCopy(user_input_string, user_input_buffer);
-		LYConvertToURL(&user_input_string);
-		strcpy(user_input_buffer, user_input_string);
-		FREE(user_input_string);
-	    }
+	    StrAllocCopy(temp, user_input_buffer);
+	    LYFillLocalFileURL((char **)&temp, "file://localhost");
+	    LYEnsureAbsoluteURL((char **)&temp, "");
+	    sprintf(user_input_buffer, "%.*s",
+	    	    (sizeof(user_input_buffer) - 1), temp);
+	    FREE(temp);
 	    if ((no_file_url || no_goto_file) &&
 	        !strncmp(user_input_buffer,"file:",5)) {
                 _statusline(GOTO_FILE_DISALLOWED);
@@ -2065,64 +2404,6 @@ check_recall:
                 sleep(MessageSecs);
 
            } else {
-		/* make a name for this new URL */
-	        StrAllocCopy(newdoc.title, "A URL specified by the user");
-
-		/*
-		 * If it's a file URL and the host is defaulted,
-		 * force in "//localhost".  We need this until
-		 * all the other Lynx code which performs security
-		 * checks based on the "localhost" string is changed
-		 * to assume "//localhost" when a host field is not
-		 * present in file URLs - FM
-		 */
-		if (!strncmp(user_input_buffer, "file:", 5)) {
-		    if (user_input_buffer[5] == '\0') {
-		        strcat(user_input_buffer, "//localhost");
-		    } else if (!strcmp(user_input_buffer, "file://")) {
-		        strcat(user_input_buffer, "localhost");
-		    } else if (!strncmp(user_input_buffer, "file:///", 8)) {
-		        StrAllocCopy(temp, (user_input_buffer+7));
-		        strcpy(user_input_buffer, "file://localhost");
-		        strcat(user_input_buffer, temp);
-		        FREE(temp);
-		    } else if (!strncmp(user_input_buffer, "file:/", 6) &&
-		    	      user_input_buffer[6] != '/') {
-		        StrAllocCopy(temp, (user_input_buffer+5));
-		        strcpy(user_input_buffer, "file://localhost");
-		        strcat(user_input_buffer, temp);
-		        FREE(temp);
-		    }
-		}
-
-		/*
-		 * No path in a file://localhost URL means a
-		 * directory listing for the current default. - FM
-		 */
-		if (!strcmp(user_input_buffer, "file://localhost")) {
-#ifdef VMS
-		    strcat(user_input_buffer, HTVMS_wwwName(getenv("PATH")));
-#else
-		    char curdir[DIRNAMESIZE];
-#ifdef NO_GETCWD
-		    getwd (curdir);
-#else
-		    getcwd (curdir, DIRNAMESIZE);
-#endif /* NO_GETCWD */
-		    strcat(user_input_buffer, curdir);
-#endif /* VMS */
-		}
-
-#ifdef VMS
-		/*
-		 *  On VMS, a file://localhost/ URL means
-		 *  a listing for the login directory. - FM
-		 */
-		if (!strcmp(user_input_buffer, "file://localhost/"))
-		    strcat(user_input_buffer,
-		    	   (HTVMS_wwwName((char *)Home_Dir())+1));
-#endif /* VMS */
-
 	        StrAllocCopy(newdoc.address, user_input_buffer);
 		newdoc.isHEAD = FALSE;
 		/*
@@ -2130,41 +2411,54 @@ check_recall:
 		 *  form.  If so, dont't free the content. -- FM
 		 */
 		if (are_different(&curdoc, &newdoc)) {
+		    /*
+		     *  Make a name for this new URL.
+		     */
+	            StrAllocCopy(newdoc.title, "A URL specified by the user");
 		    FREE(newdoc.post_data);
 		    FREE(newdoc.post_content_type);
 		    FREE(newdoc.bookmark);
-		}
-		force_load = TRUE;
-		LYUserSpecifiedURL = TRUE;
+		    newdoc.safe = FALSE;
+		    force_load = TRUE;
+		    LYUserSpecifiedURL = TRUE;
 #ifdef DIRED_SUPPORT
-		if (lynx_edit_mode) 
-		    HTuncache_current_document();
+		    if (lynx_edit_mode) 
+		        HTuncache_current_document();
 #endif /* DIRED_SUPPORT */
-		HTAddGotoURL(user_input_buffer);
+		    HTAddGotoURL(newdoc.address);
+		}
 	    } 
 	    break;
 
 	case LYK_HELP:			/* show help file */
 	    if (!STREQ(curdoc.address, helpfile)) {
-	        StrAllocCopy(newdoc.address, helpfile);  /* set the filename */
-		/* make a name for this help file */
+	        /*
+		 *  Set the filename.
+		 */
+	        StrAllocCopy(newdoc.address, helpfile);
+		/*
+		 *  Make a name for this help file.
+		 */
 	        StrAllocCopy(newdoc.title, "Help Screen");
 		FREE(newdoc.post_data);
 		FREE(newdoc.post_content_type);
 		FREE(newdoc.bookmark);
 		newdoc.isHEAD = FALSE;
+		newdoc.safe = FALSE;
 	    }
 	    break;
 
 	case LYK_INDEX:  /* index file */
-	    /* make sure we are not in the index already */
+	    /*
+	     *  Make sure we are not in the index already.
+	     */
 	    if (!STREQ(curdoc.address, indexfile)) {
 
 	        if (indexfile[0]=='\0') { /* no defined index */
 			if (old_c != real_c)	{
-				old_c = real_c;
-		    		_statusline(NO_INDEX_FILE);
-		    		sleep(MessageSecs);
+			    old_c = real_c;
+		    	    _statusline(NO_INDEX_FILE);
+		    	    sleep(MessageSecs);
 			}
 
 	        } else {
@@ -2174,6 +2468,7 @@ check_recall:
 		    FREE(newdoc.post_content_type);
 		    FREE(newdoc.bookmark);
 		    newdoc.isHEAD = FALSE;
+		    newdoc.safe = FALSE;
 	        } /* end else */
 	    }  /* end if */
 	    break;
@@ -2190,7 +2485,8 @@ check_recall:
 		    /*
 		     *	Code to handle multiple submit buttons?
 		     *	Taken out due to bug it causes.
-		    if (links[curdoc.link].form->type == F_SUBMIT_TYPE)	{
+		    if (links[curdoc.link].form->type == F_SUBMIT_TYPE ||
+		        links[curdoc.link].form->type == F_IMAGESUBMIT_TYPE) {
 			curdoc.address = NULL;
 		    }
 		     */
@@ -2222,7 +2518,9 @@ check_recall:
 #endif /* NOT_USED */
 
 	case LYK_MAIN_MENU:	/* return to main screen */
-	    /* if its already the homepage then don't reload it */
+	    /*
+	     *  If its already the homepage then don't reload it.
+	     */
 	    if (!STREQ(curdoc.address,homepage)) {
 		
 		_statusline(CONFIRM_MAIN_SCREEN);
@@ -2234,6 +2532,7 @@ check_recall:
 		    FREE(newdoc.post_content_type);
 		    FREE(newdoc.bookmark);
 		    newdoc.isHEAD = FALSE;
+		    newdoc.safe = FALSE;
 	            highlight(OFF,curdoc.link); 
 #ifdef DIRED_SUPPORT
 		    if (lynx_edit_mode)
@@ -2254,27 +2553,64 @@ check_recall:
 	    break;
 
 	case LYK_OPTIONS:     /* options screen */
-
 #ifdef DIRED_SUPPORT
 	    c = dir_list_style;
 #endif /* DIRED_SUPPORT */
 	    options(); /* do the options stuff */
 
 	    if (keypad_mode_flag != keypad_mode ||
+	        (user_mode_flag != user_mode &&
+		 (user_mode_flag == NOVICE_MODE ||
+		  user_mode == NOVICE_MODE)) ||
+		(((HTfileSortMethod_flag != HTfileSortMethod) ||
 #ifdef DIRED_SUPPORT
-		c != dir_list_style ||
+		  (c != dir_list_style) ||
 #endif /* DIRED_SUPPORT */
-		HTfileSortMethod_flag != HTfileSortMethod ||
+		  (show_dotfiles_flag != show_dotfiles)) &&
+		 (!strncmp(curdoc.address, "file:", 5) ||
+		  !strncmp(curdoc.address, "ftp:", 4))) ||
 		CurrentCharSet_flag != current_char_set ||
-		show_dotfiles_flag != show_dotfiles ||
 		LYRawMode_flag != LYRawMode ||
 		LYSelectPopups_flag != LYSelectPopups ||
-		strcmp(CurrentUserAgent, (LYUserAgent ?
-					  LYUserAgent : ""))) {
-		HTuncache_current_document();
-		StrAllocCopy(newdoc.address, curdoc.address);
-		FREE(curdoc.address);
+		(strcmp(CurrentUserAgent, (LYUserAgent ?
+					   LYUserAgent : "")) &&
+		 !strncmp(curdoc.address, "http", 4))) {
+	        /*
+		 *  Check if this is a reply from a POST, and if so,
+		 *  seek confirmation of reload if the safe element
+		 *  is not set. - FM
+		 */
+		if ((curdoc.post_data != NULL &&
+		     curdoc.safe != TRUE) &&
+		    HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
+		    _statusline(WILL_NOT_RELOAD_DOC);
+		    sleep(InfoSecs);
+	    
+		} else {
+		    LYforce_no_cache = TRUE;
+		    StrAllocCopy(newdoc.address, curdoc.address);
+		    if (keypad_mode_flag != keypad_mode ||
+		        (user_mode_flag != user_mode &&
+			 (user_mode_flag == NOVICE_MODE ||
+			  user_mode == NOVICE_MODE)) ||
+		        (((HTfileSortMethod_flag != HTfileSortMethod) ||
+#ifdef DIRED_SUPPORT
+			  (c != dir_list_style) ||
+#endif /* DIRED_SUPPORT */
+			  (show_dotfiles_flag != show_dotfiles)) &&
+			 (!strncmp(curdoc.address, "file:", 5) ||
+			  !strncmp(curdoc.address, "ftp:", 4))) ||
+			LYSelectPopups_flag != LYSelectPopups ||
+			(strcmp(CurrentUserAgent, (LYUserAgent ?
+			 			   LYUserAgent : "")) &&
+			 !strncmp(curdoc.address, "http", 4))) {
+		        HTuncache_current_document();
+		        FREE(curdoc.address);
+		    } else {
+		    }
+		}
 		keypad_mode_flag = keypad_mode;
+		user_mode_flag = user_mode;
 		HTfileSortMethod_flag = HTfileSortMethod;
 		CurrentCharSet_flag = current_char_set;
 		show_dotfiles_flag = show_dotfiles;
@@ -2287,91 +2623,110 @@ check_recall:
 	    break;
 
 	case LYK_INDEX_SEARCH: /* search for a user string */
-	     if (is_www_index) {
-               /* perform a database search */
-
-		/* do_www_search will try to go out and get the document
-		 * if it returns yes a new document was returned and is
-		 * named in the newdoc.address
+	    if (is_www_index) {
+	        /*
+		 *  Perform a database search.
+		 *
+		 *  do_www_search will try to go out and get the document.
+		 *  If it returns TRUE, a new document was returned and is
+		 *  named in the newdoc.address.
 		 */
 		newdoc.isHEAD = FALSE;
+		newdoc.safe = FALSE;
 		if (do_www_search(&newdoc) == NORMAL) {
-		   /* Yah, the search succeeded. */
-		   if (TRACE && LYCursesON) {
-		      move(LYlines-1, LYcols-1); /* make sure cursor is down */
+		    /*
+		     *  Yah, the search succeeded.
+		     */
+		    if (TRACE && LYCursesON) {
+		        /*
+			 *  Make sure cursor is down.
+			 */
+		        move(LYlines-1, LYcols-1);
 #ifdef USE_SLANG
-		      addstr("\n");
+		        addstr("\n");
 #endif /* USE_SLANG */
-		      refresh();
-		}
-                   LYpush(&curdoc);
-		   /* Make the curdoc.address the newdoc.address so that
-		    * getfile doesn't try to get the newdoc.address.
-		    * Since we have already gotton it.
-		    */ 
-		   StrAllocCopy(curdoc.address, newdoc.address);
-		   StrAllocCopy(newdoc.post_data, curdoc.post_data);
-		   curdoc.line = -1;
-		   newline = 0;
-		   refresh_screen = TRUE; /* redisplay it */
+		        refresh();
+		    }
+                    LYpush(&curdoc, ForcePush);
+		    /*
+		     *  Make the curdoc.address the newdoc.address so that
+		     *  getfile doesn't try to get the newdoc.address.
+		     *  Since we have already gotton it.
+		     */ 
+		    StrAllocCopy(curdoc.address, newdoc.address);
+		    StrAllocCopy(newdoc.post_data, curdoc.post_data);
+		    curdoc.line = -1;
+		    Newline = 0;
+		    refresh_screen = TRUE; /* redisplay it */
 		} else if (use_this_url_instead != NULL) {
-		   /* Got back a redirecting URL. Check it out. */
-		   _user_message("Using %s", use_this_url_instead);
-		   /* Make a name for this URL */
-	           StrAllocCopy(newdoc.title, "A URL specified by redirection");
-	           StrAllocCopy(newdoc.address, use_this_url_instead);
-		   FREE(newdoc.post_data);
-		   FREE(newdoc.post_content_type);
-		   FREE(newdoc.bookmark);
-		   newdoc.isHEAD = FALSE;
-	           FREE(use_this_url_instead);
-		   force_load = TRUE;
-		   break;
+		    /*
+		     *  Got back a redirecting URL.  Check it out.
+		     */
+		    _user_message("Using %s", use_this_url_instead);
+		    /*
+		     *  Make a name for this URL.
+		     */
+	            StrAllocCopy(newdoc.title,
+		    		 "A URL specified by redirection");
+	            StrAllocCopy(newdoc.address, use_this_url_instead);
+		    FREE(newdoc.post_data);
+		    FREE(newdoc.post_content_type);
+		    FREE(newdoc.bookmark);
+		    newdoc.isHEAD = FALSE;
+		    newdoc.safe = FALSE;
+	            FREE(use_this_url_instead);
+		    force_load = TRUE;
+		    break;
 		} else {
-		   /* Yuk, the search failed.  Restore the old file. */
-		   StrAllocCopy(newdoc.address, curdoc.address);  
-		   StrAllocCopy(newdoc.post_data, curdoc.post_data);
-		   newdoc.isHEAD = curdoc.isHEAD;
+		    /*
+		     *  Yuk, the search failed.  Restore the old file.
+		     */
+		    StrAllocCopy(newdoc.address, curdoc.address);  
+		    StrAllocCopy(newdoc.post_data, curdoc.post_data);
+		    StrAllocCopy(newdoc.post_content_type,
+		    		 curdoc.post_content_type);
+		    StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
+		    newdoc.isHEAD = curdoc.isHEAD;
+		    newdoc.safe = curdoc.safe;
 		}
-	     } else if (old_c != real_c)	{
+	    } else if (old_c != real_c)	{
 		old_c = real_c;
 		_statusline(NOT_ISINDEX);
 		sleep(MessageSecs);
-	     }
-	     break;
+	    }
+	    break;
 
 	case LYK_WHEREIS: /* search within the document */
-  	/* search for the next occurrence of the user string */
-	case LYK_NEXT:
+	case LYK_NEXT:    /* search for the next occurrence in the document */
             /* user search */
 	    if (cmd != LYK_NEXT) {
 	        /* 
-		 * Reset prev_target to force prompting
-		 * for a new search string and to turn
-		 * off highlighting in no search string
-		 * is entered by the user.
+		 *  Reset prev_target to force prompting
+		 *  for a new search string and to turn
+		 *  off highlighting in no search string
+		 *  is entered by the user.
 		 */
 	        *prev_target = '\0';
 	        textsearch(&curdoc, prev_target, FALSE);
 	    } else {
 	        /*
-		 * When the third argument is TRUE, the previous
-		 * search string, if any, will be recalled from
-		 * a buffer, loaded into prev_target, and used
-		 * for the search without prompting for a new
-		 * search string.  This allows the LYK_NEXT
-		 * command to repeat a search in a new document,
-		 * after prev_target was reset on fetch of that
-		 * document.
+		 *  When the third argument is TRUE, the previous
+		 *  search string, if any, will be recalled from
+		 *  a buffer, loaded into prev_target, and used
+		 *  for the search without prompting for a new
+		 *  search string.  This allows the LYK_NEXT
+		 *  command to repeat a search in a new document,
+		 *  after prev_target was reset on fetch of that
+		 *  document.
 		 */
 	        textsearch(&curdoc, prev_target, TRUE);
 	    }
 	    
 	    /*
-	     * Force a redraw to ensure highlighting of hits
-	     * even when found on the same page, or clearing
-	     * of highlighting is the default search string
-	     * was erased without replacement. - FM
+	     *  Force a redraw to ensure highlighting of hits
+	     *  even when found on the same page, or clearing
+	     *  of highlighting is the default search string
+	     *  was erased without replacement. - FM
 	     */
 	    refresh_screen = TRUE;
 	    break;
@@ -2401,6 +2756,7 @@ check_recall:
 			 */
 		        char *address = NULL;
 			char *path = HTParse(curdoc.address, "", PARSE_PATH);
+
 			if (path != NULL) {
 			    HTUnEscape(path);
 			    if (*path == '~' && strlen(path) > 1) {
@@ -2467,7 +2823,7 @@ check_recall:
 	        if (dir_list_style == MIXED_STYLE) {
 		    if (!strcmp(links[curdoc.link].hightext, "../")) 
 		        break;
-	        } else if (!strncmp(links[curdoc.link].hightext,"Up to ",6)) 
+	        } else if (!strncmp(links[curdoc.link].hightext, "Up to ", 6)) 
 		    break;
 	        {
 		    /*
@@ -2478,7 +2834,7 @@ check_recall:
 		    BOOLEAN found = FALSE;
 
 		    while ((tagname = (char *)HTList_nextObject(t1)) != NULL) {
-		        if (!strcmp(links[curdoc.link].lname,tagname)) {
+		        if (!strcmp(links[curdoc.link].lname, tagname)) {
 			    found = TRUE;
 			    HTList_removeObject(tagged, tagname);
 			    FREE(tagname);
@@ -2495,39 +2851,59 @@ check_recall:
 		        tagflag(ON,curdoc.link);
 		    }
 	        }
-	   }
-	   break;
+		if (curdoc.link < nlinks-1) {
+		    highlight(OFF, curdoc.link);
+		    curdoc.link++;
+		} else if (!more && Newline == 1 && curdoc.link == nlinks-1) {
+		    highlight(OFF,curdoc.link); 
+		    curdoc.link = 0;
+		} else if (more) {  /* next page */
+		    Newline += (display_lines);
+		}
+	    }
+	    break;
 
 	case LYK_MODIFY:  /* rename a file or directory */
-           if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
-	      int ret;
-
-	      ret = local_modify(&curdoc, &newdoc.address);
-	      if (ret == PERMIT_FORM_RESULT) {      /* Permit form thrown up */
-		 refresh_screen=TRUE;
-	      } else if (ret) {
-		 HTuncache_current_document();
-		 StrAllocCopy(newdoc.address, curdoc.address);
-		 FREE(curdoc.address);	
-		 newdoc.line = curdoc.line;
-		 newdoc.link = curdoc.link;
-		 clear();
-	      }
-	   }
-           break;
+	    if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
+	        int ret;
+
+	        ret = local_modify(&curdoc, &newdoc.address);
+	        if (ret == PERMIT_FORM_RESULT) { /* Permit form thrown up */
+		    refresh_screen=TRUE;
+	        } else if (ret) {
+		    HTuncache_current_document();
+		    StrAllocCopy(newdoc.address, curdoc.address);
+		    FREE(curdoc.address);	
+		    FREE(newdoc.post_data);
+		    FREE(newdoc.post_content_type);
+		    FREE(newdoc.bookmark);
+		    newdoc.isHEAD = FALSE;
+		    newdoc.safe = FALSE;
+		    newdoc.line = curdoc.line;
+		    newdoc.link = curdoc.link;
+		    clear();
+	        }
+	    }
+            break;
 
 	case LYK_CREATE:  /* create a new file or directory */
-           if (lynx_edit_mode && !no_dired_support) {
-	      if (local_create(&curdoc)) {
-		 HTuncache_current_document();
-		 StrAllocCopy(newdoc.address, curdoc.address);
-		 FREE(curdoc.address);	
-		 newdoc.line = curdoc.line;
-		 newdoc.link = curdoc.link > -1 ? curdoc.link : 0;
-		 clear();
-	      }
-	   }
-           break;
+            if (lynx_edit_mode && !no_dired_support) {
+	        if (local_create(&curdoc)) {
+		    HTuncache_current_document();
+		    StrAllocCopy(newdoc.address, curdoc.address);
+		    FREE(curdoc.address);	
+		    FREE(curdoc.address);	
+		    FREE(newdoc.post_data);
+		    FREE(newdoc.post_content_type);
+		    FREE(newdoc.bookmark);
+		    newdoc.isHEAD = FALSE;
+		    newdoc.safe = FALSE;
+		    newdoc.line = curdoc.line;
+		    newdoc.link = curdoc.link > -1 ? curdoc.link : 0;
+		    clear();
+	        }
+	    }
+            break;
 #endif /* DIRED_SUPPORT */
 
 	case LYK_EDIT:  /* edit */
@@ -2541,99 +2917,108 @@ check_recall:
 	    }
 
 #ifdef DIRED_SUPPORT
-
-/* Allow the user to edit the link rather than curdoc in edit mode */
-
-	   if (lynx_edit_mode && editor && *editor != '\0' &&
-	   			!no_dired_support) {
-	      if (nlinks > 0) {
-		 cp = links[curdoc.link].lname;
-		 if (is_url(cp) == FILE_URL_TYPE) {
-		    tp = cp;
-		    if (!strncmp(tp,"file://localhost",16))
-		       tp += 16;
-		    else if (!strncmp(tp,"file:",5))
-		       tp += 5;
-		    strcpy(tmpbuf,tp);
-		    HTUnEscape(tmpbuf);
-		    if (stat(tmpbuf,&dir_info) == -1) {
-		       _statusline(NO_STATUS);
-		       sleep(AlertSecs);
-		    } else {
-		       if (((dir_info.st_mode) & S_IFMT) == S_IFREG) {
-			  strcpy(tmpbuf,cp);
-			  HTUnEscapeSome(tmpbuf,"/");
-			  if (edit_current_file(tmpbuf,curdoc.link,newline))
-			  {
-			    	HTuncache_current_document();
-			  	StrAllocCopy(newdoc.address, curdoc.address);
-			  	FREE(curdoc.address);
+	    /*
+	     *  Allow the user to edit the link rather
+	     *  than curdoc in edit mode.
+	     */
+	    if (lynx_edit_mode &&
+	        editor && *editor != '\0' && !no_dired_support) {
+	        if (nlinks > 0) {
+		    cp = links[curdoc.link].lname;
+		    if (is_url(cp) == FILE_URL_TYPE) {
+		        tp = cp;
+		        if (!strncmp(tp, "file://localhost", 16))
+		            tp += 16;
+		        else if (!strncmp(tp, "file:", 5))
+		           tp += 5;
+		        strcpy(tmpbuf, tp);
+		        HTUnEscape(tmpbuf);
+		        if (stat(tmpbuf, &dir_info) == -1) {
+		            _statusline(NO_STATUS);
+		            sleep(AlertSecs);
+			} else {
+		            if (((dir_info.st_mode) & S_IFMT) == S_IFREG) {
+			        strcpy(tmpbuf, cp);
+			        HTUnEscapeSome(tmpbuf, "/");
+			        if (edit_current_file(tmpbuf,
+			      			      curdoc.link, Newline)) {
+			    	    HTuncache_current_document();
+			  	    StrAllocCopy(newdoc.address,
+				    		 curdoc.address);
+			  	    FREE(curdoc.address);
 #ifdef NO_SEEK_OLD_POSITION
-				/* Go to top of file */
-				newdoc.line = 1;
-				newdoc.link = 0;
+				    /*
+				     *  Go to top of file.
+				     */
+				    newdoc.line = 1;
+				    newdoc.link = 0;
 #else
-				/* Seek old position, which probably changed */
-				newdoc.line =
+				    /*
+				     *  Seek old position,
+				     *  which probably changed.
+				     */
+				    newdoc.line =
 					((curdoc.line > 0) ? curdoc.line : 1);
-				newdoc.link =
+				    newdoc.link =
 					((curdoc.link > -1) ? curdoc.link : 0);
 #endif /* NO_SEEK_OLD_POSITION */
-			  	clear();  /* clear the screen */
-			  }
-			}
+			  	    clear();  /* clear the screen */
+			        }
+			    }
+		        }
 		    }
-		 }
-	      }
-	   } else
+	        }
+	    } else
 #endif /* DIRED_SUPPORT */
-	   if (editor && *editor != '\0') {
-		if (edit_current_file(newdoc.address, curdoc.link, newline))
-		{
-	            	HTuncache_current_document();
-			LYforce_no_cache = TRUE;  /*force the document to be reloaded*/
-	        	FREE(curdoc.address); /* so it doesn't get pushed */
+	    if (editor && *editor != '\0') {
+		if (edit_current_file(newdoc.address, curdoc.link, Newline)) {
+	            HTuncache_current_document();
+		    LYforce_no_cache = TRUE;  /*force reload of document */
+	            FREE(curdoc.address); /* so it doesn't get pushed */
 #ifdef NO_SEEK_OLD_POSITION
-			/* Go to top of file */
-			newdoc.line = 1;
-			newdoc.link = 0;
+		    /*
+		     *  Go to top of file.
+		     */
+		    newdoc.line = 1;
+		    newdoc.link = 0;
 #else
-			/* Seek old position, which probably changed */
-			newdoc.line = curdoc.line;
-			newdoc.link = curdoc.link;
+		    /*
+		     *  Seek old position, which probably changed.
+		     */
+		    newdoc.line = curdoc.line;
+		    newdoc.link = curdoc.link;
 #endif /* NO_SEEK_OLD_POSITION */
-			clear();  /* clear the screen */
+		    clear();  /* clear the screen */
 		}
 
-	   } else {
-		if (old_c != real_c)	{
-			old_c = real_c;
-			_statusline(NO_EDITOR);
-			sleep(MessageSecs);
+	    } else {
+		if (old_c != real_c) {
+		    old_c = real_c;
+		    _statusline(NO_EDITOR);
+		    sleep(MessageSecs);
 		}
-	   }
-	   break;
+	    }
+	    break;
 
-	case LYK_DEL_BOOKMARK:  /* delete home page link */
+	case LYK_DEL_BOOKMARK:	/* remove a bookmark file link */
 #ifdef DIRED_SUPPORT
-	case LYK_REMOVE:  /* remove files and directories */
-	   c = 'N';
-	   if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
+	case LYK_REMOVE: 	/* remove files and directories */
+	    c = 'N';
+	    if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
 		local_remove(&curdoc);
 		c = 'Y';
-	   } else
+	    } else
 #endif /* DIRED_SUPPORT */
-
 	    if (curdoc.bookmark != NULL) {
 		_statusline(CONFIRM_BOOKMARK_DELETE);
-             	c = LYgetch();
-                if (TOUPPER(c) != 'Y')
-                    break;
-                remove_bookmark_link(links[curdoc.link].anchor_number-1,
+		c = LYgetch();
+		if (TOUPPER(c) != 'Y')
+		    break;
+		remove_bookmark_link(links[curdoc.link].anchor_number-1,
 				     curdoc.bookmark);
 	    } else {	/* behave like REFRESH for backward compatability */
 	        refresh_screen = TRUE;
-	        break;
+		break;
 	    }
 	    if (TOUPPER(c) == 'Y') {
 		HTuncache_current_document();
@@ -2653,20 +3038,31 @@ check_recall:
 
 #ifdef DIRED_SUPPORT
 	case LYK_INSTALL:  /* install a file into system area */
-	   if (lynx_edit_mode && nlinks > 0 && !no_dired_support)
-	      local_install(NULL, links[curdoc.link].lname, &newdoc.address);
-	   break;
+	    if (lynx_edit_mode && nlinks > 0 && !no_dired_support)
+	        local_install(NULL, links[curdoc.link].lname, &newdoc.address);
+	    break;
 #endif /* DIRED_SUPPORT */
 
 	case LYK_INFO:  /* show document info */
-	   /* don't do if already viewing info page */	
-	   if (strcmp((curdoc.title ? curdoc.title : ""), SHOWINFO_TITLE)) {
-	        showinfo(&curdoc, lines_in_file, &newdoc, owner_address);
+	    /*
+	     *  Don't do if already viewing info page.
+	     */	
+	    if (strcmp((curdoc.title ? curdoc.title : ""), SHOWINFO_TITLE)) {
+	        if (!showinfo(&curdoc, lines_in_file,
+			      &newdoc, owner_address))
+		    break;
+		FREE(newdoc.post_data);
+		FREE(newdoc.post_content_type);
+		FREE(newdoc.bookmark);
+		newdoc.isHEAD = FALSE;
+		newdoc.safe = FALSE;
 		LYforce_no_cache = TRUE;
 		if (LYValidate || check_realm)
 		    LYPermitURL = TRUE;
             } else {
-		/* if already in info page; get out */
+		/*
+		 *  If already in info page, get out.
+		 */
 		cmd = LYK_PREV_DOC;
 		goto new_cmd;
 	    }
@@ -2682,12 +3078,22 @@ check_recall:
 		break;
 	    }
 
-	    /* don't do if already viewing print options page */	
+	    /*
+	     *  Don't do if already viewing print options page.
+	     */	
 	    if (strcmp((curdoc.title ? curdoc.title : ""),
 	    	       PRINT_OPTIONS_TITLE)) {	
 
                 if (print_options(&newdoc.address, lines_in_file) < 0)
 		    break;
+		if (!strcmp((curdoc.title ? curdoc.title : ""),
+			    HISTORY_PAGE_TITLE))
+		FREE(newdoc.post_data);
+		FREE(newdoc.post_content_type);
+		FREE(newdoc.bookmark);
+		newdoc.isHEAD = FALSE;
+		newdoc.safe = FALSE;
+		ForcePush = TRUE;
 		if (check_realm)
 		    LYPermitURL = TRUE;
 	        refresh_screen=TRUE;  /* redisplay */
@@ -2695,19 +3101,64 @@ check_recall:
 	    break;
 
 	case LYK_LIST:  /* list links in the current document */
-	    /* don't do if already viewing list page */	
-	    if (strcmp((curdoc.title ? curdoc.title : ""),
-	    	       LIST_PAGE_TITLE)) {
-		if (showlist(&newdoc.address, TRUE) < 0)
-		    break;
-		refresh_screen=TRUE;  /* redisplay */
-		if (LYValidate || check_realm) {
-		    LYPermitURL = TRUE;
-		    StrAllocCopy(lynxlistfile, newdoc.address);
-		}
+	    /*
+	     *  Don't do if already viewing list page.
+	     */	
+	    if (!strcmp((curdoc.title ? curdoc.title : ""),
+	    		LIST_PAGE_TITLE)) {
+		/*
+		 *  Already viewing list page, so get out.
+		 */
+		cmd = LYK_PREV_DOC;
+		goto new_cmd;
+	    }
+
+	    /*
+	     *  Print list page to file.
+	     */
+	    if (showlist(&newdoc.address, TRUE) < 0)
+		break;
+	    FREE(newdoc.post_data);
+	    FREE(newdoc.post_content_type);
+	    FREE(newdoc.bookmark);
+	    newdoc.isHEAD = FALSE;
+	    newdoc.safe = FALSE;
+	    refresh_screen = TRUE;  /* redisplay */
+	    if (LYValidate || check_realm) {
+		LYPermitURL = TRUE;
+		StrAllocCopy(lynxlistfile, newdoc.address);
 	    }
 	    break;
 
+	case LYK_VLINKS:  /* list links visited during the current session */
+	    if (!strcmp(curdoc.title, VISITED_LINKS_TITLE)) {
+		/*
+		 *  Already viewing visited links page, so get out.
+		 */
+		cmd = LYK_PREV_DOC;
+		goto new_cmd;
+	    }
+
+	    /*
+	     *  Print visited links page to file.
+	     */
+	    if (LYShowVisitedLinks(&newdoc.address) < 0) {
+	        _statusline(VISITED_LINKS_EMPTY);
+		sleep(MessageSecs);
+		break;
+	    }
+	    FREE(newdoc.post_data);
+	    FREE(newdoc.post_content_type);
+	    FREE(newdoc.bookmark);
+	    newdoc.isHEAD = FALSE;
+	    newdoc.safe = FALSE;
+	    refresh_screen = TRUE;
+	    if (LYValidate || check_realm) {
+		LYPermitURL = TRUE;
+		StrAllocCopy(lynxlinksfile, newdoc.address);
+	    }
+	    break; 
+
 	case LYK_TOOLBAR:  /* go to Toolbar or Banner in current document */
 	    if (!HText_hasToolbar(HTMainText)) {
 		if (old_c != real_c) {
@@ -2730,19 +3181,142 @@ check_recall:
 	    }
 	    break;
 
-#ifdef DIRED_SUPPORT
+#if defined(DIRED_SUPPORT) || defined(VMS) 
        case LYK_DIRED_MENU:  /* provide full file management menu */
-	    /* don't do if not allowed or already viewing the menu */	
+#ifdef VMS
+	    /*
+	     *  Check if the CSwing Directory/File Manager is available.
+	     *  Will be disabled if LYCSwingPath is NULL, zero-length,
+	     *  or "none" (case insensitive), if no_file_url was set via
+	     *  the file_url restriction, if no_goto_file was set for
+	     *  the anonymous account, or if HTDirAccess was set to
+	     *  HT_DIR_FORBID or HT_DIR_SELECTIVE via the -nobrowse
+	     *  or -selective switches. - FM
+	     */
+	    if (!(LYCSwingPath && *LYCSwingPath) ||
+	        !strcasecomp(LYCSwingPath, "none") ||
+		no_file_url || no_goto_file ||
+		HTDirAccess == HT_DIR_FORBID ||
+		HTDirAccess == HT_DIR_SELECTIVE) {
+		if (old_c != real_c)	{
+		    old_c = real_c;
+		    _statusline(DFM_NOT_AVAILABLE);
+		    sleep(MessageSecs);
+		}
+		break;
+	    }
+
+	    /*
+	     *  If we are viewing a local directory listing or a
+	     *  local file which is not temporary, invoke CSwing
+	     *  with the URL's directory converted to VMS path specs
+	     *  and passed as the argument, so we start up CSwing
+	     *  positioned on that node of the directory tree.
+	     *  Otherwise, pass the current default directory as
+	     *  the argument. - FM
+	     */
+	    if (LYisLocalFile(curdoc.address) &&
+	        strncasecomp(curdoc.address,
+			     lynx_temp_space, strlen(lynx_temp_space))) {
+		/*
+		 *  We are viewing a local directory or a local file
+		 *  which is not temporary. - FM
+		 */
+		struct stat stat_info;
+
+		cp = HTParse(curdoc.address, "", PARSE_PATH|PARSE_PUNCTUATION);
+		HTUnEscape(cp);
+		if (HTStat(cp, &stat_info) == -1) {
+		    if (TRACE)
+		        fprintf(stderr, "mainloop: Can't stat %s\n", cp);
+		    FREE(cp);
+		    temp = (char *)calloc(1, (strlen(LYCSwingPath) + 4));
+		    if (temp == NULL)
+		        outofmem(__FILE__, "mainloop");
+		    sprintf(temp, "%s []", LYCSwingPath);
+		    refresh_screen = TRUE;  /* redisplay */
+		} else {
+		    char *VMSdir = NULL;
+
+		    if (((stat_info.st_mode) & S_IFMT) == S_IFDIR) {
+		        /*
+			 *  We're viewing a local directory.  Make
+			 *  that the CSwing argument. - FM
+			 */
+		        if (cp[(strlen(cp) - 1)] != '/')
+			    StrAllocCat(cp, "/");
+		        StrAllocCopy(VMSdir, HTVMS_name("", cp));
+			FREE(cp);
+		    } else {
+		        /*
+			 *  We're viewing a local file.  Make it's
+			 *  directory the CSwing argument. - FM
+			 */ 
+		        StrAllocCopy(VMSdir, HTVMS_name("", cp));
+			FREE(cp);
+			if ((cp = strrchr(VMSdir, ']')) != NULL) {
+			    *(cp + 1) = '\0';
+			    cp == NULL;
+			} else if ((cp = strrchr(VMSdir, ':')) != NULL) {
+			    *(cp + 1) = '\0';
+			    cp == NULL;
+			}
+		    }
+		    temp = (char *)calloc(1,
+					  (strlen(LYCSwingPath) +
+					   strlen(VMSdir) +
+					   2));
+		    if (temp == NULL)
+			outofmem(__FILE__, "mainloop");
+		    sprintf(temp, "%s %s", LYCSwingPath, VMSdir);
+		    FREE(VMSdir);
+		    /*
+		     *  Uncache the current document in case we
+		     *  change, move, or delete it during the
+		     *  CSwing session. - FM
+		     */
+		    HTuncache_current_document();
+		    StrAllocCopy(newdoc.address, curdoc.address);
+		    StrAllocCopy(newdoc.title,
+		    		 curdoc.title ? curdoc.title : "");
+		    StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
+		    FREE(curdoc.address);	
+		    newdoc.line = curdoc.line;
+		    newdoc.link = curdoc.link;
+		}
+	    } else {
+	        /*
+		 *  We're not viewing a local directory or file.
+		 *  Pass CSwing the current default directory as
+		 *  an argument and don't uncache the current
+		 *  document. - FM
+		 */
+	    	temp = (char *)calloc(1, (strlen(LYCSwingPath) + 4));
+		if (temp == NULL)
+		    outofmem(__FILE__, "mainloop");
+		sprintf(temp, "%s []", LYCSwingPath);
+		refresh_screen = TRUE;  /* redisplay */
+	    }
+	    stop_curses();
+	    system(temp);
+	    start_curses();
+	    FREE(temp);
+	    break;
+#else
+	    /*
+	     *  Don't do if not allowed or already viewing the menu.
+	     */	
 	    if (lynx_edit_mode && !no_dired_support &&
 	        strcmp((curdoc.title ? curdoc.title : ""),
 		       DIRED_MENU_TITLE)) {
 	        dired_options(&curdoc,&newdoc.address);
-	        refresh_screen=TRUE;  /* redisplay */
+	        refresh_screen = TRUE;  /* redisplay */
 	    }
 	    break;
-#endif /* DIRED_SUPPORT */
+#endif /* VMS */
+#endif /* DIRED_SUPPORT || VMS*/
 
-	case LYK_ADD_BOOKMARK:  /* a to add link to bookmark file */
+	case LYK_ADD_BOOKMARK:  /* add link to bookmark file */
 	    if (LYValidate) {
 		if (old_c != real_c)	{
 		    old_c = real_c;
@@ -2769,6 +3343,8 @@ check_recall:
 	        strcmp((curdoc.title ? curdoc.title : ""),
 		       DOWNLOAD_OPTIONS_TITLE) &&
 	        strcmp((curdoc.title ? curdoc.title : ""),
+		       COOKIE_JAR_TITLE) &&
+	        strcmp((curdoc.title ? curdoc.title : ""),
 		       LIST_PAGE_TITLE)) {
 		if (nlinks > 0) {
 		    if (curdoc.post_data == NULL &&
@@ -2787,7 +3363,11 @@ check_recall:
 			}
 		    } else {
 			if (LYMultiBookmarks == FALSE &&
-			    curdoc.bookmark != NULL) {
+			    curdoc.bookmark != NULL &&
+			    strstr(curdoc.address,
+			    	   (*bookmark_page == '.'
+				   		  ?
+				(bookmark_page+1) : bookmark_page)) != NULL) {
 			    /*
 			     *  If multiple bookmarks are disabled, offer
 			     *  the L)ink or C)ancel, but with wording
@@ -2813,10 +3393,14 @@ check_recall:
 			if (links[curdoc.link].type != WWW_FORM_LINK_TYPE) {
 			    save_bookmark_link(links[curdoc.link].lname, 
 					       links[curdoc.link].hightext);
+			    refresh_screen = TRUE; /* MultiBookmark support */
 			} else {
 			    _statusline(NOBOOK_FORM_FIELD);
 			    sleep(MessageSecs);
+			    break;
 			}
+		    } else {
+		        break;
 		    }
 		} else if (curdoc.post_data != NULL) {
 		    /*
@@ -2824,11 +3408,24 @@ check_recall:
 		     */
 		    _statusline(NOBOOK_POST_FORM);
 		    sleep(MessageSecs);
+		    break;
+		} else if (curdoc.bookmark != NULL) {
+		    /*
+		     *  It's a bookmark file from which all
+		     *  of the links were deleted. - FM
+		     */
+		    _statusline(BOOKMARKS_NOLINKS);
+		    sleep(MessageSecs);
+		    break;
 		} else {
 		    _statusline(BOOK_D_OR_CANCEL);
 		    c = LYgetch();
-		    if (TOUPPER(c) == 'D')
+		    if (TOUPPER(c) == 'D') {
 		        save_bookmark_link(curdoc.address, curdoc.title);
+			refresh_screen = TRUE; /* MultiBookmark support */
+		    } else {
+		        break;
+		    }
 		}
 check_add_bookmark_to_self:
 		if (curdoc.bookmark && BookmarkPage &&
@@ -2848,7 +3445,6 @@ check_add_bookmark_to_self:
 			sleep(MessageSecs);
 		}
 	    }
-            refresh_screen = TRUE; /* MultiBookmark support */
 	    break;
 
 	case LYK_VIEW_BOOKMARK:   /* v to view home page */
@@ -2868,27 +3464,27 @@ check_add_bookmark_to_self:
 	    if ((cp = get_bookmark_filename(&newdoc.address)) != NULL) {
 	        if (*cp == '\0' || !strcmp(cp, " ") ||
 		    !strcmp(curdoc.address, newdoc.address)) {
-		    refresh_screen = TRUE; /* MultiBookmark support */
+		    if (LYMultiBookmarks == TRUE)
+		        refresh_screen = TRUE;
 		    break;
 		}
-		LYforce_HTML_mode = TRUE;  /* force HTML */
 		LYforce_no_cache = TRUE;  /*force the document to be reloaded*/
 		StrAllocCopy(newdoc.title, BOOKMARK_TITLE);
 		StrAllocCopy(newdoc.bookmark, BookmarkPage);
 		FREE(newdoc.post_data);
 		FREE(newdoc.post_content_type);
 		newdoc.isHEAD = FALSE;
-		if (check_realm) {
-		    StrAllocCopy(lynxbookfile, newdoc.address);
-		}
+		newdoc.safe = FALSE;
 	    } else {
-		if (old_c != real_c)	{
-			old_c = real_c;
-			_statusline(BOOKMARKS_NOT_OPEN);
-       			sleep(MessageSecs);
+		if (old_c != real_c) {
+		    old_c = real_c;
+		    LYMBM_statusline(BOOKMARKS_NOT_OPEN);
+       		    sleep(AlertSecs);
+		    if (LYMultiBookmarks == TRUE) {
+		        refresh_screen = TRUE;
+		    }
 		}
 	    }
-            refresh_screen = TRUE; /* MultiBookmark support */
 	    break;
 
 	case LYK_SHELL:  /* shell escape */
@@ -2913,7 +3509,9 @@ check_add_bookmark_to_self:
 	    break;
 
 	case LYK_DOWNLOAD:
-	    /* don't do if both download and disk_save are restricted */
+	    /*
+	     *  Don't do if both download and disk_save are restricted.
+	     */
 	    if (LYValidate ||
 	        (no_download && !override_no_download && no_disk_save)) {
 		if (old_c != real_c)	{
@@ -2924,14 +3522,17 @@ check_add_bookmark_to_self:
 		break;
 	    }
 
-	    /* don't do if already viewing download options page */	
-	    if (0==strcmp((curdoc.title ? curdoc.title : ""),
-	    		  DOWNLOAD_OPTIONS_TITLE))
+	    /*
+	     *  Don't do if already viewing download options page.
+	     */	
+	    if (!strcmp((curdoc.title ? curdoc.title : ""),
+	    		DOWNLOAD_OPTIONS_TITLE))
 	        break;
 
 	    if (nlinks > 0) {
                 if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
-		    if (links[curdoc.link].form->type == F_SUBMIT_TYPE) {
+		    if (links[curdoc.link].form->type == F_SUBMIT_TYPE ||
+		        links[curdoc.link].form->type == F_IMAGE_SUBMIT_TYPE) {
 		        if (links[curdoc.link].form->submit_method ==
 				 URL_MAIL_METHOD) {
 			    if (old_c != real_c) {
@@ -2952,8 +3553,16 @@ check_add_bookmark_to_self:
 			sleep(MessageSecs);
 		    }
 
-		} else if (0==strcmp((curdoc.title ? curdoc.title : ""),
-				     PRINT_OPTIONS_TITLE)) {
+		} else if (!strcmp((curdoc.title ? curdoc.title : ""),
+				   COOKIE_JAR_TITLE)) {
+		    if (old_c != real_c)	{
+			old_c = real_c;
+			_statusline(NO_DOWNLOAD_COOKIES);
+			sleep(MessageSecs);
+		    }
+
+		} else if (!strcmp((curdoc.title ? curdoc.title : ""),
+				   PRINT_OPTIONS_TITLE)) {
 		    if (old_c != real_c)	{
 			old_c = real_c;
 			_statusline(NO_DOWNLOAD_PRINT_OP);
@@ -2961,16 +3570,16 @@ check_add_bookmark_to_self:
 		    }
 
 #ifdef DIRED_SUPPORT
-		} else if (0==strcmp((curdoc.title ? curdoc.title : ""),
-				     UPLOAD_OPTIONS_TITLE)) {
+		} else if (!strcmp((curdoc.title ? curdoc.title : ""),
+				  UPLOAD_OPTIONS_TITLE)) {
 		    if (old_c != real_c)	{
 			old_c = real_c;
 			_statusline(NO_DOWNLOAD_UPLOAD_OP);
 			sleep(MessageSecs);
 		    }
 
-		} else if (0==strcmp((curdoc.title ? curdoc.title : ""),
-				     PERMIT_OPTIONS_TITLE)) {
+		} else if (!strcmp((curdoc.title ? curdoc.title : ""),
+				   PERMIT_OPTIONS_TITLE)) {
 		    if (old_c != real_c)	{
 			old_c = real_c;
 			_statusline(NO_DOWNLOAD_PERMIT_OP);
@@ -2978,7 +3587,9 @@ check_add_bookmark_to_self:
 		    }
 
                 } else if (lynx_edit_mode && !no_dired_support) {
-		    /* Don't bother making a /tmp copy of the local file */
+		    /*
+		     *  Don't bother making a /tmp copy of the local file.
+		     */
 		    StrAllocCopy(temp, newdoc.address);
                     StrAllocCopy(newdoc.address, links[curdoc.link].lname);
                     if (LYdownload_options(&newdoc.address,
@@ -2987,12 +3598,19 @@ check_add_bookmark_to_self:
 		    FREE(temp);
 #endif /* DIRED_SUPPORT */
 
-		} else if (0==strcmp((curdoc.title ? curdoc.title : ""),
-				     HISTORY_PAGE_TITLE)) {
+		} else if (!strcmp((curdoc.title ? curdoc.title : ""),
+				   HISTORY_PAGE_TITLE)) {
 		    int number = atoi(links[curdoc.link].lname+9);
+		    if ((history[number].post_data != NULL &&
+		         history[number].safe != TRUE) &&
+			HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
+			_statusline(CANCELLED);
+			sleep(InfoSecs);
+			break;
+		    } 
 		    StrAllocCopy(newdoc.address, history[number].address);
                     StrAllocCopy(newdoc.title, links[curdoc.link].hightext);
-		    StrAllocCopy(newdoc.address, history[number].bookmark);
+		    StrAllocCopy(newdoc.bookmark, history[number].bookmark);
 		    FREE(newdoc.post_data);
 		    FREE(newdoc.post_content_type);
 		    if (history[number].post_data)
@@ -3002,12 +3620,14 @@ check_add_bookmark_to_self:
 		        StrAllocCopy(newdoc.post_content_type,
 				     history[number].post_content_type);
 		    newdoc.isHEAD = history[number].isHEAD;
+		    newdoc.safe = history[number].safe;
                     newdoc.link = 0;
 	            HTOutputFormat = HTAtom_for("www/download");
 		    LYUserSpecifiedURL = TRUE;
-		    /*force the document to be reloaded*/
+		    /*
+		     *  Force the document to be reloaded.
+		     */
 		    LYforce_no_cache = TRUE;
-		    force_load = TRUE;  /* force MainLoop to reload */
 		    
 		} else if (!strncasecomp(links[curdoc.link].lname,
 					 "data:", 5)) {
@@ -3018,27 +3638,29 @@ check_add_bookmark_to_self:
 
                 } else {   /* Not a forms, options or history link */
                     /*
-		     * Follow a normal link or anchor.  Note that
-		     * if it's an anchor within the same document,
-		     * entire document will be downloaded
+		     *  Follow a normal link or anchor.  Note that
+		     *  if it's an anchor within the same document,
+		     *  entire document will be downloaded.
 		     */
                     StrAllocCopy(newdoc.address, links[curdoc.link].lname);
                     StrAllocCopy(newdoc.title, links[curdoc.link].hightext);
 		    /*
-		     * Might be an anchor in the same doc from a POST
-		     * form.  If so, don't free the content. -- FM
+		     *  Might be an anchor in the same doc from a POST
+		     *  form.  If so, don't free the content. -- FM
 		     */
 		    if (are_different(&curdoc, &newdoc)) {
 			FREE(newdoc.post_data);
 			FREE(newdoc.post_content_type);
 			FREE(newdoc.bookmark);
 			newdoc.isHEAD = FALSE;
+			newdoc.safe = FALSE;
 		    }
                     newdoc.link = 0;
 	            HTOutputFormat = HTAtom_for("www/download");
-		    /*force the document to be reloaded*/
+		    /*
+		     *  Force the document to be reloaded.
+		     */
 		    LYforce_no_cache = TRUE;
-		    force_load = TRUE;  /* force MainLoop to reload */
                 }
             } else if (old_c != real_c)	{
 		old_c = real_c;
@@ -3049,14 +3671,22 @@ check_add_bookmark_to_self:
 
 #ifdef DIRED_SUPPORT
 	  case LYK_UPLOAD:
-	    /* don't do if already viewing upload options page */	
-	    if (0==strcmp((curdoc.title ? curdoc.title : ""),
-	    		  UPLOAD_OPTIONS_TITLE))
+	    /*
+	     *  Don't do if already viewing upload options page.
+	     */
+	    if (!strcmp((curdoc.title ? curdoc.title : ""),
+	    		UPLOAD_OPTIONS_TITLE))
 	        break;
 
 	    if (lynx_edit_mode && !no_dired_support) {
                 LYUpload_options((char **)&newdoc.address,
 				 (char *)curdoc.address);
+		FREE(curdoc.address);	
+		FREE(newdoc.post_data);
+		FREE(newdoc.post_content_type);
+		FREE(newdoc.bookmark);
+		newdoc.isHEAD = FALSE;
+		newdoc.safe = FALSE;
 	     }
 	    break;
 #endif /* DIRED_SUPPORT */
@@ -3113,7 +3743,8 @@ check_add_bookmark_to_self:
 	case LYK_HEAD:
 	    if (nlinks > 0 &&
 	        (links[curdoc.link].type != WWW_FORM_LINK_TYPE ||
-	    	 links[curdoc.link].form->type == F_SUBMIT_TYPE)) {
+	    	 links[curdoc.link].form->type == F_SUBMIT_TYPE ||
+		 links[curdoc.link].form->type == F_IMAGE_SUBMIT_TYPE)) {
 	        _statusline(HEAD_D_L_OR_CANCEL);
 		c = LYgetch();
 		if (TOUPPER(c) == 'D') {
@@ -3121,6 +3752,18 @@ check_add_bookmark_to_self:
 		        _statusline(DOC_NOT_HTTP_URL);
 			sleep(MessageSecs);
 		    } else {
+			/*
+			 *  Check if this is a reply from a POST,
+			 *  and if so, seek confirmation if the
+			 *  safe element is not set. - FM
+			 */
+			if ((curdoc.post_data != NULL &&
+			     curdoc.safe != TRUE) &&
+			    HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
+			    _statusline(CANCELLED);
+			    sleep(InfoSecs);
+			    break;
+			} 
 		        HEAD_request = TRUE;
 			LYforce_no_cache = TRUE;
 			if (HTLoadedDocumentIsHEAD()) {
@@ -3153,6 +3796,17 @@ check_add_bookmark_to_self:
 		}
 		break;
 	    } else {
+		/*
+		 *  Check if this is a reply from a POST, and if so,
+		 *  seek confirmation if the safe element is not set. - FM
+		 */
+		if ((curdoc.post_data != NULL &&
+		     curdoc.safe != TRUE) &&
+		    HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
+		    _statusline(CANCELLED);
+		    sleep(InfoSecs);
+		    break;
+		} 
 	        if (nlinks > 0) {
 		    _statusline(HEAD_D_OR_CANCEL);
 	            c = LYgetch();
@@ -3175,10 +3829,6 @@ check_add_bookmark_to_self:
 	    }
 	    break;	
 
-	case LYK_DO_NOTHING:
-	    /* pretty self explanitory */
-	    break;
-
 	case LYK_TOGGLE_HELP:
     	    if (user_mode==NOVICE_MODE) {
 	        toggle_novice_line();
@@ -3194,9 +3844,10 @@ check_add_bookmark_to_self:
 	        FREE(newdoc.post_content_type);
 		FREE(newdoc.bookmark);
 		newdoc.isHEAD = FALSE;
+		newdoc.safe = FALSE;
 		/*
-		 * If vi_keys changed, the keymap did too,
-		 * so force no cache, and reset the flag. - FM
+		 *  If vi_keys changed, the keymap did too,
+		 *  so force no cache, and reset the flag. - FM
 		 */
 		if (vi_keys_flag != vi_keys ||
 		    emacs_keys_flag != emacs_keys) {
@@ -3205,9 +3856,10 @@ check_add_bookmark_to_self:
 		    emacs_keys_flag = emacs_keys;
 		}
 #if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
-		/* Remember whether we are in dired menu
-		 * so we can display the right keymap.
-		 * Don't cache the keymap because it changes. - EF
+		/*
+		 *  Remember whether we are in dired menu
+		 *  so we can display the right keymap.
+		 *  Don't cache the keymap because it changes. - EF
 		 */
 		if (!no_dired_support) {
 		    prev_lynx_edit_mode = lynx_edit_mode;
@@ -3264,6 +3916,7 @@ check_add_bookmark_to_self:
 	    	      FREE(newdoc.post_content_type);
 		      FREE(newdoc.bookmark);
 		      newdoc.isHEAD = FALSE;
+		      newdoc.safe = FALSE;
 		      FREE(ret);
 		      LYUserSpecifiedURL = TRUE;
 		  } else {
@@ -3286,16 +3939,21 @@ check_add_bookmark_to_self:
 	    break;
 #endif /* NOT_USED */
 
+	case LYK_DO_NOTHING:	/* pretty self explanatory */
+	    break;
+
 	} /* end of BIG switch */
     }
 }
 
-PRIVATE int are_different ARGS2(document *,doc1, document *,doc2)
+PRIVATE int are_different ARGS2(
+	document *,	doc1,
+	document *,	doc2)
 {
     char *cp1, *cp2;
 
     /*
-     * Do we have two addresses?
+     *  Do we have two addresses?
      */
     if (!doc1->address || !doc2->address)
 	return (TRUE);
@@ -3307,16 +3965,16 @@ PRIVATE int are_different ARGS2(document *,doc1, document *,doc2)
         return (TRUE);
 
     /*
-     * See if the addresses are different, making sure
-     * we're not tripped up by multiple anchors in the
-     * the same document from a POST form. -- FM
+     *  See if the addresses are different, making sure
+     *  we're not tripped up by multiple anchors in the
+     *  the same document from a POST form. -- FM
      */
     if ((cp1 = strchr(doc1->address, '#')) != NULL)
         *cp1 = '\0';
     if ((cp2 = strchr(doc2->address, '#')) != NULL)
         *cp2 = '\0';
     /* 
-     * Are the base addresses different?
+     *  Are the base addresses different?
      */
     if (strcmp(doc1->address, doc2->address))
       {
@@ -3332,7 +3990,7 @@ PRIVATE int are_different ARGS2(document *,doc1, document *,doc2)
         *cp2 = '#';
 
     /*
-     * Do the docs have different contents?
+     *  Do the docs have different contents?
      */
     if (doc1->post_data)
       {
@@ -3349,13 +4007,13 @@ PRIVATE int are_different ARGS2(document *,doc1, document *,doc2)
 	    return(TRUE);
 
     /*
-     * We'll assume the two documents in fact are the same.
+     *  We'll assume the two documents in fact are the same.
      */
     return(FALSE);
 }
 
 /* 
- * Utility for freeing the list of goto URLs. - FM
+ *  Utility for freeing the list of goto URLs. - FM
  */
 PUBLIC void HTGotoURLs_free NOARGS
 {
@@ -3374,10 +4032,11 @@ PUBLIC void HTGotoURLs_free NOARGS
 }
 
 /* 
- * Utility for listing Goto URLs, making any
- * repeated URLs the most current in the list. - FM
+ *  Utility for listing Goto URLs, making any
+ *  repeated URLs the most current in the list. - FM
  */
-PUBLIC void HTAddGotoURL ARGS1(char *, url)
+PUBLIC void HTAddGotoURL ARGS1(
+	char *,		url)
 {
     char *new;
     char *old;
diff --git a/src/LYMap.c b/src/LYMap.c
index 9720586b..3126611c 100644
--- a/src/LYMap.c
+++ b/src/LYMap.c
@@ -214,6 +214,7 @@ PRIVATE int LYLoadIMGmap ARGS4 (
         WWWDoc.post_content_type = NULL;
         WWWDoc.bookmark = NULL;
 	WWWDoc.isHEAD = FALSE;
+	WWWDoc.safe = FALSE;
         LYforce_no_cache = TRUE;
 	reloading = TRUE;
 	HTOutputFormat = WWW_PRESENT;
@@ -249,6 +250,7 @@ PRIVATE int LYLoadIMGmap ARGS4 (
         WWWDoc.post_content_type = NULL;
         WWWDoc.bookmark = NULL;
 	WWWDoc.isHEAD = FALSE;
+	WWWDoc.safe = FALSE;
         LYforce_no_cache = TRUE;
 	reloading = TRUE;
 	HTOutputFormat = WWW_PRESENT;
diff --git a/src/LYNews.c b/src/LYNews.c
index 2bdab054..eb1da221 100644
--- a/src/LYNews.c
+++ b/src/LYNews.c
@@ -51,6 +51,7 @@ PUBLIC int LYNewsPost ARGS2(document *,newdoc, BOOLEAN,followup)
 	WWWDoc.post_content_type = newdoc->post_content_type;
 	WWWDoc.bookmark = newdoc->bookmark;
 	WWWDoc.isHEAD = newdoc->isHEAD;
+	WWWDoc.safe = newdoc->safe;
         if(!HTLoadAbsolute(&WWWDoc)) {
 	    FREE(newsgroups);
             return(NOT_FOUND);
diff --git a/src/LYOptions.c b/src/LYOptions.c
index 345c7d0e..a795fcfb 100644
--- a/src/LYOptions.c
+++ b/src/LYOptions.c
@@ -35,31 +35,27 @@ PRIVATE int boolean_choice PARAMS((int status, int line,
 
 #define MAXCHOICES 10
 
-PRIVATE void option_statusline ARGS1(char *,text)
+PRIVATE void option_statusline ARGS1(
+	char *,		text)
 {
-    char buffer[256];
-
-    if (!text || text == NULL)
+    /*
+     *  Make sure we have a pointer to a string.
+     */
+    if (text == NULL)
         return;
 
-        /* don't print statusline messages if dumping to stdout
-         */
+    /*
+     *  Don't print statusline messages if dumping to stdout.
+     */
     if (dump_output_immediately)
         return;
 
-    /* make sure text is not longer than COLS */
-    LYstrncpy(buffer, text, LYcols-1);
-
-    move(LYlines-1, 0);
-
-    clrtoeol();
-    if (text != NULL && *buffer) {
-        start_reverse();
-        addstr(buffer);
-        stop_reverse();
-    }
-
-    refresh();
+    /*
+     *  Use _statusline() set to output on the bottom line. - FM
+     */
+    LYStatusLine = (LYlines - 1);
+    _statusline(text);
+    LYStatusLine = -1;
 }
 
 PUBLIC void options NOARGS
@@ -108,119 +104,129 @@ PUBLIC void options NOARGS
     signal(SIGINT, terminate_options);
 
 draw_options:
+    /*
+     *  NOTE that printw() should be avoided for strings that
+     *  might have non-ASCII or multibyte/CJK characters. - FM
+     */
     response = 0;
     clear(); 
     move(0, 5);
     if (bold_H1 || bold_headers)
         start_bold();
-    printw("         Options Menu (%s Version %s)",
-    	   			   LYNX_NAME, LYNX_VERSION);
+    addstr("         Options Menu (");
+    addstr(LYNX_NAME);
+    addstr(" Version ");
+    addstr(LYNX_VERSION);
+    addch(')');
     if (bold_H1 || bold_headers)
         stop_bold();
     move(L_EDITOR, 5);  
-    printw("E)ditor                      : %s",
-    		((editor && *editor) ? editor : "NONE"));
-
-    move(L_DISPLAY, 5);  
-    printw("D)ISPLAY variable            : %s",
-    		((display && *display) ? display : "NONE"));
+    addstr("E)ditor                      : ");
+    addstr((editor && *editor) ? editor : "NONE");
 
-    move(L_MAIL_ADDRESS, 5);  
-    printw("P)ersonal mail address       : %s",
-    		((personal_mail_address && *personal_mail_address) ?
-					     personal_mail_address : "NONE"));
+    move(L_DISPLAY, 5);
+    addstr("D)ISPLAY variable            : ");
+    addstr((display && *display) ? display : "NONE");
 
     move(L_HOME, 5);
-    printw("mu(L)ti-bookmarks: %s",
-		(LYMultiBookmarks ? (LYMBMAdvanced ?
-                                     "ADVANCED" : "STANDARD") : "OFF"));
+    addstr("mu(L)ti-bookmarks: ");
+    addstr((LYMultiBookmarks ?
+    	      (LYMBMAdvanced ? "ADVANCED"
+	      		     : "STANDARD")
+			     : "OFF"));
     move(L_HOME, B_BOOK);
     if (LYMultiBookmarks) {
-        printw("review/edit B)ookmarks files");
+        addstr("review/edit B)ookmarks files");
     } else {
-        printw("B)ookmark file: %s",
-    		((bookmark_page && *bookmark_page) ? bookmark_page : "NONE"));
+        addstr("B)ookmark file: ");
+	addstr((bookmark_page && *bookmark_page) ? bookmark_page : "NONE");
     }
 
     move(L_FTPSTYPE, 5);
-    printw("F)TP sort criteria           : %s",(HTfileSortMethod==FILE_BY_NAME ?
-					"By Filename" :
-					  (HTfileSortMethod==FILE_BY_SIZE ?
-					    "By Size" : 
-					      (HTfileSortMethod==FILE_BY_TYPE ?
-						"By Type" : "By Date"))));
+    addstr("F)TP sort criteria           : ");
+    addstr((HTfileSortMethod==FILE_BY_NAME ? "By Filename" :
+	   (HTfileSortMethod==FILE_BY_SIZE ? "By Size" : 
+	   (HTfileSortMethod==FILE_BY_TYPE ? "By Type" :
+	   				     "By Date"))));
+
+    move(L_MAIL_ADDRESS, 5);
+    addstr("P)ersonal mail address       : ");
+    addstr((personal_mail_address && *personal_mail_address) ?
+    				       personal_mail_address : "NONE");
+
     move(L_SSEARCH, 5); 
-    printw("S)earching type              : %s",(case_sensitive ?
-				        "CASE SENSITIVE" : "CASE INSENSITIVE"));
+    addstr("S)earching type              : ");
+    addstr(case_sensitive ? "CASE SENSITIVE" : "CASE INSENSITIVE");
 
     move(L_CHARSET, 5);
-    printw("display (C)haracter set      : %s", 
-    					LYchar_set_names[current_char_set]);
+    addstr("display (C)haracter set      : "); 
+    addstr(LYchar_set_names[current_char_set]);
     
     move(L_RAWMODE, 5);
-    printw("Raw 8-bit or CJK m(O)de      : %s", (LYRawMode ? "ON" : "OFF"));
+    addstr("Raw 8-bit or CJK m(O)de      : ");
+    addstr(LYRawMode ? "ON" : "OFF");
 
     move(L_LANGUAGE, 5);
-    printw("preferred document lan(G)uage: %s",
-    		((language && *language) ? language : "NONE"));
+    addstr("preferred document lan(G)uage: ");
+    addstr((language && *language) ? language : "NONE");
 
     move(L_PREF_CHARSET, 5);
-    printw("preferred document c(H)arset : %s",
-    		((pref_charset && *pref_charset) ? pref_charset : "NONE"));
+    addstr("preferred document c(H)arset : ");
+    addstr((pref_charset && *pref_charset) ? pref_charset : "NONE");
 
     move(L_BOOL_A, B_VIKEYS);
-    printw("V)I keys: %s", (vi_keys ? "ON" : "OFF"));
+    addstr("V)I keys: ");
+    addstr(vi_keys ? "ON" : "OFF");
     
     move(L_BOOL_A, B_EMACSKEYS);
-    printw("e(M)acs keys: %s", (emacs_keys ? "ON" : "OFF"));
+    addstr("e(M)acs keys: ");
+    addstr(emacs_keys ? "ON" : "OFF");
     
     move(L_BOOL_A, B_SHOW_DOTFILES);
-    printw("sho(W) dot files: %s",
-    			((!no_dotfiles && show_dotfiles) ? "ON" : "OFF"));
+    addstr("sho(W) dot files: ");
+    addstr((!no_dotfiles && show_dotfiles) ? "ON" : "OFF");
 
     move(L_SELECT_POPUPS, 5);
-    printw("popups for selec(T) fields   : %s",
-    			(LYSelectPopups ? "ON" : "OFF"));
+    addstr("popups for selec(T) fields   : ");
+    addstr(LYSelectPopups ? "ON" : "OFF");
 
     move(L_KEYPAD, 5); 
-    printw("K)eypad mode                 : %s", 
-			   		  (keypad_mode == NUMBERS_AS_ARROWS ? 
-					   "Numbers act as arrows" : 
-				           "Links are numbered"));
+    addstr("K)eypad mode                 : "); 
+    addstr((keypad_mode == NUMBERS_AS_ARROWS) ? "Numbers act as arrows" : 
+						"Links are numbered");
 
     move(L_LINEED, 5);
-    printw("li(N)e edit style            : %s",
-    					   LYLineeditNames[current_lineedit]);
+    addstr("li(N)e edit style            : ");
+    addstr(LYLineeditNames[current_lineedit]);
 
 #ifdef DIRED_SUPPORT
     move(L_DIRED, 5);
-    printw("l(I)st directory style       : %s",
-                     (dir_list_style == FILES_FIRST ? "Files first          " :
-		     (dir_list_style == MIXED_STYLE ? "Mixed style          " : 
-                                                      "Directories first    ")));
+    addstr("l(I)st directory style       : ");
+    addstr((dir_list_style == FILES_FIRST) ? "Files first          " :
+	  ((dir_list_style == MIXED_STYLE) ? "Mixed style          " : 
+					     "Directories first    "));
 #endif /* DIRED_SUPPORT */
 
     move(L_USER_MODE, 5);
-    printw("U)ser mode                   : %s",
-			(user_mode == NOVICE_MODE ? "Novice" : 
-			(user_mode == INTERMEDIATE_MODE ? "Intermediate" :
-							     "Advanced")));
+    addstr("U)ser mode                   : ");
+    addstr(  (user_mode == NOVICE_MODE) ? "Novice" : 
+      ((user_mode == INTERMEDIATE_MODE) ? "Intermediate" :
+					  "Advanced"));
 
     move(L_USER_AGENT, 5);
-    printw("user (A)gent                 : %s",
-    		((LYUserAgent && *LYUserAgent) ? LYUserAgent : "NONE"));
-
+    addstr("user (A)gent                 : ");
+    addstr((LYUserAgent && *LYUserAgent) ? LYUserAgent : "NONE");
 
 #ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS
     move(L_EXEC, 5);
-    printw("local e(X)ecution links      : ");
+    addstr("local e(X)ecution links      : ");
 #ifndef NEVER_ALLOW_REMOTE_EXEC
-    addstr((local_exec ? "ALWAYS ON" :
-                    (local_exec_on_local_files ? "FOR LOCAL FILES ONLY" :
-                                                              "ALWAYS OFF")));
+    addstr(		  local_exec ? "ALWAYS ON" :
+          (local_exec_on_local_files ? "FOR LOCAL FILES ONLY" :
+				       "ALWAYS OFF"));
 #else
     addstr(local_exec_on_local_files ? "FOR LOCAL FILES ONLY" :
-                                                              "ALWAYS OFF");
+				       "ALWAYS OFF");
 #endif /* NEVER_ALLOW_REMOTE_EXEC */
 #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */
 
@@ -422,10 +428,11 @@ draw_options:
 			move(L_HOME, B_BOOK);
 			clrtoeol();
     			if (LYMultiBookmarks) {
-    			    printw("review/edit B)ookmarks files");
+    			    addstr("review/edit B)ookmarks files");
     			} else {
-			    printw("B)ookmark file: %s",
-    		((bookmark_page && *bookmark_page) ? bookmark_page : "NONE"));
+			    addstr("B)ookmark file: ");
+			    addstr((bookmark_page && *bookmark_page) ?
+			    			       bookmark_page : "NONE");
     			}
 			response = ' ';
 			break;
@@ -459,11 +466,19 @@ draw_options:
 			        ch == -1 || *display_option == '\0') {
 			        addstr((bookmark_page && *bookmark_page) ?
 						    bookmark_page : "NONE");
+			    } else if (!LYPathOffHomeOK(display_option,
+						    sizeof(display_option))) {
+			        addstr((bookmark_page && *bookmark_page) ?
+						    bookmark_page : "NONE");
+				clrtoeol();
+				option_statusline(USE_PATH_OFF_HOME);
+				response = ' ';
+				break;
 			    } else {
 			        StrAllocCopy(bookmark_page, display_option);
 				StrAllocCopy(MBM_A_subbookmark[0],
 					     bookmark_page);
-				addstr(display_option);
+				addstr(bookmark_page);
 			    }
 			    clrtoeol();
 			    option_statusline(VALUE_ACCEPTED);
@@ -930,10 +945,10 @@ draw_options:
     signal(SIGINT, cleanup_sig);
 }
 
-/* take a boolean status and prompt the user for a new status
- * and return it
+/*
+ *  Take a boolean status,prompt the user for a new status,
+ *  and return it.
  */
-
 PRIVATE int boolean_choice ARGS4(
 	int,		status,
 	int,		line,
@@ -987,7 +1002,8 @@ PRIVATE int boolean_choice ARGS4(
     }
 }
 
-PRIVATE void terminate_options ARGS1(int,sig)
+PRIVATE void terminate_options ARGS1(
+	int,		sig)
 {
     term_options=TRUE;
     /* Reassert the AST */
@@ -1011,6 +1027,7 @@ PUBLIC void edit_bookmarks NOARGS
 #define	MULTI_OFFSET 8
     int a; /* misc counter */
     char MBM_tmp_line[256]; /* buffer for LYgetstr */
+    char ehead_buffer[265];
     
     /*
      *  We need (MBM_V_MAXFILES + MULTI_OFFSET) lines to display
@@ -1022,15 +1039,21 @@ PUBLIC void edit_bookmarks NOARGS
     signal(SIGINT, terminate_options);
 
 draw_bookmark_list:
+    /*
+     *  Display menu of bookmarks.  NOTE that we avoid printw()'s
+     *  to increase the chances that any non-ASCII or multibyte/CJK
+     *  characters will be handled properly. - FM
+     */
     clear(); 
     move(0, 5);
     if (bold_H1 || bold_headers)
         start_bold();
-    if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET))
-	printw("Editing Bookmark DESCRIPTION and FILEPATH (%d of 2)",
-		MBM_current);
-    else
-        printw("         Editing Bookmark DESCRIPTION and FILEPATH");
+    if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) {
+        sprintf(ehead_buffer, MULTIBOOKMARKS_EHEAD_MASK, MBM_current);
+	addstr(ehead_buffer);
+    } else {
+        addstr(MULTIBOOKMARKS_EHEAD);
+    }
     if (bold_H1 || bold_headers)
         stop_bold();
 
@@ -1038,20 +1061,28 @@ draw_bookmark_list:
 	for (a = ((MBM_V_MAXFILES/2 + 1) * (MBM_current - 1));
                       a <= ((float)MBM_V_MAXFILES/2 * MBM_current); a++) {
 	    move((3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)), 5);
-	    printw("%c : %s", (a + 'A'),
-		   (!MBM_A_subdescript[a] ? "" : MBM_A_subdescript[a]));
+	    addch((unsigned char)(a + 'A'));
+	    addstr(" : ");
+	    if (MBM_A_subdescript[a])
+	        addstr(MBM_A_subdescript[a]);
 	    move((3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)), 35);
-	    printw("| %s",
-		   (!MBM_A_subbookmark[a] ? "" : MBM_A_subbookmark[a]));
+	    addstr("| ");
+	    if (MBM_A_subbookmark[a]) {
+	        addstr(MBM_A_subbookmark[a]);
+	    }
         }
     } else {
 	for (a = 0; a <= MBM_V_MAXFILES; a++) {
 	    move(3 + a, 5);
-	    printw("%c : %s", (a + 'A'),
-		   (!MBM_A_subdescript[a] ? "" : MBM_A_subdescript[a]));
+	    addch((unsigned char)(a + 'A'));
+	    addstr(" : ");
+	    if (MBM_A_subdescript[a])
+	        addstr(MBM_A_subdescript[a]);
 	    move(3 + a, 35);
-	    printw("| %s",
-		   (!MBM_A_subbookmark[a] ? "" : MBM_A_subbookmark[a]));
+	    addstr("| ");
+	    if (MBM_A_subbookmark[a]) {
+	        addstr(MBM_A_subbookmark[a]);
+	    }
 	}
     }
 
@@ -1059,10 +1090,19 @@ draw_bookmark_list:
      *  Only needed when we have 2 screens.
      */
     if (LYlines < MBM_V_MAXFILES + MULTI_OFFSET) {
-       move((LYlines - 4), 0);
-       start_reverse();
-       addstr(MULTIBOOKMARKS_MOVE);
-       stop_reverse();
+        move((LYlines - 4), 0);
+	addstr("'");
+	standout();
+	addstr("[");
+	standend();
+	addstr("' ");
+	addstr(PREVIOUS);
+	addstr(", '");
+	standout();
+	addstr("]");
+	standend();
+	addstr("' ");
+	addstr(NEXT_SCREEN);
     }
 
     move((LYlines - 3), 0);
@@ -1089,7 +1129,7 @@ draw_bookmark_list:
 
 	move((LYlines - 2), 0);
 	start_reverse();
-	addstr("Letter: ");
+	addstr(MULTIBOOKMARKS_LETTER);
 	stop_reverse();
 
 	refresh();
@@ -1200,9 +1240,10 @@ draw_bookmark_list:
 			     5);
 		    else
     			move((3 + a), 5);
-    		    printw("%c : %s", (a + 'A'),
-    			   (!MBM_A_subdescript[a] ?
-			       		"" : MBM_A_subdescript[a]));
+		    addch((unsigned char)(a + 'A'));
+		    addstr(" : ");
+    		    if (MBM_A_subdescript[a])
+			addstr(MBM_A_subdescript[a]);
 		    clrtoeol();
 	   	    refresh();
 		}
@@ -1212,7 +1253,7 @@ draw_bookmark_list:
 		    	 35);
 		else
     		    move((3 + a), 35);
-    		printw("| ");
+    		addstr("| ");
 
 		standout();
 		strcpy(MBM_tmp_line,
@@ -1226,6 +1267,10 @@ draw_bookmark_list:
 		        StrAllocCopy(MBM_A_subbookmark[a], bookmark_page);
 		    else
 		        FREE(MBM_A_subbookmark[a]);
+		} else if (!LYPathOffHomeOK(MBM_tmp_line,
+					    sizeof(MBM_tmp_line))) {
+			LYMBM_statusline(USE_PATH_OFF_HOME);
+			sleep(AlertSecs);
 		} else {
 		    StrAllocCopy(MBM_A_subbookmark[a], MBM_tmp_line);
 		    if (a == 0) {
@@ -1237,8 +1282,9 @@ draw_bookmark_list:
 		    	 35);
 		else
     		    move((3 + a), 35);
-    		printw("| %s", (!MBM_A_subbookmark[a] ?
-						   "" : MBM_A_subbookmark[a]));
+		addstr("| ");
+    		if (MBM_A_subbookmark[a])
+		    addstr(MBM_A_subbookmark[a]);
 	   	clrtoeol();
 		move(LYlines-1, 0);
 		clrtoeol();
diff --git a/src/LYOptions.h b/src/LYOptions.h
index f89159aa..e7464226 100644
--- a/src/LYOptions.h
+++ b/src/LYOptions.h
@@ -3,6 +3,7 @@
 #define LYOPTIONS_H
 
 extern void options NOPARAMS;
+extern void edit_bookmarks NOPARAMS;
 
 /* values for options */
 #define L_EDITOR	 2
diff --git a/src/LYPrint.c b/src/LYPrint.c
index 8e14c938..3b3a5fe4 100644
--- a/src/LYPrint.c
+++ b/src/LYPrint.c
@@ -67,6 +67,7 @@ PUBLIC int printfile ARGS1(document *,newdoc)
     int FnameTotal;
     int FnameNum;
     BOOLEAN FirstRecall = TRUE;
+    char *content_base = NULL, *content_location = NULL;
 #ifdef VMS
     extern BOOLEAN HadVMSInterrupt;
 #endif /* VMS */
@@ -85,10 +86,42 @@ PUBLIC int printfile ARGS1(document *,newdoc)
     WWWDoc.post_content_type = newdoc->post_content_type;
     WWWDoc.bookmark = newdoc->bookmark;
     WWWDoc.isHEAD = newdoc->isHEAD;
-    if(!HTLoadAbsolute(&WWWDoc))
+    WWWDoc.safe = newdoc->safe;
+    if (!HTLoadAbsolute(&WWWDoc))
         return(NOT_FOUND);
   
     /*
+     *  If document is source, load the content_base
+     *  and content_location strings. - FM
+     */
+    if (HTisDocumentSource()) {
+    	if (HText_getContentBase()) {
+	    StrAllocCopy(content_base, HText_getContentBase());
+	    collapse_spaces(content_base);
+	    if (!(content_base && *content_base)) {
+	        FREE(content_base);
+	    }
+	}
+    	if (HText_getContentLocation()) {
+	    StrAllocCopy(content_location, HText_getContentLocation());
+	    collapse_spaces(content_location);
+	    if (!(content_location && *content_location)) {
+	        FREE(content_location);
+	    }
+	}
+	if (!content_base) {
+	    if ((content_location) && is_url(content_location)) {
+	        StrAllocCopy(content_base, content_location);
+	    } else {
+	        StrAllocCopy(content_base, newdoc->address);
+	    }
+	}
+	if (!content_location) {
+	    StrAllocCopy(content_location, newdoc->address);
+	}
+    }
+
+    /*
      *  Load the suggested filename string. - FM
      */
     if (HText_getSugFname() != NULL)
@@ -113,7 +146,6 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 	pages = lines_in_file/66;
     }
 	
-
     /*
      *  Determine the type.
      */
@@ -141,7 +173,6 @@ PUBLIC int printfile ARGS1(document *,newdoc)
         }
     }
 
-
     /*
      *  Set up the sug_filenames recall buffer.
      */
@@ -149,7 +180,9 @@ PUBLIC int printfile ARGS1(document *,newdoc)
     recall = ((FnameTotal >= 1) ? RECALL : NORECALL);
     FnameNum = FnameTotal;
 
-
+    /*
+     *  Act on the request. - FM
+     */
     switch (type) {
 	case TO_FILE:
 		_statusline(FILENAME_PROMPT);
@@ -343,15 +376,16 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 
 		if (HTisDocumentSource()) {
 		    /*
-		     *  Added the document's URL as a BASE tag
+		     *  Added the document's base as a BASE tag
 		     *  to the top of the file.  May create
 		     *  technically invalid HTML, but will help
 		     *  get any partial or relative URLs resolved
 		     *  properly if no BASE tag is present to
 		     *  replace it. - FM
 		     */
-		    fprintf(outfile_fp, "<BASE HREF=\"%s\">\n",
-		    			newdoc->address);
+		    fprintf(outfile_fp,
+		    	    "<!-- X-URL: %s -->\n<BASE HREF=\"%s\">\n",
+			    newdoc->address, content_base);
 		}
 		print_wwwfile_to_fd(outfile_fp,0);
 		if (keypad_mode)
@@ -419,18 +453,21 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		    break;
 		}
 
-		/* write the contents to a temp file */
+		/*
+		 *  Write the contents to a temp file.
+		 */
 		if (HTisDocumentSource()) {
 		    /*
-		     *  Added the document's URL as a BASE tag to
+		     *  Added the document's base as a BASE tag to
 		     *  the top of the message body.  May create
 		     *  technically invalid HTML, but will help
 		     *  get any partial or relative URLs resolved
 		     *  properly if no BASE tag is present to
 		     *  replace it. - FM
 		     */
-		    fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n",
-		    			newdoc->address);
+		    fprintf(outfile_fp,
+		    	    "<!-- X-URL: %s -->\n<BASE HREF=\"%s\">\n\n",
+			    newdoc->address, content_base);
 		} else {
 		    fprintf(outfile_fp, "X-URL: %s\n\n", newdoc->address);
 		}
@@ -445,7 +482,9 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 
         	stop_curses();
 		printf(MAILING_FILE);
+		fflush(stdout);
         	system(buffer);
+		fflush(stdout);
 		sleep(MessageSecs);
         	start_curses();
 #else /* Unix: */
@@ -475,30 +514,26 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		    } else {
 		        fprintf(outfile_fp, "\n");
 		    }
-		    fprintf(outfile_fp, "Content-Location: %s\n",
-		    			newdoc->address);
 		    fprintf(outfile_fp, "Content-Base: %s\n",
-		    			newdoc->address);
-		} else {
-		    /*
-		     *  Add an X-URL header for rendered HTML or
-		     *  plain text. - FM
-		     */
-		    fprintf(outfile_fp, "X-URL: %s\n", newdoc->address);
+		    			content_base);
+		    fprintf(outfile_fp, "Content-Location: %s\n",
+		    			content_location);
 		}
+		fprintf(outfile_fp, "X-URL: %s\n", newdoc->address);
 		fprintf(outfile_fp, "To: %s\nSubject:%s\n\n",
 				     user_response, sug_filename);
 		if (HTisDocumentSource()) {
 		    /*
-		     *  Added the document's URL as a BASE tag to
+		     *  Added the document's base as a BASE tag to
 		     *  the top of the message body.  May create
 		     *  technically invalid HTML, but will help
 		     *  get any partial or relative URLs resolved
 		     *  properly if no BASE tag is present to
 		     *  replace it. - FM
 		     */
-		    fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n",
-		    			newdoc->address);
+		    fprintf(outfile_fp,
+		    	    "<!-- X-URL: %s -->\n<BASE HREF=\"%s\">\n\n",
+			    newdoc->address, content_base);
 		}
 		print_wwwfile_to_fd(outfile_fp, 0);
 		if (keypad_mode)
@@ -553,15 +588,16 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 
 		if (HTisDocumentSource()) {
 		    /*
-		     *  Added the document's URL as a BASE tag
+		     *  Added the document's base as a BASE tag
 		     *  to the top of the file.  May create
 		     *  technically invalid HTML, but will help
 		     *  get any partial or relative URLs resolved
 		     *  properly if no BASE tag is present to
 		     *  replace it. - FM
 		     */
-		    fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n",
-		    			newdoc->address);
+		    fprintf(outfile_fp,
+		    	    "<!-- X-URL: %s -->\n<BASE HREF=\"%s\">\n\n",
+			    newdoc->address, content_base);
 		}
 		print_wwwfile_to_fd(outfile_fp, 0);
 		if (keypad_mode)
@@ -639,15 +675,16 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 
 		if (HTisDocumentSource()) {
 		    /*
-		     *  Added the document's URL as a BASE tag
+		     *  Added the document's base as a BASE tag
 		     *  to the top of the file.  May create
 		     *  technically invalid HTML, but will help
 		     *  get any partial or relative URLs resolved
 		     *  properly if no BASE tag is present to
 		     *  replace it. - FM
 		     */
-		    fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n",
-		    			newdoc->address);
+		    fprintf(outfile_fp,
+		    	    "<!-- X-URL: %s -->\n<BASE HREF=\"%s\">\n\n",
+			    newdoc->address, content_base);
 		}
 		print_wwwfile_to_fd(outfile_fp, 0);
 		if (keypad_mode)
@@ -816,6 +853,7 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		if (TRACE)
 		    fprintf(stderr, "command: %s\n", buffer);
 		printf(PRINTING_FILE);
+		fflush(stdout);
 		system(buffer);
 		fflush(stdout);
 #ifndef VMS
@@ -828,6 +866,8 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 
     FREE(link_info);
     FREE(sug_filename);
+    FREE(content_base);
+    FREE(content_location);
     return(NORMAL);
 }	
 
diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c
index 686eb13e..c0ede5b9 100644
--- a/src/LYReadCFG.c
+++ b/src/LYReadCFG.c
@@ -41,7 +41,7 @@ PUBLIC BOOLEAN LYUseNoviceLineTwo=TRUE;
 PRIVATE int is_true ARGS1(
 	char *,	string)
 {
-    if(!strncasecomp(string,"TRUE",4))
+    if (!strncasecomp(string,"TRUE",4))
 	return(TRUE);
     else
 	return(FALSE);
@@ -153,7 +153,7 @@ PRIVATE void add_item_to_list ARGS2(
 	 *  Process name field
 	 */
         cur_item->name = (char *)calloc((colon-buffer+1),sizeof(char));
-	if(cur_item->name == NULL)
+	if (cur_item->name == NULL)
 	    perror("Out of memory in read_cfg");
 	LYstrncpy(cur_item->name, buffer, (int)(colon-buffer));	
 	remove_backslashes(cur_item->name);
@@ -242,8 +242,8 @@ PRIVATE void add_printer_to_list ARGS2(
         /*
 	 *  Process name field.
 	 */
-        cur_item->name = (char *)calloc((colon-buffer+1),sizeof(char));
-	if(cur_item->name == NULL)
+        cur_item->name = (char *)calloc((colon-buffer+1), sizeof(char));
+	if (cur_item->name == NULL)
 	    perror("Out of memory in read_cfg");
         LYstrncpy(cur_item->name, buffer, (int)(colon-buffer));	
         remove_backslashes(cur_item->name);
@@ -385,12 +385,12 @@ PUBLIC void read_cfg ARGS1(
      *  Locate and open the file.
      */
     if (!cfg_filename || strlen(cfg_filename) == 0) {
-	if(TRACE)
+	if (TRACE)
 	    fprintf(stderr,"No filename following -cfg switch!\n");
 	return;
     }
-    if((fp = fopen(cfg_filename,"r")) == NULL) {
-	if(TRACE)
+    if ((fp = fopen(cfg_filename,"r")) == NULL) {
+	if (TRACE)
 	    fprintf(stderr,"lynx.cfg file not found as %s\n",cfg_filename);
 	return;
     }
@@ -403,7 +403,7 @@ PUBLIC void read_cfg ARGS1(
 	/*
 	 *  Strip off \n at the end.
 	 */
-	if((line_feed = (char *)strchr(buffer,'\n')) != NULL)
+	if ((line_feed = (char *)strchr(buffer, '\n')) != NULL)
 	    *line_feed = '\0';
 	
 	/*
@@ -424,285 +424,210 @@ PUBLIC void read_cfg ARGS1(
         /*
 	 * Process the string buffer.
 	 */
-        if (!strncasecomp(buffer,"SUFFIX:",7)) {
-	    char *extention;
-	    char *mime_type;
-
-	    if (strlen(buffer) > 9) {
-	        extention = buffer + 7;
-	        if ((mime_type = strchr(extention, ':')) != NULL) {
-		    *mime_type++ = '\0';
-		    for (i = 0, j = 0; mime_type[i]; i++) {
-		        if (mime_type[i] != ' ') {
-		            mime_type[j++] = TOLOWER(mime_type[i]);
-			}
-		    }
-		    mime_type[j] = '\0';
-		    if (strstr(mime_type, "tex") != NULL ||
-		        strstr(mime_type, "postscript") != NULL ||
-			strstr(mime_type, "sh") != NULL ||
-			strstr(mime_type, "troff") != NULL ||
-			strstr(mime_type, "rtf") != NULL)
-			HTSetSuffix(extention, mime_type, "8bit", 1.0);
-		    else
-		        HTSetSuffix(extention, mime_type, "binary", 1.0);
-		}
-	    }
-
-        } else if (!strncasecomp(buffer,"VIEWER:",7)) {
-	    char *mime_type;
-	    char *viewer;
-	    char *environment;
-
-	    if (strlen(buffer) > 9) {
-	        mime_type = buffer + 7;
-	        if ((viewer = strchr(mime_type, ':')) != NULL) {
-		    *viewer++ = '\0';
-		    for (i = 0, j = 0; mime_type[i]; i++) {
-		        if (mime_type[i] != ' ') {
-		            mime_type[j++] = TOLOWER(mime_type[i]);
-			}
-		    }
-		    mime_type[j] = '\0';
-		    environment = strrchr(viewer, ':');
-		    if ((environment != NULL) &&
-		        (strlen(viewer) > 1) && *(environment-1) != '\\') {
-			*environment++ = '\0';
-			remove_backslashes(viewer);
-			/*
-			 *  If environment equals xwindows then only
-			 *  assign the presentation if there is a display
-			 *  variable.
-			 */
-			if (!strcasecomp(environment,"XWINDOWS")) {
-			    if (getenv(DISPLAY)) 
-		      		HTSetPresentation(mime_type, viewer,
-						  1.0, 3.0, 0.0, 0);
-			} else if (!strcasecomp(environment,"NON_XWINDOWS")) {
-			    if (!getenv(DISPLAY)) 
-		      		HTSetPresentation(mime_type, viewer, 
-						  1.0, 3.0, 0.0, 0);
-			} else {
-		            HTSetPresentation(mime_type, viewer,
-						  1.0, 3.0, 0.0, 0);
-			}
-		    } else {
-		        remove_backslashes(viewer);
-		        HTSetPresentation(mime_type, viewer,
-						  1.0, 3.0, 0.0, 0);
-		    }
+	switch (TOUPPER(buffer[0])) {
+
+	case 'A':
+	if (!strncasecomp(buffer, "ALERTSECS:", 10)) {
+	    strcpy(temp, buffer+10);
+	    for (i = 0; temp[i]; i++) {
+		if (!isdigit(temp[i])) {
+		    temp[i] = '\0';
+		    break;
 		}
 	    }
+	    if (temp[0])
+		AlertSecs = atoi(temp);
 
-        } else if(!strncasecomp(buffer,"KEYMAP:",7)) {
-            char *key;
-            char *func;
-  
-            key = buffer + 7;
-            if ((func = strchr(key, ':')) != NULL)	{
-                *func++ = '\0';
-		/* Allow comments on the ends of key remapping lines. - DT */
-            	if (!remap(key, strtok(func, " \t\n#")))
-                    fprintf(stderr,
-		    	    "key remapping of %s to %s failed\n",key,func);
-		else if (!strcmp("TOGGLE_HELP", strtok(func, " \t\n#")))
-		    LYUseNoviceLineTwo = FALSE;
-	    }
+	} else if (!strncasecomp(buffer, "ALWAYS_RESUBMIT_POSTS:", 22)) {
+	    LYresubmit_posts = is_true(buffer+22);
 
-	} else if(!strncasecomp(buffer,"GLOBAL_MAILCAP:",15)) {
-
-	    StrAllocCopy(global_type_map, buffer+15);
+#ifdef EXEC_LINKS
+	} else if (!strncasecomp(buffer, "ALWAYS_TRUSTED_EXEC:", 20)) {
+	    add_trusted(&buffer[20], ALWAYS_EXEC_PATH); /* Add exec path */
+#endif /* EXEC_LINKS */
+	}
+	break;
 
-	} else if(!strncasecomp(buffer,"GLOBAL_EXTENSION_MAP:",21)) {
+	case 'B':
+	if (!strncasecomp(buffer, "BLOCK_MULTI_BOOKMARKS:", 22)) {
+	    LYMBMBlocked = is_true(buffer+22);
 
-	    StrAllocCopy(global_extension_map, buffer+21);
+	} else if (!strncasecomp(buffer, "BOLD_H1:", 8)) {
+	    bold_H1 = is_true(buffer+8);
 
-	} else if(!strncasecomp(buffer,"PERSONAL_MAILCAP:",17)) {
+	} else if (!strncasecomp(buffer, "BOLD_HEADERS:", 13)) {
+	    bold_headers = is_true(buffer+13);
 
-            StrAllocCopy(personal_type_map, buffer+17);
-
-        } else if(!strncasecomp(buffer,"PERSONAL_EXTENSION_MAP:",23)) {
+	} else if (!strncasecomp(buffer, "BOLD_NAME_ANCHORS:", 18)) {
+	    bold_name_anchors = is_true(buffer+18);
+	}
+	break;
 
-            StrAllocCopy(personal_extension_map, buffer+23);
+	case 'C':
+	if (!strncasecomp(buffer, "CASE_SENSITIVE_ALWAYS_ON:", 25)) {
+	     case_sensitive = is_true(buffer+25);
 
-	} else if(!strncasecomp(buffer,"CHARACTER_SET:",14)) {
-	    for(i = 0; LYchar_set_names[i]; i++)
-		if(!strncmp(buffer+14,LYchar_set_names[i],strlen(buffer+14)))
-		{
+	} else if (!strncasecomp(buffer, "CHARACTER_SET:", 14)) {
+	    for (i = 0; LYchar_set_names[i]; i++) {
+		if (!strncmp(buffer+14,
+			     LYchar_set_names[i], strlen(buffer+14))) {
 		    current_char_set=i;
 		    HTMLSetRawModeDefault(i);
 		    break;
 		}
+	    }
 
-	} else if(!strncasecomp(buffer,"STARTFILE:",10)) {
-
-	    StrAllocCopy(startfile, buffer+10);
-
-	} else if(!strncasecomp(buffer,"HELPFILE:",9)) {
-
-	    StrAllocCopy(helpfile, buffer+9);
-
-	} else if(!strncasecomp(buffer,"DEFAULT_INDEX_FILE:",19)) {
-	    StrAllocCopy(indexfile, buffer+19);
-
-#if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS)
-	} else if(!strncasecomp(buffer,
-				    "LOCAL_EXECUTION_LINKS_ALWAYS_ON:",32)) {
-	    local_exec = is_true(buffer+32);
+	} else if (!strncasecomp(buffer, "CHECKMAIL:", 10)) {
+	    check_mail = is_true(buffer+10);
 
-	} else if(!strncasecomp(buffer,
-			    "LOCAL_EXECUTION_LINKS_ON_BUT_NOT_REMOTE:",40)) {
-	    local_exec_on_local_files = is_true(buffer+40);
-#endif /* defined(EXEC_LINKS) || defined(EXEC_SCRIPTS) */
+	} else if (!strncasecomp(buffer, "COLLAPSE_BR_TAGS:", 17)) {
+		LYCollapseBRs = is_true(buffer+17);
 
-	} else if(!strncasecomp(buffer,"MAIL_SYSTEM_ERROR_LOGGING:",26)) {
-	    error_logging = is_true(buffer+26);
+#ifdef USE_SLANG
+	} else if (!strncasecomp(buffer, "COLOR:", 6)) {
+		parse_color(buffer + 6);
+#endif /* USE_SLANG */
 
-	} else if(!strncasecomp(buffer,"CHECKMAIL:",10)) {
-	    check_mail = is_true(buffer+10);
+	} else if (!strncasecomp(buffer, "cso_proxy:", 10)) {
+	    if (getenv("cso_proxy") == NULL) {
+#ifdef VMS
+		strcpy(temp, "cso_proxy");
+		Define_VMSLogical(temp, (char *)&buffer[10]);
+#else
+		strcpy(temp, "cso_proxy=");
+		StrAllocCopy(cso_proxy_putenv_cmd, temp);
+		StrAllocCat(cso_proxy_putenv_cmd, (char *)&buffer[10]);
+		putenv(cso_proxy_putenv_cmd);
+#endif /* VMS */
+	    }
 
 #ifdef VMS
-	} else if(!strncasecomp(buffer,"USE_FIXED_RECORDS:",18)) {
-	    UseFixedRecords = is_true(buffer+18);
+	} else if (!strncasecomp(buffer, "CSWING_PATH:", 12)) {
+	    StrAllocCopy(LYCSwingPath, buffer+12);
 #endif /* VMS */
+	}
+	break;
 
-	} else if(!strncasecomp(buffer,"VI_KEYS_ALWAYS_ON:",18)) {
-	    vi_keys = is_true(buffer+18);
+	case 'D':
+	if (!strncasecomp(buffer, "DEFAULT_BOOKMARK_FILE:", 22)) {
+	    StrAllocCopy(bookmark_page, buffer+22);
+	    StrAllocCopy(BookmarkPage, bookmark_page);
+	    StrAllocCopy(MBM_A_subbookmark[0], bookmark_page);
+	    StrAllocCopy(MBM_A_subdescript[0], MULTIBOOKMARKS_DEFAULT);
 
-	} else if(!strncasecomp(buffer,"EMACS_KEYS_ALWAYS_ON:",21)) {
-	    emacs_keys = is_true(buffer+21);
+	} else if (!strncasecomp(buffer, "DEFAULT_CACHE_SIZE:", 19)) {
+		HTCacheSize = atoi(buffer+19);
 
-	} else if(!strncasecomp(buffer,
-			"DEFAULT_KEYPAD_MODE_IS_NUMBERS_AS_ARROWS:",41)) {
-	    if(is_true(buffer+41))
+	} else if (!system_editor &&
+		   !strncasecomp(buffer, "DEFAULT_EDITOR:", 15)) {
+	    StrAllocCopy(editor, buffer+15);
+
+	} else if (!strncasecomp(buffer, "DEFAULT_INDEX_FILE:", 19)) {
+	    StrAllocCopy(indexfile, buffer+19);
+
+	} else if (!strncasecomp(buffer,
+			"DEFAULT_KEYPAD_MODE_IS_NUMBERS_AS_ARROWS:", 41)) {
+	    if (is_true(buffer+41))
 		keypad_mode = NUMBERS_AS_ARROWS;
 	    else
 		keypad_mode = LINKS_ARE_NUMBERED;
 
-	} else if(!strncasecomp(buffer,"CASE_SENSITIVE_ALWAYS_ON:",25)) {
-	     case_sensitive = is_true(buffer+25);
-
-	} else if(!strncasecomp(buffer,"DEFAULT_USER_MODE:",18)) {
-		if(!strncasecomp(buffer+18,"NOVICE",5))
-		   user_mode = NOVICE_MODE;
-		else if(!strncasecomp(buffer+18,"INTER",5))
-		   user_mode = INTERMEDIATE_MODE;
-		else if(!strncasecomp(buffer+18,"ADVANCE",7))
-		   user_mode = ADVANCED_MODE;
-
-	} else if(!strncasecomp(buffer,"DEFAULT_BOOKMARK_FILE:",22)) {
-		StrAllocCopy(bookmark_page, buffer+22);
-		StrAllocCopy(BookmarkPage, bookmark_page);
-		StrAllocCopy(MBM_A_subbookmark[0], bookmark_page);
-		StrAllocCopy(MBM_A_subdescript[0], MULTIBOOKMARKS_DEFAULT);
-
-	} else if(!strncasecomp(buffer,"MULTI_BOOKMARK_SUPPORT:",23)) {
-		LYMultiBookmarks = is_true(buffer+23);
-
-	} else if(!strncasecomp(buffer,"BLOCK_MULTI_BOOKMARKS:",22)) {
-		LYMBMBlocked = is_true(buffer+22);
-
-	} else if(!strncasecomp(buffer,"ADVANCED_MULTI_BOOKMARKS:",25)) {
-		LYMBMAdvanced = is_true(buffer+25);
-
-	} else if(!system_editor && 
-		  !strncasecomp(buffer,"DEFAULT_EDITOR:",15)) {
-		StrAllocCopy(editor,buffer+15);
-
-	} else if(!strncasecomp(buffer,"GOTOBUFFER:",11)) {
-		goto_buffer = is_true(buffer+11);
-
-	} else if(!strncasecomp(buffer,"JUMPFILE:",9)) {
-		if (!LYJumpInit(buffer)) {
-		    if (TRACE)
-		        fprintf(stderr, "Failed to register %s\n", buffer);
-		}
-
-	} else if(!strncasecomp(buffer,"JUMP_PROMPT:",12)) {
-		StrAllocCopy(jumpprompt,buffer+12);
-
-	} else if(!strncasecomp(buffer,"JUMPBUFFER:",11)) {
-		jump_buffer = is_true(buffer+11);
-
-	} else if(!strncasecomp(buffer,"NO_DOT_FILES:",13)) {
-	    no_dotfiles = is_true(buffer+13);
-
-	} else if(!strncasecomp(buffer,"NO_FROM_HEADER:",15)) {
-	    LYNoFromHeader = is_true(buffer+15);
-
-	} else if(!strncasecomp(buffer,"NO_REFERER_HEADER:",18)) {
-	    LYNoRefererHeader = is_true(buffer+18);
-
-	} else if(!strncasecomp(buffer,"NO_FILE_REFERER:",16)) {
-	    no_filereferer = is_true(buffer+16);
-
-	} else if(!strncasecomp(buffer,"MAKE_LINKS_FOR_ALL_IMAGES:",26)) {
-	    clickable_images = is_true(buffer+26);
-
-	} else if(!strncasecomp(buffer,"MAKE_PSEUDO_ALTS_FOR_INLINES:",29)) {
-	    pseudo_inline_alts = is_true(buffer+29);
+	} else if (!strncasecomp(buffer, "DEFAULT_USER_MODE:", 18)) {
+	    if (!strncasecomp(buffer+18, "NOVICE", 5))
+		user_mode = NOVICE_MODE;
+	    else if (!strncasecomp(buffer+18, "INTER", 5))
+		user_mode = INTERMEDIATE_MODE;
+	    else if (!strncasecomp(buffer+18, "ADVANCE", 7))
+		user_mode = ADVANCED_MODE;
 
-	} else if(!strncasecomp(buffer,"BOLD_HEADERS:",13)) {
-		bold_headers = is_true(buffer+13);
-
-	} else if(!strncasecomp(buffer,"BOLD_H1:",8)) {
-		bold_H1 = is_true(buffer+8);
-
-	} else if(!strncasecomp(buffer,"BOLD_NAME_ANCHORS:",18)) {
-		bold_name_anchors = is_true(buffer+18);
-
- 	} else if(!strncasecomp(buffer,"SYSTEM_EDITOR:",14)) {
-		StrAllocCopy(editor,buffer+14);
- 		system_editor = TRUE;
-
-	} else if(!strncasecomp(buffer,"PREFERRED_LANGUAGE:",19)) {
-		StrAllocCopy(language,buffer+19);
+#if defined(VMS) && defined(VAXC) && !defined(__DECC)
+	} else if (!strncasecomp(buffer, 
+				 "DEFAULT_VIRTUAL_MEMORY_SIZE:", 28)) {
+		HTVirtualMemorySize = atoi(buffer+28);
+#endif /* VMS && VAXC && !__DECC */
 
-	} else if(!strncasecomp(buffer,"PREFERRED_CHARSET:",18)) {
-		StrAllocCopy(pref_charset,buffer+18);
+#ifdef DIRED_SUPPORT
+	} else if (!strncasecomp(buffer, "DIRED_MENU:", 11)) {
+	    add_menu_item(&buffer[11]);
+#endif /* DIRED_SUPPORT */
 
-	} else if(!strncasecomp(buffer,"URL_DOMAIN_PREFIXES:",20)) {
-		StrAllocCopy(URLDomainPrefixes, buffer+20);
+	} else if (!strncasecomp(buffer, "DOWNLOADER:", 11)) {
+	    add_item_to_list(&buffer[11], &downloaders);
+	}
+	break;
 
-	} else if(!strncasecomp(buffer,"URL_DOMAIN_SUFFIXES:",20)) {
-		StrAllocCopy(URLDomainSuffixes, buffer+20);
+	case 'E':
+	if (!strncasecomp(buffer, "EMACS_KEYS_ALWAYS_ON:", 21)) {
+	    emacs_keys = is_true(buffer+21);
 
-	} else if(!strncasecomp(buffer,"INEWS:",6)) {
-		StrAllocCopy(inews_path,buffer+6);
-		if (*inews_path == '\0' || !strcasecomp(inews_path,"none"))
-		    no_newspost = TRUE;
-		else
-		    no_newspost = FALSE;
+	} else if (!strncasecomp(buffer, "ENABLE_SCROLLBACK:", 18)) {
+	    enable_scrollback = is_true(buffer+18);
+	}
+	break;
 
-	} else if(!strncasecomp(buffer,"SYSTEM_MAIL:",12)) {
-		StrAllocCopy(system_mail,buffer+12);
+	case 'F':
+	if (!strncasecomp(buffer, "finger_proxy:", 13)) {
+	    if (getenv("finger_proxy") == NULL) {
+#ifdef VMS
+		strcpy(temp, "finger_proxy");
+		Define_VMSLogical(temp, (char *)&buffer[13]);
+#else
+		strcpy(temp, "finger_proxy=");
+		StrAllocCopy(finger_proxy_putenv_cmd, temp);
+		StrAllocCat(finger_proxy_putenv_cmd, (char *)&buffer[13]);
+		putenv(finger_proxy_putenv_cmd);
+#endif /* VMS */
+	    }
 
+	} else if (!strncasecomp(buffer, "ftp_proxy:", 10)) {
+	    if (getenv("ftp_proxy") == NULL) {
 #ifdef VMS
-	} else if(!strncasecomp(buffer,"MAIL_ADRS:",10)) {
-		StrAllocCopy(mail_adrs,buffer+10);
+		strcpy(temp, "ftp_proxy");
+		Define_VMSLogical(temp, (char *)&buffer[10]);
+#else
+		strcpy(temp, "ftp_proxy=");
+		StrAllocCopy(ftp_proxy_putenv_cmd, temp);
+		StrAllocCat(ftp_proxy_putenv_cmd, (char *)&buffer[10]);
+		putenv(ftp_proxy_putenv_cmd);
 #endif /* VMS */
+	    }
+	}
+	break;
 
-	} else if(!strncasecomp(buffer,"PRINTER:",8)) {
-	        add_printer_to_list (&buffer[8],&printers);
+	case 'G':
+	if (!strncasecomp(buffer, "GLOBAL_EXTENSION_MAP:", 21)) {
+	    StrAllocCopy(global_extension_map, buffer+21);
 
-	} else if(!strncasecomp(buffer,"DOWNLOADER:",11)) {
-	        add_item_to_list(&buffer[11],&downloaders);
+	} else if (!strncasecomp(buffer, "GLOBAL_MAILCAP:", 15)) {
+	    StrAllocCopy(global_type_map, buffer+15);
 
-	} else if(!strncasecomp(buffer,"NNTPSERVER:",11)) {
-	    if(getenv("NNTPSERVER") == NULL) {
+	} else if (!strncasecomp(buffer, "gopher_proxy:", 13)) {
+	    if (getenv("gopher_proxy") == NULL) {
 #ifdef VMS
-		strcpy(temp, "NNTPSERVER");
-		Define_VMSLogical(temp, (char *)&buffer[11]);
+		strcpy(temp, "gopher_proxy");
+		Define_VMSLogical(temp, (char *)&buffer[13]);
 #else
-		strcpy(temp, "NNTPSERVER=");
-		StrAllocCopy(NNTPSERVER_putenv_cmd, temp);
-		StrAllocCat(NNTPSERVER_putenv_cmd, (char *)&buffer[11]);
-		putenv(NNTPSERVER_putenv_cmd);
+		strcpy(temp, "gopher_proxy=");
+		StrAllocCopy(gopher_proxy_putenv_cmd, temp);
+		StrAllocCat(gopher_proxy_putenv_cmd, (char *)&buffer[13]);
+		putenv(gopher_proxy_putenv_cmd);
 #endif /* VMS */
 	    }
 
-	} else if(!strncasecomp(buffer,"http_proxy:",11)) {
-	    if(getenv("http_proxy") == NULL) {
+	} else if (!strncasecomp(buffer, "GOTOBUFFER:", 11)) {
+	    goto_buffer = is_true(buffer+11);
+	}
+	break;
+
+	case 'H':
+	if (!strncasecomp(buffer, "HELPFILE:", 9)) {
+	    StrAllocCopy(helpfile, buffer+9);
+
+	} else if (!strncasecomp(buffer, "HISTORICAL_COMMENTS:", 20)) {
+	    historical_comments = is_true(buffer+20);
+
+	} else if (!strncasecomp(buffer, "http_proxy:", 11)) {
+	    if (getenv("http_proxy") == NULL) {
 #ifdef VMS
 		strcpy(temp, "http_proxy");
 		Define_VMSLogical(temp, (char *)&buffer[11]);
@@ -714,8 +639,8 @@ PUBLIC void read_cfg ARGS1(
 #endif /* VMS */
 	    }
 
-	} else if(!strncasecomp(buffer,"https_proxy:",12)) {
-	    if(getenv("https_proxy") == NULL) {
+	} else if (!strncasecomp(buffer, "https_proxy:", 12)) {
+	    if (getenv("https_proxy") == NULL) {
 #ifdef VMS
 		strcpy(temp, "https_proxy");
 		Define_VMSLogical(temp, (char *)&buffer[12]);
@@ -726,48 +651,159 @@ PUBLIC void read_cfg ARGS1(
 		putenv(https_proxy_putenv_cmd);
 #endif /* VMS */
 	    }
+	}
+	break;
 
-	} else if(!strncasecomp(buffer,"ftp_proxy:",10)) {
-	    if(getenv("ftp_proxy") == NULL) {
-#ifdef VMS
-		strcpy(temp, "ftp_proxy");
-		Define_VMSLogical(temp, (char *)&buffer[10]);
-#else
-		strcpy(temp, "ftp_proxy=");
-		StrAllocCopy(ftp_proxy_putenv_cmd, temp);
-		StrAllocCat(ftp_proxy_putenv_cmd, (char *)&buffer[10]);
-		putenv(ftp_proxy_putenv_cmd);
-#endif /* VMS */
+	case 'I':
+	if (!strncasecomp(buffer, "INEWS:", 6)) {
+	    StrAllocCopy(inews_path, buffer+6);
+	    if (*inews_path == '\0' || !strcasecomp(inews_path, "none"))
+		no_newspost = TRUE;
+	    else
+		no_newspost = FALSE;
+
+	} else if (!strncasecomp(buffer, "INFOSECS:", 9)) {
+	    strcpy(temp, buffer+9);
+	    for (i = 0; temp[i]; i++) {
+		if (!isdigit(temp[i])) {
+		    temp[i] = '\0';
+		    break;
+		}
 	    }
+	    if (temp[0])
+		InfoSecs = atoi(temp);
+	}
+	break;
 
-	} else if(!strncasecomp(buffer,"gopher_proxy:",13)) {
-	    if(getenv("gopher_proxy") == NULL) {
-#ifdef VMS
-		strcpy(temp, "gopher_proxy");
-		Define_VMSLogical(temp, (char *)&buffer[13]);
-#else
-		strcpy(temp, "gopher_proxy=");
-		StrAllocCopy(gopher_proxy_putenv_cmd, temp);
-		StrAllocCat(gopher_proxy_putenv_cmd, (char *)&buffer[13]);
-		putenv(gopher_proxy_putenv_cmd);
-#endif /* VMS */
+	case 'J':
+	if (!strncasecomp(buffer, "JUMP_PROMPT:", 12)) {
+	    StrAllocCopy(jumpprompt, buffer+12);
+
+	} else if (!strncasecomp(buffer, "JUMPBUFFER:", 11)) {
+	    jump_buffer = is_true(buffer+11);
+
+	} else if (!strncasecomp(buffer, "JUMPFILE:", 9)) {
+	    if (!LYJumpInit(buffer)) {
+		if (TRACE)
+		    fprintf(stderr, "Failed to register %s\n", buffer);
 	    }
+	}
+	break;
+
+	case 'K':
+        if (!strncasecomp(buffer, "KEYMAP:", 7)) {
+            char *key;
+            char *func;
+  
+            key = buffer + 7;
+            if ((func = strchr(key, ':')) != NULL)	{
+                *func++ = '\0';
+		/* Allow comments on the ends of key remapping lines. - DT */
+            	if (!remap(key, strtok(func, " \t\n#")))
+                    fprintf(stderr,
+		    	    "key remapping of %s to %s failed\n",key,func);
+		else if (!strcmp("TOGGLE_HELP", strtok(func, " \t\n#")))
+		    LYUseNoviceLineTwo = FALSE;
+	    }
+	}
+	break;
+
+	case 'L':
+	if (!strncasecomp(buffer, "LIST_NEWS_NUMBERS:", 18)) {
+		LYListNewsNumbers = is_true(buffer+18);
+
+	} else if (!strncasecomp(buffer, "LIST_NEWS_DATES:", 16)) {
+		LYListNewsDates = is_true(buffer+16);
+
+#ifndef VMS
+	} else if (!strncasecomp(buffer, "LIST_FORMAT:", 12)) {
+	    StrAllocCopy(list_format, buffer+12);
+#endif /* !VMS */
+
+	} else if (!strncasecomp(buffer, "LOCALHOST_ALIAS:", 16)) {
+	    LYAddLocalhostAlias(buffer+16);
+
+	} else if (!strncasecomp(buffer, "LOCAL_DOMAIN:", 13)) {
+	    StrAllocCopy(LYLocalDomain, buffer+13);
+
+#if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS)
+	} else if (!strncasecomp(buffer,
+			 "LOCAL_EXECUTION_LINKS_ALWAYS_ON:", 32)) {
+	    local_exec = is_true(buffer+32);
+
+	} else if (!strncasecomp(buffer,
+			 "LOCAL_EXECUTION_LINKS_ON_BUT_NOT_REMOTE:", 40)) {
+	    local_exec_on_local_files = is_true(buffer+40);
+#endif /* defined(EXEC_LINKS) || defined(EXEC_SCRIPTS) */
+
+#ifdef LYNXCGI_LINKS
+	} else if (!strncasecomp(buffer, "LYNXCGI_ENVIRONMENT:", 20)) {
+	    add_lynxcgi_environment(buffer+20);
+#endif /* LYNXCGI_LINKS */
+
+	} else if (!strncasecomp(buffer, "LYNX_HOST_NAME:", 15)) {
+	    StrAllocCopy(LYHostName, buffer+15);
+	}
+	break;
+
+	case 'M':
+	if (!strncasecomp(buffer, "MAIL_SYSTEM_ERROR_LOGGING:", 26)) {
+	    error_logging = is_true(buffer+26);
 
-	} else if(!strncasecomp(buffer,"cso_proxy:",10)) {
-	    if(getenv("cso_proxy") == NULL) {
 #ifdef VMS
-		strcpy(temp, "cso_proxy");
-		Define_VMSLogical(temp, (char *)&buffer[10]);
-#else
-		strcpy(temp, "cso_proxy=");
-		StrAllocCopy(cso_proxy_putenv_cmd, temp);
-		StrAllocCat(cso_proxy_putenv_cmd, (char *)&buffer[10]);
-		putenv(cso_proxy_putenv_cmd);
+	} else if (!strncasecomp(buffer, "MAIL_ADRS:", 10)) {
+	    StrAllocCopy(mail_adrs, buffer+10);
 #endif /* VMS */
+
+	} else if (!strncasecomp(buffer, "MAKE_LINKS_FOR_ALL_IMAGES:", 26)) {
+	    clickable_images = is_true(buffer+26);
+
+	} else if (!strncasecomp(buffer,
+				 "MAKE_PSEUDO_ALTS_FOR_INLINES:", 29)) {
+	    pseudo_inline_alts = is_true(buffer+29);
+
+	} else if (!strncasecomp(buffer, "MESSAGESECS:", 12)) {
+	    strcpy(temp, buffer+12);
+	    for (i = 0; temp[i]; i++) {
+		if (!isdigit(temp[i])) {
+		    temp[i] = '\0';
+		    break;
+		}
 	    }
+	    if (temp[0])
+		MessageSecs = atoi(temp);
+
+	} else if (!strncasecomp(buffer, "MINIMAL_COMMENTS:", 17)) {
+	    minimal_comments = is_true(buffer+17);
+
+	} else if (!strncasecomp(buffer, "MULTI_BOOKMARK_SUPPORT:", 23)) {
+	    LYMultiBookmarks = is_true(buffer+23);
+	}
+	break;
+
+	case 'N':
+	if (!strncasecomp(buffer, "NEWS_CHUNK_SIZE:", 16)) {
+		HTNewsChunkSize = atoi(buffer+16);
+		/*
+		 * If the new HTNewsChunkSize exceeds the maximum,
+		 * increase HTNewsMaxChunk to this size. - FM
+		 */
+		if (HTNewsChunkSize > HTNewsMaxChunk) {
+		    HTNewsMaxChunk = HTNewsChunkSize; 
+		}
 
-	} else if(!strncasecomp(buffer,"news_proxy:",11)) {
-	    if(getenv("news_proxy") == NULL) {
+	} else if (!strncasecomp(buffer, "NEWS_MAX_CHUNK:", 15)) {
+		HTNewsMaxChunk = atoi(buffer+15);
+		/*
+		 * If HTNewsChunkSize exceeds the new maximum,
+		 * reduce HTNewsChunkSize to this maximum. - FM
+		 */
+		if (HTNewsChunkSize > HTNewsMaxChunk) {
+		    HTNewsChunkSize = HTNewsMaxChunk;
+		}
+
+	} else if (!strncasecomp(buffer, "news_proxy:", 11)) {
+	    if (getenv("news_proxy") == NULL) {
 #ifdef VMS
 		strcpy(temp, "news_proxy");
 		Define_VMSLogical(temp, (char *)&buffer[11]);
@@ -779,21 +815,8 @@ PUBLIC void read_cfg ARGS1(
 #endif /* VMS */
 	    }
 
-	} else if(!strncasecomp(buffer,"snews_proxy:",12)) {
-	    if(getenv("snews_proxy") == NULL) {
-#ifdef VMS
-		strcpy(temp, "snews_proxy");
-		Define_VMSLogical(temp, (char *)&buffer[12]);
-#else
-		strcpy(temp, "snews_proxy=");
-		StrAllocCopy(snews_proxy_putenv_cmd, temp);
-		StrAllocCat(snews_proxy_putenv_cmd, (char *)&buffer[12]);
-		putenv(snews_proxy_putenv_cmd);
-#endif /* VMS */
-	    }
-
-	} else if(!strncasecomp(buffer,"nntp_proxy:",11)) {
-	    if(getenv("nntp_proxy") == NULL) {
+	} else if (!strncasecomp(buffer, "nntp_proxy:", 11)) {
+	    if (getenv("nntp_proxy") == NULL) {
 #ifdef VMS
 		strcpy(temp, "nntp_proxy");
 		Define_VMSLogical(temp, (char *)&buffer[11]);
@@ -805,34 +828,30 @@ PUBLIC void read_cfg ARGS1(
 #endif /* VMS */
 	    }
 
-	} else if(!strncasecomp(buffer,"wais_proxy:",11)) {
-	    if(getenv("wais_proxy") == NULL) {
+	} else if (!strncasecomp(buffer, "NNTPSERVER:", 11)) {
+	    if (getenv("NNTPSERVER") == NULL) {
 #ifdef VMS
-		strcpy(temp, "wais_proxy");
+		strcpy(temp, "NNTPSERVER");
 		Define_VMSLogical(temp, (char *)&buffer[11]);
 #else
-		strcpy(temp, "wais_proxy=");
-		StrAllocCopy(wais_proxy_putenv_cmd, temp);
-		StrAllocCat(wais_proxy_putenv_cmd, (char *)&buffer[11]);
-		putenv(wais_proxy_putenv_cmd);
+		strcpy(temp, "NNTPSERVER=");
+		StrAllocCopy(NNTPSERVER_putenv_cmd, temp);
+		StrAllocCat(NNTPSERVER_putenv_cmd, (char *)&buffer[11]);
+		putenv(NNTPSERVER_putenv_cmd);
 #endif /* VMS */
 	    }
 
-	} else if(!strncasecomp(buffer,"finger_proxy:",13)) {
-	    if(getenv("finger_proxy") == NULL) {
-#ifdef VMS
-		strcpy(temp, "finger_proxy");
-		Define_VMSLogical(temp, (char *)&buffer[13]);
-#else
-		strcpy(temp, "finger_proxy=");
-		StrAllocCopy(finger_proxy_putenv_cmd, temp);
-		StrAllocCat(finger_proxy_putenv_cmd, (char *)&buffer[13]);
-		putenv(finger_proxy_putenv_cmd);
-#endif /* VMS */
-	    }
+	} else if (!strncasecomp(buffer, "NO_DOT_FILES:", 13)) {
+	    no_dotfiles = is_true(buffer+13);
 
-	} else if(!strncasecomp(buffer,"no_proxy:",9)) {
-	    if(getenv("no_proxy") == NULL) {
+	} else if (!strncasecomp(buffer, "NO_FILE_REFERER:", 16)) {
+	    no_filereferer = is_true(buffer+16);
+
+	} else if (!strncasecomp(buffer, "NO_FROM_HEADER:", 15)) {
+	    LYNoFromHeader = is_true(buffer+15);
+
+	} else if (!strncasecomp(buffer, "no_proxy:", 9)) {
+	    if (getenv("no_proxy") == NULL) {
 #ifdef VMS
 		strcpy(temp, "no_proxy");
 		Define_VMSLogical(temp, (char *)&buffer[9]);
@@ -844,159 +863,221 @@ PUBLIC void read_cfg ARGS1(
 #endif /* VMS */
 	    }
 
-#ifdef EXEC_LINKS
-	} else if(!strncasecomp(buffer,"TRUSTED_EXEC:",13)) {
-		add_trusted(&buffer[13], EXEC_PATH); /* Add exec path */
+	} else if (!strncasecomp(buffer, "NO_REFERER_HEADER:", 18)) {
+	    LYNoRefererHeader = is_true(buffer+18);
+	}
+	break;
 
-	} else if(!strncasecomp(buffer,"ALWAYS_TRUSTED_EXEC:",20)) {
-		add_trusted(&buffer[20], ALWAYS_EXEC_PATH); /* Add exec path */
-#endif /* EXEC_LINKS */
+	case 'P':
+	if (!strncasecomp(buffer, "PERSONAL_MAILCAP:", 17)) {
+            StrAllocCopy(personal_type_map, buffer+17);
 
-#ifdef LYNXCGI_LINKS
-	} else if(!strncasecomp(buffer,"TRUSTED_LYNXCGI:",16)) {
-		add_trusted(&buffer[16], CGI_PATH); /* Add CGI path */
+        } else if (!strncasecomp(buffer, "PERSONAL_EXTENSION_MAP:", 23)) {
+            StrAllocCopy(personal_extension_map, buffer+23);
 
-	} else if(!strncasecomp(buffer,"LYNXCGI_ENVIRONMENT:",20)) {
-		add_lynxcgi_environment(buffer+20);
-#endif /* LYNXCGI_LINKS */
+	} else if (!strncasecomp(buffer, "PREFERRED_CHARSET:", 18)) {
+	    StrAllocCopy(pref_charset, buffer+18);
 
-#ifdef DIRED_SUPPORT
-	} else if(!strncasecomp(buffer,"UPLOADER:",9)) {
-	        add_item_to_list(&buffer[9],&uploaders);
+	} else if (!strncasecomp(buffer, "PREFERRED_LANGUAGE:", 19)) {
+	    StrAllocCopy(language, buffer+19);
 
-	} else if(!strncasecomp(buffer,"DIRED_MENU:",11)) {
-	        add_menu_item(&buffer[11]);
-#endif /* DIRED_SUPPORT */
+	} else if (!strncasecomp(buffer, "PRINTER:", 8)) {
+	    add_printer_to_list(&buffer[8], &printers);
+	}
+	break;
 
-	} else if(!strncasecomp(buffer,"LYNX_HOST_NAME:",15)) {
-		StrAllocCopy(LYHostName,buffer+15);
+	case 'S':
+	if (!strncasecomp(buffer, "SAVE_SPACE:", 11)) {
+	    StrAllocCopy(lynx_save_space, buffer+11);
 
-	} else if(!strncasecomp(buffer,"LOCALHOST_ALIAS:",16)) {
-	        LYAddLocalhostAlias(buffer+16);
+	} else if (!strncasecomp(buffer, "SCAN_FOR_BURIED_NEWS_REFS:", 26)) {
+	    scan_for_buried_news_references = is_true(buffer+26);
 
-	} else if(!strncasecomp(buffer,"LOCAL_DOMAIN:",13)) {
-		StrAllocCopy(LYLocalDomain,buffer+13);
+	} else if (!strncasecomp(buffer, "SET_COOKIES:", 12)) {
+	    LYSetCookies = is_true(buffer+12);
 
-	} else if(!strncasecomp(buffer,"SUBSTITUTE_UNDERSCORES:",23)) {
-		use_underscore = is_true(buffer+23);
+	} else if (!strncasecomp(buffer, "SHOW_CURSOR:", 12)) {
+	    LYShowCursor = is_true(buffer+12);
 
-	} else if(!strncasecomp(buffer,"HISTORICAL_COMMENTS:",20)) {
-		historical_comments = is_true(buffer+20);
+	} else if (!strncasecomp(buffer, "snews_proxy:", 12)) {
+	    if (getenv("snews_proxy") == NULL) {
+#ifdef VMS
+		strcpy(temp, "snews_proxy");
+		Define_VMSLogical(temp, (char *)&buffer[12]);
+#else
+		strcpy(temp, "snews_proxy=");
+		StrAllocCopy(snews_proxy_putenv_cmd, temp);
+		StrAllocCat(snews_proxy_putenv_cmd, (char *)&buffer[12]);
+		putenv(snews_proxy_putenv_cmd);
+#endif /* VMS */
+	    }
 
-	} else if(!strncasecomp(buffer,"MINIMAL_COMMENTS:",17)) {
-		minimal_comments = is_true(buffer+17);
+	} else if (!strncasecomp(buffer, "SOFT_DQUOTES:", 13)) {
+	    soft_dquotes = is_true(buffer+13);
 
-	} else if(!strncasecomp(buffer,"SOFT_DQUOTES:",13)) {
-		soft_dquotes = is_true(buffer+13);
+	} else if (!strncasecomp(buffer, "STARTFILE:", 10)) {
+	    StrAllocCopy(startfile, buffer+10);
 
-	} else if(!strncasecomp(buffer,"ENABLE_SCROLLBACK:",18)) {
-		enable_scrollback = is_true(buffer+18);
+	} else if (!strncasecomp(buffer, "SUBSTITUTE_UNDERSCORES:", 23)) {
+	    use_underscore = is_true(buffer+23);
 
-	} else if(!strncasecomp(buffer,"SCAN_FOR_BURIED_NEWS_REFS:",26)) {
-		scan_for_buried_news_references = is_true(buffer+26);
+        } else if (!strncasecomp(buffer, "SUFFIX:", 7)) {
+	    char *extention;
+	    char *mime_type;
 
-	} else if(!strncasecomp(buffer,"INFOSECS:",9)) {
-		strcpy(temp, buffer+9);
-		for (i = 0; temp[i]; i++) {
-		    if (!isdigit(temp[i])) {
-		        temp[i] = '\0';
-			break;
-		    }
-		}
-		if (temp[0])
-		    InfoSecs = atoi(temp);
-
-	} else if(!strncasecomp(buffer,"MESSAGESECS:",12)) {
-		strcpy(temp, buffer+12);
-		for (i = 0; temp[i]; i++) {
-		    if (!isdigit(temp[i])) {
-		        temp[i] = '\0';
-			break;
-		    }
-		}
-		if (temp[0])
-		    MessageSecs = atoi(temp);
-
-	} else if(!strncasecomp(buffer,"ALERTSECS:",10)) {
-		strcpy(temp, buffer+10);
-		for (i = 0; temp[i]; i++) {
-		    if (!isdigit(temp[i])) {
-		        temp[i] = '\0';
-			break;
+	    if (strlen(buffer) > 9) {
+	        extention = buffer + 7;
+	        if ((mime_type = strchr(extention, ':')) != NULL) {
+		    *mime_type++ = '\0';
+		    for (i = 0, j = 0; mime_type[i]; i++) {
+		        if (mime_type[i] != ' ') {
+		            mime_type[j++] = TOLOWER(mime_type[i]);
+			}
 		    }
+		    mime_type[j] = '\0';
+		    if (strstr(mime_type, "tex") != NULL ||
+		        strstr(mime_type, "postscript") != NULL ||
+			strstr(mime_type, "sh") != NULL ||
+			strstr(mime_type, "troff") != NULL ||
+			strstr(mime_type, "rtf") != NULL)
+			HTSetSuffix(extention, mime_type, "8bit", 1.0);
+		    else
+		        HTSetSuffix(extention, mime_type, "binary", 1.0);
 		}
-		if (temp[0])
-		    AlertSecs = atoi(temp);
+	    }
 
-#ifndef VMS
-	} else if(!strncasecomp(buffer,"LIST_FORMAT:",12)) {
-		StrAllocCopy(list_format, buffer+12);
-#endif /* !VMS */
+ 	} else if (!strncasecomp(buffer, "SYSTEM_EDITOR:", 14)) {
+	    StrAllocCopy(editor, buffer+14);
+ 	    system_editor = TRUE;
 
-	} else if(!strncasecomp(buffer,"ALWAYS_RESUBMIT_POSTS:",22)) {
-		LYresubmit_posts = is_true(buffer+22);
+	} else if (!strncasecomp(buffer, "SYSTEM_MAIL:", 12)) {
+	    StrAllocCopy(system_mail, buffer+12);
+	}
+	break;
 
-	} else if(!strncasecomp(buffer,"SAVE_SPACE:",11)) {
-		StrAllocCopy(lynx_save_space, buffer+11);
+	case 'T':
+#ifdef EXEC_LINKS
+	if (!strncasecomp(buffer, "TRUSTED_EXEC:", 13)) {
+	    add_trusted(&buffer[13], EXEC_PATH); /* Add exec path */
+	}
+#endif /* EXEC_LINKS */
 
-#ifdef USE_SLANG
-	} else if (!strncasecomp(buffer, "COLOR:", 6)) {
-		parse_color(buffer + 6);
-#endif /* USE_SLANG */
+#ifdef LYNXCGI_LINKS
+	if (!strncasecomp(buffer, "TRUSTED_LYNXCGI:", 16)) {
+	    add_trusted(&buffer[16], CGI_PATH); /* Add CGI path */
+	}
+#endif /* LYNXCGI_LINKS */
+	break;
 
-	} else if (!strncasecomp(buffer, "LIST_NEWS_NUMBERS:", 18)) {
-		LYListNewsNumbers = is_true(buffer+18);
+	case 'U':
+	if (!strncasecomp(buffer, "URL_DOMAIN_PREFIXES:", 20)) {
+	    StrAllocCopy(URLDomainPrefixes, buffer+20);
 
-	} else if (!strncasecomp(buffer, "LIST_NEWS_DATES:", 16)) {
-		LYListNewsDates = is_true(buffer+16);
+	} else if (!strncasecomp(buffer, "URL_DOMAIN_SUFFIXES:", 20)) {
+	    StrAllocCopy(URLDomainSuffixes, buffer+20);
 
-	} else if (!strncasecomp(buffer, "NEWS_CHUNK_SIZE:", 16)) {
-		HTNewsChunkSize = atoi(buffer+16);
-		/*
-		 * If the new HTNewsChunkSize exceeds the maximum,
-		 * increase HTNewsMaxChunk to this size. - FM
-		 */
-		if (HTNewsChunkSize > HTNewsMaxChunk) {
-		    HTNewsMaxChunk = HTNewsChunkSize; 
-		}
+#ifdef DIRED_SUPPORT
+	} else if (!strncasecomp(buffer, "UPLOADER:", 9)) {
+	    add_item_to_list(&buffer[9], &uploaders);
+#endif /* DIRED_SUPPORT */
 
-	} else if (!strncasecomp(buffer, "NEWS_MAX_CHUNK:", 15)) {
-		HTNewsMaxChunk = atoi(buffer+15);
-		/*
-		 * If HTNewsChunkSize exceeds the new maximum,
-		 * reduce HTNewsChunkSize to this maximum. - FM
-		 */
-		if (HTNewsChunkSize > HTNewsMaxChunk) {
-		    HTNewsChunkSize = HTNewsMaxChunk;
-		}
+#ifdef VMS
+	} else if (!strncasecomp(buffer, "USE_FIXED_RECORDS:", 18)) {
+	    UseFixedRecords = is_true(buffer+18);
+#endif /* VMS */
 
-	} else if(!strncasecomp(buffer,"USE_SELECT_POPUPS:",17)) {
-		LYSelectPopups = is_true(buffer+17);
+	} else if (!strncasecomp(buffer, "USE_SELECT_POPUPS:", 18)) {
+		LYSelectPopups = is_true(buffer+18);
+	}
+	break;
 
-#if defined(VMS) && defined(VAXC) && !defined(__DECC)
-	} else if (!strncasecomp(buffer, "DEFAULT_VIRTUAL_MEMORY_SIZE:", 28)) {
-		HTVirtualMemorySize = atoi(buffer+28);
-#endif /* VMS && VAXC && !__DECC */
+	case 'V':
+	if (!strncasecomp(buffer, "VI_KEYS_ALWAYS_ON:", 18)) {
+	    vi_keys = is_true(buffer+18);
 
-	} else if (!strncasecomp(buffer, "DEFAULT_CACHE_SIZE:", 19)) {
-		HTCacheSize = atoi(buffer+19);
+        } else if (!strncasecomp(buffer, "VIEWER:", 7)) {
+	    char *mime_type;
+	    char *viewer;
+	    char *environment;
+
+	    if (strlen(buffer) > 9) {
+	        mime_type = buffer + 7;
+	        if ((viewer = strchr(mime_type, ':')) != NULL) {
+		    *viewer++ = '\0';
+		    for (i = 0, j = 0; mime_type[i]; i++) {
+		        if (mime_type[i] != ' ') {
+		            mime_type[j++] = TOLOWER(mime_type[i]);
+			}
+		    }
+		    mime_type[j] = '\0';
+		    environment = strrchr(viewer, ':');
+		    if ((environment != NULL) &&
+		        (strlen(viewer) > 1) && *(environment-1) != '\\') {
+			*environment++ = '\0';
+			remove_backslashes(viewer);
+			/*
+			 *  If environment equals xwindows then only
+			 *  assign the presentation if there is a display
+			 *  variable.
+			 */
+			if (!strcasecomp(environment,"XWINDOWS")) {
+			    if (getenv(DISPLAY)) 
+		      		HTSetPresentation(mime_type, viewer,
+						  1.0, 3.0, 0.0, 0);
+			} else if (!strcasecomp(environment,"NON_XWINDOWS")) {
+			    if (!getenv(DISPLAY)) 
+		      		HTSetPresentation(mime_type, viewer, 
+						  1.0, 3.0, 0.0, 0);
+			} else {
+		            HTSetPresentation(mime_type, viewer,
+						  1.0, 3.0, 0.0, 0);
+			}
+		    } else {
+		        remove_backslashes(viewer);
+		        HTSetPresentation(mime_type, viewer,
+						  1.0, 3.0, 0.0, 0);
+		    }
+		}
+	    }
+	}
+	break;
+
+	case 'W':
+	if (!strncasecomp(buffer, "wais_proxy:", 11)) {
+	    if (getenv("wais_proxy") == NULL) {
+#ifdef VMS
+		strcpy(temp, "wais_proxy");
+		Define_VMSLogical(temp, (char *)&buffer[11]);
+#else
+		strcpy(temp, "wais_proxy=");
+		StrAllocCopy(wais_proxy_putenv_cmd, temp);
+		StrAllocCat(wais_proxy_putenv_cmd, (char *)&buffer[11]);
+		putenv(wais_proxy_putenv_cmd);
+#endif /* VMS */
+	    }
+	}
+	break;
+
+	default:
+	break;
 
-        }  /* end of Huge if */
+        }  /* end of Huge switch */
     } /* end of while */
     fclose(fp);
 
     /*
-     * If any DOWNLOADER: commands have always_enabled set (:TRUE),
-     * make override_no_download TRUE, so that other restriction
-     * settings will not block presentation of a download menu
-     * with those always_enabled options still available. - FM
+     *  If any DOWNLOADER: commands have always_enabled set (:TRUE),
+     *  make override_no_download TRUE, so that other restriction
+     *  settings will not block presentation of a download menu
+     *  with those always_enabled options still available. - FM
      */
     if (downloaders != NULL) {
     	int count;
 	lynx_html_item_type *cur_download;
 
-        for(count=0, cur_download=downloaders; cur_download != NULL; 
-			    cur_download = cur_download->next, count++) {
+        for (count = 0, cur_download = downloaders;
+	     cur_download != NULL; 
+	     cur_download = cur_download->next, count++) {
 	    if (cur_download->always_enabled) {
 	        override_no_download = TRUE;
 		break;
diff --git a/src/LYShowInfo.c b/src/LYShowInfo.c
index 9566967e..d2ffc786 100644
--- a/src/LYShowInfo.c
+++ b/src/LYShowInfo.c
@@ -247,6 +247,10 @@ PUBLIC int showinfo ARGS4(
     fprintf(fp0,
     	    "<dt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>URL:</em> %s\n", Address);
 
+    if (HTLoadedDocumentCharset())
+        fprintf(fp0, "<dt><em>&nbsp;Charset:</em> %s\n",
+		     HTLoadedDocumentCharset());
+
     if ((cp = HText_getServer()) != NULL && *cp != '\0')
         fprintf(fp0, "<dt><em>&nbsp;&nbsp;Server:</em> %s\n", cp);
 
diff --git a/src/LYStructs.h b/src/LYStructs.h
index 6ef5d8a7..12ad43be 100644
--- a/src/LYStructs.h
+++ b/src/LYStructs.h
@@ -30,10 +30,11 @@ typedef struct _document {
    char * address;
    char * post_data;
    char * post_content_type;
-   int    link;
-   int    line;
+   BOOL   safe;
    BOOL   isHEAD;
    char * bookmark;
+   int    link;
+   int    line;
 } document;
 
 #ifndef HTFORMS_H
@@ -45,12 +46,18 @@ typedef struct _histstruct {
     char * address;
     char * post_data;
     char * post_content_type;
+    BOOL   safe;
+    char * bookmark;
+    BOOL   isHEAD;
     int    link;
     int    page;
-    BOOL   isHEAD;
-    char * bookmark;
 } histstruct;
 
+typedef struct _VisitedLink {
+    char * title;
+    char * address;
+} VisitedLink;
+
 extern histstruct history[MAXHIST];
 extern int nhist;
 
diff --git a/src/LYTraversal.c b/src/LYTraversal.c
index a12c8ebe..255d8dae 100644
--- a/src/LYTraversal.c
+++ b/src/LYTraversal.c
@@ -100,18 +100,12 @@ PUBLIC void dump_traversal_history NOARGS
     int x;
     FILE *ifp;
 
+    if (nhist <= 0)
+        return;
+
     if ((ifp = fopen(TRAVERSE_FILE,"a+")) == NULL) {
         perror("unable to open traversal file");
-	(void) signal(SIGHUP, SIG_DFL);
-	(void) signal(SIGTERM, SIG_DFL);
-#ifndef VMS
-	(void) signal(SIGINT, SIG_DFL);
-#endif /* !VMS */
-#ifdef SIGTSTP
-	if (no_suspend)
-	    (void) signal(SIGTSTP,SIG_DFL);
-#endif /* SIGTSTP */
-        exit(-1);
+	return;
     }
 
     fprintf(ifp, "\n\nTRAVERSAL WAS INTERUPTED\n\n\
diff --git a/src/LYUtils.c b/src/LYUtils.c
index d1cf11f7..c003579e 100644
--- a/src/LYUtils.c
+++ b/src/LYUtils.c
@@ -73,7 +73,9 @@ PUBLIC  HTList * sug_filenames = NULL;		/* Suggested filenames   */
 /*
  * highlight (or unhighlight) a given link
  */
-PUBLIC void highlight ARGS2(int,flag, int,cur)
+PUBLIC void highlight ARGS2(
+	int,		flag,
+	int,		cur)
 {
     char buffer[200];
     int i;
@@ -109,7 +111,8 @@ PUBLIC void highlight ARGS2(int,flag, int,cur)
 	    int avail_space = (LYcols-links[cur].lx)-1;
 
 	    LYstrncpy(buffer,
-	    	      links[cur].hightext, 
+	    	      (links[cur].hightext ?
+		       links[cur].hightext : ""), 
 		      (avail_space > links[cur].form->size ? 
 				      links[cur].form->size : avail_space));
 	    addstr(buffer);  
@@ -123,7 +126,10 @@ PUBLIC void highlight ARGS2(int,flag, int,cur)
 	    /* copy into the buffer only what will fit within the
 	     * width of the screen
 	     */
-	    LYstrncpy(buffer,links[cur].hightext, LYcols-links[cur].lx-1);
+	    LYstrncpy(buffer,
+	    	      (links[cur].hightext ?
+		       links[cur].hightext : ""),
+		      LYcols-links[cur].lx-1);
 	    addstr(buffer);  
 	}
 
@@ -151,7 +157,7 @@ PUBLIC void highlight ARGS2(int,flag, int,cur)
 	        start_bold();
 	    }
 
-	    for (i=0; (tmp[0] = links[cur].hightext2[i]) != '\0' &&
+	    for (i = 0; (tmp[0] = links[cur].hightext2[i]) != '\0' &&
 	    	      i+links[cur].hightext2_offset < LYcols; i++) {
 		if (!IsSpecialAttrChar(links[cur].hightext2[i])) {
 		    /* For CJK strings, by Masanobu Kimura */
@@ -193,7 +199,8 @@ PUBLIC void highlight ARGS2(int,flag, int,cur)
  * free_and_clear will free a pointer if it is non-zero and
  * then set it to zero
  */
-PUBLIC void free_and_clear ARGS1(char **,pointer)
+PUBLIC void free_and_clear ARGS1(
+	char **,	pointer)
 {
     if (*pointer) {
 	free(*pointer);
@@ -205,7 +212,8 @@ PUBLIC void free_and_clear ARGS1(char **,pointer)
 /*
  * Collapse (REMOVE) all spaces in the string. 
  */
-PUBLIC void collapse_spaces ARGS1(char *,string)
+PUBLIC void collapse_spaces ARGS1(
+	char *,		string)
 {
     int i=0;
     int j=0;
@@ -214,7 +222,7 @@ PUBLIC void collapse_spaces ARGS1(char *,string)
         return;
 
     for (; string[i] != '\0'; i++) 
-	if (!isspace(string[i])) 
+	if (!isspace((unsigned char)string[i])) 
 	    string[j++] = string[i];
 
     string[j] = '\0';  /* terminate */
@@ -226,7 +234,8 @@ PUBLIC void collapse_spaces ARGS1(char *,string)
  * (ignore newlines if the preceding character is a space) and convert
  * tabs to single spaces (but don't ignore any explicit tabs or spaces).
  */
-PUBLIC void convert_to_spaces ARGS1(char *,string)
+PUBLIC void convert_to_spaces ARGS1(
+	char *,		string)
 {
     char *s = string;
     char *ns = string;
@@ -263,11 +272,26 @@ PUBLIC void convert_to_spaces ARGS1(char *,string)
 }
 
 /*
+ *  Strip trailing slashes from directory paths.
+ */
+PUBLIC char * strip_trailing_slash ARGS1(
+	char *,		dirname)
+{
+    int i;
+
+    i = strlen(dirname) - 1;
+    while (i >= 0 && dirname[i] == '/')
+        dirname[i--] = '\0';
+    return(dirname);
+}
+
+/*
  * display (or hide) the status line
  */
 BOOLEAN mustshow = FALSE;
 
-PUBLIC void statusline ARGS1(char *,text)
+PUBLIC void statusline ARGS1(
+	char *,		text)
 {
     char buffer[256];
     unsigned char *temp = NULL;
@@ -303,7 +327,7 @@ PUBLIC void statusline ARGS1(char *,text)
     if ((buffer[0] != '\0') &&
         (LYHaveCJKCharacterSet)) {
         /*
-	 *  Translate or filter any escape sequences.
+	 *  Translate or filter any escape sequences. - FM
 	 */
 	if ((temp = (unsigned char *)calloc(1, strlen(text) + 1)) == NULL)
 	    outofmem(__FILE__, "statusline");
@@ -321,7 +345,7 @@ PUBLIC void statusline ARGS1(char *,text)
 	}
 
         /*
-	 *  Deal with any newlines or tabs in the string.
+	 *  Deal with any newlines or tabs in the string. - FM
 	 */
 	convert_to_spaces((char *)temp);
 
@@ -356,26 +380,34 @@ PUBLIC void statusline ARGS1(char *,text)
 	}
 	buffer[len] = '\0';
         /*
-	 *  Deal with any newlines or tabs in the string.
+	 *  Deal with any newlines or tabs in the string. - FM
 	 */
 	convert_to_spaces(buffer);
     }
 
     /*
-     *  Move to the statusline window and output the text highlighted.
+     *  Move to the desired statusline window and
+     *  output the text highlighted. - FM
      */
-    if (user_mode == NOVICE_MODE)
-        move(LYlines-3,0);
-    else
-        move(LYlines-1,0);
+    if (LYStatusLine >= 0) {
+        if (LYStatusLine < LYlines-1) {
+	    move(LYStatusLine, 0);
+	} else {
+	    move(LYlines-1, 0);
+	}
+    } else if (user_mode == NOVICE_MODE) {
+        move(LYlines-3, 0);
+    } else {
+        move(LYlines-1, 0);
+    }
     clrtoeol();
     if (text != NULL) {
 	start_reverse();
 	addstr(buffer);
 	stop_reverse();
     }
-
     refresh();
+
     return;
 }
 
@@ -400,7 +432,8 @@ PUBLIC void toggle_novice_line NOARGS
 	return;
 }
 
-PUBLIC void noviceline ARGS1(int,more)
+PUBLIC void noviceline ARGS1(
+	int,		more)
 {
 
     if (dump_output_immediately)
@@ -534,10 +567,11 @@ PUBLIC int HTCheckForInterrupt NOARGS
  * A file URL for a remote host is an obsolete ftp URL.
  * Return YES only if we're certain it's a local file. - FM
  */
-PUBLIC BOOLEAN LYisLocalFile ARGS1(char *,filename)
+PUBLIC BOOLEAN LYisLocalFile ARGS1(
+	char *,		filename)
 {
-    char *host=NULL;
-    char *access=NULL;
+    char *host = NULL;
+    char *access = NULL;
     char *cp;
 
     if (!filename)
@@ -576,9 +610,10 @@ PUBLIC BOOLEAN LYisLocalFile ARGS1(char *,filename)
  * Utility for checking URLs with a host field.
  * Return YES only if we're certain it's the local host. - FM
  */
-PUBLIC BOOLEAN LYisLocalHost ARGS1(char *,filename)
+PUBLIC BOOLEAN LYisLocalHost ARGS1(
+	char *,		filename)
 {
-    char *host=NULL;
+    char *host = NULL;
     char *cp;
 
     if (!filename)
@@ -590,7 +625,7 @@ PUBLIC BOOLEAN LYisLocalHost ARGS1(char *,filename)
 	return NO;
     }
 
-    if ((cp=strchr(host, ':')) != NULL)
+    if ((cp = strchr(host, ':')) != NULL)
         *cp = '\0';
 
 #ifdef VMS
@@ -632,7 +667,8 @@ PUBLIC void LYLocalhostAliases_free NOARGS
 /* 
  * Utility for listing hosts to be treated as local aliases. - FM
  */
-PUBLIC void LYAddLocalhostAlias ARGS1(char *, alias)
+PUBLIC void LYAddLocalhostAlias ARGS1(
+	char *,		alias)
 {
     char *LocalAlias;
 
@@ -656,9 +692,10 @@ PUBLIC void LYAddLocalhostAlias ARGS1(char *, alias)
  * Utility for checking URLs with a host field.
  * Return YES only if we've listed the host as a local alias. - FM
  */
-PUBLIC BOOLEAN LYisLocalAlias ARGS1(char *,filename)
+PUBLIC BOOLEAN LYisLocalAlias ARGS1(
+	char *,		filename)
 {
-    char *host=NULL;
+    char *host = NULL;
     char *alias;
     char *cp;
     HTList *cur = localhost_aliases;
@@ -672,7 +709,7 @@ PUBLIC BOOLEAN LYisLocalAlias ARGS1(char *,filename)
 	return NO;
     }
 
-    if ((cp=strchr(host, ':')) != NULL)
+    if ((cp = strchr(host, ':')) != NULL)
         *cp = '\0';
 
     while (NULL != (alias = (char *)HTList_nextObject(cur))) {
@@ -701,8 +738,10 @@ PUBLIC BOOLEAN LYisLocalAlias ARGS1(char *,filename)
 **  it returns UNKNOWN_URL_TYPE.  Otherwise, it returns
 **  0 (not a URL). - FM
 */
-PUBLIC int LYCheckForProxyURL ARGS1(char *, filename) {
-    char *cp=filename;
+PUBLIC int LYCheckForProxyURL ARGS1(
+	char *,		filename)
+{
+    char *cp = filename;
     char *cp1;
     char *cp2 = NULL;
 
@@ -713,14 +752,14 @@ PUBLIC int LYCheckForProxyURL ARGS1(char *, filename) {
         return(0);
 
     /* kill beginning spaces */
-    while (isspace(*cp))
+    while (isspace((unsigned char)*cp))
         cp++;
 
     /*
      * Check for a colon, and if present,
      * see if we have proxying set up.
      */
-    if ((cp1=strchr((cp+1), ':')) != NULL) {
+    if ((cp1 = strchr((cp+1), ':')) != NULL) {
 	*cp1 = '\0';
 	StrAllocCopy(cp2, cp);
 	*cp1 = ':';
@@ -731,8 +770,8 @@ PUBLIC int LYCheckForProxyURL ARGS1(char *, filename) {
 	}
 	FREE(cp2);
 	cp1++;
-	if (isdigit(*cp1)) {
-	    while (*cp1 && isdigit(*cp1))
+	if (isdigit((unsigned char)*cp1)) {
+	    while (*cp1 && isdigit((unsigned char)*cp1))
 	        cp1++;
 	    if (*cp1 && *cp1 != '/')
 	        return(UNKNOWN_URL_TYPE);
@@ -754,7 +793,8 @@ PUBLIC int LYCheckForProxyURL ARGS1(char *, filename) {
 **  Chains to LYCheckForProxyURL() if a colon
 **  is present but the type is not recognized.
 */
-PUBLIC int is_url ARGS1(char *,filename)
+PUBLIC int is_url ARGS1(
+	char *,		filename)
 {
     char *cp = filename;
     char *cp1;
@@ -775,7 +815,7 @@ PUBLIC int is_url ARGS1(char *,filename)
     /*
      *  Kill beginning spaces.
      */
-    while (isspace(*cp))
+    while (isspace((unsigned char)*cp))
         cp++;
 
     if (!strncasecomp(cp, "news:", 5)) {
@@ -785,6 +825,13 @@ PUBLIC int is_url ARGS1(char *,filename)
 	}
 	return(NEWS_URL_TYPE);
 
+    } else if (!strncasecomp(cp, "nntp:", 5)) {
+        if (strncmp(cp, "nntp", 4)) {
+	    for (i = 0; i < 4; i++)
+	        cp[i] = TOLOWER(cp[i]);
+	}
+	return(NNTP_URL_TYPE);
+
     } else if (!strncasecomp(cp, "snews:", 6)) {
         if (strncmp(cp, "snews", 5)) {
 	    for (i = 0; i < 5; i++)
@@ -799,6 +846,19 @@ PUBLIC int is_url ARGS1(char *,filename)
 	}
 	return(MAILTO_URL_TYPE);
 
+    } else if (!strncasecomp(cp, "file:", 5)) {
+        if (strncmp(cp, "file", 4)) {
+	    for (i = 0; i < 4; i++)
+	        cp[i] = TOLOWER(cp[i]);
+	}
+        if (LYisLocalFile(cp)) {
+	    return(FILE_URL_TYPE);
+	} else if (cp[5] == '/' && cp[6] == '/') {
+	    return(FTP_URL_TYPE);
+	} else {
+	    return(0);
+	}
+
     } else if (!strncasecomp(cp, "data:", 5)) {
         if (strncmp(cp, "data", 4)) {
 	    for (i = 0; i < 4; i++)
@@ -920,9 +980,19 @@ PUBLIC int is_url ARGS1(char *,filename)
 	}
 	return(LYNXIMGMAP_URL_TYPE);
 
-    } else if (strstr((cp+3), ":/") == NULL) {  
+    } else if (!strncasecomp(cp, "LYNXCOOKIE:", 11)) {
 	/*
-	 *  If it doesn't contain ":/", and it's not one of the
+	 *  Special Internal Lynx type.
+	 */
+	if (strncmp(cp, "LYNXCOOKIE", 10)) {
+	    for (i = 0; i < 10; i++)
+	        cp[i] = TOUPPER(cp[i]);
+	}
+	return(LYNXCOOKIE_URL_TYPE);
+
+    } else if (strstr((cp+3), "://") == NULL) {  
+	/*
+	 *  If it doesn't contain "://", and it's not one of the
 	 *  the above, it can't be a URL with a scheme we know,
 	 *  so check if it's an unknown scheme for which proxying
 	 *  has been set up. - FM
@@ -943,25 +1013,6 @@ PUBLIC int is_url ARGS1(char *,filename)
 	}
 	return(HTTP_URL_TYPE);
 
-    } else if (!strncasecomp(cp, "file:", 5)) {
-        if (strncmp(cp, "file", 4)) {
-	    for (i = 0; i < 4; i++)
-	        cp[i] = TOLOWER(cp[i]);
-	}
-        /*
-	 *  We won't expend the overhead here of
-	 *  determining whether it's really an
-	 *  ftp URL unless we are restricting
-	 *  ftp access, in which case getfile()
-	 *  needs to know in order to issue an
-	 *  appropriate statusline message and
-	 *  and return NULLFILE.
-	 */
-        if ((ftp_ok) || LYisLocalFile(cp))
-	    return(FILE_URL_TYPE);
-	else
-	    return(FTP_URL_TYPE);
-
     } else if (!strncasecomp(cp, "gopher:", 7)) {
         if (strncmp(cp, "gopher", 6)) {
 	    for (i = 0; i < 6; i++)
@@ -1017,13 +1068,6 @@ PUBLIC int is_url ARGS1(char *,filename)
 	}
 	return(RLOGIN_URL_TYPE);
 
-    } else if (!strncasecomp(cp, "nntp:", 5)) {
-        if (strncmp(cp, "nntp", 4)) {
-	    for (i = 0; i < 4; i++)
-	        cp[i] = TOLOWER(cp[i]);
-	}
-	return(NNTP_URL_TYPE);
-
     } else if (!strncasecomp(cp, "cso:", 4)) {
         if (strncmp(cp, "cso", 3)) {
 	    for (i = 0; i < 3; i++)
@@ -1064,7 +1108,8 @@ PUBLIC int is_url ARGS1(char *,filename)
 /*
  *  Remove backslashes from any string.
  */
-PUBLIC void remove_backslashes ARGS1(char *,buf)
+PUBLIC void remove_backslashes ARGS1(
+	char *,		buf)
 {
     char *cp;
 
@@ -1090,7 +1135,8 @@ PUBLIC void remove_backslashes ARGS1(char *,buf)
  *  string using single quotes, escaping the real single quotes
  *  with double quotes. This may be gross but it seems to work.
  */
-PUBLIC char * quote_pathname ARGS1(char *, pathname)
+PUBLIC char * quote_pathname ARGS1(
+	char *,		pathname)
 {
     int i, n = 0;
     char * result;
@@ -1137,7 +1183,7 @@ PUBLIC BOOLEAN inlocaldomain NOARGS
     int n;
     FILE *fp;
     struct utmp me;
-    char *cp, *mytty=NULL;
+    char *cp, *mytty = NULL;
     char *ttyname();
 
     if ((cp=ttyname(0)))
@@ -1190,8 +1236,19 @@ PUBLIC BOOLEAN inlocaldomain NOARGS
 #endif /* HAVE_TERMIO_H */
 #endif /* HAVE_TERMIOS_H */
 
-PUBLIC void size_change ARGS1(int,sig)
+PUBLIC void size_change ARGS1(
+	int,		sig)
 {
+#ifdef USE_SLANG
+    SLtt_get_screen_size();
+    LYlines = SLtt_Screen_Rows;
+    LYcols  = SLtt_Screen_Cols;
+    if (sig == 0)
+        /*
+	 *  Called from start_curses().
+	 */
+	return;
+#else /* Curses: */
 #ifndef NO_SIZECHANGE
 #ifdef TIOCGSIZE
     struct ttysize win;
@@ -1204,11 +1261,7 @@ PUBLIC void size_change ARGS1(int,sig)
 #ifdef TIOCGSIZE
     if (ioctl(0, TIOCGSIZE, &win) == 0) {
         if (win.ts_lines != 0) {
-#ifdef USE_SLANG
-	    LYlines = win.ts_lines;
-#else
 	    LYlines = win.ts_lines - 1;
-#endif /* USE_SLANG */
 	}
 	if (win.ts_cols != 0) {
 	    LYcols = win.ts_cols;
@@ -1218,11 +1271,7 @@ PUBLIC void size_change ARGS1(int,sig)
 #ifdef TIOCGWINSZ
     if (ioctl(0, TIOCGWINSZ, &win) == 0) {
         if (win.ws_row != 0) {
-#ifdef USE_SLANG
-	    LYlines = win.ws_row;
-#else
 	    LYlines = win.ws_row - 1;
-#endif /* USE_SLANG */
 	}
 	if (win.ws_col != 0) {
 	    LYcols = win.ws_col;
@@ -1236,12 +1285,6 @@ PUBLIC void size_change ARGS1(int,sig)
         LYlines = 24;
     if (LYcols <= 0)
         LYcols = 80;
-
-#ifdef USE_SLANG
-    SLtt_Screen_Rows = LYlines; 
-    SLtt_Screen_Cols = LYcols;
-    if (sig == 0)
-        return;	/* called from start_curses */
 #endif /* USE_SLANG */
 
     recent_sizechange = TRUE; 
@@ -1275,7 +1318,8 @@ PUBLIC void HTSugFilenames_free NOARGS
  *  Utility for listing suggested filenames, making any
  *  repeated filenanmes the most current in the list. - FM
  */
-PUBLIC void HTAddSugFilename ARGS1(char *, fname)
+PUBLIC void HTAddSugFilename ARGS1(
+	char *,		fname)
 {
     char *new;
     char *old;
@@ -1312,7 +1356,8 @@ PUBLIC void HTAddSugFilename ARGS1(char *, fname)
  *  CHANGE_SUG_FILENAME -- Foteos Macrides 29-Dec-1993
  *	Upgraded for use with Lynx2.2 - FM 17-Jan-1994
  */
-PUBLIC void change_sug_filename ARGS1(char *,fname)
+PUBLIC void change_sug_filename ARGS1(
+	char *,		fname)
 {
      char *temp, *cp, *cp1, *end;
      int len;
@@ -1525,11 +1570,12 @@ PUBLIC void change_sug_filename ARGS1(char *,fname)
 /*
  *	To create standard temporary file names
  */
-PUBLIC void tempname ARGS2(char *,namebuffer, int,action)
+PUBLIC void tempname ARGS2(
+	char *,		namebuffer,
+	int,		action)
 {
 	static int counter = 0;
 
-
 	if (action == REMOVE_FILES) { /* REMOVE ALL FILES */ 
 	    for (; counter > 0; counter--) {
 	        sprintf(namebuffer, "%sL%d%uTMP.txt", lynx_temp_space,
@@ -1552,7 +1598,8 @@ PUBLIC void tempname ARGS2(char *,namebuffer, int,action)
 /*
  *  Convert 4, 6, 2, 8 to left, right, down, up, etc.
  */
-PUBLIC int number2arrows ARGS1(int,number)
+PUBLIC int number2arrows ARGS1(
+	int,		number)
 {
       switch(number) {
             case '1':
@@ -1671,7 +1718,8 @@ PRIVATE BOOLEAN *restrict_flag[] = {
 #endif /* DIRED_SUPPORT */
        (BOOLEAN *) 0  };
 
-PUBLIC void parse_restrictions ARGS1(char *,s)
+PUBLIC void parse_restrictions ARGS1(
+	char *,		s)
 {
       char *p;
       char *word;
@@ -1729,7 +1777,7 @@ PUBLIC void parse_restrictions ARGS1(char *,s)
 
       p = s;
       while (*p) {
-          while (isspace(*p))
+          while (isspace((unsigned char)*p))
               p++;
           if (*p == '\0')
               break;
@@ -1797,7 +1845,10 @@ PUBLIC int LYCheckMail NOARGS
         }
         user[userlen] = '\0';
         while (user[0] &&
-	       isspace(user[--userlen])) /* suck up trailing spaces */
+	       /*
+	        *  Suck up trailing spaces.
+	        */
+	       isspace((unsigned char)user[--userlen]))
             user[userlen] = '\0';
     }
 
@@ -1881,14 +1932,56 @@ PUBLIC int LYCheckMail NOARGS
 #endif /* VMS */
 
 /*
+**  This function ensures that an href will be
+**  converted to a fully resolved, absolute URL,
+**  with guessing of the host or expansions of
+**  lead tildes via LYConvertToURL() if needed,
+**  and tweaking/simplifying via HTParse().  It
+**  is used for LynxHome, startfile, homepage,
+**  an 'g'oto entries, after they have been
+**  passed to LYFillLocalFileURL(). - FM
+*/
+PUBLIC void LYEnsureAbsoluteURL ARGS2(
+	char **,	href,
+	char *,		name)
+{
+    char *temp = NULL;
+
+    if (!(*href && *(*href)))
+        return;
+
+    /*
+     *  If it is not a URL then make it one.
+     */
+    if (!strcasecomp(*href, "news:")) {
+        StrAllocCat(*href, "*");
+    } else if (!strcasecomp(*href, "nntp:") ||
+    	       !strcasecomp(*href, "snews:")) {
+        StrAllocCat(*href, "/*");
+    }
+    if (!is_url(*href)) {
+	if (TRACE)
+	    fprintf(stderr, "%s%s'%s' is not a URL\n",
+	    	    (name ? name : ""), (name ? " " : ""), *href);
+        LYConvertToURL(href);
+    }
+    if ((temp = HTParse(*href, "", PARSE_ALL)) != NULL && *temp != '\0')
+        StrAllocCopy(*href, temp);
+    FREE(temp);
+}
+
+/*
  *  Rewrite and reallocate a previously allocated string
  *  as a file URL if the string resolves to a file or
  *  directory on the local system, otherwise as an
  *  http URL. - FM
  */
-PUBLIC void LYConvertToURL ARGS1(char **, AllocatedString)
+PUBLIC void LYConvertToURL ARGS1(
+	char **,	AllocatedString)
 {
     char *old_string = *AllocatedString;
+    char *temp = NULL;
+    char *cp = NULL;
 
     if (!old_string || *old_string == '\0')
         return;
@@ -1897,11 +1990,12 @@ PUBLIC void LYConvertToURL ARGS1(char **, AllocatedString)
     StrAllocCopy(*AllocatedString,"file://localhost");
 
     if (*old_string != '/') {
+	char *fragment = NULL;
 #ifdef VMS
 	/*
 	 *  Not a SHELL pathspec.  Get the full VMS spec and convert it.
 	 */
-	char *cp, *cur_dir=NULL;
+	char *cur_dir = NULL;
 	static char url_file[256], file_name[256], dir_name[256];
 	unsigned long context = 0;
 	$DESCRIPTOR(url_file_dsc, url_file);
@@ -1909,14 +2003,25 @@ PUBLIC void LYConvertToURL ARGS1(char **, AllocatedString)
 	if (*old_string == '~') {
 	    /*
 	     *  On VMS, we'll accept '~' on the command line as
-	     *  $HOME, and assume the rest of the path, if any,
-	     *  has SHELL syntax.
+	     *  Home_Dir(), and assume the rest of the path, if
+	     *  any, has SHELL syntax.
 	     */
-	    StrAllocCat(*AllocatedString, HTVMS_wwwName(getenv("HOME")));
-	    if (old_string[1])
-		StrAllocCat(*AllocatedString, (old_string+1));
+	    StrAllocCat(*AllocatedString, HTVMS_wwwName((char *)Home_Dir()));
+	    if ((cp = strchr(old_string, '/')) != NULL) {
+	        /*
+		 *  Append rest of path, if present, skipping "user" if
+		 *  "~user" was entered, simplifying, and eliminating
+		 *  any residual relative elements. - FM
+		 */
+		StrAllocCopy(temp, cp);
+		LYTrimRelFromAbsPath(temp);
+		StrAllocCat(*AllocatedString, temp);
+		FREE(temp);
+	    }
 	    goto have_VMS_URL;
 	} else {
+	    if ((fragment = strchr(old_string, '#')) != NULL)
+	        *fragment = '\0';
 	    strcpy(url_file, old_string);
 	}
 	url_file_dsc.dsc$w_length = (short) strlen(url_file);
@@ -1925,36 +2030,52 @@ PUBLIC void LYConvertToURL ARGS1(char **, AllocatedString)
 	    /*
 	     *  We found the file.  Convert to a URL pathspec.
 	     */
-	    if ((cp=strchr(file_name, ';')) != NULL) {
+	    if ((cp = strchr(file_name, ';')) != NULL) {
 		*cp = '\0';
 	    }
 	    for (cp = file_name; *cp; cp++) {
 		*cp = TOLOWER(*cp);
 	    }
 	    StrAllocCat(*AllocatedString, HTVMS_wwwName(file_name));
-	    if ((cp=strchr(old_string, ';')) != NULL) {
+	    if ((cp = strchr(old_string, ';')) != NULL) {
 		StrAllocCat(*AllocatedString, cp);
 	    }
+	    if (fragment != NULL) {
+	        *fragment = '#';
+	        StrAllocCat(*AllocatedString, fragment);
+		fragment = NULL;
+	    }
 	} else if ((NULL != getcwd(dir_name, 255, 0)) &&
 		   0 == chdir(old_string)) {
 	    /*
 	     * Probably a directory.  Try converting that.
 	     */
 	    StrAllocCopy(cur_dir, dir_name);
+	    if (fragment != NULL) {
+	        *fragment = '#';
+	    }
 	    if (NULL != getcwd(dir_name, 255, 0)) {
 		/*
 		 * Yup, we got it!
 		 */
+		for (cp = dir_name; *cp; cp++) {
+		    *cp = TOLOWER(*cp);
+		}
 		StrAllocCat(*AllocatedString, dir_name);
+		if (fragment != NULL) {
+		    StrAllocCat(*AllocatedString, fragment);
+		    fragment = NULL;
+		}
 	    } else {
 		/*
 		 *  Nope.  Assume it's an http URL with
 		 *  the "http://" defaulted, if we can't
 		 *  rule out a bad VMS path.
 		 */
+		fragment = NULL;
 		if (strchr(old_string, '[') ||
-		    ((cp=strchr(old_string, ':')) != NULL &&
-		     !isdigit(cp[1])) ||
+		    ((cp = strchr(old_string, ':')) != NULL &&
+		     !isdigit((unsigned char)cp[1])) ||
 		    !LYExpandHostForURL((char **)&old_string,
 		    			URLDomainPrefixes,
 					URLDomainSuffixes)) {
@@ -1990,9 +2111,13 @@ PUBLIC void LYConvertToURL ARGS1(char **, AllocatedString)
 	     *  with the "http://" defaulted, if we can't
 	     *  rule out a bad VMS path.
 	     */
+	    if (fragment != NULL) {
+	        *fragment = '#';
+		fragment = NULL;
+	    }
 	    if (strchr(old_string, '[') ||
-		((cp=strchr(old_string, ':')) != NULL &&
-		 !isdigit(cp[1])) ||
+		((cp = strchr(old_string, ':')) != NULL &&
+		 !isdigit((unsigned char)cp[1])) ||
 		!LYExpandHostForURL((char **)&old_string,
 		    		    URLDomainPrefixes,
 				    URLDomainSuffixes)) {
@@ -2031,11 +2156,19 @@ have_VMS_URL:
 #else /* Unix: */
 	if (*old_string == '~') {
 	    /*
-	     * On Unix, covert '~' to $HOME.
+	     *  On Unix, covert '~' to Home_Dir().
 	     */
-	    StrAllocCat(*AllocatedString, getenv("HOME"));
-	    if (old_string[1]) {
-		StrAllocCat(*AllocatedString, (old_string+1));
+	    StrAllocCat(*AllocatedString, Home_Dir());
+	    if ((cp = strchr(old_string, '/')) != NULL) {
+	        /*
+		 *  Append rest of path, if present, skipping "user" if
+		 *  "~user" was entered, simplifying, and eliminating
+		 *  any residual relative elements. - FM
+		 */
+		StrAllocCopy(temp, cp);
+		LYTrimRelFromAbsPath(temp);
+		StrAllocCat(*AllocatedString, temp);
+		FREE(temp);
 	    }
 	    if (TRACE) {
 		fprintf(stderr, "Converted '%s' to '%s'\n",
@@ -2046,22 +2179,64 @@ have_VMS_URL:
 	     *  Create a full path to the current default directory.
 	     */
 	    char curdir[DIRNAMESIZE];
-	    char *temp=NULL;
 	    struct stat st;
-	    FILE *fptemp=NULL;
+	    FILE *fptemp = NULL;
+	    BOOL is_local = FALSE;
 #ifdef NO_GETCWD
 	    getwd (curdir);
 #else
 	    getcwd (curdir, DIRNAMESIZE);
 #endif /* NO_GETCWD */
+	    /*
+	     *  Concatenate and simplify, trimming any
+	     *  residual relative elements. - FM
+	     */
 	    StrAllocCopy(temp, curdir);
 	    StrAllocCat(temp, "/");
 	    StrAllocCat(temp, old_string);
+	    LYTrimRelFromAbsPath(temp);
 	    if (TRACE) {
 		fprintf(stderr, "Converted '%s' to '%s'\n", old_string, temp);
 	    }
-	    if ((stat(temp, &st) < 0) &&
-		!(fptemp=fopen(temp, "r"))) {
+	    if ((stat(temp, &st) > -1) ||
+	        (fptemp = fopen(temp, "r")) != NULL) {
+		/*
+		 *  It is a subdirectory or file on the local system.
+		 */
+		StrAllocCat(*AllocatedString, temp);
+		if (TRACE) {
+		    fprintf(stderr, "Converted '%s' to '%s'\n",
+				    old_string, *AllocatedString);
+		}
+		is_local = TRUE;
+	    } else {
+	        if ((fragment = strchr(temp, '#')) != NULL)
+	            *fragment = '\0';
+		StrAllocCopy(cp, temp);
+		HTUnEscape(cp);
+		if ((stat(cp, &st) > -1) ||
+		    (fptemp = fopen(cp, "r")) != NULL) {
+		    /*
+		     *  It is a subdirectory of file on the local system
+		     *  with escaped characters and/or a fragment to be
+		     *  appended to the URL. - FM
+		     */
+		    *fragment = '#';
+		    fragment = NULL;
+		    StrAllocCat(*AllocatedString, temp);
+		    if (TRACE) {
+		        fprintf(stderr, "Converted '%s' to '%s'\n",
+					old_string, *AllocatedString);
+		    }
+		    is_local = TRUE;
+		}
+		FREE(cp);
+		if (fragment != NULL) {
+		    *fragment = '#';
+		    fragment = NULL;
+		}
+	    }
+	    if (is_local == FALSE) {
 		/*
 		 *  It's not an accessible subdirectory or file on the
 		 *  local system, so assume it's a URL request and guess
@@ -2085,15 +2260,6 @@ have_VMS_URL:
 		if (TRACE) {
 		    fprintf(stderr, "Trying: '%s'\n", *AllocatedString);
 		}
-	    } else {
-		/*
-		 *  It is a subdirectory or file on the local system.
-		 */
-		StrAllocCat(*AllocatedString, temp);
-		if (TRACE) {
-		    fprintf(stderr, "Converted '%s' to '%s'\n",
-				    old_string, *AllocatedString);
-		}
 	    }
 	    FREE(temp);
 	    if (fptemp) {
@@ -2103,17 +2269,56 @@ have_VMS_URL:
 #endif /* VMS */
     } else { 
 	/*
-	 *  Path begins with a slash.  Use it as is.
+	 *  Path begins with a slash.  Simplify and use it.
 	 */
-	StrAllocCat(*AllocatedString, old_string);
+	if (old_string[1] == '\0') {
+	    /*
+	     *  Request for root.  Respect it on Unix, but
+	     *  on VMS we treat that as a listing of the
+	     *  login directory. - FM
+	     */
+#ifdef VMS
+	    StrAllocCat(*AllocatedString, HTVMS_wwwName((char *)Home_Dir()));
+#else
+	    StrAllocCat(*AllocatedString, "/");
+#endif /* VMS */
+	} else if (old_string[1] == '~') {
+	    /*
+	     *  Has a Home_Dir() reference.  Handle it
+	     *  as if there weren't a lead slash. - FM
+	     */
+#ifdef VMS
+	    StrAllocCat(*AllocatedString, HTVMS_wwwName((char *)Home_Dir()));
+#else
+	    StrAllocCat(*AllocatedString, Home_Dir());
+#endif /* VMS */
+	    if ((cp = strchr((old_string + 1), '/')) != NULL) {
+	        /*
+		 *  Append rest of path, if present, skipping "user" if
+		 *  "~user" was entered, simplifying, and eliminating
+		 *  any residual relative elements. - FM
+		 */
+		StrAllocCopy(temp, cp);
+		LYTrimRelFromAbsPath(temp);
+		StrAllocCat(*AllocatedString, temp);
+		FREE(temp);
+	    }
+	} else {
+	    /*
+	     *  Normal absolute path.  Simplify, trim any
+	     *  residual relative elements, and append it. - FM
+	     */
+	    StrAllocCopy(temp, old_string);
+	    LYTrimRelFromAbsPath(temp);
+	    StrAllocCat(*AllocatedString, temp);
+	    FREE(temp);
+	}
 	if (TRACE) {
 	    fprintf(stderr, "Converted '%s' to '%s'\n",
 			    old_string, *AllocatedString);
 	}
     }
-    if (old_string) {
-	FREE(old_string);
-    }
+    FREE(old_string);
     if (TRACE) {
 	/* Pause so we can read the messages before invoking curses */
 	sleep(AlertSecs);
@@ -2146,17 +2351,29 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
     char DomainPrefix[80], *StartP, *EndP;
     char DomainSuffix[80], *StartS, *EndS;
     char *Str = NULL, *StrColon = NULL, *MsgStr = NULL;
-    char *Host = NULL, *HostColon = NULL;
+    char *Host = NULL, *HostColon = NULL, *host = NULL;
     char *Path = NULL;
+    char *Fragment = NULL;
     struct hostent  *phost;
     BOOLEAN GotHost = FALSE;
+    BOOLEAN Startup = (helpfilepath == NULL);
+
+    /*
+     *  If it's a NULL or zero-length string,
+     *  or if it begins with a slash or hash,
+     *  don't continue pointlessly. - FM
+     */
+    if (!(*AllocatedString) || *AllocatedString[0] == '\0' ||
+        *AllocatedString[0] == '/' || *AllocatedString[0] == '#') {
+        return GotHost;
+    }
 
     /*
-     *  If we were passed a NULL or zero-length string, or if it
-     *  begins with a slash, don't continue pointlessly. - FM
+     *  If it's a partial or relative path,
+     *  don't continue pointlessly. - FM
      */
-    if (!(*AllocatedString) ||
-        *AllocatedString[0] == '\0' || *AllocatedString[0] == '/') {
+    if (!strncmp(*AllocatedString, "..", 2) ||
+        !strncmp(*AllocatedString, "./", 2)) {
         return GotHost;
     }
 
@@ -2168,7 +2385,18 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
      */
     StrAllocCopy(Str, *AllocatedString);
     if ((Path = strchr(Str, '/')) != NULL) {
+        /*
+	 *  Have a path.  Any fragment should
+	 *  already be included in Path. - FM
+	 */
         *Path = '\0';
+    } else if ((Fragment = strchr(Str, '#')) != NULL) {
+        /*
+	 *  No path, so check for a fragment and
+	 *  trim that, to be restored after filling
+	 *  in the Host[:port] field. - FM
+	 */
+        *Fragment = '\0';
     }
 
     /*
@@ -2177,7 +2405,8 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
      *  information so we can restore the port field after
      *  filling in the host field. - FM
      */
-    if ((StrColon = strrchr(Str, ':')) != NULL && isdigit(StrColon[1])) {
+    if ((StrColon = strrchr(Str, ':')) != NULL &&
+        isdigit((unsigned char)StrColon[1])) {
         if (StrColon == Str) {
 	    FREE(Str);
 	    return GotHost;
@@ -2189,14 +2418,19 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
      *  Do a DNS test on the potential host field
      *  as presently trimmed. - FM
      */
+    StrAllocCopy(host, Str);
+    HTUnEscape(host);
     if (LYCursesON) {
         StrAllocCopy(MsgStr, "Looking up ");
-	StrAllocCat(MsgStr, Str);
+	StrAllocCat(MsgStr, host);
 	StrAllocCat(MsgStr, " first.");
 	HTProgress(MsgStr);
+    } else if (Startup && !dump_output_immediately) {
+	fprintf(stdout, "Looking up '%s' first.\n", host);
     }
-    if ((phost = gethostbyname(Str)) != NULL) {
+    if ((phost = gethostbyname(host)) != NULL) {
         GotHost = TRUE;
+	FREE(host);
         FREE(Str);
         FREE(MsgStr);
 	return GotHost;
@@ -2209,6 +2443,25 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
     */
     StartP = ((prefix_list && Str[strlen(Str)-1] != '.') ?
     					     prefix_list : "");
+    /*
+    **  If we have a prefix, but the allocated string is
+    **  one of the common host prefixes, make our prefix
+    **  a zero-length string. - FM
+    */
+    if (*StartP && *StartP != '.') {
+        if (!strncasecomp(*AllocatedString, "www.", 4) ||
+	    !strncasecomp(*AllocatedString, "ftp.", 4) ||
+	    !strncasecomp(*AllocatedString, "gopher.", 7) ||
+	    !strncasecomp(*AllocatedString, "wais.", 5) ||
+	    !strncasecomp(*AllocatedString, "cso.", 4) ||
+	    !strncasecomp(*AllocatedString, "ns.", 3) ||
+	    !strncasecomp(*AllocatedString, "ph.", 3) ||
+	    !strncasecomp(*AllocatedString, "finger.", 7) ||
+	    !strncasecomp(*AllocatedString, "news.", 5) ||
+	    !strncasecomp(*AllocatedString, "nntp.", 5)) {
+	    StartP = "";
+	}
+    }
     while ((*StartP) && (WHITE(*StartP) || *StartP == ',')) {
         StartP++;	/* Skip whitespace and separators */
     }
@@ -2249,16 +2502,20 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 	    }
 	    StrAllocCat(Host, DomainSuffix);
 	    if ((HostColon = strrchr(Host, ':')) != NULL &&
-	        isdigit(HostColon[1])) {
+	        isdigit((unsigned char)HostColon[1])) {
 		*HostColon = '\0';
 	    }
+	    StrAllocCopy(host, Host);
+	    HTUnEscape(host);
 	    if (LYCursesON) {
  	        StrAllocCopy(MsgStr, "Looking up ");
- 		StrAllocCat(MsgStr, Host);
+ 		StrAllocCat(MsgStr, host);
  		StrAllocCat(MsgStr, ", guessing...");
  		HTProgress(MsgStr);
+	    } else if (Startup && !dump_output_immediately) {
+	        fprintf(stdout, "Looking up '%s', guessing...\n", host);
 	    }
-	    GotHost = ((phost = gethostbyname(Host)) != NULL);
+	    GotHost = ((phost = gethostbyname(host)) != NULL);
 	    if (HostColon != NULL) {
 	        *HostColon = ':';
 	    }
@@ -2270,11 +2527,12 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 		    if (TRACE) {
 			fprintf(stderr,
 	 "*** LYExpandHostForURL interrupted while %s failed to resolve\n",
-				Host);
+				host);
 			    }
 		    FREE(Str);
 		    FREE(MsgStr);
 		    FREE(Host);
+		    FREE(host);
 		    return FALSE; /* We didn't find a valid name. */
 		}
 
@@ -2323,6 +2581,10 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
         if (Path) {
 	    *Path = '/';
 	    StrAllocCat(Host, Path);
+	} else if (Fragment) {
+	    StrAllocCat(Host, "/");
+	    *Fragment = '#';
+	    StrAllocCat(Host, Fragment);
 	}
 	StrAllocCopy(*AllocatedString, Host);
     }
@@ -2333,6 +2595,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
     FREE(Str);
     FREE(MsgStr);
     FREE(Host);
+    FREE(host);
     return GotHost;
 }
 
@@ -2442,6 +2705,83 @@ PUBLIC BOOLEAN LYAddSchemeForURL ARGS2(
 }
 
 /*
+ *  This function expects an absolute Unix or VMS SHELL path
+ *  spec as an allocated string, simplifies it, and trims out
+ *  any residual relative elements.  It also checks whether
+ *  the path had a terminal slash, and if it didn't, makes
+ *  sure that the simplified path doesn't either.  If it's
+ *  a directory, our convention is to exclude "Up to parent"
+ *  links when a terminal slash is present. - FM
+ */
+PUBLIC void LYTrimRelFromAbsPath ARGS1(
+	char *,		path)
+{
+    char *cp;
+    int i;
+    BOOL TerminalSlash;
+
+    /*
+     *  Make sure we have a pointer to an absolute path. - FM
+     */
+    if (path == NULL || *path != '/')
+        return;
+
+    /*
+     *  Check whether the path has a terminal slash. - FM
+     */
+    TerminalSlash = (path[(strlen(path) - 1)] == '/');
+
+    /*
+     *  Simplify the path and then do any necessary trimming. - FM
+     */
+    HTSimplify(path);
+    cp = path;
+    while (cp[1] == '.') {
+	if (cp[2] == '\0') {
+	    /*
+	     *  Eliminate trailing dot. - FM
+	     */
+	    cp[1] = '\0';
+	} else if (cp[2] == '/') {
+	    /*
+	     *  Skip over the "/." of a "/./". - FM
+	     */
+	    cp += 2;
+	} else if (cp[2] == '.' && cp[3] == '\0') {
+	    /*
+	     *  Eliminate trailing dotdot. - FM
+	     */
+	    cp[1] = '\0';
+	} else if (cp[2] == '.' && cp[3] == '/') {
+	    /*
+	     *  Skip over the "/.." of a "/../". - FM
+	     */
+	    cp += 3;
+	} else {
+	    /*
+	     *  Done trimming. - FM
+	     */
+	    break;
+	}
+    }
+
+    /*
+     *  Load any shifts into path, and eliminate any
+     *  terminal slash created by HTSimplify() or our
+     *  walk, but not present originally. - FM
+     */
+    if (cp > path) {
+        for (i = 0; cp[i] != '\0'; i++)
+	    path[i] = cp[i];
+	path[i] = '\0';
+    }
+    if (TerminalSlash == FALSE &&
+        path[(strlen(path) - 1)] == '/') {
+        path[(strlen(path) - 1)] = '\0';
+    }
+}
+
+/*
  *  Example Client-Side Include interface.
  *
  *  This is called from SGML.c and simply returns markup for reporting
@@ -2478,7 +2818,9 @@ PUBLIC void LYDoCSI ARGS3(
  *  Define_VMSLogical -- Fote Macrides 04-Apr-1995
  *	Define VMS logicals in the process table.
  */
-PUBLIC void Define_VMSLogical ARGS2(char *, LogicalName, char *, LogicalValue)
+PUBLIC void Define_VMSLogical ARGS2(
+	char *,		LogicalName,
+	char *,		LogicalValue)
 {
     $DESCRIPTOR(lname, "");
     $DESCRIPTOR(lvalue, "");
@@ -2532,6 +2874,513 @@ PUBLIC CONST char * Home_Dir NOARGS
     return homedir;
 }
 
+/*
+ *  This function checks the acceptability of file paths that
+ *  are intended to be off the home directory.  The file path
+ *  should be passed in fbuffer, together with the size of the
+ *  buffer.  The function simplifies the file path, and if it
+ *  is acceptible, loads it into fbuffer and returns TRUE.
+ *  Otherwise, it does not modify fbuffer and returns FALSE.
+ *  If a subdirectory is present and the path does not begin
+ *  with "./", that is prefixed to make the situation clear. - FM
+ */
+PUBLIC BOOLEAN LYPathOffHomeOK ARGS2(
+	char *,		fbuffer,
+	int,		fbuffer_size)
+{
+    char *file = NULL;
+    char *cp, *cp1;
+
+    /*
+     *  Make sure we have an fbuffer and a string in it. - FM
+     */
+    if (!fbuffer || fbuffer_size < 2 || fbuffer[0] == '\0') {
+	return(FALSE);
+    }
+    StrAllocCopy(file, fbuffer);
+    cp = file;
+
+    /*
+     *  Check for an inappropriate reference to the
+     *  home directory, and correct it if we can. - FM
+     */
+#ifdef VMS
+    if (!strncasecomp(cp, "sys$login", 9)) {
+        if (*(cp + 9) == '\0') {
+	    /*
+	     *  Reject "sys$login". - FM
+	     */
+	    FREE(file);
+	    return(FALSE);
+	}
+	if (*(cp + 9) == ':') {
+	    cp += 10;
+	    if (*cp == '\0') {
+	        /*
+		 *  Reject "sys$login:".  Otherwise, we have
+		 *  converted "sys$login:file" to "file", or
+		 *  have left a strange path for VMS as it
+		 *  was originally. - FM
+		 */
+	        FREE(file);
+		return(FALSE);
+	    }
+	}
+    }
+#endif /* VMS */
+    if (*cp == '~') {
+        if (*(cp + 1) == '/') {
+	    if (*(cp + 2) != '\0') {
+	        if ((cp1 = strchr((cp + 2), '/')) != NULL) {
+	            /*
+		     *  Convert "~/subdir(s)/file"
+		     *  to "./subdir(s)/file". - FM
+		     */
+		    *cp = '.';
+		} else {
+	            /*
+		     *  Convert "~/file" to "file". - FM
+		     */
+		    cp += 2;
+		}
+	    } else {
+	        /*
+		 *  Reject "~/". - FM
+		 */
+	        FREE(file);
+		return(FALSE);
+	    }
+	} else if ((*(cp + 1) != '\0') &&
+		   (cp1 = strchr((cp + 1), '/')) != NULL) {
+	    cp = (cp1 - 1) ;
+	    if (*(cp + 2) != '\0') {
+	        if ((cp1 = strchr((cp + 2), '/')) != NULL) {
+		    /*
+		     *  Convert "~user/subdir(s)/file" to
+		     *  "./subdir(s)/file".  If user is someone
+		     *  else, we covered a spoof.  Otherwise, 
+		     *  we simplified. - FM
+		     */
+		    *cp = '.';
+		} else {
+		    /*
+		     *  Convert "~user/file" to "file". - FM
+		     */
+		    cp += 2;
+		}
+	    } else {
+	        /*
+		 *  Reject "~user/". - FM
+		 */
+	        FREE(file);
+		return(FALSE);
+	    }
+	} else {
+	    /*
+	     *  Reject "~user". - FM
+	     */
+	    FREE(file);
+	    return(FALSE);
+	}
+    }
+
+#ifdef VMS
+    /*
+     *  Check for VMS path specs, and reject if still present. - FM
+     */
+    if (strchr(cp, ':') != NULL || strchr(cp, ']') != NULL) {
+        FREE(file);
+	return(FALSE);
+    }
+#endif /* VMS */
+
+    /*
+     *  Check for a URL or absolute path, and reject if present. - FM
+     */
+    if (is_url(cp) || *cp == '/') {
+        FREE(file);
+	return(FALSE);
+    }
+
+    /*
+     *  Simplify it. - FM
+     */
+    HTSimplify(cp);
+
+    /*
+     *  Check if it has a pointless "./". - FM
+     */
+    if (!strncmp(cp, "./", 2)) {
+        if ((cp1 = strchr((cp + 2), '/')) == NULL) {
+	    cp += 2;
+	}
+    }
+
+    /*
+     *  Check for spoofing. - FM
+     */
+    if (*cp == '\0' || *cp == '/' || cp[(strlen(cp) - 1)] == '/' ||
+        strstr(cp, "..") != NULL || !strcmp(cp, ".")) {
+        FREE(file);
+	return(FALSE);
+    }
+
+    /*
+     *  Load what we have at this point into fbuffer,
+     *  trimming if too long, and claim it's OK. - FM
+     */
+    if (fbuffer_size > 3 && strncmp(cp, "./", 2) && strchr(cp, '/')) {
+        /*
+	 *  We have a subdirectory and no lead "./", so
+	 *  prefix it to make the situation clear. - FM
+	 */
+        strcpy(fbuffer, "./");
+	if (strlen(cp) > (fbuffer_size - 3))
+	    cp[(fbuffer_size - 3)] = '\0';
+        strcat(fbuffer, cp);
+    } else {
+        if (strlen(cp) > (fbuffer_size - 1))
+	    cp[(fbuffer_size - 1)] = '\0';
+	strcpy(fbuffer, cp);
+    }
+    FREE(file);
+    return(TRUE);
+}
+
+/*
+ *  This function appends fname to the home path and returns
+ *  the full path and filename.  The fname string can be just
+ *  a filename (e.g., "lynx_bookmarks.html"), or include a
+ *  subirectory off the home directory, in which case fname
+ *  should begin with "./" (e.g., ./BM/lynx_bookmarks.html)
+ *  Use LYPathOffHomeOK() to check and/or fix up fname before
+ *  calling this function.  On VMS, the resultant full path
+ *  and filename are converted to VMS syntax. - FM
+ */
+PUBLIC void LYAddPathToHome ARGS3(
+	char *,		fbuffer,
+	int,		fbuffer_size,
+	char *,		fname)
+{
+    char *home = NULL;
+    char *file = fname;
+    int len;
+
+    /*
+     *  Make sure we have a buffer. - FM
+     */
+    if (!fbuffer)
+        return;
+    if (fbuffer_size < 2) {
+        fbuffer[0] = '\0';
+	return;
+    }
+    fbuffer[(fbuffer_size - 1)] = '\0';
+
+    /*
+     *  Make sure we have a file name. - FM
+     */
+    if (!file)
+        file = "";
+
+    /*
+     *  Set up home string and length. - FM
+     */
+    StrAllocCopy(home, Home_Dir());
+    if (!(home && *home))
+	/*
+	 *  Home_Dir() has a bug if this ever happens. - FM
+	 */
+#ifdef VMS
+        StrAllocCopy(home, "Error:");
+#else
+	StrAllocCopy(home, "/error");
+#endif /* VMS */
+    len = fbuffer_size - (strlen(home) + 1);
+    if (len <= 0) {
+        /*
+	 *  Buffer is smaller than or only big enough for the home path.
+	 *  Load what fits of the home path and return.  This will fail,
+	 *  but we need something in the buffer. - FM
+	 */
+        LYstrncpy(fbuffer, home, (fbuffer_size - 1));
+	FREE(home);
+	return;
+    }
+
+#ifdef VMS
+    /*
+     *  Check whether we have a subdirectory path or just a filename. - FM
+     */
+    if (!strncmp(file, "./", 2)) {
+        /*
+	 *  We have a subdirectory path. - FM
+	 */
+	if (home[strlen(home)-1] == ']') {
+	    /*
+	     *  We got the home directory, so convert it to
+	     *  SHELL syntax and append subdirectory path,
+	     *  then convert that to VMS syntax. - FM
+	     */
+	    char *temp = (char *)calloc(1,
+	    				(strlen(home) + strlen(file) + 10));
+	    sprintf(temp, "%s%s", HTVMS_wwwName(home), (file + 1));
+	    sprintf(fbuffer, "%.*s",
+	    	    (fbuffer_size - 1), HTVMS_name("", temp));
+	    FREE(temp);
+	} else {
+	    /*
+	     *  This will fail, but we need something in the buffer. - FM
+	     */
+	    sprintf(fbuffer, "%s%.*s", home, len, file);
+	}
+    } else {
+        /*
+	 *  We have a file in the home directory. - FM
+	 */
+	sprintf(fbuffer, "%s%.*s", home, len, file);
+    }
+#else
+    /*
+     *  Check whether we have a subdirectory path or just a filename. - FM
+     */
+    sprintf(fbuffer, "%s/%.*s", home, len,
+		     (strncmp(file, "./", 2) ? file : (file + 2)));
+#endif /* VMS */
+    FREE(home);
+}
+
+/*
+ *  This function takes a string in the format
+ *	"Mon, 01-Jan-96 13:45:35 GMT" or
+ *	"Mon,  1 Jan 1996 13:45:35 GMT""
+ *  as an argument, and returns its conversion to clock format
+ *  (seconds since 00:00:00 Jan 1 1970), or 0 if the string
+ *  doesn't match the expected pattern.  It also returns 0
+ *  if the time is in the past.  It is intended for handling
+ *  'expires' strings homologously to 'max-age' strings, for
+ *  which 0 is the minimum, and greater values are handled
+ *  as '[max-age seconds] + time(NULL)'. - FM
+ */
+PUBLIC time_t LYmktime ARGS1(
+	char *,		string)
+{
+    char *s;
+    time_t now, clock;
+    int day, month, year, hour, minutes, seconds;
+    char *start;
+    char temp[8];
+
+    /*
+     *  Make sure we have a string to parse. - FM
+     */
+    if (!(string && *string))
+        return(0);
+    s = string;
+    if (TRACE)
+        fprintf(stderr, "LYmktime: Parsing '%s'\n", s);
+         
+    /*
+     *  Skip the "Day, " field. - FM
+     */
+    while (*s != '\0' && *s != ',')
+        s++;
+    if (*s == '\0')
+        return(0);
+    s++;
+    while (*s != '\0' && isspace((unsigned char)*s))
+        s++;
+    if (*s == '\0' || !isdigit((unsigned char)*s))
+        return(0);
+
+    /*
+     *  Get the numeric day and convert to an integer. - FM
+     */
+    start = s;
+    while (*s != '\0' && isdigit((unsigned char)*s))
+       s++;
+    if (*s == '\0' || (s - start) > 2)
+        return(0);
+    LYstrncpy(temp, start, (int)(s - start));
+    day = atoi(temp);
+    if (day < 1 || day > 31)
+        return(0);
+
+    /*
+     *  Get the month string and convert to an integer. - FM
+     */
+    while (*s != '\0' && !isalpha((unsigned char)*s))
+        s++;
+    if (*s == '\0')
+        return(0);
+    start = s;
+    while (*s != '\0' && isalpha((unsigned char)*s))
+        s++;
+    if (*s == '\0' || (s - start) < 3 || (s - start) > 9)
+        return(0);
+    LYstrncpy(temp, start, 3);
+    switch (TOUPPER(temp[0])) {
+        case 'A':
+	    if (!strcasecomp(temp, "Apr")) {
+	        month = 4;
+	    } else if (!strcasecomp(temp, "Aug")) {
+	        month = 8;
+	    } else {
+	        return(0);
+	    }
+	    break;
+	case 'D':
+	    if (!strcasecomp(temp, "Dec")) {
+	        month = 12;
+	    } else {
+	        return(0);
+	    }
+	    break;
+	case 'F':
+	    if (!strcasecomp(temp, "Feb")) {
+	        month = 2;
+	    } else {
+	        return(0);
+	    }
+	    break;
+	case 'J':
+	    if (!strcasecomp(temp, "Jan")) {
+	        month = 1;
+	    } else if (!strcasecomp(temp, "Jun")) {
+	        month = 6;
+	    } else if (!strcasecomp(temp, "Jul")) {
+	        month = 7;
+	    } else {
+	        return(0);
+	    }
+	    break;
+	case 'M':
+	    if (!strcasecomp(temp, "Mar")) {
+	        month = 3;
+	    } else if (!strcasecomp(temp, "May")) {
+	        month = 5;
+	    } else {
+	        return(0);
+	    }
+	    break;
+	case 'N':
+	    if (!strcasecomp(temp, "Nov")) {
+	        month = 11;
+	    } else {
+	        return(0);
+	    }
+	    break;
+	case 'O':
+	    if (!strcasecomp(temp, "Oct")) {
+	        month = 10;
+	    } else {
+	        return(0);
+	    }
+	    break;
+	case 'S':
+	    if (!strcasecomp(temp, "Sep")) {
+	        month = 9;
+	    } else {
+	        return(0);
+	    }
+	    break;
+	default:
+	    return(0);
+    }
+
+    /*
+     *  Get the numeric year string and convert to an integer. - FM
+     */
+    while (*s != '\0' && !isdigit((unsigned char)*s))
+        s++;
+    if (*s == '\0')
+        return(0);
+    start = s;
+    while (*s != '\0' && isdigit((unsigned char)*s))
+        s++;
+    if (*s == '\0')
+        return(0);
+    if ((s - start) == 4) {
+        LYstrncpy(temp, start, 4);
+    } else if ((s - start) == 2) {
+    	now = time(NULL);
+	LYstrncpy(temp, ((char *)ctime(&now) + 20), 2);
+	strncat(temp, start, 2);
+	temp[4] = '\0'; 
+    } else {
+        return(0);
+    }
+    year = atoi(temp);
+    
+    /*
+     *  Get the numeric hour string and convert to an integer. - FM
+     */
+    while (*s != '\0' && !isdigit((unsigned char)*s))
+        s++;
+    if (*s == '\0')
+        return(0);
+    start = s;
+    while (*s != '\0' && isdigit((unsigned char)*s))
+        s++;
+    if (*s != ':' || (s - start) > 2)
+        return(0);
+    LYstrncpy(temp, start, (int)(s - start));
+    hour = atoi(temp);
+
+    /*
+     *  Get the numeric minutes string and convert to an integer. - FM
+     */
+    while (*s != '\0' && !isdigit((unsigned char)*s))
+        s++;
+    if (*s == '\0')
+        return(0);
+    start = s;
+    while (*s != '\0' && isdigit((unsigned char)*s))
+        s++;
+    if (*s != ':' || (s - start) > 2)
+        return(0);
+    LYstrncpy(temp, start, (int)(s - start));
+    minutes = atoi(temp);
+
+    /*
+     *  Get the numeric seconds string and convert to an integer. - FM
+     */
+    while (*s != '\0' && !isdigit((unsigned char)*s))
+        s++;
+    if (*s == '\0')
+        return(0);
+    start = s;
+    while (*s != '\0' && isdigit((unsigned char)*s))
+        s++;
+    if (*s == '\0' || (s - start) > 2)
+        return(0);
+    LYstrncpy(temp, start, (int)(s - start));
+    seconds = atoi(temp);
+
+    /*
+     *  Convert to clock format (seconds since 00:00:00 Jan 1 1970),
+     *  but then zero it if it's in the past.  - FM
+     */
+    month -= 3;
+    if (month < 0) {
+         month += 12;
+	 year--;
+    }
+    day += (year - 1968)*1461/4;
+    day += ((((month*153) + 2)/5) - 672);
+    clock = (time_t)((day * 60 * 60 * 24) +
+    		     (hour * 60 * 60) +
+    		     (minutes * 60) +
+		     seconds);
+    if (clock <= time(NULL))
+        clock = (time_t)0;
+    if (TRACE && clock > 0)
+        fprintf(stderr,
+		"LYmktime: clock=%i, ctime=%s", clock, ctime(&clock));
+
+    return(clock);
+}
+
 #ifdef NO_PUTENV
 /* no putenv on the next so we use this code instead!
  */
@@ -2581,9 +3430,8 @@ extern int errno;
 extern char **environ;
 
 /* Put STRING, which is of the form "NAME=VALUE", in  the environment.  */
-int
-putenv (string)
-     const char *string;
+PUBLIC int putenv ARGS1(
+	CONST char *,	string)
 {
   char *name_end = index (string, '=');
   register size_t size;
@@ -2633,76 +3481,3 @@ putenv (string)
   return 0;
 }
 #endif /* NO_PUTENV */
-
-#ifdef VMS
-/*
- *  This function appends fname to the home path and returns
- *  the full path and filename in VMS syntax.  The fname
- *  string can be just a filename, or include a subirectory
- *  off the home directory, in which chase fname should
- *  with "./" (e.g., ./BM/lynx_bookmarks.html). - FM
- */
-PUBLIC void LYVMS_HomePathAndFilename ARGS3(
-	char *,		fbuffer,
-	int,		fbuffer_size,
-	char *,		fname)
-{
-    char *home = NULL;
-    char *temp = NULL;
-    int len;
-
-    /*
-     *  Make sure we have a buffer and string. - FM
-     */
-    if (!fbuffer)
-        return;
-    if (!(fname && *fname) || fbuffer_size < 1) {
-        fbuffer[0] = '\0';
-	return;
-    }
-
-    /*
-     *  Set up home string and length. - FM
-     */
-    StrAllocCopy(home, Home_Dir());
-    if (!(home && *home))
-        StrAllocCopy(home, "Error:");
-    len = fbuffer_size - strlen(home) - 1;
-    if (len < 0) {
-        len = 0;
-	home[fbuffer_size] = '\0';
-    }
-
-    /*
-     *  Check whether we have a subdirectory path or just a filename. - FM
-     */
-    if (!strncmp(fname, "./", 2)) {
-        /*
-	 *  We have a subdirectory path. - FM
-	 */
-	if (home[strlen(home)-1] == ']') {
-	    /*
-	     *  We got the home directory, so convert it to
-	     *  SHELL syntax and append subdirectory path,
-	     *  then convert that to VMS syntax. - FM
-	     */
-	    temp = (char *)calloc(1, (strlen(home) + strlen(fname) + 10));
-	    sprintf(temp, "%s%s", HTVMS_wwwName(home), (fname + 1));
-	    sprintf(fbuffer, "%.*s",
-	    	    (fbuffer_size - 1), HTVMS_name("", temp));
-	    FREE(temp);
-	} else {
-	    /*
-	     *  This will fail, but we need something in the buffer. - FM
-	     */
-	    sprintf(fbuffer,"%s%.*s", home, len, fname);
-	}
-    } else {
-        /*
-	 *  We have a file in the home directory. - FM
-	 */
-	sprintf(fbuffer,"%s%.*s", home, len, fname);
-    }
-    FREE(home);
-}
-#endif /* VMS */
diff --git a/src/LYUtils.h b/src/LYUtils.h
index 7e91f071..05bdff41 100644
--- a/src/LYUtils.h
+++ b/src/LYUtils.h
@@ -8,13 +8,15 @@
 #include "HTList.h"
 #endif /* HTLIST_H */
 
-/* for tempname */
-#define NEW_FILE     0
-#define REMOVE_FILES 1
-
+extern void highlight PARAMS((int flag, int cur));
+extern void free_and_clear PARAMS((char **obj));
+extern void collapse_spaces PARAMS((char *string));
+extern void convert_to_spaces PARAMS((char *string));
+extern char * strip_trailing_slash PARAMS((char * dirname));
 extern void statusline PARAMS((char *text));
-extern void noviceline PARAMS((int more));
 extern void toggle_novice_line NOPARAMS;
+extern void noviceline PARAMS((int more));
+extern int HTCheckForInterrupt NOPARAMS;
 extern BOOLEAN LYisLocalFile PARAMS((char *filename));
 extern BOOLEAN LYisLocalHost PARAMS((char *filename));
 extern void LYLocalhostAliases_free NOPARAMS;
@@ -23,43 +25,49 @@ extern BOOLEAN LYisLocalAlias PARAMS((char *filename));
 extern int LYCheckForProxyURL PARAMS((char *filename));
 extern int is_url PARAMS((char *filename));
 extern void remove_backslashes PARAMS((char *buf));
-extern void collapse_spaces PARAMS((char *string));
-extern void convert_to_spaces PARAMS((char *string));
+extern char *quote_pathname PARAMS((char *pathname));
 extern BOOLEAN inlocaldomain NOPARAMS;
 extern void size_change PARAMS((int sig));
-extern HTList * sug_filenames;
 extern void HTSugFilenames_free NOPARAMS;
 extern void HTAddSugFilename PARAMS((char *fname));
 extern void change_sug_filename PARAMS((char *fname));
 extern void tempname PARAMS((char *namebuffer, int action));
-extern int HTCheckForInterrupt NOPARAMS;
 extern int number2arrows PARAMS((int number));
-extern void highlight PARAMS((int flag, int cur));
-extern CONST char * Home_Dir NOPARAMS;
 extern void parse_restrictions PARAMS((char *s));
-extern void free_and_clear PARAMS((char **obj));
-extern char * quote_pathname PARAMS((char *pathname));
 extern void checkmail NOPARAMS;
 extern int LYCheckMail NOPARAMS;
+extern void LYEnsureAbsoluteURL PARAMS((char **href, char *name));
 extern void LYConvertToURL PARAMS((char **AllocatedString));
 extern BOOLEAN LYExpandHostForURL PARAMS((
 	char **AllocatedString, char *prefix_list, char *suffix_list));
 extern BOOLEAN LYAddSchemeForURL PARAMS((
 	char **AllocatedString, char *default_scheme));
+extern void LYTrimRelFromAbsPath PARAMS((char *path));
+extern void LYDoCSI PARAMS((char *url, CONST char *comment, char **csi));
 #ifdef VMS
 extern void Define_VMSLogical PARAMS((
 	char *LogicalName, char *LogicalValue));
-extern void LYVMS_HomePathAndFilename PARAMS((
-	char *fbuffer, int fbuffer_size, char * fname));
 #endif /* VMS */
+extern CONST char *Home_Dir NOPARAMS;
+extern BOOLEAN LYPathOffHomeOK PARAMS((char *fbuffer, int fbuffer_size));
+extern void LYAddPathToHome PARAMS((
+	char *fbuffer, int fbuffer_size, char *fname));
+extern time_t LYmktime PARAMS((char *string));
+#ifdef NO_PUTENV
+extern int putenv PARAMS((CONST char *string));
+#endif /* NO_PUTENV */
 
-/*	Whether or not the status line must be shown.
+/*
+ *  Whether or not the status line must be shown.
  */
 extern BOOLEAN mustshow;
 #define _statusline(msg)	mustshow = TRUE, statusline(msg)
 
-/* for is_url */
-/* universal document id types */
+/*
+ *  For is_url().
+ *
+ *  Universal document id types.
+ */
 #define HTTP_URL_TYPE		 1
 #define FILE_URL_TYPE		 2
 #define FTP_URL_TYPE		 3
@@ -95,12 +103,27 @@ extern BOOLEAN mustshow;
 #define LYNXDOWNLOAD_URL_TYPE	29
 #define LYNXKEYMAP_URL_TYPE	30
 #define LYNXIMGMAP_URL_TYPE	31
-#define LYNXDIRED_URL_TYPE	32
+#define LYNXCOOKIE_URL_TYPE	32
+#define LYNXDIRED_URL_TYPE	33
+
+#define PROXY_URL_TYPE		34
 
-#define PROXY_URL_TYPE		33
+#define UNKNOWN_URL_TYPE	35
 
-#define UNKNOWN_URL_TYPE	34
+/*
+ *  For change_sug_filename().
+ */
+extern HTList *sug_filenames;
 
+/*
+ *  For tempname().
+ */
+#define NEW_FILE     0
+#define REMOVE_FILES 1
+
+/*
+ *  Miscellaneous.
+ */
 #define ON      1
 #define OFF     0
 #define STREQ(a,b) (strcmp(a,b) == 0)
diff --git a/src/LYexit.c b/src/LYexit.c
index 61543393..0429c017 100644
--- a/src/LYexit.c
+++ b/src/LYexit.c
@@ -5,98 +5,154 @@
 #include "tcp.h"
 #include "LYexit.h"
 #ifndef VMS
+#include "LYGlobalDefs.h"
+#include "LYUtils.h"
+#include "LYSignal.h"
+#include "LYClean.h"
 #ifdef SYSLOG_REQUESTED_URLS
 #include <syslog.h>
 #endif /* SYSLOG_REQUESTED_URLS */
 #endif /* !VMS */
 
+#define FREE(x) if (x) {free(x); x = NULL;}
+
+/*
+ *  Stack of functions to call upon exit.
+ */
+PRIVATE void (*callstack[ATEXITSIZE])();
+PRIVATE int topOfStack = 0;
+
+/*
+ *  Flag for outofmem macro. - FM
+ */
+PUBLIC BOOL LYOutOfMemory = FALSE;
+
+/*
+ *  Forward declarations.
+ */
 PRIVATE void LYCompleteExit NOPARAMS;
 
-PUBLIC void LYexit ARGS1(int, status)	{
 /*
- *	Purpose:	Terminates program.
- *	Arguments:	status	Exit code.
- *	Return Value:	void
- *	Remarks/Portability/Dependencies/Restrictions:
- *		Function calls stdlib.h exit
- *	Revision History:
- *		06-15-94	created Lynx 2-3-1 Garrett Arch Blythe
+ *  Purpose:		Terminates program.
+ *  Arguments:		status	Exit code.
+ *  Return Value:	void
+ *  Remarks/Portability/Dependencies/Restrictions:
+ *	Function calls stdlib.h exit
+ *  Revision History:
+ *	06-15-94	created Lynx 2-3-1 Garrett Arch Blythe
  */
+PUBLIC void LYexit ARGS1(
+	int,		status)
+{
+#ifndef VMS	/*  On VMS, the VMSexit() handler does these. - FM */
+    if (LYOutOfMemory == TRUE) {
+	/*
+	 *  Ignore further interrupts. - FM
+ 	 */
+	(void) signal (SIGHUP, SIG_IGN);
+	(void) signal (SIGTERM, SIG_IGN);
+	(void) signal (SIGINT, SIG_IGN);
+#ifndef __linux__
+	(void) signal(SIGBUS, SIG_IGN);
+#endif /* !__linux__ */
+	(void) signal(SIGSEGV, SIG_IGN);
+	(void) signal(SIGILL, SIG_IGN);
+
+         /*
+	  *  Flush all messages. - FM
+	  */
+	 fflush(stderr);
+	 fflush(stdout);
 
 	/*
-	 *	Do functions registered with LYatexit
+	 *  Deal with curses, if on, and clean up. - FM
 	 */
-	LYCompleteExit();
+	if (LYCursesON) {
+	    sleep(AlertSecs);
+	}
+	cleanup_sig(0);
+#ifndef __linux__
+	signal(SIGBUS, SIG_DFL);
+#endif /* !__linux__ */
+	signal(SIGSEGV, SIG_DFL);
+	signal(SIGILL, SIG_DFL);
+    }
+#endif /* !VMS */
+
+    /*
+     *	Do functions registered with LYatexit. - GAB
+     */
+    LYCompleteExit();
 
 #ifndef VMS
 #ifdef SYSLOG_REQUESTED_URLS
-	syslog(LOG_INFO, "Session over");
-	closelog();
+    syslog(LOG_INFO, "Session over");
+    closelog();
 #endif /* SYSLOG_REQUESTED_URLS */
 #endif /* !VMS */
 
 #ifdef exit
-/*
- *	Make sure we use stdlib exit and not LYexit.
- */
+/*  Make sure we use stdlib exit and not LYexit. - GAB
+*/
 #undef exit
 #endif /* exit */
 
-	exit(status);
+#ifndef VMS	/*  On VMS, the VMSexit() handler does these. - FM */
+    if (LYOutOfMemory == TRUE) {
+	LYOutOfMemory = FALSE;
+	printf("\r\n%s\r\n\r\n", MEMORY_EXHAUSTED_ABORT);
+	fflush(stdout);
+    }
+#endif /* !VMS */
+    exit(status);
 }
 
 /*
- *	Stack of functions to call upon exit.
+ *  Purpose:		Registers termination function.
+ *  Arguments:		function	The function to register.
+ *  Return Value:	int	0	registered
+ *				!0	no more space to register
+ *  Remarks/Portability/Dependencies/Restrictions:
+ *  Revision History:
+ *	06-15-94	created Lynx 2-3-1 Garrett Arch Blythe
  */
-PRIVATE void (*callstack[ATEXITSIZE])();
-PRIVATE int topOfStack = 0;
-
 #ifdef __STDC__
-PUBLIC int LYatexit(void (*function)())	{
+PUBLIC int LYatexit(void (*function)())
 #else /* Not ANSI, ugh! */
 PUBLIC int LYatexit(function)
-void (*function)();	{
+void (*function)();
 #endif /* __STDC__ */
-/*
- *	Purpose:	Registers termination function.
- *	Arguments:	function	The function to register.
- *	Return Value:	int	0	registered
- *				!0	no more space to register
- *	Remarks/Portability/Dependencies/Restrictions:
- *	Revision History:
- *		06-15-94	created Lynx 2-3-1 Garrett Arch Blythe
- */
-	/*
-	 *	Check for available space
-	 */
-	if(topOfStack == ATEXITSIZE)	{
-		return(-1);
-	}
+{
+    /*
+     *  Check for available space.
+     */
+    if (topOfStack == ATEXITSIZE) {
+	return(-1);
+    }
 
-	/*
-	 *	Register the function.
-	 */
-	callstack[topOfStack] = function;
-	topOfStack++;
-	return(0);
+    /*
+     *  Register the function.
+     */
+    callstack[topOfStack] = function;
+    topOfStack++;
+    return(0);
 }
 
-PRIVATE void LYCompleteExit NOPARAMS	{
 /*
- *	Purpose:	Call the functions registered with LYatexit
- *	Arguments:	void
- *	Return Value:	void
- *	Remarks/Portability/Dependencies/Restrictions:
- *	Revision History:
- *		06-15-94	created Lynx 2-3-1 Garrett Arch Blythe
+ *  Purpose:		Call the functions registered with LYatexit
+ *  Arguments:		void
+ *  Return Value:	void
+ *  Remarks/Portability/Dependencies/Restrictions:
+ *  Revision History:
+ *	06-15-94	created Lynx 2-3-1 Garrett Arch Blythe
  */
-
-	/*
-	 *	Just loop through registered functions.
-	 *	This is reentrant if more exits occur in the registered
-	 *		functions.
-	 */
-	while(--topOfStack >= 0)	{
-		callstack[topOfStack]();
-	}
+PRIVATE void LYCompleteExit NOPARAMS
+{
+    /*
+     *  Just loop through registered functions.
+     *  This is reentrant if more exits occur in the registered functions.
+     */
+    while (--topOfStack >= 0) {
+	callstack[topOfStack]();
+    }
 }
diff --git a/src/LYrcFile.c b/src/LYrcFile.c
index 9b8aaa39..4d59e861 100644
--- a/src/LYrcFile.c
+++ b/src/LYrcFile.c
@@ -10,7 +10,7 @@
 
 #include "LYLeaks.h"
 
-PUBLIC void read_rc()
+PUBLIC void read_rc NOPARAMS
 {
     char line_buffer[256];
     char rcfile[256];
@@ -22,121 +22,111 @@ PUBLIC void read_rc()
     char *MBM_cp, *MBM_cp2, *MBM_cp1;
     int  MBM_i1, MBM_i2;
 
-    /* make a name */
-#ifdef UNIX
-    sprintf(rcfile,"%s/.lynxrc", Home_Dir());  /* UNIX */
+    /*
+     *  Make an RC file name.
+     */
+#ifdef VMS
+    sprintf(rcfile, "sys$login:.lynxrc");
 #else
-    sprintf(rcfile,"sys$login:.lynxrc");  /* VMS */
-#endif /* UNIX */
+    sprintf(rcfile, "%s/.lynxrc", Home_Dir());
+#endif /* VMS */
 
-    if ((fp = fopen(rcfile,"r")) == NULL) {
+    /*
+     *  Open the RC file for reading.
+     */
+    if ((fp = fopen(rcfile, "r")) == NULL) {
 	return;
     }
 
+    /*
+     *  Process the entries.
+     */
     while (fgets(line_buffer, 256, fp) != NULL) {
-
-	/* remove the end /n */
+	/*
+	 *  Remove the /n from the end of the line.
+	 */
 	if (line_buffer[0] && line_buffer[strlen(line_buffer)-1] == '\n')
 	    line_buffer[strlen(line_buffer)-1] = '\0';
 
-	/* remove trailing white space */
+	/*
+	 *  Remove any trailing white space.
+	 */
 	while (line_buffer[0] && isspace(line_buffer[strlen(line_buffer)-1]))
 	    line_buffer[strlen(line_buffer)-1] = '\0';
 	
-	/*  skip any comment or blank lines */
+	/*
+	 *  Skip any comment or blank lines.
+	 */
 	if (line_buffer[0] == '\0' || line_buffer[0] == '#')
 	    continue;
 
-        /* find the line position of the number sign if there is one */
-        if ((cp = (char *)strchr(line_buffer,'#')) == NULL)
+        /*
+	 *  Find the line position of the number sign if there is one.
+	 */
+        if ((cp = (char *)strchr(line_buffer, '#')) == NULL)
 	    number_sign = 999;
 	else
 	    number_sign = cp - line_buffer;
 
+        /*
+	 *  File editor.
+	 */
+	if (!system_editor &&
+	    (cp = LYstrstr(line_buffer, "file_editor")) != NULL &&
+	    cp-line_buffer < number_sign) {
 
-	/* Character set */
-	if ((cp=LYstrstr(line_buffer,"character_set"))!=NULL &&
-		cp-line_buffer < number_sign) {
-
-		int i=0;
-
-	       	if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		    cp = cp2+1;
-
-	       	while (isspace(*cp)) cp++;  /* get rid of spaces */
-
-                for (; LYchar_set_names[i]; i++)
-                    if (!strncmp(cp,LYchar_set_names[i],strlen(cp))) {
-                        current_char_set=i;
-			HTMLSetRawModeDefault(i);
-                        break;
-                    }
-
-	/* Linedit mode */
-	} else if ((cp=LYstrstr(line_buffer,"lineedit_mode"))!=NULL &&
-		cp-line_buffer < number_sign) {
-
-		int i=0;
-
-	       	if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		    cp = cp2+1;
-
-	       	while (isspace(*cp)) cp++;  /* get rid of spaces */
-
-                for (; LYLineeditNames[i]; i++)
-                    if (!strncmp(cp,LYLineeditNames[i],strlen(cp))) {
-                        current_lineedit=i;
-                        break;
-                    }
-
-	/* user mode */
-	} else if ((cp=LYstrstr(line_buffer,"user_mode"))!=NULL &&
-		cp-line_buffer < number_sign) {
-
-		if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		    cp = cp2+1;
-
-		while (isspace(*cp)) cp++;  /* get rid of spaces */
-	
-		if (LYstrstr(cp,"ADVANCED") != NULL)
-	            user_mode = ADVANCED_MODE;
-		else if (LYstrstr(cp,"INTERMEDIATE") != NULL)
-	            user_mode = INTERMEDIATE_MODE;
-		else
-	            user_mode = NOVICE_MODE;
-
-        /* file editor */
-	} else if (!system_editor &&
-		(cp=LYstrstr(line_buffer,"file_editor"))!=NULL &&
-		cp-line_buffer < number_sign) {
-
-	       if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		    cp = cp2+1;
-
-	       while (isspace(*cp)) cp++;  /* get rid of spaces */
-	
- 	       StrAllocCopy(editor, cp);
+	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+	 	cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+ 	    StrAllocCopy(editor, cp);
 
-	/* bookmark file */
+	/*
+	 *  Default bookmark file.
+	 */
 	} else if ((cp = LYstrstr(line_buffer, "bookmark_file")) != NULL &&
 		    cp-line_buffer < number_sign) {
 
 	    if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2+1;
-
+		cp = cp2 + 1;
 	    while (isspace(*cp))
 	        cp++;  /* get rid of spaces */
 
             /*
-	     *  Since this is the "default" saveto, we save it.
+	     *  Since this is the "Default Bookmark File", we save it
+	     *  as a globals, and as the first MBM_A_subbookmark entry.
 	     */
 	    StrAllocCopy(bookmark_page, cp);
 	    StrAllocCopy(BookmarkPage, cp);
             StrAllocCopy(MBM_A_subbookmark[0], cp);
             StrAllocCopy(MBM_A_subdescript[0], MULTIBOOKMARKS_DEFAULT);
 
+	/*
+	 *  Multiple (sub)bookmark support settings.
+	 */
+        } else if ((cp = LYstrstr(line_buffer, "sub_bookmarks")) != NULL &&
+                   cp-line_buffer < number_sign) {
+
+           if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+                cp = (cp2 + 1);
+           while (isspace(*cp))
+	       cp++;  /* get rid of spaces */
+           if (!strncasecomp(cp, "standard", 8)) {
+              LYMultiBookmarks = TRUE;
+              LYMBMAdvanced = FALSE;
+           } else if (!strncasecomp(cp, "advanced", 8)) {
+              LYMultiBookmarks = TRUE;
+              LYMBMAdvanced = TRUE;
+           } else {
+              LYMultiBookmarks = FALSE;
+	   }
+
+	/*
+	 *  Multiple (sub)bookmark definitions and descriptions.
+	 */
 	} else if ((cp = LYstrstr(line_buffer, "multi_bookmark")) != NULL &&
                    cp-line_buffer < number_sign) {
+
             /*
 	     *  Found the root, now cycle through all the
              *  possible spaces and match specific ones.
@@ -202,25 +192,17 @@ PUBLIC void read_rc()
 		}
 	    }
 
-	/* personal_mail_address */
-        } else if((cp=LYstrstr(line_buffer,"personal_mail_address"))!=NULL &&
-		cp-line_buffer < number_sign) {
-
-	   if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2+1;
-
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
-
-	   StrAllocCopy(personal_mail_address, cp);
-
-	} else if ((cp = LYstrstr(line_buffer,"file_sorting_method")) != NULL &&
-		cp-line_buffer < number_sign) {
-
-	   if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2+1;
-
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
+	/*
+	 * FTP/file sorting method.
+	 */
+	} else if ((cp = LYstrstr(line_buffer,
+				  "file_sorting_method")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
+	   if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	   while (isspace(*cp))
+	       cp++;  /* get rid of spaces */
 	   if (!strncasecomp(cp, "BY_FILENAME", 11))
 		HTfileSortMethod = FILE_BY_NAME;
 	   else if (!strncasecomp(cp, "BY_TYPE", 7))
@@ -230,182 +212,247 @@ PUBLIC void read_rc()
 	   else if (!strncasecomp(cp, "BY_DATE", 7))
 		HTfileSortMethod = FILE_BY_DATE;
 
-	} else if ((cp = LYstrstr(line_buffer,"case_sensitive_searching"))
-								   != NULL &&
-		cp-line_buffer < number_sign) {
-
-	   if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2+1;
-
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
-
-	   if (!strncasecomp(cp, "on", 2))
-	      case_sensitive=TRUE;
-	   else
-	      case_sensitive=FALSE;
-
-#ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS
-
-	} else if ((cp = LYstrstr(line_buffer,"run_all_execution_links")) 
-								 != NULL &&
-		cp-line_buffer < number_sign) {
-
-	   if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2+1;
-
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
+	/*
+	 *  Personal mail address.
+	 */
+        } else if ((cp = LYstrstr(line_buffer,
+				  "personal_mail_address")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-	   if (!strncasecomp(cp, "on", 2))
-	      local_exec=TRUE;
-	   else
-	      local_exec=FALSE;
+	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    StrAllocCopy(personal_mail_address, cp);
 
+	/*
+	 *  Searching type.
+	 */
 	} else if ((cp = LYstrstr(line_buffer,
-			"run_execution_links_on_local_files")) != NULL &&
-		cp-line_buffer < number_sign) {
-
-	   if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2+1;
-
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
-
-	   if (!strncasecomp(cp, "on", 2))
-	      local_exec_on_local_files=TRUE;
-	   else
-	      local_exec_on_local_files=FALSE;
+				  "case_sensitive_searching")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-#endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */
+	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    if (!strncasecomp(cp, "on", 2))
+	        case_sensitive = TRUE;
+	    else
+	        case_sensitive = FALSE;
+
+	/*
+	 *  Character set.
+	 */
+	} else if ((cp = LYstrstr(line_buffer, "character_set")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-	} else if ((cp=LYstrstr(line_buffer,"vi_keys"))!=NULL &&
-		cp-line_buffer < number_sign) {
+	    int i = 0;
 
-	   if ((cp2 = (char * )strchr(cp,'=')) != NULL)
-		cp = cp2+1;
+	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+            for (; LYchar_set_names[i]; i++) {
+                if (!strncmp(cp, LYchar_set_names[i], strlen(cp))) {
+                    current_char_set=i;
+		    HTMLSetRawModeDefault(i);
+                    break;
+                }
+	    }
 
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
-	
-	   if (!strncasecomp(cp, "on", 2))
-	      vi_keys=TRUE;
-	   else
-	      vi_keys=FALSE;
+	/*
+	 *  Preferred language.
+	 */
+	} else if ((cp = LYstrstr(line_buffer,
+				  "preferred_language")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-        } else if ((cp=LYstrstr(line_buffer,"emacs_keys"))!=NULL &&
-                cp-line_buffer < number_sign) {
+	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    StrAllocCopy(language, cp);
 
-           if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-                cp = cp2+1;
+	/*
+	 *  Preferred charset.
+	 */
+	} else if ((cp = LYstrstr(line_buffer,
+				  "preferred_charset")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-           while (isspace(*cp)) cp++;  /* get rid of spaces */
+	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    StrAllocCopy(pref_charset, cp);
 
-           if (!strncasecomp(cp, "on", 2))
-              emacs_keys=TRUE;
-           else
-              emacs_keys=FALSE;
+	/*
+	 * VI keys.
+	 */
+	} else if ((cp = LYstrstr(line_buffer, "vi_keys")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-	/* multi bookmarks */
-        } else if ((cp = LYstrstr(line_buffer, "sub_bookmarks")) != NULL &&
+	    if ((cp2 = (char * )strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    if (!strncasecomp(cp, "on", 2))
+	        vi_keys = TRUE;
+	    else
+	        vi_keys = FALSE;
+
+	/*
+	 *  EMACS keys.
+	 */
+        } else if ((cp = LYstrstr(line_buffer, "emacs_keys")) != NULL &&
                    cp-line_buffer < number_sign) {
 
-           if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-                cp = (cp2 + 1);
-
-           while (isspace(*cp))
-	       cp++;  /* get rid of spaces */
-
-           if (!strncmp(cp, "on", 2) || !strncmp(cp, "ON", 2))
-              LYMultiBookmarks = TRUE;
-           else if (!strncmp(cp, "standard", 8) ||
-                        !strncmp(cp, "STANDARD", 8)) {
-              LYMultiBookmarks = TRUE;
-              LYMBMAdvanced = FALSE;
-           } else if (!strncmp(cp, "advanced", 8) ||
-                          !strncmp(cp, "ADVANCED", 8)) {
-              LYMultiBookmarks = TRUE;
-              LYMBMAdvanced = TRUE;
-           } else
-              LYMultiBookmarks = FALSE;
-
-	} else if ((cp=LYstrstr(line_buffer,"keypad_mode"))!=NULL &&
+            if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+                cp = cp2 + 1;
+            while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+            if (!strncasecomp(cp, "on", 2))
+                emacs_keys = TRUE;
+            else
+                emacs_keys=FALSE;
+
+	/*
+	 *  Show dot files.
+	 */
+	} else if ((cp = LYstrstr(line_buffer, "show_dotfiles")) != NULL &&
 		   cp-line_buffer < number_sign) {
 
-	   if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2+1;
-
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
-	
-	   if (LYstrstr(cp,"LINKS_ARE_NUMBERED"))
-	      keypad_mode = LINKS_ARE_NUMBERED;
-	   else
-	      keypad_mode = NUMBERS_AS_ARROWS;
-
-	/* preferred language */
-	} else if ((cp=LYstrstr(line_buffer,"preferred_language"))!=NULL &&
-		cp-line_buffer < number_sign) {
-
-	   if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2+1;
-
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
-
-	   StrAllocCopy(language, cp);
-
-	/* preferred charset */
-	} else if ((cp=LYstrstr(line_buffer,"preferred_charset"))!=NULL &&
-		cp-line_buffer < number_sign) {
+	    if ((cp2 = (char * )strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    if (!strncasecomp(cp, "on", 2))
+	        show_dotfiles = TRUE;
+	    else
+	        show_dotfiles = FALSE;
+
+	/*
+	 *  Select popups.
+	 */
+	} else if ((cp = LYstrstr(line_buffer, "select_popups")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-	   if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2+1;
+	    if ((cp2 = (char * )strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    if (!strncasecomp(cp, "off", 3))
+	        LYSelectPopups = FALSE;
+	    else
+	        LYSelectPopups = TRUE;
+
+	/*
+	 *  Keypad mode.
+	 */
+	} else if ((cp = LYstrstr(line_buffer, "keypad_mode")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
+	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    if (LYstrstr(cp,"LINKS_ARE_NUMBERED"))
+	        keypad_mode = LINKS_ARE_NUMBERED;
+	    else
+	        keypad_mode = NUMBERS_AS_ARROWS;
+
+	/*
+	 *  Linedit mode.
+	 */
+	} else if ((cp = LYstrstr(line_buffer, "lineedit_mode")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-	   StrAllocCopy(pref_charset, cp);
+	    int i = 0;
 
-	/* show dot files */
-	} else if ((cp=LYstrstr(line_buffer,"show_dotfiles")) != NULL &&
-		cp-line_buffer < number_sign) {
+	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+            for (; LYLineeditNames[i]; i++) {
+                if (!strncmp(cp, LYLineeditNames[i], strlen(cp))) {
+                    current_lineedit = i;
+                    break;
+                }
+	    }
 
-	   if ((cp2 = (char * )strchr(cp,'=')) != NULL)
-		cp = cp2+1;
+#ifdef DIRED_SUPPORT
+	/*
+	 *  List directory style.
+	 */
+	} else if ((cp = LYstrstr(line_buffer, "dir_list_style")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
-	
-	   if (!strncasecomp(cp, "on", 2))
-	      show_dotfiles=TRUE;
-	   else
-	      show_dotfiles=FALSE;
+	    if ((cp2 = (char *)strchr(cp,'=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    if (LYstrstr(cp, "FILES_FIRST") != NULL) {
+	        dir_list_style = FILES_FIRST;
+	    } else if (LYstrstr(cp,"DIRECTORIES_FIRST") != NULL) {
+	        dir_list_style = 0;
+	    } else {
+	        dir_list_style = MIXED_STYLE;
+	    }
+#endif /* DIRED_SUPPORT */
 
-#ifdef DIRED_SUPPORT
-	/* list directory style */
-	} else if ((cp=LYstrstr(line_buffer,"dir_list_style"))!=NULL &&
-		cp-line_buffer < number_sign) {
+	/*
+	 *  User mode.
+	 */
+	} else if ((cp = LYstrstr(line_buffer, "user_mode")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-		if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		    cp = cp2+1;
+	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    if (LYstrstr(cp, "ADVANCED") != NULL) {
+	        user_mode = ADVANCED_MODE;
+	    } else if (LYstrstr(cp,"INTERMEDIATE") != NULL) {
+	        user_mode = INTERMEDIATE_MODE;
+	    } else {
+	        user_mode = NOVICE_MODE;
+	    }
 
-		while (isspace(*cp)) cp++;  /* get rid of spaces */
-	
-		if (LYstrstr(cp,"FILES_FIRST") != NULL)
-	            dir_list_style = FILES_FIRST;
-		else if (LYstrstr(cp,"DIRECTORIES_FIRST") != NULL)
-	            dir_list_style = 0;
-		else
-	            dir_list_style = MIXED_STYLE;
+#ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS
+        /*
+	 *  Local execution mode - all links.
+	 */
+	} else if ((cp = LYstrstr(line_buffer,
+				  "run_all_execution_links")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-#endif /* DIRED_SUPPORT */
+	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
 
-	/* select popups */
-	} else if ((cp=LYstrstr(line_buffer,"select_popups")) != NULL &&
-		cp-line_buffer < number_sign) {
+	    if (!strncasecomp(cp, "on", 2))
+	        local_exec = TRUE;
+	     else
+	        local_exec = FALSE;
 
-	   if ((cp2 = (char * )strchr(cp,'=')) != NULL)
-		cp = cp2+1;
+        /*
+	 *  Local execution mode - only links in local files.
+	 */
+	} else if ((cp = LYstrstr(line_buffer,
+			"run_execution_links_on_local_files")) != NULL &&
+		   cp-line_buffer < number_sign) {
 
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
-	
-	   if (!strncasecomp(cp, "off", 3))
-	       LYSelectPopups = FALSE;
-	   else
-	       LYSelectPopups = TRUE;
+	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    if (!strncasecomp(cp, "on", 2))
+	        local_exec_on_local_files = TRUE;
+	    else
+	        local_exec_on_local_files=FALSE;
+#endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */
 
 	} /* end of if */
 
@@ -414,219 +461,160 @@ PUBLIC void read_rc()
     fclose(fp);
 } /* big end */
 	
-PUBLIC int save_rc ()
+PUBLIC int save_rc NOPARAMS
 {
     char rcfile[256];
     FILE *fp;
     int i;
     int MBM_c;
 
-    /* make a name */
-#ifdef UNIX
-    sprintf(rcfile,"%s/.lynxrc", Home_Dir());  /* UNIX */
-#else
+    /*
+     *  Make a name.
+     */
 #ifdef VMS
-    sprintf(rcfile,"sys$login:.lynxrc");  /* VMS */
+    sprintf(rcfile, "sys$login:.lynxrc");
 #else
-    sprintf(rcfile,".lynxrc");   /* anything else */
+    sprintf(rcfile, "%s/.lynxrc", Home_Dir());
 #endif /* VMS */
-#endif /* UNIX */
     
-    if ((fp = fopen(rcfile,"w")) == NULL) {
+    /*
+     *  Open the file for write.
+     */
+    if ((fp = fopen(rcfile, "w")) == NULL) {
 	return FALSE;
     }
 
-    /* header */
-    fprintf(fp,"# Lynx user defaults file\n\n");
+    /*
+     *  Header.
+     */
+    fprintf(fp, "# Lynx User Defaults File\n\n");
 
-    /* user mode */
-    fprintf(fp,"\
-# user_mode specifies the users level of knowledge with Lynx.\n\
-# The default is NOVICE which displays two extra lines of help at the\n\
-# bottom of the screen to aid the user in learning the basic Lynx\n\
-# commands.  Set user_mode to INTERMEDIATE to turn off the extra info.\n\
-# Use ADVANCED to see the URL of the currently selected link at the\n\
-# bottom of the screen\n");
-    fprintf(fp,"user_mode=%s\n\n",(user_mode==NOVICE_MODE ? "NOVICE" : 
-				  (user_mode==ADVANCED_MODE ? "ADVANCED" :
-							"INTERMEDIATE")));
-
-    /* editor */
-    fprintf(fp,"\
-# file editor specifies the editor to be invoked when editing Lynx files.\n\
-# if no editor is specified then file editing is disabled unless it\n\
-# is activated from the command line\n");
-    fprintf(fp,"file_editor=%s\n\n", (editor ? editor : ""));
-
-    /* home file */
-    fprintf(fp,"\
-# bookmark_file specifies the name and location of a custom file which the\n\
-# user can paste links to for easy access at a later date\n");
-    fprintf(fp,"bookmark_file=%s\n\n", (bookmark_page ? bookmark_page : ""));
-
-    /* personal_mail_address */
-    fprintf(fp,"\
+    /*
+     *  File editor
+     */
+    fprintf(fp, "\
+# file_editor specifies the editor to be invoked when editing local files\n\
+# or sending mail.  If no editor is specified, then file editing is disabled\n\
+# unless it is activated from the command line, and the built-in line editor\n\
+# will be used for sending mail.\n");
+    fprintf(fp, "file_editor=%s\n\n", (editor ? editor : ""));
+
+    /*
+     *  Default bookmark file.
+     */
+    fprintf(fp, "\
+# bookmark_file specifies the name and location of the default bookmark\n\
+# file into which the user can paste links for easy access at a later\n\
+# date.\n");
+    fprintf(fp, "bookmark_file=%s\n\n", (bookmark_page ? bookmark_page : ""));
+
+    /*
+     *  Multiple (sub)bookmark support settings.
+     */
+    fprintf(fp, "\
+# If sub_bookmarks is not turned \"off\", and multiple bookmarks have\n\
+# been defined (see below), then all bookmark operations will first\n\
+# prompt the user to select an active sub-bookmark file.  If the default\n\
+# Lynx bookmark_file is defined (see above), it will be used as the\n\
+# default selection.  When this option is set to \"advanced\", and the\n\
+# user mode is advanced, the 'v'iew bookmark command will invoke a\n\
+# statusline prompt instead of the menu seen in novice and intermediate\n\
+# user modes.  When this option is set to \"standard\", the menu will be\n\
+# presented regardless of user mode.\n");
+    fprintf(fp, "sub_bookmarks=%s\n\n", (LYMultiBookmarks ?
+          				   (LYMBMAdvanced ?
+					       "advanced" : "standard")
+					       		  : "off"));
+
+    /*
+     *  Multiple (sub)bookmark definitions and descriptions.
+     */
+    fprintf(fp, "\
+# The following allow you to define sub-bookmark files and descriptions.\n\
+# The format is multi_bookmark<capital_letter>=<filename>,<description>\n\
+# Up to 26 bookmark files (for the English capital letters) are allowed.\n\
+# We start with \"multi_bookmarkB\" since 'A' is the default (see above).\n");
+    for (MBM_c = 1; MBM_c <= MBM_V_MAXFILES; MBM_c++)
+       fprintf(fp, "multi_bookmark%c=%s%s%s\n",
+       		   (MBM_c + 'A'),
+		   (MBM_A_subbookmark[MBM_c] ?
+		    MBM_A_subbookmark[MBM_c] : ""),
+		   (MBM_A_subbookmark[MBM_c] ?
+		   			 "," : ""),
+		   (MBM_A_subdescript[MBM_c] ?
+		    MBM_A_subdescript[MBM_c] : ""));
+    fprintf(fp, "\n");
+
+    /*
+     *  FTP/file sorting method.
+     */
+    fprintf(fp, "\
+# The file_sorting_method specifies which value to sort on when viewing\n\
+# file lists such as FTP directories.  The options are:\n\
+#    BY_FILENAME -- sorts on the name of the file\n\
+#    BY_TYPE     -- sorts on the type of the file\n\
+#    BY_SIZE     -- sorts on the size of the file\n\
+#    BY_DATE     -- sorts on the date of the file\n");
+    fprintf(fp, "file_sorting_method=%s\n\n",
+     		(HTfileSortMethod == FILE_BY_NAME ? "BY_FILENAME"
+				    		  : 
+	 	(HTfileSortMethod == FILE_BY_SIZE ? "BY_SIZE"
+						  :
+		(HTfileSortMethod == FILE_BY_TYPE ? "BY_TYPE"
+						  : "BY_DATE"))));
+
+    /*
+     *  Personal mail address.
+     */
+    fprintf(fp, "\
 # personal_mail_address specifies your personal mail address.  The\n\
 # address will be sent during HTTP file transfers for authorization and\n\
 # logging purposes, and for mailed comments.\n\
-# If you do not want this information given out, leave this field blank\n");
-    fprintf(fp,"personal_mail_address=%s\n\n", (personal_mail_address ?
-						personal_mail_address : ""));
-
-    /* case sensitive */
-    fprintf(fp,"\
-# if case sensitive searching is on then when the user invokes a search\n\
+# If you do not want this information given out, set the NO_FROM_HEADER\n\
+# to TRUE in lynx.cfg, or use the -nofrom command line switch.  You also\n\
+# could leave this field blank, but then you won't have if it included in\n\
+# your mailed comments.\n");
+    fprintf(fp, "personal_mail_address=%s\n\n",
+    		(personal_mail_address ? personal_mail_address : ""));
+
+    /*
+     *  Searching type.
+     */
+    fprintf(fp, "\
+# If case_sensitive_searching is \"on\" then when the user invokes a search\n\
 # using the 's' or '/' keys, the search performed will be case sensitive\n\
-# instead of case INsensitive.\n# the default is usually off\n");
-  fprintf(fp,"case_sensitive_searching=%s\n\n",(case_sensitive ? "on" : "off"));
+# instead of case INsensitive.  The default is usually \"off\".\n");
+    fprintf(fp, "case_sensitive_searching=%s\n\n",
+  		(case_sensitive ? "on" : "off"));
 
-    /* file sort method */
-    fprintf(fp,"\
-# The file sort method specifies which value to sort on when viewing file\n\
-# lists such as FTP directories.  The options are:\n\
-#    BY_FILENAME -- sorts on the name of the file\n\
-#    BY_TYPE     -- sorts on the type of the file\n\
-#    BY_SIZE     -- sorts on the size of the file\n\
-#    BY_DATE     -- sorts on the date of the file\n");
-  fprintf(fp,"file_sorting_method=%s\n\n",
-	  (HTfileSortMethod==FILE_BY_NAME ? "BY_FILENAME" : 
-	 	(HTfileSortMethod==FILE_BY_SIZE ? "BY_SIZE" :
-			(HTfileSortMethod==FILE_BY_TYPE ? "BY_TYPE" :
-				"BY_DATE"))));
-
-    /* Character Set */
-    fprintf(fp,"\
-# The character set definition controls the representation of\n\
-# 8 bit characters for your terminal.  If 8 bit characters do\n\
-# not show up correctly on your screen you may try changing\n\
-# to a different 8 bit set or using the 7 bit character approximations.\n\
+    /*
+     *  Character set.
+     */
+    fprintf(fp, "\
+# The character_set definition controls the representation of 8 bit\n\
+# characters for your terminal.  If 8 bit characters do not show up\n\
+# correctly on your screen you may try changing to a different 8 bit\n\
+# set or using the 7 bit character approximations.\n\
 # Current valid characters sets are:\n");
-    for (i=0;LYchar_set_names[i];i++)
-	fprintf(fp,"#    %s\n",LYchar_set_names[i]);
-    fprintf(fp,"character_set=%s\n\n",LYchar_set_names[current_char_set]);
-
+    for (i = 0; LYchar_set_names[i]; i++)
+	fprintf(fp, "#    %s\n", LYchar_set_names[i]);
+    fprintf(fp, "character_set=%s\n\n", LYchar_set_names[current_char_set]);
 
-#if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS) 
-    /* local_exec */
-    fprintf(fp,"\
-# if run all execution links is on then all local exection links will\n\
-# be executed when they are selected.\n\
-#\n\
-# WARNING - this is potentially VERY dangerous.  Since you may view\n\
-#           information that is written by unknown and untrusted sources\n\
-#           there exists the possibility that trojan horse links could be\n\
-#           written.  Trojan horse links could be written to erase files\n\
-#           or compromise security.  This should only be set to on if you\n\
-#           are viewing trusted source information\n");
 
-    fprintf(fp, "run_all_execution_links=%s\n\n",(local_exec ? "on" : "off"));
-
-    /* local_exec_on_local_files */
-    fprintf(fp,"\
-# if run all execution links is on then all local exection links that\n\
-# are found in LOCAL files will be executed when they are selected.\n\
-# This is different from \"run all execution links\" in that only files\n\
-# that reside on the local system will have execution link permissions\n\
-#\n\
-# WARNING - this is potentially dangerous.  Since you may view\n\
-#           information that is written by unknown and untrusted sources\n\
-#           there exists the possibility that trojon horse links could be\n\
-#           written.  Trojon horse links could be written to erase files\n\
-#           or compromise security.  This should only be set to on if you\n\
-#           are viewing trusted source information\n");
-
-   fprintf(fp,"run_execution_links_on_local_files=%s\n\n",
-			(local_exec_on_local_files ? "on" : "off"));
-
-#endif /* defined(EXEC_LINKS) || defined(EXEC_SCRIPTS) */
-
-    /* vi keys */
-    fprintf(fp,"\
-# if VI keys are turned on then the normal VI movement keys:\n\
-# j - down    k - up\n\
-# h - left    l - right\n\
-# will be enabled.\n\
-# These keys are only lower case.\n\
-# Capital 'H' will still activate help\n");
-    fprintf(fp,"vi_keys=%s\n\n",(vi_keys ? "on" : "off"));
-
-    /* emacs keys */
-    fprintf(fp,"\
-# if EMACS keys are turned on then the normal EMACS movement keys:\n\
-# ^N - down    ^p - up\n\
-# ^B - left    ^F - right\n\
-# will be enabled.\n");
-    fprintf(fp, "emacs_keys=%s\n\n", (emacs_keys ? "on" : "off"));
-
-    /* multiple bookmarks - on or off */
-    fprintf(fp,"\
-# If sub_bookmarks are turned on then all bookmark operations\n\
-# will first prompt the user to select an active sub-bookmark file.\n\
-# If the default lynx bookmarks file is defined, it will be used as\n\
-# the default selection. When this option is set to 'advanced', and\n\
-# the user mode is advanced, the 'v'iew bookmark command will invoke\n\
-# a statusline prompt instead of the menu seen in novice and intermediate\n\
-# user modes. When this option is set to 'standard', the menu will be\n\
-# presented regardless of user mode. If this option is set to 'off',\n\
-# sub-bookmark files are disabled.\n");
-    fprintf(fp,"sub_bookmarks=%s\n\n", (LYMultiBookmarks ?
-          (LYMBMAdvanced ? "advanced" : "standard") : "off"));
-
-    /* multiple bookmarks support - list out sub-bookmarks */
-    fprintf(fp,"\
-# The following allow you to define sub-bookmark files and definitions.\n\
-# Format is <keyword><letter>=<filename>,<description>\n\
-# Up to MBM_V_MAXFILES (26 MAX) are allowed.\n\
-# We start with 'multi_bookmarkB' since 'A' is reserved!\n");
-    for (MBM_c = 1; MBM_c <= MBM_V_MAXFILES; MBM_c++)
-       fprintf(fp,"multi_bookmark%c=%s%s%s\n", (MBM_c + 'A'),
-             (MBM_A_subbookmark[MBM_c] ? MBM_A_subbookmark[MBM_c] : ""),
-             (MBM_A_subbookmark[MBM_c] ? "," : ""),
-             (MBM_A_subdescript[MBM_c] ? MBM_A_subdescript[MBM_c] : ""));
-    fprintf(fp,"\n");
-
-    /* keypad mode */
-    fprintf(fp,"\
-# if keypad_mode is set to NUMBERS_AS_ARROWS then the numbers\n\
-# on your keypad when the numlock is on will act as arrow keys.\n\
-# i.e. 4 - Left Arrow, 6 - Right Arrow, 2 - Down Arrow, 8 - Up Arrow, etc.\n\
-# if keypad_mode is set to LINKS_ARE_NUMBERED then numbers will appear\n\
-# next to each link and numbers are used to select links.\n\
-# note: some fixed format documents may look disfigured when\n\
-# LINKS_ARE_NUMBERED is enabled.\n");
-    fprintf(fp,"keypad_mode=%s\n\n",(keypad_mode==NUMBERS_AS_ARROWS ? 
-				"NUMBERS_AS_ARROWS" : "LINKS_ARE_NUMBERED"));
- 
-    /* lineedit */
-    fprintf(fp,"\
-# linedit_mode specifies the key binding used for inputting strings in\n\
-# prompts and forms. if line_editmode is set to DEFAULT_BINDING then the\n\
-# following control characters are used for moving and deleting:\n\
-#\n\
-#      left word char       char word right     Enter = Next line\n\
-#            W E    remove   R T                ^G    = Cancel input\n\
-#             D <-   move  -> F                 ^U    = Erase line\n\
-#\n\
-# Current lineedit modes are:\n");
-
-    { char **bindings = LYLineeditNames;
-      while (*bindings) {
-          fprintf(fp,"#    %s\n",*bindings);
-          bindings++;
-      }
-    }
-    fprintf(fp,"lineedit_mode=%s\n\n",LYLineeditNames[current_lineedit]);
-
-    /* preferred language */
-    fprintf(fp,"\
+    /*
+     *  Preferred language.
+     */
+    fprintf(fp, "\
 # preferred_language specifies the language in MIME notation (e.g., en,\n\
 # fr) which Lynx will indicate you prefer in requests to http servers.\n\
 # If a file in that language is available, the server will send it.\n\
 # Otherwise, the server will send the file in it's default language.\n");
-    fprintf(fp,"preferred_language=%s\n\n", (language ? language : ""));
+    fprintf(fp, "preferred_language=%s\n\n", (language ? language : ""));
 
-    /* preferred charset */
-    fprintf(fp,"\
+    /*
+     *  Preferred charset.
+     */
+    fprintf(fp, "\
 # preferred_charset specifies the character set in MIME notation (e.g.,\n\
 # ISO-8859-2, ISO-8859-5) which Lynx will indicate you prefer in requests\n\
 # to http servers using an Accept-Charset header.  The value should NOT\n\
@@ -634,31 +622,45 @@ PUBLIC int save_rc ()
 # default.  If a file in that character set is available, the server will\n\
 # send it.  Otherwise, the server will send the file in ISO-8859-1 or\n\
 # US-ASCII.\n");
-    fprintf(fp,"preferred_charset=%s\n\n", (pref_charset ? pref_charset : ""));
+    fprintf(fp, "preferred_charset=%s\n\n",
+    		(pref_charset ? pref_charset : ""));
+
+    /*
+     *  VI keys.
+     */
+    fprintf(fp, "\
+# If vi_keys is set to \"on\", then the normal VI movement keys:\n\
+#   j = down    k = up\n\
+#   h = left    l = right\n\
+# will be enabled.  These keys are only lower case.\n\
+# Capital 'H', 'J' and 'K will still activate help, jump shortcuts,\n\
+# and the keymap display, respectively.\n");
+     fprintf(fp, "vi_keys=%s\n\n", (vi_keys ? "on" : "off"));
+
+    /*
+     *  EMACS keys.
+     */
+    fprintf(fp, "\
+# If emacs_keys is to \"on\" then the normal EMACS movement keys:\n\
+#   ^N = down    ^P = up\n\
+#   ^B = left    ^F = right\n\
+# will be enabled.\n");
+    fprintf(fp, "emacs_keys=%s\n\n", (emacs_keys ? "on" : "off"));
 
-    /* show dot files */
+    /*
+     *  Show dot files.
+     */
     fprintf(fp, "\
 # show_dotfiles specifies that the directory listing should include\n\
 # \"hidden\" (dot) files/directories.  If set \"on\", this will be\n\
 # honored only if enabled via userdefs.h and/or lynx.cfg, and not\n\
 # restricted via a command line switch.  If display of hidden files\n\
 # is disabled, creation of such files via Lynx also is disabled.\n");
-    fprintf(fp, "show_dotfiles=%s\n\n",(show_dotfiles ? "on" : "off"));
+    fprintf(fp, "show_dotfiles=%s\n\n", (show_dotfiles ? "on" : "off"));
 
-#ifdef DIRED_SUPPORT
-    /* list directory style */
-    fprintf(fp,"\
-# dir_list_styles specifies the directory list style under DIRED_SUPPORT\n\
-# (if implemented).  The default is MIXED_STYLE, which sorts both files and\n\
-# directories together.  FILES_FIRST lists files first and DIRECTORIES_FIRST\n\
-# lists directories first.\n");
-    fprintf(fp,"dir_list_style=%s\n\n",
-    			(dir_list_style==FILES_FIRST ? "FILES_FIRST" : 
-			 (dir_list_style==MIXED_STYLE ? "MIXED_STYLE" :
-							"DIRECTORIES_FIRST")));
-#endif /* DIRED_SUPPORT */
-
-    /* select popups */
+    /*
+     *  Select popups.
+     */
     fprintf(fp, "\
 # select_popups specifies whether the OPTIONs in a SELECT block which\n\
 # lacks a MULTIPLE attribute are presented as a vertical list of radio\n\
@@ -667,17 +669,132 @@ PUBLIC int save_rc ()
 # of checkboxes for the OPTIONs.  A value of \"on\" will set popup menus\n\
 # as the default while a value of \"off\" will set use of radio boxes.\n\
 # The default can be overridden via the -popup command line toggle.\n");
-    fprintf(fp, "select_popups=%s\n\n",(LYSelectPopups ? "on" : "off"));
+    fprintf(fp, "select_popups=%s\n\n", (LYSelectPopups ? "on" : "off"));
+
+    /*
+     *  Keypad mode.
+     */
+    fprintf(fp, "\
+# If keypad_mode is set to \"NUMBERS_AS_ARROWS\", then the numbers on\n\
+# your keypad when the numlock is on will act as arrow keys:\n\
+#             8 = Up Arrow\n\
+#   4 = Left Arrow    6 = Right Arrow\n\
+#             2 = Down Arrow\n\
+# If keypad_mode is set to \"LINKS_ARE_NUMBERED\", then numbers will\n\
+# appear next to each link and numbers are used to select links.\n\
+# NOTE: Some fixed format documents may look disfigured when\n\
+# \"LINKS_ARE_NUMBERED\" is enabled.\n");
+    fprintf(fp, "keypad_mode=%s\n\n",
+    		(keypad_mode==NUMBERS_AS_ARROWS ? 
+			    "NUMBERS_AS_ARROWS" : "LINKS_ARE_NUMBERED"));
+ 
+    /*
+     *  Lineedit mode.
+     */
+    fprintf(fp, "\
+# linedit_mode specifies the key binding used for inputting strings in\n\
+# prompts and forms.  If lineedit_mode is set to \"Default Binding\" then\n\
+# the following control characters are used for moving and deleting:\n\
+#\n\
+#              Prev  Next       Enter = Accept input\n\
+#    Move char: <-    ->        ^G    = Cancel input\n\
+#    Move word: ^P    ^N        ^U    = Erase line\n\
+#  Delete char: ^H    ^R        ^A    = Beginning of line\n\
+#  Delete word: ^B    ^F        ^E    = End of line\n\
+#\n\
+# Current lineedit modes are:\n");
+    {
+	char **bindings = LYLineeditNames;
+	while (*bindings) {
+	    fprintf(fp, "#    %s\n", *bindings);
+	    bindings++;
+	}
+    }
+    fprintf(fp, "lineedit_mode=%s\n\n", LYLineeditNames[current_lineedit]);
+
+#ifdef DIRED_SUPPORT
+    /*
+     *  List directory style.
+     */
+    fprintf(fp, "\
+# dir_list_styles specifies the directory list style under DIRED_SUPPORT\n\
+# (if implemented).  The default is \"MIXED_STYLE\", which sorts both\n\
+# files and directories together.  \"FILES_FIRST\" lists files first and\n\
+# \"DIRECTORIES_FIRST\" lists directories first.\n");
+    fprintf(fp, "dir_list_style=%s\n\n",
+    		(dir_list_style==FILES_FIRST ? "FILES_FIRST"
+					     : 
+		(dir_list_style==MIXED_STYLE ? "MIXED_STYLE"
+					     : "DIRECTORIES_FIRST")));
+#endif /* DIRED_SUPPORT */
+
+    /*
+     *  User mode.
+     */
+    fprintf(fp, "\
+# user_mode specifies the users level of knowledge with Lynx.  The\n\
+# default is \"NOVICE\" which displays two extra lines of help at the\n\
+# bottom of the screen to aid the user in learning the basic Lynx\n\
+# commands.  Set user_mode to \"INTERMEDIATE\" to turn off the extra info.\n\
+# Use \"ADVANCED\" to see the URL of the currently selected link at the\n\
+# bottom of the screen.\n");
+    fprintf(fp, "user_mode=%s\n\n",
+    		(user_mode == NOVICE_MODE ? "NOVICE" : 
+			 (user_mode == ADVANCED_MODE ? 
+			 		  "ADVANCED" : "INTERMEDIATE")));
+
+#if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS) 
+    /*
+     *  Local execution mode - all links.
+     */
+    fprintf(fp, "\
+# If run_all_execution_links is set \"on\" then all local exection links\n\
+# will be executed when they are selected.\n\
+#\n\
+# WARNING - This is potentially VERY dangerous.  Since you may view\n\
+#           information that is written by unknown and untrusted sources\n\
+#           there exists the possibility that Trojan horse links could be\n\
+#           written.  Trojan horse links could be written to erase files\n\
+#           or compromise security.  This should only be set to \"on\" if\n\
+#           you are viewing trusted source information.\n");
+    fprintf(fp, "run_all_execution_links=%s\n\n",
+    		(local_exec ? "on" : "off"));
+
+    /*
+     *  Local execution mode - only links in local files.
+     */
+    fprintf(fp, "\
+# If run_execution_links_on_local_files is set \"on\" then all local\n\
+# execution links that are found in LOCAL files will be executed when they\n\
+# are selected.  This is different from run_all_execution_links in that\n\
+# only files that reside on the local system will have execution link\n\
+# permissions.\n\
+#\n\
+# WARNING - This is potentially dangerous.  Since you may view\n\
+#           information that is written by unknown and untrusted sources\n\
+#           there exists the possibility that Trojan horse links could be\n\
+#           written.  Trojan horse links could be written to erase files\n\
+#           or compromise security.  This should only be set to \"on\" if\n\
+#           you are viewing trusted source information.\n");
+    fprintf(fp, "run_execution_links_on_local_files=%s\n\n",
+		(local_exec_on_local_files ? "on" : "off"));
+#endif /* defined(EXEC_LINKS) || defined(EXEC_SCRIPTS) */
 
+    /*
+     *  Close the RC file.
+     */
     fclose(fp);
 
-    /* get rid of any copies of the .lynxrc file that VMS creates */
 #ifdef VMS
-	while (remove("sys$login:.lynxrc;-1") == 0) ;
-	/* reset version number */
+    /*
+     *  Get rid of any copies of the .lynxrc file that VMS creates.
+     */
+    while (remove("sys$login:.lynxrc;-1") == 0) ;
+	/*
+	 *  Reset version number.
+	 */
 	rename("sys$login:.lynxrc", "sys$login:.lynxrc;1");
 #endif /* VMS */
 
    return TRUE;
-
 }
diff --git a/src/Makefile b/src/Makefile
index 4b8d5741..73e271b9 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -5,7 +5,7 @@ LYOptions.o LYReadCFG.o LYSearch.o LYHistory.o \
 LYForms.o LYPrint.o LYrcFile.o LYDownload.o LYNews.o LYKeymap.o \
 HTML.o HTFWriter.o HTInit.o DefaultStyle.o LYLocal.o LYUpload.o \
 LYLeaks.o LYexit.o LYJump.o LYList.o LYCgi.o LYTraversal.o \
-LYEditmap.o LYCharSets.o LYCharUtils.o LYMap.o
+LYEditmap.o LYCharSets.o LYCharUtils.o LYMap.o LYCookie.o
 
 CFLAGS= $(MCFLAGS) -I.. $(SLANGINC)
 
@@ -45,3 +45,4 @@ HTInit.o: ../userdefs.h
 LYTraversal.o: ../userdefs.h
 LYMail.o: ../userdefs.h
 LYCharSets.o: ../userdefs.h
+LYCookie.o: ../userdefs.h
diff --git a/src/descrip.mms b/src/descrip.mms
index 6451ee8b..389514f0 100644
--- a/src/descrip.mms
+++ b/src/descrip.mms
@@ -52,11 +52,11 @@
 
 OBJS = 	DefaultStyle.obj, GridText.obj, HTAlert.obj, HTFWriter.obj, -
 	HTInit.obj, HTML.obj, LYBookmark.obj, LYCgi.obj, LYCharSets.obj, -
-	LYCharUtils.obj, LYClean.obj, LYCurses.obj, LYDownload.obj, -
-	LYEdit.obj, LYEditmap.obj, LYexit.obj, LYForms.obj, LYGetFile.obj, -
-	LYHistory.obj, LYJump.obj, LYKeymap.obj, LYLeaks.obj, LYList.obj, -
-	LYMail.obj, LYMain.obj, LYMainLoop.obj, LYMap.obj, LYNews.obj, -
-	LYOptions.obj, LYPrint.obj, LYrcFile.obj, LYReadCFG.obj, -
+	LYCharUtils.obj, LYClean.obj, LYCookie.obj, LYCurses.obj, -
+	LYDownload.obj, LYEdit.obj, LYEditmap.obj, LYexit.obj, LYForms.obj, -
+	LYGetFile.obj, LYHistory.obj, LYJump.obj, LYKeymap.obj, LYLeaks.obj, -
+	LYList.obj, LYMail.obj, LYMain.obj, LYMainLoop.obj, LYMap.obj, -
+	LYNews.obj, LYOptions.obj, LYPrint.obj, LYrcFile.obj, LYReadCFG.obj, -
 	LYSearch.obj, LYShowInfo.obj, LYStrings.obj, LYTraversal.obj, -
 	LYUpload.obj, LYUtils.obj