about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DefaultStyle.c100
-rw-r--r--src/GridText.c299
-rw-r--r--src/GridText.h4
-rw-r--r--src/HTAlert.c90
-rw-r--r--src/HTAlert.h4
-rw-r--r--src/HTFWriter.c147
-rw-r--r--src/HTFont.h2
-rw-r--r--src/HTInit.c9
-rw-r--r--src/HTML.c75
-rw-r--r--src/HTML.h4
-rw-r--r--src/LYCharUtils.c103
-rw-r--r--src/LYCookie.c430
-rw-r--r--src/LYCurses.c6
-rw-r--r--src/LYForms.c3
-rw-r--r--src/LYGetFile.c52
-rw-r--r--src/LYLocal.c4
-rw-r--r--src/LYMain.c4
-rw-r--r--src/LYMainLoop.c63
-rw-r--r--src/LYOptions.c3
-rw-r--r--src/LYShowInfo.c3
-rw-r--r--src/LYUtils.c122
-rw-r--r--src/Makefile1
-rw-r--r--src/UCAux.c5
-rw-r--r--src/UCdomap.c3
-rw-r--r--src/chrtrans/MAKEW32.BAT4
-rw-r--r--src/chrtrans/Makefile1
-rw-r--r--src/chrtrans/build-chrtrans.com2
-rw-r--r--src/chrtrans/cp1251_uni.tbl1
-rw-r--r--src/chrtrans/cp866_uni.tbl189
-rw-r--r--src/chrtrans/koi8r_uni.tbl14
-rw-r--r--src/chrtrans/makefile.in1
-rw-r--r--src/makefile.in1
32 files changed, 1197 insertions, 552 deletions
diff --git a/src/DefaultStyle.c b/src/DefaultStyle.c
index 974a27db..140f0a77 100644
--- a/src/DefaultStyle.c
+++ b/src/DefaultStyle.c
@@ -38,324 +38,324 @@ PRIVATE HTTabStop tabs_16[] = {
 
 PRIVATE HTStyle HTStyleNormal = { 
 	0,  "Normal", "P",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	3, 3, 6, HT_LEFT,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleDivCenter = { 
 	&HTStyleNormal,  "DivCenter", "DCENTER",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	3, 3, 6, HT_CENTER,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleDivLeft = { 
 	&HTStyleDivCenter,  "DivLeft", "DLEFT",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	3, 3, 6, HT_LEFT,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleDivRight = { 
 	&HTStyleDivLeft,  "DivRight", "DRIGHT",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	3, 3, 6, HT_RIGHT,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleBanner = { 
 	&HTStyleDivRight,  "Banner", "BANNER",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	3, 3, 6, HT_LEFT,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleBlockquote = { 
 	&HTStyleBanner,  "Blockquote", "BLOCKQUOTE",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	5, 5, 7, HT_LEFT,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleBq = { /* HTML 3.0 BLOCKQUOTE - FM */
 	&HTStyleBlockquote,  "Bq", "BQ",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	5, 5, 7, HT_LEFT,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleFootnote = { /* HTML 3.0 FN - FM */
 	&HTStyleBq,  "Footnote", "FN",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	5, 5, 7, HT_LEFT,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleList = { 
 	&HTStyleFootnote,  "List", "UL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	3, 7, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0 };	
 
 PRIVATE HTStyle HTStyleList1 = { 
 	&HTStyleList,  "List1", "UL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	8, 12, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0 };	
 
 PRIVATE HTStyle HTStyleList2 = { 
 	&HTStyleList1,  "List2", "UL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	13, 17, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0 };	
 
 PRIVATE HTStyle HTStyleList3 = { 
 	&HTStyleList2,  "List3", "UL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	18, 22, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0 };	
 
 PRIVATE HTStyle HTStyleList4 = { 
 	&HTStyleList3,  "List4", "UL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	23, 27, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0 };	
 
 PRIVATE HTStyle HTStyleList5 = { 
 	&HTStyleList4,  "List5", "UL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	28, 32, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0 };	
 
 PRIVATE HTStyle HTStyleList6 = { 
 	&HTStyleList5,  "List6", "UL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	33, 37, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0 };	
 
 PRIVATE HTStyle HTStyleMenu = {
 	&HTStyleList6,  "Menu", "MENU",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	3, 7, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleMenu1 = {
 	&HTStyleMenu,  "Menu1", "MENU",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	8, 12, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleMenu2= {
 	&HTStyleMenu1,  "Menu2", "MENU",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	13, 17, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleMenu3= {
 	&HTStyleMenu2,  "Menu3", "MENU",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	18, 22, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleMenu4= {
 	&HTStyleMenu3,  "Menu4", "MENU",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	23, 27, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleMenu5= {
 	&HTStyleMenu4,  "Menu5", "MENU",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	28, 33, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleMenu6= {
 	&HTStyleMenu5,  "Menu6", "MENU",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	33, 38, 6, HT_LEFT,		1, 0,	0,
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleGlossary = {
 	&HTStyleMenu6,  "Glossary", "DL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	3, 10, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 1, 1,			0
 };	
 
 PRIVATE HTStyle HTStyleGlossary1 = {
 	&HTStyleGlossary,  "Glossary1", "DL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	8, 16, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 1, 1,			0
 };	
 
 PRIVATE HTStyle HTStyleGlossary2 = {
 	&HTStyleGlossary1,  "Glossary2", "DL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	14, 22, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 1, 1,			0
 };	
 
 PRIVATE HTStyle HTStyleGlossary3 = {
 	&HTStyleGlossary2,  "Glossary3", "DL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	20, 28, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 1, 1,			0
 };	
 
 PRIVATE HTStyle HTStyleGlossary4 = {
 	&HTStyleGlossary3,  "Glossary4", "DL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	26, 34, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 1, 1,			0
 };	
 
 PRIVATE HTStyle HTStyleGlossary5 = {
 	&HTStyleGlossary4,  "Glossary5", "DL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	32, 40, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 1, 1,			0
 };	
 
 PRIVATE HTStyle HTStyleGlossary6 = {
 	&HTStyleGlossary5,  "Glossary6", "DL",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	38, 46, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 1, 1,			0
 };	
 
 PRIVATE HTStyle HTStyleGlossaryCompact = {
 	&HTStyleGlossary6,  "GlossaryCompact", "DLC",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	3, 10, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleGlossaryCompact1 = {
 	&HTStyleGlossaryCompact,  "GlossaryCompact1", "DLC",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	8, 15, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleGlossaryCompact2 = {
 	&HTStyleGlossaryCompact1,  "GlossaryCompact2", "DLC",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	13, 20, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleGlossaryCompact3 = {
 	&HTStyleGlossaryCompact2,  "GlossaryCompact3", "DLC",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	18, 25, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleGlossaryCompact4 = {
 	&HTStyleGlossaryCompact3,  "GlossaryCompact4", "DLC",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	23, 30, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleGlossaryCompact5 = {
 	&HTStyleGlossaryCompact4,  "GlossaryCompact5", "DLC",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	28, 35, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleGlossaryCompact6 = {
 	&HTStyleGlossaryCompact5,  "GlossaryCompact6", "DLC",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	33, 40, 6, HT_LEFT,		1, 0,	0, 
 	YES, YES, 0, 0,			0
 };
 
 PRIVATE HTStyle HTStyleExample = {
 	&HTStyleGlossaryCompact6,  "Example", "XMP",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	0, 0, 0, HT_LEFT,		1, 0,	tabs_8,
 	NO, NO, 0, 0,			0
 };	
 
 PRIVATE HTStyle HTStylePreformatted = {
 	&HTStyleExample,  	"Preformatted", "PRE",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	0, 0, 0, HT_LEFT,		1, 0,	tabs_8,
 	NO, NO, 0, 0,			0
 };	
 
 PRIVATE HTStyle HTStyleListing = {
 	&HTStylePreformatted,  "Listing", "LISTING",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	0, 0, 0, HT_LEFT,		1, 0,	tabs_8,
 	NO, NO, 0, 0,			0 };	
 
 PRIVATE HTStyle HTStyleAddress = {
 	&HTStyleListing,  "Address", "ADDRESS",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	4, 4, 7, HT_LEFT,		1, 0,	tabs_8,
 	YES, YES, 2, 0,			0 };	
 
 PRIVATE HTStyle HTStyleNote = { /* HTML 3.0 NOTE - FM */
 	&HTStyleAddress,  "Note", "NOTE",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
+	HT_FONT, 1, HT_BLACK,		0, 0,
 	5, 5, 7, HT_LEFT,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleHeading1 = {
 	&HTStyleNote,  "Heading1", "H1",
-	HT_FONT+HT_BOLD, 1.0, HT_BLACK,	0, 0,
+	HT_FONT+HT_BOLD, 1, HT_BLACK,	0, 0,
 	0, 0, 0, HT_CENTER,		1, 0,	0,
 	YES, YES, 1, 1,			0 };	
 
 PRIVATE HTStyle HTStyleHeading2 = {
 	&HTStyleHeading1,  "Heading2", "H2",
-	HT_FONT+HT_BOLD, 1.0, HT_BLACK,	0, 0,
+	HT_FONT+HT_BOLD, 1, HT_BLACK,	0, 0,
 	0, 0, 0, HT_LEFT,		1, 0,	0,
 	YES, YES, 1, 1,			0 };	
 
 PRIVATE HTStyle HTStyleHeading3 = { 
 	&HTStyleHeading2,  "Heading3", "H3",
-	HT_FONT+HT_BOLD, 1.0, HT_BLACK,	0, 0,
+	HT_FONT+HT_BOLD, 1, HT_BLACK,	0, 0,
 	2, 2, 0, HT_LEFT,		1, 0,	0, 
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleHeading4 = { 
 	&HTStyleHeading3,  "Heading4", "H4",
-	HT_FONT+HT_BOLD, 1.0, HT_BLACK,	0, 0,
+	HT_FONT+HT_BOLD, 1, HT_BLACK,	0, 0,
 	4, 4, 0, HT_LEFT,		1, 0,	0,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleHeading5 = { 
 	&HTStyleHeading4,  "Heading5", "H5",
-	HT_FONT+HT_BOLD, 1.0, HT_BLACK,	0, 0,
+	HT_FONT+HT_BOLD, 1, HT_BLACK,	0, 0,
 	6, 6, 0, HT_LEFT,		1, 0,	0,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleHeading6 = { 
 	&HTStyleHeading5,  "Heading6", "H6",
-	HT_FONT+HT_BOLD, 1.0, HT_BLACK,	0, 0,
+	HT_FONT+HT_BOLD, 1, HT_BLACK,	0, 0,
 	8, 8, 0, HT_LEFT,		1, 0,	0,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleHeadingCenter = { 
 	&HTStyleHeading6,  "HeadingCenter", "HCENTER",
-	HT_FONT+HT_BOLD, 1.0, HT_BLACK,	0, 0,
+	HT_FONT+HT_BOLD, 1, HT_BLACK,	0, 0,
 	0, 0, 3, HT_CENTER,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleHeadingLeft = { 
 	&HTStyleHeadingCenter,  "HeadingLeft", "HLEFT",
-	HT_FONT+HT_BOLD, 1.0, HT_BLACK,	0, 0,
+	HT_FONT+HT_BOLD, 1, HT_BLACK,	0, 0,
 	0, 0, 3, HT_LEFT,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
 PRIVATE HTStyle HTStyleHeadingRight = { 
 	&HTStyleHeadingLeft,  "HeadingRight", "HRIGHT",
-	HT_FONT+HT_BOLD, 1.0, HT_BLACK,	0, 0,
+	HT_FONT+HT_BOLD, 1, HT_BLACK,	0, 0,
 	0, 0, 3, HT_RIGHT,		1, 0,	tabs_8,
 	YES, YES, 1, 0,			0 };	
 
diff --git a/src/GridText.c b/src/GridText.c
index 0f764f49..e1c414d6 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -230,7 +230,7 @@ PRIVATE int ctrl_chars_on_this_line = 0; /* num of ctrl chars in current line */
 
 PRIVATE HTStyle default_style =
 	{ 0,  "(Unstyled)", "",
-	(HTFont)0, 1.0, HT_BLACK,		0, 0,
+	(HTFont)0, 1, HT_BLACK,		0, 0,
 	0, 0, 0, HT_LEFT,		1, 0,	0, 
 	NO, NO, 0, 0,			0 };	
 
@@ -1834,10 +1834,18 @@ PRIVATE void split_line ARGS2(
      */
     if (split > 0) {
 	for (a = text->first_anchor; a; a = a->next) {
-	    if (a->line_num == CurLine && a->line_pos >= split) {
-		a->start += (1 + SpecialAttrChars - HeadTrim - TailTrim);
-		a->line_pos -= (split - SpecialAttrChars + HeadTrim);
-		a->line_num = text->Lines;
+	    if (a->line_num == CurLine) {
+		if (a->line_pos >= split) {
+		    a->start += (1 + SpecialAttrChars - HeadTrim - TailTrim);
+		    a->line_pos -= (split - SpecialAttrChars + HeadTrim);
+		    a->line_num = text->Lines;
+		} else if ((a->link_type & HYPERTEXT_ANCHOR) &&
+			   (a->line_pos + a->extent) >= split) {
+		    a->extent -= (TailTrim + HeadTrim);
+		    if (a->extent < 0) {
+		        a->extent = 0;
+		    }
+		}
 	    }
 	}
     }
@@ -2431,8 +2439,8 @@ PUBLIC int HText_beginAnchor ARGS3(
     
     if (a == NULL)
         outofmem(__FILE__, "HText_beginAnchor");
-    a->hightext  = 0;
-    a->hightext2 = 0;
+    a->hightext  = NULL;
+    a->hightext2 = NULL;
     a->start = text->chars + text->last_line->size;
     a->inUnderline = underline;
 
@@ -2946,7 +2954,7 @@ PRIVATE void remove_special_attr_chars ARGS1(
 PUBLIC void HText_endAppend ARGS1(
 	HText *,	text)
 {
-    int cur_line, cur_char, cur_shift;
+    int cur_line, cur_char, cur_shift, len;
     TextAnchor *anchor_ptr;
     HTLine *line_ptr;
     unsigned char ch;
@@ -3084,16 +3092,41 @@ re_parse:
 	     *  Double check that we have a line pointer,
 	     *  and if so, copy into hightext2.
 	     */
-	    if (line_ptr) {
+	    if (line_ptr2) {
 		StrnAllocCopy(anchor_ptr->hightext2,
 			      line_ptr2->data,
 			      (anchor_ptr->extent -
 			       strlen(anchor_ptr->hightext)));
 	        anchor_ptr->hightext2offset = line_ptr2->offset;
 	 	remove_special_attr_chars(anchor_ptr->hightext2);
+		if (anchor_ptr->link_type & HYPERTEXT_ANCHOR) {
+		    if ((len = strlen(anchor_ptr->hightext2)) > 0) {
+			len--;
+			while (len >= 0 &&
+			       isspace((unsigned char)
+				       anchor_ptr->hightext2[len])) {
+			    anchor_ptr->hightext2[len] = '\0';
+			    len--;
+			}
+		    }
+		    if (len <= 0 && anchor_ptr->hightext2[0] == '\0') {
+			FREE(anchor_ptr->hightext2);
+			anchor_ptr->hightext2offset = 0;
+		    }
+		}
 	    }
-	}   
+	}
 	remove_special_attr_chars(anchor_ptr->hightext);
+	if (anchor_ptr->link_type & HYPERTEXT_ANCHOR) {
+	    if ((len = strlen(anchor_ptr->hightext)) > 0) {
+		len--;
+		while (len >= 0 &&
+		       isspace((unsigned char)anchor_ptr->hightext[len])) {
+		    anchor_ptr->hightext[len] = '\0';
+		    len--;
+	        }
+	    }
+	}
 
         /*
 	 *  Subtract any formatting characters from the x position
@@ -3511,7 +3544,7 @@ PUBLIC BOOL HText_getFirstTargetInLine ARGS7(
  */
 PUBLIC int HText_getNumOfLines NOARGS
 {
-     return(HTMainText ? HTMainText->Lines : 0);
+    return(HTMainText ? HTMainText->Lines : 0);
 }
 
 /*
@@ -3520,7 +3553,7 @@ PUBLIC int HText_getNumOfLines NOARGS
  */
 PUBLIC char * HText_getTitle NOARGS
 {
-   return(HTMainText ?
+    return(HTMainText ?
    	  (char *) HTAnchor_title(HTMainText->node_anchor) : NULL);
 }
 
@@ -3535,21 +3568,212 @@ PUBLIC char *HText_getStyle NOARGS
 /*
  *  HText_getSugFname returns the suggested filename of the current
  *  document (normally derived from a Content-Disposition header with
- *  file; filename=name.suffix). - FM
+ *  attachment; filename=name.suffix). - FM
  */
 PUBLIC char * HText_getSugFname NOARGS
 {
-   return(HTMainText ?
+    return(HTMainText ?
    	  (char *) HTAnchor_SugFname(HTMainText->node_anchor) : NULL);
 }
 
 /*
+ *  HTCheckFnameForCompression receives the address of an allocated
+ *  string containing a filename, and an anchor pointer, and expands
+ *  or truncates the string's suffix if appropriate, based on whether
+ *  the anchor indicates that the file is compressed.  We assume
+ *  that the file was not uncompressed (as when downloading), and
+ *  believe the headers about whether it's compressed or not. - FM
+ *
+ *  Added third arg - if strip_ok is FALSE, we don't trust the anchor
+ *  info enough to remove a compression suffix if the anchor object
+ *  does not indicate compression. - kw
+ */
+PUBLIC void HTCheckFnameForCompression ARGS3(
+	char **,		fname,
+	HTParentAnchor *,	anchor,
+	BOOL,			strip_ok)
+{
+    char *fn = *fname;
+    char *dot = NULL, *cp = NULL;
+    CONST char *ct = NULL;
+    CONST char *ce = NULL;
+    BOOLEAN method = 0;
+
+    /*
+     *  Make sure we have a string and anchor. - FM
+     */
+    if (!(fn && *fn && anchor))
+        return;
+
+    /*
+     *  Make sure we have a file, not directory, name. -FM
+     */
+    if ((cp = strrchr(fn, '/')) != NULL) {
+	fn = (cp +1);
+	if (*fn == '\0') {
+	    return;
+	}
+    } 
+
+    /*
+     *  Check the anchor's content_type and content_encoding
+     *  elements for a gzip or Unix compressed file. - FM
+     */
+    ct = HTAnchor_content_type(anchor);
+    ce = HTAnchor_content_encoding(anchor);
+    if (ce == NULL) {
+        /*
+	 *  No Content-Encoding, so check
+	 *  the Content-Type. - FM
+	 */
+        if (!strncasecomp((ct ? ct : ""), "application/gzip", 16) ||
+	    !strncasecomp((ct ? ct : ""), "application/x-gzip", 18)) {
+	    method = 1;
+	} else if (!strncasecomp((ct ? ct : ""),
+				 "application/compress", 20) ||
+		   !strncasecomp((ct ? ct : ""),
+				 "application/x-compress", 22)) {
+	    method = 2;
+	}
+    } else if (!strcasecomp(ce, "gzip") ||
+	       !strcasecomp(ce, "x-gzip")) {
+	    /*
+	     *  It's gzipped. - FM
+	     */
+	    method = 1;
+    } else if (!strcasecomp(ce, "compress") ||
+	       !strcasecomp(ce, "x-compress")) {
+	    /*
+	     *  It's Unix compressed. - FM
+	     */
+	    method = 2;
+    }
+
+    /*
+     *  If no Content-Encoding has been detected via the anchor
+     *  pointer, but strip_ok is not set, there is nothing left
+     *  to do. - kw
+     */
+    if (method == 0 && !strip_ok)
+	return;
+
+    /*
+     *  Seek the last dot, and check whether
+     *  we have a gzip or compress suffix. - FM
+     */
+    if ((dot = strrchr(fn, '.')) != NULL) {
+	if (!strcasecomp(dot, ".tgz") ||
+	    !strcasecomp(dot, ".gz") ||
+	    !strcasecomp(dot, ".Z")) {
+	    if (!method) {
+	        /*
+		 *  It has a suffix which signifies a gzipped
+		 *  or compressed file for us, but the anchor
+		 *  claims otherwise, so tweak the suffix. - FM
+		 */
+	        cp = (dot + 1);
+		*dot = '\0';
+		if (!strcasecomp(cp, "tgz")) {
+		    StrAllocCat(*fname, ".tar");
+		}
+	    }
+	    return;
+	}
+	if (strlen(dot) > 4) {
+	    cp = ((dot + strlen(dot)) - 3);
+	    if (!strcasecomp(cp, "-gz") ||
+		!strcasecomp(cp, "_gz")) {
+		if (!method) {
+	            /*
+		     *  It has a tail which signifies a gzipped
+		     *  file for us, but the anchor claims otherwise,
+		     *  so tweak the suffix. - FM
+		     */
+		    *dot = '\0';
+		} else {
+		    /*
+		     *  The anchor claims it's gzipped, and we
+		     *  believe it, so force this tail to the
+		     *  conventional suffix. - FM
+		     */
+#ifdef VMS
+		    *cp = '-';
+#else
+		    *cp = '.';
+#endif /* VMS */
+		    cp++;
+		    *cp = TOLOWER(*cp);
+		    cp++;
+		    *cp = TOLOWER(*cp);
+		}
+		return;
+	    }
+	}
+	if (strlen(dot) > 3) {
+	    cp = ((dot + strlen(dot)) - 2);
+	    if (!strcasecomp(cp, "-Z") ||
+		!strcasecomp(cp, "_Z")) {
+		if (!method) {
+	            /*
+		     *  It has a tail which signifies a compressed
+		     *  file for us, but the anchor claims otherwise,
+		     *  so tweak the suffix. - FM
+		     */
+		    *dot = '\0';
+		} else {
+		    /*
+		     *  The anchor claims it's compressed, and
+		     *  we believe it, so force this tail to the
+		     *  conventional suffix. - FM
+		     */
+#ifdef VMS
+		    *cp = '-';
+#else
+		    *cp = '.';
+#endif /* VMS */
+		    cp++;
+		    *cp = TOUPPER(*cp);
+		}
+		return;
+	    }
+	}
+    }
+    if (!method) {
+        /*
+	 *  Don't know what compression method
+	 *  was used, if any, so we won't do
+	 *  anything. - FM
+	 */
+	return;
+    }
+
+    /*
+     *  Add the appropriate suffix. - FM
+     */
+    if (!dot) {
+	StrAllocCat(*fname, ((method == 1) ? ".gz" : ".Z"));
+	return;
+    }
+    dot++;
+    if (*dot == '\0') {
+	StrAllocCat(*fname, ((method == 1) ? "gz" : "Z"));
+	return;
+    }
+#ifdef VMS
+    StrAllocCat(*fname, ((method == 1) ? "-gz" : "-Z"));
+#else
+    StrAllocCat(*fname, ((method == 1) ? ".gz" : ".Z"));
+#endif /* !VMS */
+    return;
+}
+
+/*
  *  HText_getLastModified returns the Last-Modified header
  *  if available, for the current document. - FM
  */
 PUBLIC char * HText_getLastModified NOARGS
 {
-   return(HTMainText ?
+    return(HTMainText ?
    	  (char *) HTAnchor_last_modified(HTMainText->node_anchor) : NULL);
 }
 
@@ -3559,7 +3783,7 @@ PUBLIC char * HText_getLastModified NOARGS
  */
 PUBLIC char * HText_getDate NOARGS
 {
-   return(HTMainText ?
+    return(HTMainText ?
    	  (char *) HTAnchor_date(HTMainText->node_anchor) : NULL);
 }
 
@@ -3569,7 +3793,7 @@ PUBLIC char * HText_getDate NOARGS
  */
 PUBLIC char * HText_getServer NOARGS
 {
-   return(HTMainText ?
+    return(HTMainText ?
    	  (char *)HTAnchor_server(HTMainText->node_anchor) : NULL);
 }
 
@@ -4258,10 +4482,22 @@ PUBLIC void print_wwwfile_to_fd ARGS2(
              fputc(' ',fp);
 
             /* add data */
-          for (i = 0; line->data[i] != '\0'; i++)
-             if (!IsSpecialAttrChar(line->data[i]))
+          for (i = 0; line->data[i] != '\0'; i++) {
+	      if (!IsSpecialAttrChar(line->data[i])) {
                  fputc(line->data[i],fp);
-	     else if (dump_output_immediately && use_underscore) {
+	     } else if (line->data[i] == LY_SOFT_HYPHEN &&
+		 line->data[i + 1] == '\0') { /* last char on line */
+		 if (dump_output_immediately &&
+		     LYRawMode &&
+		     LYlowest_eightbit[current_char_set] <= 173 &&
+		     (current_char_set == 0 ||
+		      LYCharSet_UC[current_char_set].enc == UCT_ENC_8859 ||
+		      LYCharSet_UC[current_char_set].like8859 & UCT_R_8859SPECL)) {
+		     fputc(0xad, fp); /* the iso8859 byte for SHY */
+		 } else {
+		     fputc('-', fp);
+		 }
+	     } else if (dump_output_immediately && use_underscore) {
 		switch (line->data[i]) {
 		    case LY_UNDERLINE_START_CHAR:
 		    case LY_UNDERLINE_END_CHAR:
@@ -4271,7 +4507,9 @@ PUBLIC void print_wwwfile_to_fd ARGS2(
 		    case LY_BOLD_END_CHAR:
 			break;
 		}
-	     } 
+	     }
+	  }
+
 
          /* add the return */
          fputc('\n',fp);
@@ -4320,10 +4558,23 @@ PUBLIC void print_crawl_to_fd ARGS3(
         /*
 	 *  Add data.
 	 */
-        for (i = 0; line->data[i] != '\0'; i++)
-            if (!IsSpecialAttrChar(line->data[i]))
+        for (i = 0; line->data[i] != '\0'; i++) {
+            if (!IsSpecialAttrChar(line->data[i])) {
                 fputc(line->data[i],fp);
-
+	     } else if (line->data[i] == LY_SOFT_HYPHEN &&
+		 line->data[i + 1] == '\0') { /* last char on line */
+		 if (dump_output_immediately &&
+		     LYRawMode &&
+		     LYlowest_eightbit[current_char_set] <= 173 &&
+		     (current_char_set == 0 ||
+		      LYCharSet_UC[current_char_set].enc == UCT_ENC_8859 ||
+		      LYCharSet_UC[current_char_set].like8859 & UCT_R_8859SPECL)) {
+		     fputc(0xad, fp); /* the iso8859 byte for SHY */
+		 } else {
+		     fputc('-', fp);
+		 }
+	     }
+	}
         /*
 	 *  Add the return.
 	 */
diff --git a/src/GridText.h b/src/GridText.h
index 92c2d40f..fbd8455d 100644
--- a/src/GridText.h
+++ b/src/GridText.h
@@ -71,6 +71,10 @@ extern void HText_setStale PARAMS((HText * text));
 extern void HText_refresh PARAMS((HText * text));
 extern char * HText_getTitle NOPARAMS;
 extern char * HText_getSugFname NOPARAMS;
+extern void HTCheckFnameForCompression PARAMS((
+	char **			fname,
+	HTParentAnchor *	anchor,
+	BOOLEAN			strip_ok));
 extern char * HText_getLastModified NOPARAMS;
 extern char * HText_getDate NOPARAMS;
 extern char * HText_getServer NOPARAMS;
diff --git a/src/HTAlert.c b/src/HTAlert.c
index 926a2b71..93fb0fed 100644
--- a/src/HTAlert.c
+++ b/src/HTAlert.c
@@ -421,39 +421,75 @@ PUBLIC BOOL HTConfirmCookie ARGS6(
 **
 **  On entry,
 **      Redirecting_url             is the Location.
+**	server_status		    is the server status code.
 **
 **  On exit,
 **      Returns 0 on cancel,
 **	  1 for redirect of POST with content,
 **	303 for redirect as GET without content
 */
-PUBLIC int HTConfirmPostRedirect ARGS1(
-	CONST char *,	Redirecting_url)
+PUBLIC int HTConfirmPostRedirect ARGS2(
+	CONST char *,	Redirecting_url,
+	int,		server_status)
 {
     char *show_POST_url = NULL;
+    char StatusInfo[256];
     char url[256];
     int on_screen = 0;	/* 0 - show menu
    			 * 1 - show url
 			 * 2 - menu is already on screen */
 
-    if (dump_output_immediately)
+    if (server_status == 303 ||
+        server_status == 302) {
 	/*
-	**  Treat as 303 (GET without content) if not interactive.
-	*/
-        return 303;
+	 *  HTTP.c should not have called us for either of
+	 *  these because we're treating 302 as historical,
+	 *  so just return 303. - FM
+	 */
+	return 303;
+    }
+
+    if (dump_output_immediately)
+        if (server_status == 301) {
+	    /*
+	    **  Treat 301 as historical, i.e., like 303 (GET
+	    **  without content), when not interactive. - FM
+	    */
+            return 303;
+        } else {
+	    /*
+	    **  Treat anything else (e.g., 305, 306 or 307) as too
+	    **  dangerous to redirect without confirmation, and thus
+	    **  cancel when not interactive. - FM
+	    */
+	    return 0;
+	}
 
+    StatusInfo[254] = StatusInfo[255] = '\0';
+    url[254] = url[(LYcols < 250 ? LYcols-1 : 255)] = '\0';
     if (user_mode == NOVICE_MODE) {
         on_screen = 2;
         move(LYlines-2, 0);
-        addstr(SERVER_ASKED_FOR_REDIRECTION);
+        sprintf(StatusInfo, SERVER_ASKED_FOR_REDIRECTION, server_status);
+	addstr(StatusInfo);
 	clrtoeol();
         move(LYlines-1, 0);
 	sprintf(url, "URL: %.*s",
 		    (LYcols < 250 ? LYcols-6 : 250), Redirecting_url);
         addstr(url);
 	clrtoeol();
-        _statusline(PROCEED_GET_CANCEL);
+	if (server_status == 301) {
+	    _statusline(PROCEED_GET_CANCEL);
+	} else {
+	    _statusline(PROCEED_OR_CANCEL);
+	}
     } else {
+	sprintf(StatusInfo, "%d %.*s",
+			    server_status,
+			    251,
+			    ((server_status == 301) ?
+			 ADVANCED_POST_GET_REDIRECT :
+			 ADVANCED_POST_REDIRECT));
 	StrAllocCopy(show_POST_url, LOCATION_HEADER);
 	StrAllocCat(show_POST_url, Redirecting_url);
     }
@@ -462,7 +498,7 @@ PUBLIC int HTConfirmPostRedirect ARGS1(
 
 	switch (on_screen) {
 	    case 0:
-	        _statusline(ADVANCED_POST_REDIRECT);
+		_statusline(StatusInfo);
 		break;
 	    case 1:
 	        _statusline(show_POST_url);
@@ -471,8 +507,8 @@ 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 307 redirect of POST
+		**  with same method and POST content. - FM
 		*/
 	        FREE(show_POST_url);
 		return 1;	
@@ -480,37 +516,43 @@ PUBLIC int HTConfirmPostRedirect ARGS1(
  	    case 7:
  	    case 'C':
 	        /*
-		** Cancel request.
+		**  Cancel request.
 		*/
 	        FREE(show_POST_url);
 		return 0;
 
-	    case 'G':
-	        /*
-		**  Treat as 303 (GET without content).
-		*/
-	        FREE(show_POST_url);
-		return 303;
-
 	    case 'U':
 	        /*
 		**  Show URL for intermediate or advanced mode.
 		*/
-	        if (user_mode != NOVICE_MODE)
-		    if (on_screen == 1)
+	        if (user_mode != NOVICE_MODE) {
+		    if (on_screen == 1) {
 			on_screen = 0;
-		    else
+		    } else {
 			on_screen = 1;
+		    }
+		}
 		break;
 
+	    case 'G':
+		if (server_status == 301) {
+		    /*
+		    **  Treat as 303 (GET without content).
+		    */
+		    FREE(show_POST_url);
+		    return 303;
+		}
+		/* fall through to default */
+
 	    default:
 	        /*
 		**  Get another character.
 		*/
-		if (on_screen == 1)
+		if (on_screen == 1) {
 		    on_screen = 0;
-		else
+		} else {
 		    on_screen = 2;
+		}
 	}
     }
 }
diff --git a/src/HTAlert.h b/src/HTAlert.h
index 744a2a35..bb07b2a1 100644
--- a/src/HTAlert.h
+++ b/src/HTAlert.h
@@ -112,6 +112,7 @@ extern BOOL HTConfirmCookie PARAMS((
 **	----------------------------
 **  On entry,
 **      Redirecting_url             is the Location.
+**	server_status		    is the server status code.
 **
 **  On exit,
 **      Returns 0 on cancel,
@@ -119,7 +120,8 @@ extern BOOL HTConfirmCookie PARAMS((
 **	303 for redirect as GET without content
 */
 extern int HTConfirmPostRedirect PARAMS((
-	CONST char *	Redirecting_url));
+	CONST char *	Redirecting_url,
+	int		server_status));
 
 /*
 
diff --git a/src/HTFWriter.c b/src/HTFWriter.c
index 93e75a68..5f41becb 100644
--- a/src/HTFWriter.c
+++ b/src/HTFWriter.c
@@ -72,6 +72,7 @@ struct _HTStream {
 	FILE *			fp;		/* The file we've opened */
 	char * 			end_command;	/* What to do on _free.	 */
 	char * 			remove_command;	/* What to do on _abort. */
+	char * 			viewer_command;	/* saved external viewer */
 	HTFormat		input_format;  /* Original pres->rep     */
 	HTFormat		output_format; /* Original pres->rep_out */
 	HTParentAnchor *	anchor;	    /* Original stream's anchor. */
@@ -124,7 +125,7 @@ PRIVATE void HTFWriter_write ARGS3(HTStream *, me, CONST char*, s, int, l)
 */
 PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 {
-    FILE *fp;
+    FILE *fp = NULL;
     int len;
     char *path = NULL;
     char *addr = NULL;
@@ -132,6 +133,7 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
     extern int HTLoadFile PARAMS((
     	CONST char *addr,	HTParentAnchor *anchor,
 	HTFormat format_out,	HTStream *sink));
+    BOOL use_gzread = NO;
 
     fflush(me->fp);
     if (me->end_command) {		/* Temp file */
@@ -162,6 +164,7 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 	     *  a temporary file for uncompression. - FM
 	     */
 	    if (me->anchor->FileCache != NULL) {
+		BOOL skip_loadfile = (me->viewer_command != NULL);
 	        /*
 		 *  Save the path with the "gz" or "Z" suffix trimmed,
 		 *  and remove any previous uncompressed copy. - FM
@@ -169,27 +172,38 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 	        StrAllocCopy(path, me->anchor->FileCache);
 		if ((len = strlen(path)) > 2) {
 		    if (!strcasecomp((char *)&path[len-2], "gz")) {
-		        path[len-3] = '\0';
-		        remove(path);
+#ifdef USE_ZLIB
+			if (!skip_loadfile) {
+			    use_gzread = YES;
+			} else
+#endif /* USE_ZLIB */
+			{
+			    path[len-3] = '\0';
+			    remove(path);
+			}
 		    } else if (!strcasecomp((char *)&path[len-1], "Z")) {
 		        path[len-2] = '\0';
 		        remove(path);
 		    }
 		}
-		if (!dump_output_immediately) {
+		if (!use_gzread) {
+		    if (!dump_output_immediately) {
+			/*
+			 *  Tell user what's happening. - FM
+			 */
+			_HTProgress(me->end_command);
+		    }
 		    /*
-		     *  Tell user what's happening. - FM
+		     *  Uncompress it. - FM
 		     */
-		    _HTProgress(me->end_command);
+		    if (me->end_command && me->end_command[0])
+			system(me->end_command);
+		    fp = fopen(me->anchor->FileCache, "r");
 		}
-		/*
-		 *  Uncompress it. - FM
-		 */
-		system(me->end_command);
-		if ((fp = fopen(me->anchor->FileCache, "r")) != NULL) {
+		if (fp != NULL) {
 		    /*
-		     *  It's still there with the "gz" of "Z" suffix,
-		     *  so the uncompression failed. - FM
+		     *  It's still there with the "gz" of "Z" suffix when
+		     *  it shouldn't, so the uncompression failed. - FM
 		     */
 		    fclose(fp);
 		    fp = NULL;
@@ -217,19 +231,23 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 		    StrAllocCat(addr, path);
 #endif /* VMS */
 #endif /* DOSPATH */
-		    StrAllocCopy(me->anchor->FileCache, path);
+		    if (!use_gzread) {
+			StrAllocCopy(me->anchor->FileCache, path);
+			FREE(me->anchor->content_encoding);
+		    }
 		    FREE(path);
-		    FREE(me->anchor->content_encoding);
 #ifdef EXP_CHARTRANS
 		    /*
 		     *  Lock the chartrans info we may possibly have,
 		     *  so HTCharsetFormat() will not apply the default
 		     *  for local files. - KW
 		     */
-		    HTAnchor_copyUCInfoStage(me->anchor,
-					     UCT_STAGE_PARSER,
-					     UCT_STAGE_MIME,
-					     UCT_SETBY_PARSER);
+		    if (!skip_loadfile) {
+			HTAnchor_copyUCInfoStage(me->anchor,
+						 UCT_STAGE_PARSER,
+						 UCT_STAGE_MIME,
+						 UCT_SETBY_PARSER);
+		    }
 #endif
 		    /*
 		     *  Now have HTLoadFile() handle the uncompressed
@@ -241,6 +259,49 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 			 */
 			_user_message(WWW_USING_MESSAGE, addr);
 		    }
+
+		    if (skip_loadfile) {
+			/*
+			 *  It's a temporary file we're passing to a
+			 *  viewer or helper application.
+			 *  Loading the temp file through HTLoadFile()
+			 *  would result in yet another HTStream (created
+			 *  with HTSaveAndExecute()) which would just
+			 *  copy the temp file to another temp file
+			 *  (or even the same!).  We can skip this
+			 *  needless duplication by using the
+			 *  viewer_command which has already been 
+			 *  determind when the HTCompressed stream was
+			 *  created. - kw
+			 */
+			FREE(me->end_command);
+			me->end_command = (char *)calloc (
+			    (strlen (me->viewer_command) + 10 +
+			     strlen(me->anchor->FileCache))
+			    * sizeof (char),1);
+			if (me->end_command == NULL)
+			    outofmem(__FILE__, "HTFWriter_free (HTCompressed)");
+    
+			sprintf(me->end_command,
+				me->viewer_command, me->anchor->FileCache,
+				"", "", "", "", "", "");
+			if (!dump_output_immediately) {
+			    /*
+			     *  Tell user what's happening. - FM
+			     */
+			    HTProgress(me->end_command);
+			    stop_curses();
+			}
+			system(me->end_command);
+
+			if (me->remove_command) {
+			    /* NEVER REMOVE THE FILE unless during an abort!!!*/
+			    /* system(me->remove_command); */
+			    FREE(me->remove_command);
+			}
+			if (!dump_output_immediately)
+			    start_curses();
+		    } else
 		    status = HTLoadFile(addr,
 			    		me->anchor,
 			    		me->output_format,
@@ -252,6 +313,7 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 			FREE(me->anchor->FileCache);
 			FREE(me->remove_command);
 			FREE(me->end_command);
+			FREE(me->viewer_command);
 			FREE(me);
 		        return;
 		    }
@@ -298,6 +360,7 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 	}
 	FREE(me->end_command);
     }
+    FREE(me->viewer_command);
 
     if (dump_output_immediately) {
         if (me->anchor->FileCache)
@@ -330,6 +393,7 @@ PRIVATE void HTFWriter_abort ARGS2(HTStream *, me, HTError, e)
         fprintf(stderr,"HTFWriter_abort called\n");
 
     fclose(me->fp);
+    FREE(me->viewer_command);
     if (me->end_command) {              /* Temp file */
         if (TRACE)
 	    fprintf(stderr, "HTFWriter: Aborting: file not executed.\n");
@@ -523,6 +587,7 @@ SaveAndExecute_tempname:
     }
     chmod(fnam, 0600);
 
+    StrAllocCopy(me->viewer_command, pres->command);
     /*
      *  Make command to process file.
      */
@@ -773,7 +838,8 @@ SaveToFile_tempname:
 
     StrAllocCopy(anchor->FileCache, fnam);
 Prepend_BASE:
-    if (!strncasecomp(pres->rep->name, "text/html", 9)) {
+    if (!strncasecomp(pres->rep->name, "text/html", 9) &&
+	!anchor->content_encoding) {
         /*
 	 *  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
@@ -986,13 +1052,44 @@ Compressed_tempname:
     chmod(fnam, 0600);
 
     /*
+     *  me->viewer_command will be NULL if the converter Pres found above
+     *  is not for an external viewer but an internal HTStream converter.
+     *  We also don't set it under conditions where HTSaveAndExecute would
+     *  disallow execution of the command. - kw
+     */
+    if (!dump_output_immediately && !traversal
+#if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS)
+	&& (Pres->quality != 999.0 ||
+	    (!no_exec && 	/* allowed exec link or script ? */
+	     (local_exec ||
+	      (local_exec_on_local_files &&
+	       (LYJumpFileURL ||
+		!strncmp(anchor->address,"file://localhost",16))))))
+#endif /* EXEC_LINKS || EXEC_SCRIPTS */
+	) {
+	StrAllocCopy(me->viewer_command, Pres->command);
+    }
+
+    /*
      *  Make command to process file. - FM
      */
-    me->end_command = (char *)calloc(1, (strlen(uncompress_mask) + 10 +
-    					 strlen(fnam)) * sizeof(char));
-    if (me->end_command == NULL)
-        outofmem(__FILE__, "HTCompressed");
-    sprintf(me->end_command, uncompress_mask, fnam, "", "", "", "", "", "");
+#if USE_ZLIB
+    if (compress_suffix[0] == 'g' && /* must be gzip */
+	!me->viewer_command) {
+	/*
+	 *  We won't call gzip externally, so we don't need to supply
+	 *  a command for it. - kw
+	 */
+	StrAllocCopy(me->end_command, "");
+    } else
+#endif /* USE_ZLIB */
+    {
+	me->end_command = (char *)calloc(1, (strlen(uncompress_mask) + 10 +
+					     strlen(fnam)) * sizeof(char));
+	if (me->end_command == NULL)
+	    outofmem(__FILE__, "HTCompressed");
+	sprintf(me->end_command, uncompress_mask, fnam, "", "", "", "", "", "");
+    }
     FREE(uncompress_mask);
 
     /*
diff --git a/src/HTFont.h b/src/HTFont.h
index 7b34bbb9..9ab44fd5 100644
--- a/src/HTFont.h
+++ b/src/HTFont.h
@@ -6,7 +6,7 @@
 #ifndef HTFONT_H
 #define HTFONT_H
 
-typedef long int HTLMFont;	/* For now */
+typedef long int HTMLFont;	/* For now */
 
 #define HT_NON_BREAK_SPACE ((char)1)	/* For now */
 #define HT_EM_SPACE ((char)2) 		/* For now */
diff --git a/src/HTInit.c b/src/HTInit.c
index e8c74065..5c27d8bf 100644
--- a/src/HTInit.c
+++ b/src/HTInit.c
@@ -60,9 +60,11 @@ PUBLIC void HTFormatInit NOARGS
   HTSetPresentation("image/gif",        XLoadImageCommand,  1.0, 3.0, 0.0, 0);
   HTSetPresentation("image/x-xbm",      XLoadImageCommand,  1.0, 3.0, 0.0, 0);
   HTSetPresentation("image/x-xbitmap",  XLoadImageCommand,  1.0, 3.0, 0.0, 0);
-  HTSetPresentation("image/x-png",      XLoadImageCommand,  1.0, 3.0, 0.0, 0);
+  HTSetPresentation("image/x-png",      XLoadImageCommand,  2.0, 3.0, 0.0, 0);
+  HTSetPresentation("image/png",	XLoadImageCommand,  1.0, 3.0, 0.0, 0);
   HTSetPresentation("image/x-rgb",      XLoadImageCommand,  1.0, 3.0, 0.0, 0);
-  HTSetPresentation("image/x-tiff",     XLoadImageCommand,  1.0, 3.0, 0.0, 0);
+  HTSetPresentation("image/x-tiff",     XLoadImageCommand,  2.0, 3.0, 0.0, 0);
+  HTSetPresentation("image/tiff",	XLoadImageCommand,  1.0, 3.0, 0.0, 0);
   HTSetPresentation("image/jpeg",       XLoadImageCommand,  1.0, 3.0, 0.0, 0);
   HTSetPresentation("video/mpeg",       "mpeg_play %s &",   1.0, 3.0, 0.0, 0);
 
@@ -810,7 +812,7 @@ PUBLIC void HTFileInit NOARGS
     HTSetSuffix(".pbm",		"image/x-portable-bitmap", "binary", 1.0);
     HTSetSuffix(".pgm",		"image/x-portable-graymap", "binary", 1.0);
     HTSetSuffix(".ppm",		"image/x-portable-pixmap", "binary", 1.0);
-    HTSetSuffix(".png",		"image/x-png", "binary", 1.0);
+    HTSetSuffix(".png",		"image/png", "binary", 1.0);
     HTSetSuffix(".rgb",		"image/x-rgb", "binary", 1.0);
     HTSetSuffix(".xbm",		"image/x-xbitmap", "binary", 1.0);
     HTSetSuffix(".xpm",		"image/x-xpixmap", "binary", 1.0);
@@ -842,6 +844,7 @@ PUBLIC void HTFileInit NOARGS
     HTSetSuffix(".htm",		"text/html", "8bit", 1.0);
     HTSetSuffix(".html3",	"text/html", "8bit", 1.0);
     HTSetSuffix(".ht3",		"text/html", "8bit", 1.0);
+    HTSetSuffix(".phtml",	"text/html", "8bit", 1.0);
     HTSetSuffix(".shtml",	"text/html", "8bit", 1.0);
     HTSetSuffix(".htmlx",	"text/html", "8bit", 1.0);
     HTSetSuffix(".html",	"text/html", "8bit", 1.0);
diff --git a/src/HTML.c b/src/HTML.c
index 4de030c8..4a60ac9a 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -546,11 +546,11 @@ PRIVATE void HTML_start_element ARGS5(
                 strcat (Style_className, class_string);
                 strcat (myHash, ".");
                 strcat (myHash, class_string);
-#if !defined(PREVAIL)
-        }
-#else /* PREVAIL */
+#ifdef PREVAIL
                 strcpy (prevailing_class, class_string);
+#endif
         }
+#ifdef PREVAIL
         else if (prevailing_class[0])
         {
                 strcat (Style_className, ".");
@@ -558,7 +558,7 @@ PRIVATE void HTML_start_element ARGS5(
                 strcat (myHash, ".");
                 strcat (myHash, prevailing_class);
         }
-#endif /* !PREVAIL */
+#endif /* PREVAIL */
         class_string[0]='\0';
         strtolower(myHash);
         hcode=hash_code(myHash);
@@ -2031,8 +2031,8 @@ PRIVATE void HTML_start_element ARGS5(
 	/*
 	 * Set the default TYPE.
 	 */
-	 me->OL_Type[(me->List_Nesting_Level < 5 ?
-			me->List_Nesting_Level+1 : 6)] = '1';
+	 me->OL_Type[(me->List_Nesting_Level < 11 ?
+			 me->List_Nesting_Level+1 : 11)] = '1';
 
 	/*
 	 *  Check whether we have a starting sequence number,
@@ -2065,23 +2065,23 @@ PRIVATE void HTML_start_element ARGS5(
 	     */
 	    if (present[HTML_OL_TYPE] && value[HTML_OL_TYPE]) {
 	        if (*value[HTML_OL_TYPE] == 'A') {
-		    me->OL_Type[(me->List_Nesting_Level < 5 ?
-				   me->List_Nesting_Level+1 : 6)] = 'A';
+		    me->OL_Type[(me->List_Nesting_Level < 11 ?
+				    me->List_Nesting_Level+1 : 11)] = 'A';
 		    if (seqnum < 1)
 		        seqnum = 1;
 		} else if (*value[HTML_OL_TYPE] == 'a') {
-		    me->OL_Type[(me->List_Nesting_Level < 5 ?
-				   me->List_Nesting_Level+1 : 6)] = 'a';
+		    me->OL_Type[(me->List_Nesting_Level < 11 ?
+				    me->List_Nesting_Level+1 : 11)] = 'a';
 		    if (seqnum < 1)
 		        seqnum = 1;
 		} else if (*value[HTML_OL_TYPE] == 'I') {
-		    me->OL_Type[(me->List_Nesting_Level < 5 ?
-				   me->List_Nesting_Level+1 : 6)] = 'I';
+		    me->OL_Type[(me->List_Nesting_Level < 11 ?
+				    me->List_Nesting_Level+1 : 11)] = 'I';
 		    if (seqnum < 1)
 		        seqnum = 1;
 		} else if (*value[HTML_OL_TYPE] == 'i') {
-		    me->OL_Type[(me->List_Nesting_Level < 5 ?
-				   me->List_Nesting_Level+1 : 6)] = 'i';
+		    me->OL_Type[(me->List_Nesting_Level < 11 ?
+				    me->List_Nesting_Level+1 : 11)] = 'i';
 		    if (seqnum < 1)
 		        seqnum = 1;
 		} else {
@@ -2092,29 +2092,29 @@ PRIVATE void HTML_start_element ARGS5(
 	        seqnum = OL_VOID + 1;
 	    }
 
-	    me->OL_Counter[(me->List_Nesting_Level < 5 ?
-	    		      me->List_Nesting_Level+1 : 6)] = seqnum;
+	    me->OL_Counter[(me->List_Nesting_Level < 11 ?
+	    		       me->List_Nesting_Level+1 : 11)] = seqnum;
 
 	} else if (present && present[HTML_OL_CONTINUE]) {
-	    me->OL_Counter[me->List_Nesting_Level < 5 ?
-			     me->List_Nesting_Level+1 : 6] = OL_CONTINUE;
+	    me->OL_Counter[me->List_Nesting_Level < 11 ?
+			      me->List_Nesting_Level+1 : 11] = OL_CONTINUE;
 
 	} else {
-	    me->OL_Counter[(me->List_Nesting_Level < 5 ?
-			      me->List_Nesting_Level+1 : 6)] = 1;
+	    me->OL_Counter[(me->List_Nesting_Level < 11 ?
+			       me->List_Nesting_Level+1 : 11)] = 1;
 	    if (present && present[HTML_OL_TYPE] && value[HTML_OL_TYPE]) {
 	        if (*value[HTML_OL_TYPE] == 'A') {
-		    me->OL_Type[(me->List_Nesting_Level < 5 ?
-				   me->List_Nesting_Level+1 : 6)] = 'A';
+		    me->OL_Type[(me->List_Nesting_Level < 11 ?
+				    me->List_Nesting_Level+1 : 11)] = 'A';
 		} else if (*value[HTML_OL_TYPE] == 'a') {
-		    me->OL_Type[(me->List_Nesting_Level < 5 ?
-				   me->List_Nesting_Level+1 : 6)] = 'a';
+		    me->OL_Type[(me->List_Nesting_Level < 11 ?
+				    me->List_Nesting_Level+1 : 11)] = 'a';
 		} else if (*value[HTML_OL_TYPE] == 'I') {
-		    me->OL_Type[(me->List_Nesting_Level < 5 ?
-				   me->List_Nesting_Level+1 : 6)] = 'I';
+		    me->OL_Type[(me->List_Nesting_Level < 11 ?
+				    me->List_Nesting_Level+1 : 11)] = 'I';
 		} else if (*value[HTML_OL_TYPE] == 'i') {
-		    me->OL_Type[(me->List_Nesting_Level < 5 ?
-				   me->List_Nesting_Level+1 : 6)] = 'i';
+		    me->OL_Type[(me->List_Nesting_Level < 11 ?
+				    me->List_Nesting_Level+1 : 11)] = 'i';
 		}
 	    }
 	}
@@ -2214,7 +2214,8 @@ PRIVATE void HTML_start_element ARGS5(
 	    int counter, seqnum;
 	    char seqtype;
 
-	    counter = me->List_Nesting_Level < 6 ? me->List_Nesting_Level : 6;
+	    counter = me->List_Nesting_Level < 11 ?
+			   me->List_Nesting_Level : 11;
 	    if (present && present[HTML_LI_TYPE] && value[HTML_LI_TYPE]) {
 	        if (*value[HTML_LI_TYPE] == '1') {
 		    me->OL_Type[counter] = '1';
@@ -5855,20 +5856,22 @@ PRIVATE void HTML_end_element ARGS3(
 	break;
 
     case HTML_OL:
-        me->OL_Counter[me->List_Nesting_Level < 6 ?
-			   me->List_Nesting_Level : 6] = OL_VOID;
+        me->OL_Counter[me->List_Nesting_Level < 11 ?
+			    me->List_Nesting_Level : 11] = OL_VOID;
     case HTML_DL:
     case HTML_UL:
     case HTML_MENU:
     case HTML_DIR:
 	me->List_Nesting_Level--;
-	if (TRACE)
-	    fprintf(stderr, "Reducing List Nesting Level to %d\n",
-			    me->List_Nesting_Level);
+	if (TRACE) {
+	    fprintf(stderr,
+		    "HTML_end_element: 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 (me->List_Nesting_Level >= 0)
-	    HText_NegateLineOne(me->text);
+	    LYEnsureSingleSpace(me);
         break;
 
     case HTML_SPAN:
@@ -7151,7 +7154,7 @@ PUBLIC HTStructured* HTML_new ARGS3(
      *  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] */
+    LYZero_OL_Counter(me);	 /* Initializes OL_Counter[] and OL_Type[] */
     me->Last_OL_Count = 0;	 /* last count in ordered lists */
     me->Last_OL_Type = '1';	 /* last type in ordered lists */
 
diff --git a/src/HTML.h b/src/HTML.h
index 8d313e81..0061f7d4 100644
--- a/src/HTML.h
+++ b/src/HTML.h
@@ -88,8 +88,8 @@ struct _HTStructured {
      *  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 	OL_Counter[12];		/* counter for ordered lists */
+    char 	OL_Type[12];		/* types for ordered lists */
     int 	Last_OL_Count;		/* last count in ordered lists */
     char 	Last_OL_Type;		/* last type in ordered lists */
 
diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c
index b7d82c97..8ee363e8 100644
--- a/src/LYCharUtils.c
+++ b/src/LYCharUtils.c
@@ -9,6 +9,7 @@
 #include "HTChunk.h"
 #include "HText.h"
 #include "HTStyle.h"
+#include "HTMIME.h"
 #include "HTML.h"
 
 #include "HTCJK.h"
@@ -1673,7 +1674,7 @@ PUBLIC void LYZero_OL_Counter ARGS1(
     if (!me)
         return;
 
-    for (i = 0; i < 7; i++) {
+    for (i = 0; i < 12; i++) {
         me->OL_Counter[i] = OL_VOID;
 	me->OL_Type[i] = '1';
     }
@@ -2227,25 +2228,37 @@ PUBLIC void LYHandleMETA ARGS4(
 
     /*
      *  Check for a suggested filename via a Content-Disposition with
-     *  file; filename=name.suffix in it, if we don't already have it
+     *  a 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((http_equiv ?
 	       		     http_equiv : ""), "Content-Disposition")) {
 	cp = content;
-	while (*cp != '\0' && strncasecomp(cp, "file;", 5))
+	while (*cp != '\0' && strncasecomp(cp, "filename", 8))
 	    cp++;
 	if (*cp != '\0') {
-	    cp += 5;
+	    cp += 8;
+	    while ((*cp != '\0') && (WHITE(*cp) || *cp == '='))
+	        cp++;
 	    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;
+		StrAllocCopy(me->node_anchor->SugFname, cp);
+		if (*me->node_anchor->SugFname == '\"') {
+		    if ((cp = strchr((me->node_anchor->SugFname + 1),
+		    		     '\"')) != NULL) {
+			*(cp + 1) = '\0';
+			HTMIME_TrimDoubleQuotes(me->node_anchor->SugFname);
+		    } else {
+			FREE(me->node_anchor->SugFname);
+		    }
+		    if (me->node_anchor->SugFname != NULL &&
+		        *me->node_anchor->SugFname == '\0') {
+			FREE(me->node_anchor->SugFname);
+		    }
+		}
+		if ((cp = me->node_anchor->SugFname) != NULL) {
 		    while (*cp != '\0' && !WHITE(*cp))
 			cp++;
 		    *cp = '\0';
@@ -2685,54 +2698,64 @@ PUBLIC int LYLegitimizeHREF ARGS4(
 		       "http", 4)) {
 	/*
 	 *  We will be resolving a partial reference versus an http
-	 *  or https URL, and it has lead dots, which are retained
-	 *  when resolving, in compliance with the URL specs, but
-	 *  the request would fail if the first element of the
-	 *  resultant path is two dots, because no http or https
-	 *  server accepts such paths, so if that's the case, and
-	 *  strip_dots is TRUE, we'll strip that element now, but
-	 *  issue a message about this as "immediate feedback",
-	 *  such that the bad partial reference might get corrected
-	 *  by the document provider.  Note that if the second and
-	 *  further symbolic elements also contain(s) only dots,
-	 *  those will still be retained, and the resolved URL may
-	 *  still fail, but it should, IMHO, if the partial reference
-	 *  is that much out of compliance with the URL specs. - FM
+	 *  or https URL, and it has lead dots, which may be retained
+	 *  when resolving via HTParse(), but the request would fail
+	 *  if the first element of the resultant path is two dots,
+	 *  because no http or https server accepts such paths, and
+	 *  the current URL draft, likely to become an RFC, says that
+	 *  it's optional for the UA to strip them as a form of error
+	 *  recovery.  So we will, recursively, for http/https URLs,
+	 *  like the "major market browsers" which made this problem
+	 *  so common on the Web, but we'll also issue a message about
+	 *  it, such that the bad partial reference might get corrected
+	 *  by the document provider. - FM
 	 */
         int i = 0, j = 0;
-	char *temp = NULL, *str = "";
+	char *temp = NULL, *path = NULL, *str = "", *cp;
 
-	if (((temp = HTParse((me->inBASE ?
+	if (((temp = HTParse(*href,
+			     (me->inBASE ?
 			   me->base_href : me->node_anchor->address),
-			     "", PARSE_PATH+PARSE_PUNCTUATION)) == NULL) ||
-	    temp[0] == '\0' ||
-	    !strchr((char *)&temp[1], '/')) {
-	    FREE(temp);
-	    temp = *href;
-	    if ((me->inBASE ?
-	   me->base_href[4] : me->node_anchor->address[4]) == 's')
-	        str = "s";
-	    while (temp[j] == '.')
-		j++;
-	    if ((j == 2) && (temp[j] == '/' || temp[j] == '\0')) {
+			     PARSE_ALL)) != NULL && temp[0] != '\0') &&
+	    (path = HTParse(temp, "",
+			    PARSE_PATH+PARSE_PUNCTUATION)) != NULL &&
+	    !strncmp(path, "/..", 3)) {
+	    cp = (path + 3);
+	    if (*cp == '/' || *cp == '\0') {
+		if ((me->inBASE ?
+	       me->base_href[4] : me->node_anchor->address[4]) == 's') {
+		    str = "s";
+		}
 		if (TRACE) {
 		    fprintf(stderr,
 			 "LYLegitimizeHREF: Bad value '%s' for http%s URL.\n",
 			   *href, str);
 		    fprintf(stderr,
-			   "                  Stripping lead dots.\n");
+			 "                  Stripping lead dots.\n");
 		} else if (!me->inBadHREF) {
 		    _statusline(BAD_PARTIAL_REFERENCE);
 		    me->inBadHREF = TRUE;
 		    sleep(AlertSecs);
 		}
-		while (temp[j] != '\0')
-		    temp[i++] = temp[j++];
-		temp[i] = '\0';
 	    }
-	    temp = NULL;
+	    if (*cp == '\0') {
+		StrAllocCopy(*href, "/");
+	    } else if (*cp == '/') {
+		while (!strncmp(cp, "/..", 3)) {
+		    if (*(cp + 3) == '/') {
+			cp += 3;
+			continue;
+		    } else if (*(cp + 3) == '\0') {
+		        *(cp + 1) = '\0';
+		        *(cp + 2) = '\0';
+		    }
+		    break;
+		}
+		StrAllocCopy(*href, cp);
+	    }
 	}
 	FREE(temp);
+	FREE(path);
     }
     return(url_type); 
 }
diff --git a/src/LYCookie.c b/src/LYCookie.c
index 07d51595..aacd99ac 100644
--- a/src/LYCookie.c
+++ b/src/LYCookie.c
@@ -12,6 +12,10 @@
 **   http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-man-mec-02.txt
 **		- FM					1997-07-09
 **
+**	Updated for:
+**   ftp://ds.internic.net/internet-drafts/draft-ietf-http-state-man-mec-03.txt
+**		- FM					1997-08-02
+**
 **  TO DO: (roughly in order of decreasing priority)
       * A means to specify "always allow" and "never allow" domains via
         a configuration file is needed.
@@ -34,8 +38,8 @@
 	collections to bring us back down under the limits, rather than
 	actively removing cookies and/or domains based on age or frequency
 	of use.
-      * 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
+      * If 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.
 */
@@ -309,7 +313,9 @@ PRIVATE void store_cookie ARGS3(
 	/*
 	 *  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.) 
+	 *  (A dot is embedded if it's neither the first nor last character.)
+	 *  Note that we added a lead dot ourselves if a domain attribute
+	 *  value otherwise qualified. - FM
 	 */
 	if (co->domain[0] != '.' || co->domain[1] == '\0') {
 	    if (TRACE)
@@ -682,31 +688,24 @@ PRIVATE void LYProcessSetCookies ARGS6(
 
     /*
      *  If we have both Set-Cookie and Set-Cookie2 headers.
-     *  process the Set-Cookie2 header, then the Set-Cookie
-     *  header.  The most current draft has abandoned the
-     *  the earlier requirement to combine them, but we'll
-     *  keep doing that for now, until we're sure that holds
-     *  up, since we never replace anything that was in the
-     *  Set-Cookie2 headers with it's equivalent in the
-     *  Set-Cookie header.  If we have only a Set-Cookie2
-     *  or only a Set-Cookie header, that's what we use.  So
-     *  set up a list for the cookies we process out of the
-     *  header(s).  Note that if more than one instance of a
-     *  valued attribute for the same cookie is encountered,
-     *  even within the same header, the value for the first
-     *  instance is retained, with consequent preference to
-     *  that in a Set-Cookie2 header, since that was processed
-     *  first.  We only accept up to 50 cookies from either
-     *  header, and only if a cookie's values do not exceed
-     *  the 4096 byte limit on overall size. - FM
+     *  process the Set-Cookie2 header.  Otherwise, process
+     *  whichever of the two headers we do have.  Note that
+     *  if more than one instance of a valued attribute for
+     *  the same cookie is encountered, the value for the
+     *  first instance is retained.  We only accept up to 50
+     *  cookies from the header, and only if a cookie's values
+     *  do not exceed the 4096 byte limit on overall size. - FM
      */
     CombinedCookies = HTList_new();
 
     /*
-     *  First process the Set-Cookie2 header, if present, adding
-     *  each cookie to the CombinedCookies list. - FM
+     *  Process the Set-Cookie2 header, if present and not zero-length,
+     *  adding each cookie to the CombinedCookies list. - FM
      */
     p = (SetCookie2 ? SetCookie2 : "");
+    if (TRACE && SetCookie && *p) {
+	fprintf(stderr, "LYProcessSetCookies: Using Set-Cookie2 header.\n");
+    }
     while (NumCookies <= 50 && *p) {
 	attr_start = attr_end = value_start = value_end = NULL;
 	while (*p != '\0' && isspace((unsigned char)*p)) {
@@ -955,23 +954,17 @@ PRIVATE void LYProcessSetCookies ARGS6(
 						     address,
 						     PARSE_ALL);
 		    /*
-		     *  Accept only URLs for servers. - FM
+		     *  Accept only URLs for http or https servers. - FM
 		     */
 		    if ((url_type = is_url(cur_cookie->commentURL)) &&
 		        (url_type == HTTP_URL_TYPE ||
-		    	 url_type == HTTPS_URL_TYPE ||
-			 url_type == FTP_URL_TYPE ||
-			 url_type == GOPHER_URL_TYPE ||
-			 url_type == HTML_GOPHER_URL_TYPE ||
-			 url_type == INDEX_GOPHER_URL_TYPE ||
-			 url_type == NEWS_URL_TYPE ||
-			 url_type == NNTP_URL_TYPE ||
-			 url_type == SNEWS_URL_TYPE ||
-			 url_type == WAIS_URL_TYPE ||
-			 url_type == CSO_URL_TYPE ||
-			 url_type == FINGER_URL_TYPE)) {
+		    	 url_type == HTTPS_URL_TYPE)) {
 		        length += strlen(cur_cookie->commentURL);
 		    } else {
+			if (TRACE)
+			    fprintf(stderr,
+		     "LYProcessSetCookies: Rejecting commentURL value '%s'\n",
+				    cur_cookie->commentURL);
 			FREE(cur_cookie->commentURL);
 		    }
 		}
@@ -983,7 +976,38 @@ PRIVATE void LYProcessSetCookies ARGS6(
 		     */
 		    !(cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) {
 		    length -= strlen(cur_cookie->domain);
-		    StrAllocCopy(cur_cookie->domain, value);
+		    /*
+		     *  If the value does not have a lead dot,
+		     *  but does have an embedded dot, and is
+		     *  not an exact match to the hostname, nor
+		     *  is a numeric IP address, add a lead dot.
+		     *  Otherwise, use the value as is. - FM
+		     */
+		    if (value[0] != '.' && value[0] != '\0' &&
+			value[1] != '\0' && strcmp(value, hostname)) {
+			char *ptr = strchr(value, '.');
+			if (ptr != NULL && ptr[1] != '\0') {
+			    ptr = value;
+			    while (*ptr == '.' ||
+				   isdigit((unsigned char)*ptr))
+				ptr++;
+			    if (*ptr != '\0') {
+			        if (TRACE) {
+				    fprintf(stderr,
+	       "LYProcessSetCookies: Adding lead dot for domain value '%s'\n",
+					    value);
+				}
+				StrAllocCopy(cur_cookie->domain, ".");
+				StrAllocCat(cur_cookie->domain, value);
+			    } else {
+				StrAllocCopy(cur_cookie->domain, value);
+			    }
+			} else {
+			    StrAllocCopy(cur_cookie->domain, value);
+			}
+		    } else {
+			StrAllocCopy(cur_cookie->domain, value);
+		    }
 		    length += strlen(cur_cookie->domain);
 		    cur_cookie->flags |= COOKIE_FLAG_DOMAIN_SET;
 		}
@@ -1091,7 +1115,7 @@ PRIVATE void LYProcessSetCookies ARGS6(
 	    }
 
 	    /*
-	     *  If none of the above comparisions succeeded, and we have
+	     *  If none of the above comparisons succeeded, and we have
 	     *  a value, then we have an unknown pair of the form 'foo=bar',
 	     *  which means it's time to create a new cookie.  If we don't
 	     *  have a non-zero-length value, assume it's an error or a
@@ -1111,6 +1135,19 @@ PRIVATE void LYProcessSetCookies ARGS6(
 			cur_cookie->version = 1;
 		    }
 		    HTList_appendObject(CombinedCookies, cur_cookie);
+		} else if (cur_cookie != NULL) {
+		    if (TRACE) {
+			fprintf(stderr,
+			"LYProcessSetCookies: Rejecting Set-Cookie2: %s=%s\n",
+				(cur_cookie->name ?
+				 cur_cookie->name : "[no name]"),
+				(cur_cookie->value ?
+				 cur_cookie->value : "[no value]"));
+			fprintf(stderr,
+			"                     due to excessive length!\n");
+		    }
+        	    freeCookie(cur_cookie);
+		    cur_cookie = NULL;
 		}
 		/*
 		 *  Start a new cookie. - FM
@@ -1160,14 +1197,16 @@ PRIVATE void LYProcessSetCookies ARGS6(
     }
 
     /*
-     *  Now process the Set-Cookie header, if present, checking the
-     *  CombinedCookies list for a corresponding cookie and supplementing
-     *  that if one is present, otherwise, adding the new cookie. - FM
+     *  Process the Set-Cookie header, if no non-zero-length Set-Cookie2
+     *  header was present. - FM
      */
     length = 0;
     NumCookies = 0;
     cur_cookie = NULL;
-    p = (SetCookie ? SetCookie : "");
+    p = ((SetCookie && !(SetCookie2 && *SetCookie2)) ? SetCookie : "");
+    if (TRACE && SetCookie2 && *p) {
+	fprintf(stderr, "LYProcessSetCookies: Using Set-Cookie header.\n");
+    }
     while (NumCookies <= 50 && *p) {
 	attr_start = attr_end = value_start = value_end = NULL;
 	while (*p != '\0' && isspace((unsigned char)*p)) {
@@ -1413,25 +1452,17 @@ PRIVATE void LYProcessSetCookies ARGS6(
 						     address,
 						     PARSE_ALL);
 		    /*
-		     *  Accept only URLs for servers.  The most
-		     *  recent draft says just http, so the others
-		     *  are commented out here. - FM
+		     *  Accept only URLs for http or https servers. - FM
 		     */
 		    if ((url_type = is_url(cur_cookie->commentURL)) &&
 		        (url_type == HTTP_URL_TYPE ||
-		    	 url_type == HTTPS_URL_TYPE/* ||
-			 url_type == FTP_URL_TYPE ||
-			 url_type == GOPHER_URL_TYPE ||
-			 url_type == HTML_GOPHER_URL_TYPE ||
-			 url_type == INDEX_GOPHER_URL_TYPE ||
-			 url_type == NEWS_URL_TYPE ||
-			 url_type == NNTP_URL_TYPE ||
-			 url_type == SNEWS_URL_TYPE ||
-			 url_type == WAIS_URL_TYPE ||
-			 url_type == CSO_URL_TYPE ||
-			 url_type == FINGER_URL_TYPE */)) {
+		    	 url_type == HTTPS_URL_TYPE)) {
 		        length += strlen(cur_cookie->commentURL);
 		    } else {
+			if (TRACE)
+			    fprintf(stderr,
+		     "LYProcessSetCookies: Rejecting commentURL value '%s'\n",
+				    cur_cookie->commentURL);
 			FREE(cur_cookie->commentURL);
 		    }
 		}
@@ -1443,7 +1474,38 @@ PRIVATE void LYProcessSetCookies ARGS6(
 		     */
 		    !(cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) {
 		    length -= strlen(cur_cookie->domain);
-		    StrAllocCopy(cur_cookie->domain, value);
+		    /*
+		     *  If the value does not have a lead dot,
+		     *  but does have an embedded dot, and is
+		     *  not an exact match to the hostname, nor
+		     *  is a numeric IP address, add a lead dot.
+		     *  Otherwise, use the value as is. - FM
+		     */
+		    if (value[0] != '.' && value[0] != '\0' &&
+			value[1] != '\0' && strcmp(value, hostname)) {
+			char *ptr = strchr(value, '.');
+			if (ptr != NULL && ptr[1] != '\0') {
+			    ptr = value;
+			    while (*ptr == '.' ||
+				   isdigit((unsigned char)*ptr))
+				ptr++;
+			    if (*ptr != '\0') {
+			        if (TRACE) {
+				    fprintf(stderr,
+	       "LYProcessSetCookies: Adding lead dot for domain value '%s'\n",
+					    value);
+				}
+				StrAllocCopy(cur_cookie->domain, ".");
+				StrAllocCat(cur_cookie->domain, value);
+			    } else {
+				StrAllocCopy(cur_cookie->domain, value);
+			    }
+			} else {
+			    StrAllocCopy(cur_cookie->domain, value);
+			}
+		    } else {
+			StrAllocCopy(cur_cookie->domain, value);
+		    }
 		    length += strlen(cur_cookie->domain);
 		    cur_cookie->flags |= COOKIE_FLAG_DOMAIN_SET;
 		}
@@ -1534,7 +1596,7 @@ PRIVATE void LYProcessSetCookies ARGS6(
 	    }
 
 	    /*
-	     *  If none of the above comparisions succeeded, and we have
+	     *  If none of the above comparisons succeeded, and we have
 	     *  a value, then we have an unknown pair of the form 'foo=bar',
 	     *  which means it's time to create a new cookie.  If we don't
 	     *  have a non-zero-length value, assume it's an error or a
@@ -1542,132 +1604,40 @@ PRIVATE void LYProcessSetCookies ARGS6(
 	     *  ignore it. - FM
 	     */
 	    if (!known_attr && value_end > value_start) {
-		if (cur_cookie) {
+		/*
+		 *  If we've started a cookie, and it's not too big,
+		 *  save it in the CombinedCookies list. - FM
+		 */
+		if (length <= 4096 && cur_cookie != NULL) {
+		    /*
+		     *  If we had a Set-Cookie2 header, make sure
+		     *  the version is at least 1, and mark it for
+		     *  quoting. - FM
+		     */
 		    if (SetCookie2 != NULL) {
-		        /*
-			 *  If we had a Set-Cookie2 header, make sure
-			 *  the version is at least 1, and mark it for
-			 *  quoting. - FM
-			 */
 			if (cur_cookie->version < 1) {
 			    cur_cookie->version = 1;
 			}
 			cur_cookie->quoted = TRUE;
 		    }
-		    cl = CombinedCookies;
-		    while (NULL != (co = (cookie *)HTList_nextObject(cl))) {
-			/*
-			 *  Check whether the cookie from the Set-Cookie2
-			 *  header has the same name and value as this one
-			 *  from the Set-Cookie header.  If they both had a
-			 *  domain attribute, make sure those match, and
-			 *  similarly if they both had a path attribute. - FM
-			 */
-			if ((!strcmp(co->name, cur_cookie->name) &&
-			     !strcmp(co->value, cur_cookie->value)) &&
-			    !(((co->flags & COOKIE_FLAG_DOMAIN_SET) &&
-			       (cur_cookie->flags &
-					    COOKIE_FLAG_DOMAIN_SET)) &&
-			      strcmp(co->domain, cur_cookie->domain)) &&
-			    !(((co->flags & COOKIE_FLAG_PATH_SET) &&
-			       (cur_cookie->flags &
-					    COOKIE_FLAG_PATH_SET)) &&
-			      strcmp(co->path, cur_cookie->path))) {
-			    /*
-			     *  If the Set-Cookie2 header didn't include
-			     *  a domain attribute and the Set-Cookie
-			     *  header did, add it. - FM
-			     */
-			    if (!(co->flags & COOKIE_FLAG_DOMAIN_SET) &&
-				(cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) {
-				StrAllocCopy(co->domain, cur_cookie->domain);
-				co->flags |= COOKIE_FLAG_DOMAIN_SET;
-			    }
-			    /*
-			     *  If the Set-Cookie2 header didn't include
-			     *  a path attribute and the Set-Cookie
-			     *  header did, add it. - FM
-			     */
-			    if (!(co->flags & COOKIE_FLAG_PATH_SET) &&
-				(cur_cookie->flags & COOKIE_FLAG_PATH_SET)) {
-				StrAllocCopy(co->path, cur_cookie->path);
-				co->pathlen = cur_cookie->pathlen;
-				co->flags |= COOKIE_FLAG_PATH_SET;
-			    }
-			    /*
-			     *  If the Set-Cookie2 header didn't include
-			     *  a comment attribute and the Set-Cookie
-			     *  header did, add it. - FM
-			     */
-			    if (!co->comment && cur_cookie->comment) {
-				StrAllocCopy(co->comment,
-					     cur_cookie->comment);
-			    }
-			    /*
-			     *  If the Set-Cookie2 header didn't include
-			     *  a commentURL attribute and the Set-Cookie
-			     *  header did, add it. - FM
-			     */
-			    if (!co->commentURL && cur_cookie->commentURL) {
-				StrAllocCopy(co->commentURL,
-					     cur_cookie->commentURL);
-			    }
-			    /*
-			     *  If the Set-Cookie2 header didn't include
-			     *  a port attribute and the Set-Cookie
-			     *  header did, add it. - FM
-			     */
-			    if (!co->PortList && cur_cookie->PortList) {
-				StrAllocCopy(co->PortList,
-					     cur_cookie->PortList);
-			    }
-			    /*
-			     *  If the Set-Cookie2 header didn't include
-			     *  a secure attribute and the Set-Cookie
-			     *  header did, add it. - FM
-			     */
-			    if (!(co->flags & COOKIE_FLAG_SECURE) &&
-				(cur_cookie->flags & COOKIE_FLAG_SECURE)) {
-				co->flags |= COOKIE_FLAG_SECURE;
-			    }
-			    /*
-			     *  If the Set-Cookie2 header didn't set an
-			     *  expiration and the Set-Cookie header did,
-			     *  add it. - FM
-			     */
-			    if (!(co->flags & COOKIE_FLAG_EXPIRES_SET) &&
-				(cur_cookie->flags &
-				 COOKIE_FLAG_EXPIRES_SET)) {
-				co->expires = cur_cookie->expires;
-				co->flags |= COOKIE_FLAG_EXPIRES_SET;
-			    }
-			    /*
-			     *  If the Set-Cookie2 header didn't set
-			     *  discard and the Set-Cookie header did,
-			     *  add it. - FM
-			     */
-			    if (!(co->flags & COOKIE_FLAG_DISCARD) &&
-				(cur_cookie->flags & COOKIE_FLAG_DISCARD)) {
-				co->flags |= COOKIE_FLAG_DISCARD;
-			    }
-			    /*
-			     *  If the cookie from the Set-Cookie2 header
-			     *  has a lower version than this cookie, use
-			     *  this cookie's version (though it should
-			     *  not have a version number). - FM
-			     */
-			    if (co->version < cur_cookie->version) {
-				co->version = cur_cookie->version;
-			    }
-			    freeCookie(cur_cookie);
-			    cur_cookie = NULL;
-			    break;
-			}
-		    }
-		    if (co == NULL) {
-			HTList_appendObject(CombinedCookies, cur_cookie);
+		    HTList_appendObject(CombinedCookies, cur_cookie);
+		} else if (cur_cookie != NULL) {
+		    if (TRACE) {
+			fprintf(stderr,
+			"LYProcessSetCookies: Rejecting Set-Cookie: %s=%s\n",
+				(cur_cookie->name ?
+				 cur_cookie->name : "[no name]"),
+				(cur_cookie->value ?
+				 cur_cookie->value : "[no value]"));
+			fprintf(stderr,
+			"                     due to excessive length!\n");
 		    }
+        	    freeCookie(cur_cookie);
+		    cur_cookie = NULL;
 		}
+		/*
+		 *  Start a new cookie. - FM
+		 */
 		cur_cookie = newCookie();
 		length = 0;
 		MemAllocCopy(&(cur_cookie->name), attr_start, attr_end);
@@ -1697,113 +1667,7 @@ PRIVATE void LYProcessSetCookies ARGS6(
 	    }
 	    cur_cookie->quoted = TRUE;
 	}
-	cl = CombinedCookies;
-	while (NULL != (co = (cookie *)HTList_nextObject(cl))) {
-	    /*
-	     *  Check whether the cookie from the Set-Cookie2
-	     *  header has the same name and value as this one
-	     *  from the Set-Cookie header.  If they both had a
-	     *  domain attribute, make sure those match, and
-	     *  similarly if they both had a path attribute. - FM
-	     */
-	    if ((!strcmp(co->name, cur_cookie->name) &&
-		 !strcmp(co->value, cur_cookie->value)) &&
-		!(((co->flags & COOKIE_FLAG_DOMAIN_SET) &&
-		   (cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) &&
-		  strcmp(co->domain, cur_cookie->domain)) &&
-		!(((co->flags & COOKIE_FLAG_PATH_SET) &&
-		   (cur_cookie->flags & COOKIE_FLAG_PATH_SET)) &&
-		  strcmp(co->path, cur_cookie->path))) {
-		/*
-		 *  If the Set-Cookie2 header didn't include
-		 *  a domain attribute and the Set-Cookie
-		 *  header did, add it. - FM
-		 */
-		if (!(co->flags & COOKIE_FLAG_DOMAIN_SET) &&
-		    (cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) {
-		    StrAllocCopy(co->domain, cur_cookie->domain);
-		    co->flags |= COOKIE_FLAG_DOMAIN_SET;
-		}
-		/*
-		 *  If the Set-Cookie2 header didn't include
-		 *  a path attribute and the Set-Cookie
-		 *  header did, add it. - FM
-		 */
-		if (!(co->flags & COOKIE_FLAG_PATH_SET) &&
-		    (cur_cookie->flags & COOKIE_FLAG_PATH_SET)) {
-		    StrAllocCopy(co->path, cur_cookie->path);
-		    co->pathlen = cur_cookie->pathlen;
-		    co->flags |= COOKIE_FLAG_PATH_SET;
-		}
-		/*
-		 *  If the Set-Cookie2 header didn't include
-		 *  a comment attribute and the Set-Cookie
-		 *  header did, add it. - FM
-		 */
-		if (!co->comment && cur_cookie->comment) {
-		    StrAllocCopy(co->comment, cur_cookie->comment);
-		}
-		/*
-		 *  If the Set-Cookie2 header didn't include
-		 *  a commentURL attribute and the Set-Cookie
-		 *  header did, add it. - FM
-		 */
-		if (!co->commentURL && cur_cookie->commentURL) {
-		    StrAllocCopy(co->commentURL, cur_cookie->commentURL);
-		}
-		/*
-		 *  If the Set-Cookie2 header didn't include
-		 *  a port attribute and the Set-Cookie
-		 *  header did, add it. - FM
-		 */
-		if (!co->PortList && cur_cookie->PortList) {
-		    StrAllocCopy(co->PortList, cur_cookie->PortList);
-		}
-		/*
-		 *  If the Set-Cookie2 header didn't include
-		 *  a secure attribute and the Set-Cookie
-		 *  header did, add it. - FM
-		 */
-		if (!(co->flags & COOKIE_FLAG_SECURE) &&
-		    (cur_cookie->flags & COOKIE_FLAG_SECURE)) {
-		    co->flags |= COOKIE_FLAG_SECURE;
-		}
-		/*
-		 *  If the Set-Cookie2 header didn't set an
-		 *  expiration and the Set-Cookie header did,
-		 *  add it. - FM
-		 */
-		if (!(co->flags & COOKIE_FLAG_EXPIRES_SET) &&
-		    (cur_cookie->flags & COOKIE_FLAG_EXPIRES_SET)) {
-		    co->expires = cur_cookie->expires;
-		    co->flags |= COOKIE_FLAG_EXPIRES_SET;
-		}
-		/*
-		 *  If the Set-Cookie2 header didn't set
-		 *  discard and the Set-Cookie header did,
-		 *  add it. - FM
-		 */
-		if (!(co->flags & COOKIE_FLAG_DISCARD) &&
-		    (cur_cookie->flags & COOKIE_FLAG_DISCARD)) {
-		    co->flags |= COOKIE_FLAG_DISCARD;
-		}
-		/*
-		 *  If the cookie from the Set-Cookie2 header
-		 *  has a lower version than this cookie, use
-		 *  this cookie's version (though it should
-		 *  not have a version number). - FM
-		 */
-		if (co->version < cur_cookie->version) {
-		    co->version = cur_cookie->version;
-		}
-		freeCookie(cur_cookie);
-		cur_cookie = NULL;
-		break;
-	    }
-	}
-	if (co == NULL) {
-	    HTList_appendObject(CombinedCookies, cur_cookie);
-	}
+	HTList_appendObject(CombinedCookies, cur_cookie);
     } else if (cur_cookie != NULL) {
 	if (TRACE) {
 	    fprintf(stderr,
@@ -1869,8 +1733,8 @@ PUBLIC void LYSetCookie ARGS3(
 
     /*
      *  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
+     *  the Set-Cookie and/or Set-Cookie2 header(s) if trace mode is
+     *  on, but set the cookie(s) only if LYSetCookies is TRUE. - FM
      */
     if (((hostname = HTParse(address, "", PARSE_HOST)) != NULL) &&
 	(ptr = strchr(hostname, ':')) != NULL)  {
diff --git a/src/LYCurses.c b/src/LYCurses.c
index ffffcb1c..41a29cc4 100644
--- a/src/LYCurses.c
+++ b/src/LYCurses.c
@@ -575,6 +575,12 @@ PUBLIC void start_curses NOARGS
 
     if (slinit == 0) {
 	SLtt_get_terminfo();
+#ifdef UNIX
+#if SLANG_VERSION >= 9935
+	SLang_TT_Read_FD = fileno(stdin);
+#endif /* SLANG_VERSION >= 9935 */
+#endif /* UNIX */
+
 	/*
 	 *  Check whether a saved show_color:off override is in effect. - kw
 	 */
diff --git a/src/LYForms.c b/src/LYForms.c
index 1c053bca..e48a6ca8 100644
--- a/src/LYForms.c
+++ b/src/LYForms.c
@@ -673,6 +673,9 @@ PRIVATE int popup_options ARGS7(
 	return(orig_selection);
     }
     scrollok(form_window, TRUE);
+#ifdef PDCURSES
+	keypad(form_window, TRUE);
+#endif /* PDCURSES */
 #ifdef NCURSES
 #ifdef wgetbkgd
 #define getbkgd(w) wgetbkgd(w)	/* workaround pre-1.9.9g bug */
diff --git a/src/LYGetFile.c b/src/LYGetFile.c
index f58fcd84..917bb037 100644
--- a/src/LYGetFile.c
+++ b/src/LYGetFile.c
@@ -48,6 +48,7 @@
 PRIVATE int fix_http_urls PARAMS((document *doc));
 extern char * WWW_Download_File;
 extern char LYCancelDownload;
+extern BOOL redirect_post_content;
 #ifdef VMS
 extern BOOLEAN LYDidRename;
 #endif /* VMS */
@@ -127,13 +128,15 @@ Try_Redirected_URL:
 	redirect_post_content = FALSE;
 
 	if (TRACE) {
-	    fprintf(stderr,"LYGetFile: getting %s\n\n",doc->address);
+	    fprintf(stderr,"getfile: getting %s\n\n",doc->address);
 	}
 
 	/*
 	 *  Protect against denial of service attacks
 	 *  via the port 19 CHARGEN service, and block
-	 *  connections to the port 25 ESMTP service. - FM
+	 *  connections to the port 25 ESMTP service.
+	 *  Also reject any likely spoof attempts via
+	 *  wrap arounds at 65536. - FM
 	 */
 	if ((temp = HTParse(doc->address, "", PARSE_HOST)) != NULL &&
 	    strlen(temp) > 3) {
@@ -146,21 +149,27 @@ Try_Redirected_URL:
 
 		cp++;
 	        if (sscanf(cp, "%ld", &value) == 1) {
-		    if (value > 65535 || value < 0) {
-			HTAlert(PORT_INVALID);
-			FREE(temp);
-			return(NULLFILE); 
-		    }
-		    if (value == 19) {
+		    if (value == 19 || value == 65555) {
 			HTAlert(PORT_NINETEEN_INVALID);
 			FREE(temp);
 			return(NULLFILE); 
 		    }
-		    if (value == 25) {
+		    if (value == 25 || value == 65561) {
 			HTAlert(PORT_TWENTYFIVE_INVALID);
 			FREE(temp);
 			return(NULLFILE);
 		    } 
+		    if (value > 65535 || value < 0) {
+		        char msg[265];
+			sprintf(msg, PORT_INVALID, (unsigned long)value);
+			HTAlert(msg);
+			FREE(temp);
+			return(NULLFILE);
+		    } 
+		} else if (isdigit((unsigned char)*cp)) {
+		    HTAlert(URL_PORT_BAD);
+		    FREE(temp);
+		    return(NULLFILE);
 		}
 	    }
 	}
@@ -591,7 +600,7 @@ Try_Redirected_URL:
 			    StrAllocCopy(tmp, "http://");
 			    if (TRACE)
 			        fprintf(stderr,
-					"LYGetFile: URL %s\n",
+					"getfile: URL '%s'\n",
 					doc->address);
 			    *cp = '\0';
 			    StrAllocCat(tmp, doc->address+9);
@@ -606,7 +615,7 @@ Try_Redirected_URL:
 			        StrAllocCat(tmp, cp+8);
 			    StrAllocCopy(doc->address, tmp);
 			    if (TRACE)
-			        fprintf(stderr, "    changed to %s\n",
+			        fprintf(stderr, "  changed to '%s'\n",
 						doc->address);
 			    FREE(tmp);
 			    url_type = HTTP_URL_TYPE;
@@ -639,7 +648,7 @@ Try_Redirected_URL:
 			    char *cp2;
 
 			    if (TRACE)
-			        fprintf(stderr, "LYGetFile: URL %s\n",
+			        fprintf(stderr, "getfile: URL '%s'\n",
 						doc->address);
 			    *cp1 = '\0';
 			    cp1 += 2;
@@ -661,7 +670,7 @@ Try_Redirected_URL:
 			    StrAllocCopy(doc->address, temp);
 			    FREE(temp);
 			    if (TRACE)
-			        fprintf(stderr, "    changed to %s\n",
+			        fprintf(stderr, "  changed to '%s'\n",
 						doc->address);
 			    WWWDoc.address = doc->address;
 			}
@@ -863,6 +872,15 @@ Try_Redirected_URL:
 			    } else {
 			        StrAllocCopy(fname, doc->address);
 			    }
+			    /*
+			     *  Check whether this is a compressed file,
+			     *  which we don't uncompress for downloads,
+			     *  and adjust any suffix appropriately. - FM
+			     */
+			    if (tmpanchor != NULL) {
+				HTCheckFnameForCompression(&fname, tmpanchor,
+							   FALSE);
+			    }
 			    if (LYdownload_options(&fname,
 						   WWW_Download_File) < 0) {
 				FREE(fname);
@@ -1295,10 +1313,10 @@ PRIVATE int fix_http_urls ARGS1(
 	 *  If we get to here, trim the trailing slash. - FM
 	 */
 	if (TRACE)
-	    fprintf(stderr,"LYGetFile: URL %s\n", doc->address);
+	    fprintf(stderr, "fix_http_urls: URL '%s'\n", doc->address);
 	doc->address[strlen(doc->address)-1] = '\0';
 	if (TRACE) {
-	    fprintf(stderr,"    changed to %s\n", doc->address);
+	    fprintf(stderr, "        changed to '%s'\n", doc->address);
 	    sleep(MessageSecs);
 	}
     }
@@ -1312,10 +1330,10 @@ PRIVATE int fix_http_urls ARGS1(
 	}
     }
     if (TRACE)
-        fprintf(stderr,"LYGetFile: URL %s\n", doc->address);
+        fprintf(stderr, "fix_http_urls: URL '%s'\n", doc->address);
     StrAllocCat(doc->address, "/");
     if (TRACE) {
-        fprintf(stderr,"    changed to %s\n",doc->address);
+        fprintf(stderr, "        changed to '%s'\n",doc->address);
 	sleep(MessageSecs);
     }
 
diff --git a/src/LYLocal.c b/src/LYLocal.c
index 1524d84f..df518553 100644
--- a/src/LYLocal.c
+++ b/src/LYLocal.c
@@ -44,9 +44,11 @@
 #include "LYSystem.h"
 
 #ifndef VMS
+#ifndef _WINDOWS
 #include <sys/wait.h>
 #include <errno.h>
 #include <grp.h>
+#endif /*_WINDOWS */
 #endif /* VMS */
 
 #include "LYLeaks.h"
@@ -2192,7 +2194,7 @@ PUBLIC int LYExecv ARGS3(
 	char **,	argv,
 	char *,		msg)
 {
-#ifdef VMS
+#if defined(VMS) || defined(_WINDOWS)
     if (TRACE) {
 	fprintf(stderr, "LYExecv:  Called inappropriately!\n");
     }
diff --git a/src/LYMain.c b/src/LYMain.c
index 89db134d..8b1c838a 100644
--- a/src/LYMain.c
+++ b/src/LYMain.c
@@ -1192,6 +1192,10 @@ PUBLIC int main ARGS2(
     /*
      *  Process the configuration file.
      */
+    if (TRACE) {
+	fprintf(stderr,
+		"Loading cfg file '%s'.\n", lynx_cfg_file);
+    }
     read_cfg(lynx_cfg_file);
     FREE(lynx_cfg_file);
 
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index 154930e6..40b113e3 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -156,6 +156,7 @@ int mainloop NOARGS
     BOOLEAN LYRawMode_flag = LYRawMode;
     BOOLEAN LYSelectPopups_flag = LYSelectPopups;
     BOOLEAN trace_mode_flag = FALSE;
+    BOOLEAN forced_HTML_mode = LYforce_HTML_mode;
     char cfile[128];
     FILE *cfp;
     char *cp, *toolbar;
@@ -963,6 +964,11 @@ try_again:
 	     */
 	    first_file = FALSE; 
 
+	    /*
+	     *  Set the startrealm, and deal as best we can
+	     *  with preserving forced HTML mode for a local
+	     *  startfile. - FM
+	     */
 	    temp = HTParse(curdoc.address, "",
 			   PARSE_ACCESS+PARSE_HOST+PARSE_PUNCTUATION);
 	    if (!temp || *temp == '\0') {
@@ -976,6 +982,30 @@ try_again:
 			StrAllocCat(startrealm, "/");
 		    }
 		} else {
+		    if (forced_HTML_mode &&
+			!dump_output_immediately &&
+			!curdoc.bookmark &&
+			!strncasecomp(curdoc.address, "file:", 5) &&
+			strlen(temp) > 1) {
+			/*
+			 *  We forced HTML for a local startfile which
+			 *  is not a bookmark file and has a path of at
+			 *  least two letters.  It it doesn't have a
+			 *  suffix mapped to text/html, we'll set the
+			 *  entire path (including the lead slash) as a
+			 *  "suffix" mapped to text/html to ensure it is
+			 *  always treated as an HTML source file.  We
+			 *  are counting on a tail match to this full path
+			 *  for some other URL fetched during the session
+			 *  having too low a probability to worry about,
+			 *  but it could happen. - FM
+			 */
+			HTAtom *encoding;
+
+			if (HTFileFormat(temp, &encoding) != WWW_HTML) {
+			    HTSetSuffix(temp, "text/html", "8bit", 1.0);
+			}
+		    }
 		    if ((cp = strrchr(temp, '/')) != NULL) {
 			*(cp+1) = '\0';
 			StrAllocCat(startrealm, temp);
@@ -2520,6 +2550,8 @@ new_cmd:  /*
 			    !strncmp(curdoc.address, "file:", 5)) {
 			    LYNoRefererForThis = TRUE;
 			}
+			StrAllocCopy(newdoc.title,
+				     links[curdoc.link].hightext);
 		    }
 		    c = change_form_link(&links[curdoc.link],
 					 FORM_UP, &newdoc, &refresh_screen,
@@ -4641,6 +4673,10 @@ check_add_bookmark_to_self:
 	        (links[curdoc.link].type != WWW_FORM_LINK_TYPE ||
 	    	 links[curdoc.link].form->type == F_SUBMIT_TYPE ||
 		 links[curdoc.link].form->type == F_IMAGE_SUBMIT_TYPE)) {
+		/*
+		 *  We have links, and the current link is a
+		 *  normal link or a form's submit button. - FM
+		 */
 	        _statusline(HEAD_D_L_OR_CANCEL);
 		c = LYgetch();
 		if (TOUPPER(c) == 'D') {
@@ -4662,6 +4698,7 @@ check_add_bookmark_to_self:
 			} 
 		        HEAD_request = TRUE;
 			LYforce_no_cache = TRUE;
+			StrAllocCopy(newdoc.title, curdoc.title);
 			if (HTLoadedDocumentIsHEAD()) {
 	            	    HTuncache_current_document();
 			    FREE(curdoc.address);
@@ -4688,14 +4725,16 @@ check_add_bookmark_to_self:
 			_statusline(FORM_ACTION_NOT_HTTP_URL);
 			sleep(MessageSecs);
 		    } else if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-		    	       links[curdoc.link].form->submit_method == URL_POST_METHOD &&
+		    	       links[curdoc.link].form->submit_method ==
+							  URL_POST_METHOD &&
 			       HTConfirm(CONFIRM_POST_LINK_HEAD) == FALSE) {
 			_statusline(CANCELLED);
 			sleep(InfoSecs);
 		    } else {
 			HEAD_request = TRUE;
 			LYforce_no_cache = TRUE;
-			StrAllocCat(newdoc.title, " - HEAD");
+			StrAllocCopy(newdoc.title, links[curdoc.link].hightext);
+			StrAllocCat(newdoc.title, " - (HEAD)");
 			cmd = LYK_ACTIVATE;
 			goto new_cmd;
 		    }
@@ -4704,6 +4743,7 @@ check_add_bookmark_to_self:
 		break;
 	    } else {
 		/*
+		 *  We can offer only this document for a HEAD request.
 		 *  Check if this is a reply from a POST, and if so,
 		 *  seek confirmation if the safe element is not set. - FM
 		 */
@@ -4714,18 +4754,35 @@ check_add_bookmark_to_self:
 		    sleep(InfoSecs);
 		    break;
 		} else if (nlinks > 0) {
+		    /*
+		     *  The current link is a non-submittable form
+		     *  link, so prompt the user to make it clear
+		     *  that the HEAD request would be for the
+		     *  current document, not the form link. - FM
+		     */
 		    _statusline(HEAD_D_OR_CANCEL);
 	            c = LYgetch();
 		} else {
+		    /*
+		     *  No links, so we can just assume that
+		     *  the user wants a HEAD request for the
+		     *  current document. - FM
+		     */
 		    c = 'D';
 		}
 		if (TOUPPER(c) == 'D') {
+		    /*
+		     *  The user didn't cancel, so check if
+		     *  a HEAD request is appropriate for the
+		     *  current document. - FM
+		     */ 
 		    if (strncmp(curdoc.address, "http", 4)) {
 		        _statusline(DOC_NOT_HTTP_URL);
 			sleep(MessageSecs);
 		    } else {
 		        HEAD_request = TRUE;
 			LYforce_no_cache = TRUE;
+			StrAllocCopy(newdoc.title, curdoc.title);
 			if (HTLoadedDocumentIsHEAD()) {
 	            	    HTuncache_current_document();
 			    FREE(curdoc.address);
@@ -4738,7 +4795,7 @@ check_add_bookmark_to_self:
 	    break;	
 
 	case LYK_TOGGLE_HELP:
-    	    if (user_mode==NOVICE_MODE) {
+    	    if (user_mode == NOVICE_MODE) {
 	        toggle_novice_line();
 	        noviceline(more);
 	    }
diff --git a/src/LYOptions.c b/src/LYOptions.c
index 59ba4822..c4ef236c 100644
--- a/src/LYOptions.c
+++ b/src/LYOptions.c
@@ -2133,6 +2133,9 @@ PRIVATE int popup_choice ARGS6(
 	return(orig_choice);
     }
     scrollok(form_window, TRUE);
+#ifdef PDCURSES
+       keypad(form_window, TRUE);
+#endif /* PDCURSES */
 #ifdef NCURSES
 #ifdef wgetbkgd
 #define getbkgd(w) wgetbkgd(w)	/* workaround pre-1.9.9g bug */
diff --git a/src/LYShowInfo.c b/src/LYShowInfo.c
index 156e4baf..2cd1b05b 100644
--- a/src/LYShowInfo.c
+++ b/src/LYShowInfo.c
@@ -240,7 +240,8 @@ PUBLIC int showinfo ARGS4(
 
     StrAllocCopy(Title, doc->title);
     LYEntify(&Title, TRUE);
-    fprintf(fp0,"<dt><em>Linkname:</em> %s\n", Title);
+    fprintf(fp0, "<dt><em>Linkname:</em> %s%s\n",
+    		 Title, (doc->isHEAD ? " (HEAD)" : ""));
 
     StrAllocCopy(Address, doc->address);
     LYEntify(&Address, TRUE);
diff --git a/src/LYUtils.c b/src/LYUtils.c
index 8073ac04..ba4d706d 100644
--- a/src/LYUtils.c
+++ b/src/LYUtils.c
@@ -191,7 +191,12 @@ PUBLIC void highlight ARGS3(
 	if (links[cur].hightext2 && links[cur].ly < display_lines) {
 	    lynx_stop_link_color (flag == ON, links[cur].inUnderline);
 
-	    addch('\n');
+#ifndef USE_SLANG
+	    if ((char)(inch() & A_CHARTEXT) == '-')
+		move(links[cur].ly + 1, 0);
+	    else
+#endif
+		addch('\n');
 	    for (i = 0; i < links[cur].hightext2_offset; i++)
 	        addch(' ');
 
@@ -660,8 +665,8 @@ highlight_hit_within_hightext:
 		/*
 		 *  Start emphasis immediately if we are making
 		 *  the link non-current, or we are making it
-		 *  current but this is not the first character
-		 *  of the hightext. - FM
+		 *  current but this is not the first or last
+		 *  character of the hightext. - FM
 		 */
 		if (flag != ON ||
 		    (offset > hoffset && data[itmp+1] != '\0')) {
@@ -1329,10 +1334,11 @@ highlight_hit_within_hightext2:
 		/*
 		 *  Start emphasis immediately if we are making
 		 *  the link non-current, or we are making it
-		 *  current but this is not the first character
-		 *  of the hightext2. - FM
+		 *  current but this is not the first or last
+		 *  character of the hightext2. - FM
 		 */
-		if (flag != ON || offset > hoffset) {
+		if (flag != ON ||
+		    (offset > hoffset && data[itmp+1] != '\0')) {
 		    LYstartTargetEmphasis();
 		    TargetEmphasisON = TRUE;
 		    addstr(tmp);
@@ -1350,10 +1356,11 @@ highlight_hit_within_hightext2:
 		/*
 		 *  Start emphasis immediately if we are making
 		 *  the link non-current, or we are making it
-		 *  current but this is not the first character
-		 *  of the hightext2. - FM
+		 *  current but this is not the first or last
+		 *  character of the hightext2. - FM
 		 */
-		if (flag != ON || offset > hoffset) {
+		if (flag != ON ||
+		    (offset > hoffset && data[itmp+1] != '\0')) {
 		    LYstartTargetEmphasis();
 		    TargetEmphasisON = TRUE;
 		    addstr(tmp);
@@ -1366,10 +1373,11 @@ highlight_hit_within_hightext2:
 		/*
 		 *  Start emphasis immediately if we are making
 		 *  the link non-current, or we are making it
-		 *  current but this is not the first character
-		 *  of the hightext2. - FM
+		 *  current but this is not the first or last
+		 *  character of the hightext2. - FM
 		 */
-		if (flag != ON || offset > hoffset) {
+		if (flag != ON ||
+		    (offset > hoffset && data[itmp+1] != '\0')) {
 		    LYstartTargetEmphasis();
 		    TargetEmphasisON = TRUE;
 		    addstr(tmp);
@@ -4182,29 +4190,61 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 	fprintf(stdout, "Looking up '%s' first.\n", host);
     }
 #ifndef DJGPP
-    if ((phost = gethostbyname(host)) != NULL) {
+    if ((phost = gethostbyname(host)) != NULL)
 #else
-    if (resolve(host) != 0) {
+    if (resolve(host) != 0)
 #endif /* DJGPP */
+    {
+	/*
+	 *  Clear any residual interrupt. - FM
+	 */
+	if (LYCursesON && HTCheckForInterrupt()) {
+	    if (TRACE) {
+		fprintf(stderr,
+	 "LYExpandHostForURL: Ignoring interrupt because '%s' resolved.\n",
+			host);
+	    }
+	}
+
+	/*
+	 *  Return success. - FM
+	 */
         GotHost = TRUE;
 	FREE(host);
         FREE(Str);
         FREE(MsgStr);
 	return GotHost;
+    } else if (LYCursesON && HTCheckForInterrupt()) {
+	/*
+	 *  Give the user chance to interrupt lookup cycles. - KW & FM
+	 */
+	if (TRACE) {
+	    fprintf(stderr,
+	 "LYExpandHostForURL: Interrupted while '%s' failed to resolve.\n",
+		    host);
+	}
+
+	/*
+	 *  Return failure. - FM
+	 */
+	FREE(host);
+	FREE(Str);
+	FREE(MsgStr);
+	return FALSE;
     }
 
     /*
-    **  Set the first prefix, making it a zero-length string
-    **  if the list is NULL or if the potential host field
-    **  ends with a dot. - FM
-    */
+     *  Set the first prefix, making it a zero-length string
+     *  if the list is NULL or if the potential host field
+     *  ends with a dot. - FM
+     */
     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 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) ||
@@ -4229,14 +4269,14 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
     LYstrncpy(DomainPrefix, StartP, (EndP - StartP));
 
     /*
-    **  Test each prefix with each suffix. - FM
-    */
+     *  Test each prefix with each suffix. - FM
+     */
     do {
         /*
-	**  Set the first suffix, making it a zero-length string
-	**  if the list is NULL or if the potential host field
-	**  begins with a dot. - FM
-	*/
+	 *  Set the first suffix, making it a zero-length string
+	 *  if the list is NULL or if the potential host field
+	 *  begins with a dot. - FM
+	 */
 	StartS = ((suffix_list && *Str != '.') ?
 				   suffix_list : "");
 	while ((*StartS) && (WHITE(*StartS) || *StartS == ',')) {
@@ -4249,8 +4289,8 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 	LYstrncpy(DomainSuffix, StartS, (EndS - StartS));
 
 	/*
-	**  Create domain names and do DNS tests. - FM
-	*/
+	 *  Create domain names and do DNS tests. - FM
+	 */
 	do {
 	    StrAllocCopy(Host, DomainPrefix);
 	    StrAllocCat(Host, ((*Str == '.') ? (Str + 1) : Str));
@@ -4287,7 +4327,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 		if (LYCursesON && HTCheckForInterrupt()) {
 		    if (TRACE) {
 			fprintf(stderr,
-	 "*** LYExpandHostForURL interrupted while %s failed to resolve\n",
+	 "LYExpandHostForURL: Interrupted while '%s' failed to resolve.\n",
 				host);
 			    }
 		    FREE(Str);
@@ -4298,8 +4338,8 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 		}
 
 	        /*
-		**  Advance to the next suffix, or end of suffix list. - FM
-		*/
+		 *  Advance to the next suffix, or end of suffix list. - FM
+		 */
 		StartS = ((*EndS == '\0') ? EndS : (EndS + 1));
 		while ((*StartS) && (WHITE(*StartS) || *StartS == ',')) {
 		    StartS++;	/* Skip whitespace and separators */
@@ -4314,8 +4354,8 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 
 	if (GotHost == FALSE) {
 	   /*
-	   **  Advance to the next prefix, or end of prefix list. - FM
-	   */
+	    *  Advance to the next prefix, or end of prefix list. - FM
+	    */
 	   StartP = ((*EndP == '\0') ? EndP : (EndP + 1));
 	   while ((*StartP) && (WHITE(*StartP) || *StartP == ',')) {
 	       StartP++;	/* Skip whitespace and separators */
@@ -4351,6 +4391,18 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
     }
 
     /*
+     *  Clear any residual interrupt. - FM
+     */
+    if (LYCursesON && HTCheckForInterrupt()) {
+	if (TRACE) {
+	    fprintf(stderr,
+	 "LYExpandHostForURL: Ignoring interrupt because '%s' %s.\n",
+		    host,
+		    (GotHost ? "resolved" : "timed out"));
+	}
+    }
+
+    /*
      *  Clean up and return the last test result. - FM
      */
     FREE(Str);
diff --git a/src/Makefile b/src/Makefile
index 5c8048cc..30ad4f31 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -69,6 +69,7 @@ TABLES= $(CHRTR)iso02_uni.h \
  $(CHRTR)cp437_uni.h \
  $(CHRTR)cp850_uni.h \
  $(CHRTR)cp852_uni.h \
+ $(CHRTR)cp866_uni.h \
  $(CHRTR)cp1250_uni.h \
  $(CHRTR)cp1251_uni.h \
  $(CHRTR)cp1252_uni.h \
diff --git a/src/UCAux.c b/src/UCAux.c
index e6d9247f..3eb5fcfe 100644
--- a/src/UCAux.c
+++ b/src/UCAux.c
@@ -69,12 +69,13 @@ PUBLIC BOOL UCCanTranslateFromTo ARGS2(
 
 	if (!strcmp(fromname, "koi8-r") || /* from cyrillic */
 	    !strcmp(fromname, "iso-8859-5") ||
+	    !strcmp(fromname, "cp866") ||
 	    !strcmp(fromname, "windows-1251") ||
 	    !strcmp(fromname, "koi-8")) {
 	    if (strcmp(toname, "iso-8859-5") &&
 		strcmp(toname, "koi8-r") &&
-		strcmp(toname, "windows-1251") &&
-		strcmp(toname, "iso-8859-2"))
+		strcmp(toname, "cp866") &&
+		strcmp(toname, "windows-1251"))
 		return NO;
 	}
     }
diff --git a/src/UCdomap.c b/src/UCdomap.c
index c32044f2..288b52aa 100644
--- a/src/UCdomap.c
+++ b/src/UCdomap.c
@@ -46,6 +46,7 @@
 #include "[.chrtrans]cp437_uni.h"
 #include "[.chrtrans]cp850_uni.h"
 #include "[.chrtrans]cp852_uni.h"
+#include "[.chrtrans]cp866_uni.h"
 #include "[.chrtrans]cp1250_uni.h"
 #include "[.chrtrans]cp1251_uni.h"
 #include "[.chrtrans]cp1252_uni.h"
@@ -69,6 +70,7 @@
 #include "chrtrans/cp437_uni.h"
 #include "chrtrans/cp850_uni.h"
 #include "chrtrans/cp852_uni.h"
+#include "chrtrans/cp866_uni.h"
 #include "chrtrans/cp1250_uni.h"
 #include "chrtrans/cp1251_uni.h"
 #include "chrtrans/cp1252_uni.h"
@@ -1670,6 +1672,7 @@ PUBLIC void UCInit NOARGS
     UC_CHARSET_SETUP_cp437;
     UC_CHARSET_SETUP_cp850;
     UC_CHARSET_SETUP_cp852;
+    UC_CHARSET_SETUP_cp866;
     UC_CHARSET_SETUP_windows_1250;
     UC_CHARSET_SETUP_windows_1251;
     UC_CHARSET_SETUP_iso_8859_1_windows_;
diff --git a/src/chrtrans/MAKEW32.BAT b/src/chrtrans/MAKEW32.BAT
index 3655ba0f..0c17aa1d 100644
--- a/src/chrtrans/MAKEW32.BAT
+++ b/src/chrtrans/MAKEW32.BAT
@@ -7,13 +7,17 @@ makeuctb iso02_uni.tbl > iso02_uni.h
 makeuctb iso03_uni.tbl > iso03_uni.h
 makeuctb iso04_uni.tbl > iso04_uni.h
 makeuctb iso05_uni.tbl > iso05_uni.h
+makeuctb iso06_uni.tbl > iso06_uni.h
 makeuctb iso07_uni.tbl > iso07_uni.h
+makeuctb iso08_uni.tbl > iso08_uni.h
 makeuctb iso09_uni.tbl > iso09_uni.h
 makeuctb iso10_uni.tbl > iso10_uni.h
 makeuctb cp437_uni.tbl > cp437_uni.h
+makeuctb cp866_uni.tbl > cp866_uni.h
 makeuctb cp850_uni.tbl > cp850_uni.h
 makeuctb cp852_uni.tbl > cp852_uni.h
 makeuctb cp1250_uni.tbl > cp1250_uni.h
+makeuctb cp1251_uni.tbl > cp1251_uni.h
 makeuctb cp1252_uni.tbl > cp1252_uni.h
 makeuctb utf8_uni.tbl > utf8_uni.h
 makeuctb mnemonic_suni.tbl > mnemonic_suni.h
diff --git a/src/chrtrans/Makefile b/src/chrtrans/Makefile
index af982a90..f5a44374 100644
--- a/src/chrtrans/Makefile
+++ b/src/chrtrans/Makefile
@@ -35,6 +35,7 @@ TABLES= $(CHRTR)iso02_uni.h \
  $(CHRTR)cp437_uni.h \
  $(CHRTR)cp850_uni.h \
  $(CHRTR)cp852_uni.h \
+ $(CHRTR)cp866_uni.h \
  $(CHRTR)cp1250_uni.h \
  $(CHRTR)cp1251_uni.h \
  $(CHRTR)cp1252_uni.h \
diff --git a/src/chrtrans/build-chrtrans.com b/src/chrtrans/build-chrtrans.com
index c2604a9f..f6f0609e 100644
--- a/src/chrtrans/build-chrtrans.com
+++ b/src/chrtrans/build-chrtrans.com
@@ -102,6 +102,8 @@ $ define/user sys$output 'CHRwhere'cp850_uni.h
 $ makeuctb cp850_uni.tbl
 $ define/user sys$output 'CHRwhere'cp852_uni.h
 $ makeuctb cp852_uni.tbl
+$ define/user sys$output 'CHRwhere'cp866_uni.h
+$ makeuctb cp866_uni.tbl
 $ define/user sys$output 'CHRwhere'cp1250_uni.h
 $ makeuctb cp1250_uni.tbl
 $ define/user sys$output 'CHRwhere'cp1251_uni.h
diff --git a/src/chrtrans/cp1251_uni.tbl b/src/chrtrans/cp1251_uni.tbl
index ada70396..21a44414 100644
--- a/src/chrtrans/cp1251_uni.tbl
+++ b/src/chrtrans/cp1251_uni.tbl
@@ -21,6 +21,7 @@ OWinCyrillic (cp1251)
 #
 #    The entries are in cp1251_WinCyrillic order
 #
+0x20-0x7f       idem
 0x80    U+0402  #CYRILLIC CAPITAL LETTER DJE
 0x81    U+0403  #CYRILLIC CAPITAL LETTER GJE
 0x82    U+201A  #SINGLE LOW-9 QUOTATION MARK
diff --git a/src/chrtrans/cp866_uni.tbl b/src/chrtrans/cp866_uni.tbl
new file mode 100644
index 00000000..2b109897
--- /dev/null
+++ b/src/chrtrans/cp866_uni.tbl
@@ -0,0 +1,189 @@
+#
+#The MIME name of this charset. 
+Mcp866
+
+#Name as a Display Charset (used on Options screen)
+ODosCyrillic (cp866)
+#
+#    Name:     cp866_DOSCyrillicRussian to Unicode table
+#    Unicode version: 2.0
+#    Table version: 2.00
+#    Table format:  Format A
+#    Date:          04/24/96
+#    Authors:       Lori Brownell <loribr@microsoft.com>
+#                   K.D. Chang    <a-kchang@microsoft.com>
+#    General notes: none
+#
+#    Format: Three tab-separated columns
+#        Column #1 is the cp866_DOSCyrillicRussian code (in hex)
+#        Column #2 is the Unicode (in hex as 0xXXXX)
+#        Column #3 is the Unicode name (follows a comment sign, '#')
+#
+#    The entries are in cp866_DOSCyrillicRussian order
+#
+0x20-0x40       idem
+
+# some mapppings of greek capital letters to latin letters added - kw
+0x41	U+0041	U+0391	#LATIN CAPITAL LETTER A
+0x42	U+0042	U+0392	#LATIN CAPITAL LETTER B
+0x43	U+0043	#LATIN CAPITAL LETTER C
+0x44	U+0044	#LATIN CAPITAL LETTER D
+0x45	U+0045	U+0395	#LATIN CAPITAL LETTER E
+0x46	U+0046	#LATIN CAPITAL LETTER F
+0x47	U+0047	#LATIN CAPITAL LETTER G
+0x48	U+0048	U+0397	#LATIN CAPITAL LETTER H
+0x49	U+0049	U+0399	#LATIN CAPITAL LETTER I
+0x4a	U+004a	#LATIN CAPITAL LETTER J
+0x4b	U+004b	U+039a	#LATIN CAPITAL LETTER K
+0x4c	U+004c	#LATIN CAPITAL LETTER L
+0x4d	U+004d	U+039c	#LATIN CAPITAL LETTER M
+0x4e	U+004e	U+039d	#LATIN CAPITAL LETTER N
+0x4f	U+004f	U+039f	#LATIN CAPITAL LETTER O
+0x50	U+0050	U+03a1	#LATIN CAPITAL LETTER P
+0x51	U+0051	#LATIN CAPITAL LETTER Q
+0x52	U+0052	#LATIN CAPITAL LETTER R
+0x53	U+0053	#LATIN CAPITAL LETTER S
+0x54	U+0054	U+03a4	#LATIN CAPITAL LETTER T
+0x55	U+0055	#LATIN CAPITAL LETTER U
+0x56	U+0056	#LATIN CAPITAL LETTER V
+0x57	U+0057	#LATIN CAPITAL LETTER W
+0x58	U+0058	U+03a7	#LATIN CAPITAL LETTER X
+0x59	U+0059	U+03a5	#LATIN CAPITAL LETTER Y
+0x5a	U+005a	U+0396	#LATIN CAPITAL LETTER Z
+0x5b-0x7f       idem
+
+0x80    U+0410  #CYRILLIC CAPITAL LETTER A
+0x81    U+0411  #CYRILLIC CAPITAL LETTER BE
+0x82    U+0412  #CYRILLIC CAPITAL LETTER VE
+0x83    U+0413  #CYRILLIC CAPITAL LETTER GHE
+0x84    U+0414  #CYRILLIC CAPITAL LETTER DE
+0x85    U+0415  #CYRILLIC CAPITAL LETTER IE
+0x86    U+0416  #CYRILLIC CAPITAL LETTER ZHE
+0x87    U+0417  #CYRILLIC CAPITAL LETTER ZE
+0x88    U+0418  #CYRILLIC CAPITAL LETTER I
+0x89    U+0419  #CYRILLIC CAPITAL LETTER SHORT I
+0x8a    U+041a  #CYRILLIC CAPITAL LETTER KA
+0x8b    U+041b  #CYRILLIC CAPITAL LETTER EL
+0x8c    U+041c  #CYRILLIC CAPITAL LETTER EM
+0x8d    U+041d  #CYRILLIC CAPITAL LETTER EN
+0x8e    U+041e  #CYRILLIC CAPITAL LETTER O
+0x8f    U+041f  #CYRILLIC CAPITAL LETTER PE
+0x90    U+0420  #CYRILLIC CAPITAL LETTER ER
+0x91    U+0421  #CYRILLIC CAPITAL LETTER ES
+0x92    U+0422  #CYRILLIC CAPITAL LETTER TE
+0x93    U+0423  #CYRILLIC CAPITAL LETTER U
+0x94    U+0424  #CYRILLIC CAPITAL LETTER EF
+0x95    U+0425  #CYRILLIC CAPITAL LETTER HA
+0x96    U+0426  #CYRILLIC CAPITAL LETTER TSE
+0x97    U+0427  #CYRILLIC CAPITAL LETTER CHE
+0x98    U+0428  #CYRILLIC CAPITAL LETTER SHA
+0x99    U+0429  #CYRILLIC CAPITAL LETTER SHCHA
+0x9a    U+042a  #CYRILLIC CAPITAL LETTER HARD SIGN
+0x9b    U+042b  #CYRILLIC CAPITAL LETTER YERU
+0x9c    U+042c  #CYRILLIC CAPITAL LETTER SOFT SIGN
+0x9d    U+042d  #CYRILLIC CAPITAL LETTER E
+0x9e    U+042e  #CYRILLIC CAPITAL LETTER YU
+0x9f    U+042f  #CYRILLIC CAPITAL LETTER YA
+0xa0    U+0430  #CYRILLIC SMALL LETTER A
+0xa1    U+0431  #CYRILLIC SMALL LETTER BE
+0xa2    U+0432  #CYRILLIC SMALL LETTER VE
+0xa3    U+0433  #CYRILLIC SMALL LETTER GHE
+0xa4    U+0434  #CYRILLIC SMALL LETTER DE
+0xa5    U+0435  #CYRILLIC SMALL LETTER IE
+0xa6    U+0436  #CYRILLIC SMALL LETTER ZHE
+0xa7    U+0437  #CYRILLIC SMALL LETTER ZE
+0xa8    U+0438  #CYRILLIC SMALL LETTER I
+0xa9    U+0439  #CYRILLIC SMALL LETTER SHORT I
+0xaa    U+043a  #CYRILLIC SMALL LETTER KA
+0xab    U+043b  #CYRILLIC SMALL LETTER EL
+0xac    U+043c  #CYRILLIC SMALL LETTER EM
+0xad    U+043d  #CYRILLIC SMALL LETTER EN
+0xae    U+043e  #CYRILLIC SMALL LETTER O
+0xaf    U+043f  #CYRILLIC SMALL LETTER PE
+0xb0    U+2591  #LIGHT SHADE
+0xb1    U+2592  #MEDIUM SHADE
+0xb2    U+2593  #DARK SHADE
+0xb3    U+2502  #BOX DRAWINGS LIGHT VERTICAL
+0xb4    U+2524  #BOX DRAWINGS LIGHT VERTICAL AND LEFT
+0xb5    U+2561  #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+0xb6    U+2562  #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+0xb7    U+2556  #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+0xb8    U+2555  #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+0xb9    U+2563  #BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+0xba    U+2551  #BOX DRAWINGS DOUBLE VERTICAL
+0xbb    U+2557  #BOX DRAWINGS DOUBLE DOWN AND LEFT
+0xbc    U+255d  #BOX DRAWINGS DOUBLE UP AND LEFT
+0xbd    U+255c  #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+0xbe    U+255b  #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+0xbf    U+2510  #BOX DRAWINGS LIGHT DOWN AND LEFT
+0xc0    U+2514  #BOX DRAWINGS LIGHT UP AND RIGHT
+0xc1    U+2534  #BOX DRAWINGS LIGHT UP AND HORIZONTAL
+0xc2    U+252c  #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+0xc3    U+251c  #BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+0xc4    U+2500  #BOX DRAWINGS LIGHT HORIZONTAL
+0xc5    U+253c  #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+0xc6    U+255e  #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+0xc7    U+255f  #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+0xc8    U+255a  #BOX DRAWINGS DOUBLE UP AND RIGHT
+0xc9    U+2554  #BOX DRAWINGS DOUBLE DOWN AND RIGHT
+0xca    U+2569  #BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+0xcb    U+2566  #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+0xcc    U+2560  #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+0xcd    U+2550  #BOX DRAWINGS DOUBLE HORIZONTAL
+0xce    U+256c  #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+0xcf    U+2567  #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+0xd0    U+2568  #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+0xd1    U+2564  #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+0xd2    U+2565  #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+0xd3    U+2559  #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+0xd4    U+2558  #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+0xd5    U+2552  #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+0xd6    U+2553  #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+0xd7    U+256b  #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+0xd8    U+256a  #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+0xd9    U+2518  #BOX DRAWINGS LIGHT UP AND LEFT
+0xda    U+250c  #BOX DRAWINGS LIGHT DOWN AND RIGHT
+0xdb    U+2588  #FULL BLOCK
+0xdc    U+2584  #LOWER HALF BLOCK
+0xdd    U+258c  #LEFT HALF BLOCK
+0xde    U+2590  #RIGHT HALF BLOCK
+0xdf    U+2580  #UPPER HALF BLOCK
+0xe0    U+0440  #CYRILLIC SMALL LETTER ER
+0xe1    U+0441  #CYRILLIC SMALL LETTER ES
+0xe2    U+0442  #CYRILLIC SMALL LETTER TE
+0xe3    U+0443  #CYRILLIC SMALL LETTER U
+0xe4    U+0444  #CYRILLIC SMALL LETTER EF
+0xe5    U+0445  #CYRILLIC SMALL LETTER HA
+0xe6    U+0446  #CYRILLIC SMALL LETTER TSE
+0xe7    U+0447  #CYRILLIC SMALL LETTER CHE
+0xe8    U+0448  #CYRILLIC SMALL LETTER SHA
+0xe9    U+0449  #CYRILLIC SMALL LETTER SHCHA
+0xea    U+044a  #CYRILLIC SMALL LETTER HARD SIGN
+0xeb    U+044b  #CYRILLIC SMALL LETTER YERU
+0xec    U+044c  #CYRILLIC SMALL LETTER SOFT SIGN
+0xed    U+044d  #CYRILLIC SMALL LETTER E
+0xee    U+044e  #CYRILLIC SMALL LETTER YU
+0xef    U+044f  #CYRILLIC SMALL LETTER YA
+0xf0    U+0401  #CYRILLIC CAPITAL LETTER IO
+0xf1    U+0451  #CYRILLIC SMALL LETTER IO
+0xf2    U+0404  #CYRILLIC CAPITAL LETTER UKRAINIAN IE
+0xf3    U+0454  #CYRILLIC SMALL LETTER UKRAINIAN IE
+0xf4    U+0407  #CYRILLIC CAPITAL LETTER YI
+0xf5    U+0457  #CYRILLIC SMALL LETTER YI
+0xf6    U+040e  #CYRILLIC CAPITAL LETTER SHORT U
+0xf7    U+045e  #CYRILLIC SMALL LETTER SHORT U
+0xf8    U+00b0  #DEGREE SIGN
+0xf9    U+2219  #BULLET OPERATOR
+0xfa    U+00b7  #MIDDLE DOT
+0xfb    U+221a  #SQUARE ROOT
+0xfc    U+2116  #NUMERO SIGN
+0xfd    U+00a4  #CURRENCY SIGN
+0xfe    U+25a0  #BLACK SQUARE
+0xff    U+00a0  #NO-BREAK SPACE
+
+# TRADE MARK SIGN:
+U+2122:(TM)
+
+0x60    U+2018          # left single quotation mark <`>
+0x27    U+2019-U+201b   # various single quotation marks <'>
+0x22    U+201c-U+201f   # various double quotation marks <">
diff --git a/src/chrtrans/koi8r_uni.tbl b/src/chrtrans/koi8r_uni.tbl
index 99b5e28d..c4946a50 100644
--- a/src/chrtrans/koi8r_uni.tbl
+++ b/src/chrtrans/koi8r_uni.tbl
@@ -1,11 +1,10 @@
-
-
 # Options screen name for this character set
-O KOI8-R character set
+OKOI8-R character set
 
 # MIME name for this charset
-M koi8-r
+Mkoi8-r
 
+0x20-0x7f       idem
 # Based on a table received from "Glenn E. Thobe" <thobe@lafn.org>
 #hex unicode # description     
 #--- U+---- # ---------------     
@@ -137,3 +136,10 @@ M koi8-r
 0xFD U+0429 # CAP SHCHA    
 0xFE U+0427 # CAP CHE    
 0xFF U+042A # CAP HARD SIGN   
+
+# TRADE MARK SIGN:
+U+2122:(TM)
+
+0x60    U+2018          # left single quotation mark <`>
+0x27    U+2019-U+201b   # various single quotation marks <'>
+0x22    U+201c-U+201f   # various double quotation marks <">
diff --git a/src/chrtrans/makefile.in b/src/chrtrans/makefile.in
index e293d1ad..b1e00c7d 100644
--- a/src/chrtrans/makefile.in
+++ b/src/chrtrans/makefile.in
@@ -47,6 +47,7 @@ TABLES= $(CHRTR)iso02_uni.h \
  $(CHRTR)cp437_uni.h \
  $(CHRTR)cp850_uni.h \
  $(CHRTR)cp852_uni.h \
+ $(CHRTR)cp866_uni.h \
  $(CHRTR)cp1250_uni.h \
  $(CHRTR)cp1251_uni.h \
  $(CHRTR)cp1252_uni.h \
diff --git a/src/makefile.in b/src/makefile.in
index 773fb6bf..e024ff12 100644
--- a/src/makefile.in
+++ b/src/makefile.in
@@ -101,6 +101,7 @@ TABLES= $(CHRTR)iso02_uni.h \
  $(CHRTR)cp437_uni.h \
  $(CHRTR)cp850_uni.h \
  $(CHRTR)cp852_uni.h \
+ $(CHRTR)cp866_uni.h \
  $(CHRTR)cp1250_uni.h \
  $(CHRTR)cp1251_uni.h \
  $(CHRTR)cp1252_uni.h \