about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/GridText.c611
-rw-r--r--src/GridText.h10
-rw-r--r--src/HTAlert.c7
-rw-r--r--src/HTInit.c2
-rw-r--r--src/LYCgi.c12
-rw-r--r--src/LYCharUtils.c127
-rw-r--r--src/LYCookie.c97
-rw-r--r--src/LYCookie.h25
-rw-r--r--src/LYForms.c4
-rw-r--r--src/LYGetFile.c20
-rw-r--r--src/LYGlobalDefs.h3
-rw-r--r--src/LYKeymap.c4
-rw-r--r--src/LYMail.c44
-rw-r--r--src/LYMail.h3
-rw-r--r--src/LYMain.c4
-rw-r--r--src/LYMainLoop.c78
-rw-r--r--src/LYNews.c155
-rw-r--r--src/LYPrint.c2
-rw-r--r--src/LYReadCFG.c24
-rw-r--r--src/LYStrings.c15
-rw-r--r--src/LYStrings.h7
-rw-r--r--src/LYUtils.c78
-rw-r--r--src/LYUtils.h1
-rw-r--r--src/LYrcFile.c297
-rw-r--r--src/UCdomap.c6
-rw-r--r--src/chrtrans/MAKEW32.BAT5
-rw-r--r--src/chrtrans/build-chrtrans.com6
-rw-r--r--src/chrtrans/cp866u_uni.tbl158
-rw-r--r--src/chrtrans/iso9945_uni.tbl178
-rw-r--r--src/chrtrans/koi8u_uni.tbl144
-rw-r--r--src/chrtrans/makefile.dos10
-rw-r--r--src/chrtrans/makefile.in10
-rw-r--r--src/structdump.h154
33 files changed, 1814 insertions, 487 deletions
diff --git a/src/GridText.c b/src/GridText.c
index 50a41e3b..b30102c5 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -5782,6 +5782,16 @@ PUBLIC CONST char * HText_getContentLocation NOARGS
 	   HTAnchor_content_location(HTMainText->node_anchor) : 0);
 }
 
+/*
+ *  HText_getMessageID returns the Message-ID of the
+ *  current document.
+ */
+PUBLIC CONST char * HText_getMessageID NOARGS
+{
+    return(HTMainText ?
+	   HTAnchor_messageID(HTMainText->node_anchor) : NULL);
+}
+
 PUBLIC void HTuncache_current_document NOARGS
 {
     /*
@@ -8688,14 +8698,267 @@ PUBLIC BOOL HText_AreDifferent ARGS2(
     return(FALSE);
 }
 
+
+/*
+ *  Re-render the text of a tagged ("[123]") HTLine (arg1), with the tag
+ *  number incremented by some value (arg5).  The re-rendered string may
+ *  be allowed to expand in the event of a tag width change (eg, 99 -> 100)
+ *  as controlled by arg6 (CHOP or NOCHOP).  Arg4 is either (the address
+ *  of) a value which must match, in order for the tag to be incremented,
+ *  or (the address of) a 0-value, which matches any value, and will cause
+ *  any valid tag to be incremented.  Arg2 is a pointer to the first/only
+ *  Anchor that exists on the line (if any); we may need to adjust their
+ *  position(s) on the line.  Arg3 when non-0 indicates the number of new
+ *  digits that were added to the 2nd line in a line crossing pair.
+ *
+ *  All tags fields in a line which individually match an expected new value,
+ *  are incremented.  Line crossing [tags] are handled (PITA).
+ *
+ *  Untagged or improperly tagged lines are not altered.
+ *
+ *  Returns the number of chars added to the original string's length, if
+ *  any.   KED  02/03/99
+ */
+PRIVATE int increment_tagged_htline ARGS6(
+	HTLine *,	ht,
+	TextAnchor *,   a,
+	int *,		lx_val,
+	int *,		old_val,
+	int,		incr,
+	int,		mode)
+{
+    char    buf[MAX_LINE];
+    char  lxbuf[MAX_LINE * 2];
+
+    TextAnchor *st_anchor  = a;
+    TextAnchor *nxt_anchor;
+
+    char *p   = ht->data;
+    char *s   = buf;
+    char *lx  = lxbuf;
+    char *t;
+
+    BOOLEAN   plx    = FALSE;
+    BOOLEAN   valid;
+
+    int   val;
+    int   n;
+    int   new_n;
+    int   pre_n;
+    int   fixup = 0;
+
+    /*
+     *  Cleanup for the 2nd half of a line crosser, whose number of tag
+     *  digits grew by some number of places (usually 1, when it does
+     *  happen, though it *could* be more).  The tag chars were already
+     *  rendered into the 2nd line of the pair, but the positioning and
+     *  other effects haven't been rippled through any other anchors on
+     *  the (2nd) line.  So we do that here, as a special case, since
+     *  the part of the tag that's in the 2nd line of the pair, will not
+     *  be found by the tag string parsing code.  Double PITA.
+     *
+     *  [see comments below on line crosser caused problems]
+     */
+    if (*lx_val != 0) {
+	nxt_anchor = st_anchor;
+	while ((nxt_anchor) && (nxt_anchor->line_num == a->line_num)) {
+	    nxt_anchor->line_pos += *lx_val;
+	    nxt_anchor = nxt_anchor->next;
+	}
+	fixup  = *lx_val;
+	*lx_val = 0;
+	st_anchor = st_anchor->next;
+    }
+
+    /*
+     *  Walk thru the line looking for tags (ie, "[nnn]" strings).
+     */
+    while (*p != '\0') {
+	if (*p != '[') {
+	    *s++ = *p++;
+	    continue;
+
+	} else {
+	    *s++ = *p++;
+	    t = p;
+	    n = 0;
+	    valid = TRUE;   /* p = t = byte after ']' */
+
+	    /*
+	     *  Make sure there are only digits between "[" and "]".
+	     */
+	    while  (*t != ']')  {
+		if (*t == '\0') {  /* uhoh - we have a potential line crosser */
+		    valid = FALSE;
+		    plx   = TRUE;
+		    break;
+		}
+		if (isdigit (*t++) != 0) {
+		    n++;
+		    continue;
+		} else {
+		    valid = FALSE;
+		    break;
+		}
+	    }
+
+	    /*
+	     *  If the format is OK, we check to see if the value is what
+	     *  we expect.  If not, we have a random [nn] string in the text,
+	     *  and leave it alone.
+	     *
+	     *  [It is *possible* to have a false match here, *if* there are
+	     *   two identical [nn] strings (including the numeric value of
+	     *   nn), one of which is the [tag], and the other being part of
+	     *   a document.  In such a case, the 1st [nn] string will get
+	     *   incremented; the 2nd one won't, which makes it a 50-50 chance
+	     *   of being correct, if and when such an unlikely juxitposition
+	     *   of text ever occurs.  Further validation tests of the [nnn]
+	     *   string are probably not possible, since little of the actual
+	     *   anchor-associated-text is retained in the TextAnchor or the
+	     *   FormInfo structs.  Fortunately, I think the current method is
+	     *   more than adequate to weed out 99.99% of any possible false
+	     *   matches, just as it stands.  Caveat emptor.]
+	     */
+	    if ((valid) && (n > 0)) {
+		val = atoi (p);
+		if ((val == *old_val) || (*old_val == 0)) {
+		    if (*old_val != 0)
+			(*old_val)++;
+		    val += incr;
+		    sprintf (s, "%d", val);
+		    new_n = strlen (s);
+		    s += new_n;
+		    p += n;
+
+		    /*
+		     *  If the number of digits in an existing [tag] increased
+		     *  (eg, [99] --> [100], etc), we need to "adjust" its
+		     *  horizontal position, and that of all subsequant tags
+		     *  that may be on the same line.  PITA.
+		     *
+		     *  [This seems to work as long as a tag isn't a line
+		     *   crosser; when it is, the position of anchors on either
+		     *   side of the split tag, seem to "float" and try to be
+		     *   as "centered" as possible.  Which means that simply
+		     *   incrementing the line_pos by the fixed value of the
+		     *   number of digits that got added to some tag in either
+		     *   line doesn't work quite right, and the text for (say)
+		     *   a button may get stomped on by another copy of itself,
+		     *   but offset by a few chars, when it is selected (eg,
+		     *   "Box Office" may end up looking like "BoBox Office" or
+		     *   "Box Officece", etc.
+		     *
+		     *   Dunno how to fix that behavior ATT, but at least the
+		     *   tag numbers themselves are correct.  -KED  /\oo/\ ]
+		     */
+		    if (new_n -= n) {
+			nxt_anchor = st_anchor;
+			while ((nxt_anchor) 			  &&
+			    (nxt_anchor->line_num == a->line_num)) {
+			    nxt_anchor->line_pos += new_n;
+			    nxt_anchor = nxt_anchor->next;
+			}
+			st_anchor = st_anchor->next;
+		    }
+		}
+	    }
+
+	    /*
+	     *  Unfortunately, valid [tag] strings *can* be split across two
+	     *  lines.  Perhaps it would be best to just prevent that from
+	     *  happening, but a look into that code, makes me wonder.  Anyway,
+	     *  we can handle such tags without *too* much trouble in here [I
+	     *  think], though since such animals are rather rare, it makes it
+	     *  a bit difficult to test thoroughly (ie, Beyond here, there be
+	     *  Dragons).
+	     *
+	     *  We use lxbuf[] to deal with the two lines involved.
+	     */
+	    if (plx) {
+		strcpy (lx, p);      /* <- 1st part of a possible lx'ing tag  */
+		pre_n = strlen (p);  /* count of 1st part chars in this line  */
+		strcat (lx, ht->next->data);  /* tack on NEXT line	    */
+
+		t = lx;
+		n = 0;
+		valid = TRUE;
+
+		/*
+		 *  Go hunting again for just digits, followed by a tag end ']'.
+		 */
+		while (*t != ']') {
+		    if (isdigit (*t++) != 0) {
+			n++;
+			continue;
+		    } else {
+			valid = FALSE;
+			break;
+		    }
+		}
+
+		/*
+		 *  It *looks* like a line crosser; now we value test it to
+		 *  find out for sure [but see the "false match" warning,
+		 *  above], and if it matches, increment it into the buffer,
+		 *  along with the 2nd line's text.
+		 */
+		if ((valid) && (n > 0)) {
+		    val = atoi (lx);
+		    if ((val == *old_val) || (*old_val == 0)) {
+			if (*old_val != 0)
+			    (*old_val)++;
+			val += incr;
+			sprintf (lx, "%d", val);
+			new_n = strlen (lx);
+			strcat (lx, strchr (ht->next->data, ']'));
+
+			/*
+			 *  We keep the the same number of chars from the
+			 *  adjusted tag number in the current line; any
+			 *  extra chars due to a digits increase, will be
+			 *  stuffed into the next line.
+			 *
+			 *  Keep track of any digits added, for the next
+			 *  pass through.
+			 */
+			s   = strncpy (s, lx, pre_n) + pre_n;
+			lx += pre_n;
+			strcpy (ht->next->data, lx);
+
+			*lx_val = new_n - n;
+		    }
+		}
+		break;	/* had an lx'er, so we're done with this line */
+	    }
+	}
+    }
+
+    *s = '\0';
+
+    n = strlen (ht->data);
+    if (mode == CHOP)
+	*(buf + n) = '\0';
+    strcpy (ht->data, buf);
+
+    return (strlen (buf) - n + fixup);
+}
+
+
 /*
  *  Transfer the initial contents of a TEXTAREA to a temp file, invoke the
  *  user's editor on that file, then transfer the contents of the resultant
  *  edited file back into the TEXTAREA (expanding the size of the area, if
- *  required).   KED  01/26/99
+ *  required).
+ *
+ *  Returns the number of lines that the cursor should be moved so that it
+ *  will end up on the 1st blank line of whatever number of trailing blank
+ *  lines there are in the TEXTAREA (there will *always* be at least one).
+ *
+ *  --KED  02/01/99
  */
-PUBLIC void HText_ExtEditForm ARGS1(
-            struct link *, form_link)
+PUBLIC int HText_ExtEditForm ARGS1(
+	   struct link *,  form_link)
 {
     struct stat stat_info;
 
@@ -8704,16 +8967,18 @@ PUBLIC void HText_ExtEditForm ARGS1(
 
     TextAnchor *anchor_ptr;
     TextAnchor *start_anchor = NULL;
-    TextAnchor *end_anchor  = NULL;
-    BOOLEAN	firstanchor = TRUE;
-    int 	orig_cnt    = 0;
-    int 	line_cnt    = 1;
+    TextAnchor *end_anchor   = NULL;
+    BOOLEAN	firstanchor  = TRUE;
+    int 	entry_line   = form_link->anchor_line_num;
+    int 	exit_line    = 0;
+    int 	orig_cnt     = 0;
+    int 	line_cnt     = 1;
 
     FormInfo   *form	 = form_link->form;
     char       *areaname = form->name;
     int 	form_num = form->number;
 
-    HTLine     *htline;
+    HTLine     *htline	 = NULL;
 
     TextAnchor *a = 0;
     FormInfo   *f = 0;
@@ -8722,17 +8987,26 @@ PUBLIC void HText_ExtEditForm ARGS1(
     char       *ebuf;
     char       *tbuf = NULL;
     char       *line;
+    char       *lp;
     char       *cp;
     char       *p;
+    char       *s;
+    int 	curr_tag;
+    int 	line_adj = 0;
+    int 	tag_adj  = 0;
     int 	len;
     int 	i;
     int 	n;
+    int 	lx;
     size_t	size;
 
-    ed_temp = (char *)malloc(LY_MAXPATH);
+
+    CTRACE(tfp, "GridText: entered HText_ExtEditForm()\n");
+
+    ed_temp = (char *) malloc (LY_MAXPATH);
     if ((fp = LYOpenTemp (ed_temp, "", "w")) == 0) {
 	FREE(ed_temp);
-	return;
+	return (0);
     }
 
     /*
@@ -8767,7 +9041,7 @@ PUBLIC void HText_ExtEditForm ARGS1(
 	    orig_cnt++;
 
 	    /*
-	     * Write the anchor's text to the temp edit file.
+	     *  Write the anchors' text to the temp edit file.
 	     */
 	    fputs (anchor_ptr->input_field->value, fp);
 	    fputc ('\n', fp);
@@ -8781,6 +9055,8 @@ PUBLIC void HText_ExtEditForm ARGS1(
     }
     fclose (fp);
 
+    CTRACE(tfp, "GridText: TEXTAREA name=|%s| dumped to tempfile\n", areaname);
+
     /*
      *	Go edit the TEXTAREA temp file.
      */
@@ -8798,14 +9074,16 @@ PUBLIC void HText_ExtEditForm ARGS1(
 #endif
     free (tbuf);
 
+    CTRACE(tfp, "GridText: returned from editor (%s)\n", editor);
+
     /*
-     *	Read back the edited temp file, whacking off any trailing whitespace.
+     *	Read back the edited temp file.
      */
-    if (stat (ed_temp, &stat_info) < 0
-     || !S_ISREG(stat_info.st_mode)
-     || (size = stat_info.st_size) == 0) {
+    if ((stat (ed_temp, &stat_info) < 0)   ||
+	!S_ISREG(stat_info.st_mode)	   ||
+	((size = stat_info.st_size) == 0)) {
 	size = 0;
-	ebuf = malloc(1);
+	ebuf = (char *) calloc (1, 1);
     } else {
 	ebuf = (char *) calloc (size + 1, (sizeof(char)));
 
@@ -8819,123 +9097,174 @@ PUBLIC void HText_ExtEditForm ARGS1(
     /*
      *	Nuke any blank lines from the end of the edited data.
      */
-    while ((size != 0) && isspace(ebuf[size-1]))
+    while ((size != 0) && (isspace (ebuf[size-1]) || (ebuf[size-1] == '\0')))
 	ebuf[--size] = '\0';
 
+    if (size == 0)
+	ebuf[0] = '\0'; 
+
     /*
      *	Copy each line from the temp file into the corresponding anchor
-     *	struct, removing any trailing whitespace.  Add new lines to the
-     *	TEXTAREA if needed.  (Always leave the user with a blank line at
-     *	the end of the TEXTAREA.)
+     *  struct, removing any trailing whitespace, expanding any embedded
+     *  tab's, and substituting a printable char for any other embedded
+     *  control chars.  Add new lines to the TEXTAREA if needed.  (Always
+     *  leave the user with a blank line at the end of the TEXTAREA.)
      */
-    if ((line = (char *) malloc (MAX_LINE)) == 0)
+    if (((line = (char *) malloc (MAX_LINE)) == 0) ||
+	((tbuf = (char *) malloc (MAX_LINE)) == 0))
 	outofmem(__FILE__, "HText_ExtEditForm");
 
     anchor_ptr = start_anchor;
+
     len = 0;
-    p = ebuf;
+    lp  = ebuf;
 
-    while ((line_cnt <= orig_cnt) || (*p) || ((len != 0) && (*p == '\0'))) {
+    while ((line_cnt <= orig_cnt) || (*lp) || ((len != 0) && (*lp == '\0'))) {
 
-	if ((cp = strchr (p, '\n')) != 0)
-	   len = cp - p;
+	if ((cp = strchr (lp, '\n')) != 0)
+	   len = cp - lp;
 	else
-	   len = strlen (p);
-
-	strncpy(line, "\0", MAX_LINE);
-	strncpy(line, p, len);
+	   len = strlen (lp);
 
-	cp = p;
+	strncpy (line, lp, len);
+	*(line + len) = '\0';
 
 	/*
 	 *  Whack off trailing whitespace from the line.
-	 *
-	 *  [maybe use isspace() here instead, too (portable ?)]
 	 */
-	for (size = MAX_LINE, p = line + size - 1; size != 0; p--, size--) {
+	for (i = len, p = line + (len - 1); i != 0; p--, i--) {
 	    if (isspace(*p))
 		*p = '\0';
 	    else
 		break;
 	}
 
+	if (strlen (line) != 0) {
+	    /*
+	     *  Expand any tab's, since they won't render properly in a
+	     *  TEXTAREA.
+	     *
+	     *  [is that "by spec", or just a "lynxism" ? ... as may be, it
+	     *   seems they may cause other problems, too ... haven't really
+	     *   looked into that very deeply though]
+	     */
+	    p = line;
+	    s = tbuf;
+
+	    while (*p) {
+		if ((cp = strchr (p, '\t')) != 0) {
+		    i  = cp - p;
+		    s  = (strncpy (s, p, i))      + i;
+		    n  = TABSTOP - (i % TABSTOP);
+		    s  = (strncpy (s, SPACES, n)) + n;
+		    p += (i + 1);
+
+		} else {
+
+		    strcpy (s, p);
+		    break;
+		}
+	    }
+
+	    /*
+	     *  Replace control chars with something printable.  Note that
+	     *  we leave any chars above 0x7f alone (ie, no translation is
+	     *  performed ... the assumption being that the charset used in
+	     *  the editor is compatible with the charset rendered by lynx).
+	     */
+	    for (p = line, s = tbuf; *s != '\0'; p++, s++)
+		*p = (*s < ' ') ? SPLAT : *s;
+	    *p = '\0';
+	}
+
+
 	/*
 	 *  If there are more lines in the edit buffer than were in the
 	 *  original TEXTAREA, we need to add some new lines, continuing
 	 *  until the edit buffer is empty.
 	 *
-	 *  [cloning structs should me moved to a seperate fn(), or three]
+	 *  [cloning structs could be moved to a seperate fn(), or three]
 	 */
 	if (line_cnt > orig_cnt) {
 
-	   /*
-	    *  Find line in the text that matches ending anchorline of
-	    *  the TEXTAREA.
-	    */
-	   for (htline = HTMainText->last_line->next, i = 0;
+	    /*
+	     *  Find line in the text that matches ending anchorline of
+	     *  the TEXTAREA.
+	     *
+	     *  [Yes, Virginia ... we *do* have to go thru this for each
+	     *   anchor being added, since there is NOT a 1-to-1 mapping
+	     *   between anchors and htlines.  I suppose we could create
+	     *   YAS (Yet Another Struct), but there are too many structs{}
+	     *   floating around in here, as it is.  IMNSHO.]
+	     */
+	    for (htline = HTMainText->last_line->next, i = 0;
 		i != end_anchor->line_num;
 		htline = htline->next, i++);
 
-	   /*
-	    *  Clone and initialize the structs needed to add a new
-	    *  TEXTAREA anchor.
-	    */
-	   if ((a = (TextAnchor *) calloc (1, sizeof(*a))) == 0
-	    || (f = (FormInfo   *) calloc (1, sizeof(*f))) == 0
-	    || (l = (HTLine     *) calloc (1, LINE_SIZE(MAX_LINE))) == 0)
+	    /*
+	     *  Clone and initialize the structs needed to add a new
+	     *  TEXTAREA anchor.
+	     */
+	    if (((a = (TextAnchor *) calloc (1, sizeof(*a)))	      == 0)  ||
+		((f = (FormInfo   *) calloc (1, sizeof(*f)))	      == 0)  ||
+		((l = (HTLine	  *) calloc (1, LINE_SIZE(MAX_LINE))) == 0))
 		outofmem(__FILE__, "HText_ExtEditForm");
 
-	   /*  Init all the fields in the new anchor.  */
-	   a->next	       = end_anchor->next;
-	   a->number	       = end_anchor->number;
-	   a->start	       = end_anchor->start +
+	    /*  Init all the fields in the new TextAnchor.  */
+	    a->next	       = end_anchor->next;
+	    a->number	       = end_anchor->number;
+	    a->start	       = end_anchor->start +
 				 end_anchor->input_field->size + 1;
-	   a->line_pos	       = end_anchor->line_pos;
-	   a->extent	       = end_anchor->extent;
-	   a->line_num	       = end_anchor->line_num + 1;
-	   StrAllocCopy (a->hightext, end_anchor->hightext);
-	   StrAllocCopy (a->hightext2, end_anchor->hightext2);
-	   a->hightext2offset  = end_anchor->hightext2offset;
-	   a->link_type	       = end_anchor->link_type;
-	   a->input_field      = f;
-	   a->show_anchor      = end_anchor->show_anchor;
-	   a->inUnderline      = end_anchor->inUnderline;
-	   a->anchor	       = end_anchor->anchor;
-
-	   /*  Just the (seemingly) relevant fields in the FormInfo.	*/
-	   StrAllocCopy (f->name, end_anchor->input_field->name);
-	   f->number	       = end_anchor->input_field->number;
-	   f->type	       = end_anchor->input_field->type;
-	   StrAllocCopy (f->orig_value, end_anchor->input_field->orig_value);
-	   f->size	       = end_anchor->input_field->size;
-	   f->maxlength        = end_anchor->input_field->maxlength;
-	   f->no_cache         = end_anchor->input_field->no_cache;
-
-	   /*  Init all the fields in the new HTLine (but see the #if).  */
-	   l->next	       = htline->next;
-	   l->prev	       = htline;
-	   l->offset	       = htline->offset;
-	   l->size	       = htline->size;
-	   l->split_after      = htline->split_after;
-	   l->bullet	       = htline->bullet;
+	    a->line_pos	       = end_anchor->line_pos;
+	    a->extent	       = end_anchor->extent;
+	    a->line_num	       = end_anchor->line_num + 1;
+	    StrAllocCopy (a->hightext,  end_anchor->hightext);
+	    StrAllocCopy (a->hightext2, end_anchor->hightext2);
+	    a->hightext2offset  = end_anchor->hightext2offset;
+	    a->link_type	= end_anchor->link_type;
+	    a->input_field      = f;
+	    a->show_anchor      = end_anchor->show_anchor;
+	    a->inUnderline      = end_anchor->inUnderline;
+	    a->anchor		= end_anchor->anchor;
+
+	    /*  Just the (seemingly) relevant fields in the new FormInfo.  */
+	    StrAllocCopy (f->name, end_anchor->input_field->name);
+	    f->number	       = end_anchor->input_field->number;
+	    f->type	       = end_anchor->input_field->type;
+	    StrAllocCopy (f->orig_value, "");
+	    f->size	       = end_anchor->input_field->size;
+	    f->maxlength       = end_anchor->input_field->maxlength;
+	    f->no_cache        = end_anchor->input_field->no_cache;
+
+	    /*  Init all the fields in the new HTLine (but see the #if).   */
+	    l->next	       = htline->next;
+	    l->prev	       = htline;
+	    l->offset	       = htline->offset;
+	    l->size	       = htline->size;
+	    l->split_after      = htline->split_after;
+	    l->bullet	       = htline->bullet;
 #if defined(USE_COLOR_STYLE)
-	   /* dup styles[] if needed [no need in TEXTAREA (?); leave 0's] */
-	   l->numstyles        = htline->numstyles;
+	    /* dup styles[] if needed [no need in TEXTAREA (?); leave 0's] */
+	    l->numstyles        = htline->numstyles;
 #endif
-	   for (i = 0; htline->data[i] != '\0'; i++)
-	       l->data[i] = htline->data[i];
-	   l->data[i] = '\0';
+	    strcpy (l->data,      htline->data);
+	    if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) {
+		a->number++;
+		curr_tag = 0;  /* 0 matches any [tag] number */
+		lx	 = 0;
+		increment_tagged_htline (l, a, &lx, &curr_tag, 1, CHOP);
+	    }
 
-	   /*
-	    *  Link in the new TextAnchor and make it current; link in
-	    *  the new HTLine.
-	    */
-	   end_anchor->next = a;
-	   anchor_ptr = a;
+	    /*
+	     *  Link in the new TextAnchor and make it current; link in
+	     *  the new HTLine.
+	     */
+	    end_anchor->next = a;
+	    anchor_ptr = a;
 
-	   htline->next->prev = l;
-	   htline->next = l;
-	   htline = l;
+	    htline->next->prev = l;
+	    htline->next = l;
+	    htline = l;
 	}
 
 	/*
@@ -8943,49 +9272,113 @@ PUBLIC void HText_ExtEditForm ARGS1(
 	 */
 	StrAllocCopy(anchor_ptr->input_field->value, line);
 
+
 	/*
 	 *  And do the next line, for the next anchor ...
 	 */
-	p = cp + len;
-	if (*p) p++;
+	lp += len;
+	if (*lp) lp++;
+
+	if (len > 0)
+	    exit_line = 0;
+	else if (exit_line == 0)
+	    exit_line = anchor_ptr->line_num;
 
 	end_anchor = anchor_ptr;
 	anchor_ptr = anchor_ptr->next;
+	curr_tag   = anchor_ptr->number;
+
+	if (htline != NULL)
+	    htline   = htline->next;
 
 	line_cnt++;
     }
 
+    CTRACE(tfp, "GridText: edited text inserted into lynx struct's\n");
 
     /*
      *	If new anchors were added, we need to ripple the new line numbers
-     *	(and char counts ?) thru the subsequent anchors.  Also update the
-     *	HText counts.
+     *	(and char counts ?) thru the subsequent anchors.  If form lines
+     *  are getting tagged, we need to update the displayed tag values
+     *  to match (which means re-rendering them ...sigh).  Finally update
+     *  the HText counts.
      *
      *	[dunno if the char counts really need to be done, or if we're using
-     *	 the proper values ... seems OK though ...]
+     *	 the exactly proper values ... seems to be OK though ...]
      */
     if ((n = (line_cnt - 1) - orig_cnt) > 0) {
-        i = (end_anchor->input_field->size + 1) * n;
+	i = (end_anchor->input_field->size + 1) * n;
 
-        while (anchor_ptr) {
+	while (anchor_ptr) {
+	    if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED)
+	       anchor_ptr->number += n;
 	    anchor_ptr->line_num  += n;
 	    anchor_ptr->start	  += i;
-	    anchor_ptr 	           = anchor_ptr->next;
-        }
-        HTMainText->Lines += n;
-        HTMainText->chars += i;
+	    anchor_ptr		   = anchor_ptr->next;
+	}
+	anchor_ptr = end_anchor;
+
+	/*
+	 *  If a number tag (eg, "[177]") is itself broken across a line
+	 *  boundary, this fixup only partially works.  While the tag
+	 *  numbering is done properly across the pair of lines, the
+	 *  horizontal positioning on *either* side of the split, can get
+	 *  out of sync by a char or two when it gets selected.  See [com
+	 *  ments] in  increment_tagged_htline()  for some more detail.
+	 *
+	 *  I suppose THE fix is to prevent such tag-breaking in the first
+	 *  place (dunno where yet, though).  Ah well ... at least the tag
+	 *  numbers are correct from top to bottom now.
+	 *
+	 *  All that said, about the only time this will be a problem in
+	 *  *practice*, is when a page has near 1000 links or more (possibly
+	 *  after a TEXTAREA expansion), and has line crossing tag(s), and
+	 *  the tag numbers in a line crosser go from initially all 3 digit
+	 *  numbers, to some mix of 3 and 4 digits (or all 4 digits) as a
+	 *  result of the expansion process.  Oh, and you need a "clump" of
+	 *  anchors all on the same lines.
+	 *
+	 *  Yes, it *can* happen, but in real life, it probably won't be
+	 *  seen very much ...
+	 */
+	if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) {
+	    lx = 0;
+	    while (htline != HTMainText->last_line->next) {
+		while (anchor_ptr) {
+		    if ((anchor_ptr->number - n) == curr_tag)
+			break;
+		    else
+			anchor_ptr = anchor_ptr->next;
+		}
+		line_adj = increment_tagged_htline (htline, anchor_ptr, &lx,
+						   &curr_tag, n, NOCHOP);
+		htline->size += line_adj;
+		tag_adj      += line_adj;
+		htline = htline->next;
+	   }
+	}
+
+	nlinks			       += n;
+	HTMainText->Lines	       += n;
+	HTMainText->last_anchor_number += n;
+	HTMainText->chars	       += (i + tag_adj);
+
+	if (n) more = TRUE;
     }
 
-    /*** MOVE the cursor to some logical place ... 1st/only blank line in
-     ***	  the textarea seems most reasonable; lacking that, the end
-     ***	  line of the textarea; lacking that ... the 1st line of the
-     ***	  textarea; else leave it where it is (as we now do).
-     ***/
+    CTRACE(tfp, "GridText: struct's adjusted - exiting HText_ExtEditForm()\n");
 
     free (line);
     free (ebuf);
+    free (tbuf);
     LYRemoveTemp (ed_temp);
     free (ed_temp);
 
-    return;
+    /*
+     *  Return the offset needed to move the cursor from its current
+     *  (on entry) line number, to the 1st blank line of the trailing
+     *  (group of) blank line(s), which is where we want to be.  Let
+     *  the caller deal with moving us there, however ... :-) ...
+     */
+    return (exit_line - entry_line);
 }
diff --git a/src/GridText.h b/src/GridText.h
index 30eb4376..006c577c 100644
--- a/src/GridText.h
+++ b/src/GridText.h
@@ -27,6 +27,13 @@
 
 #define IsSpecialAttrChar(a)  ((a > '\002') && (a <= '\010'))
 
+#define TABSTOP 8
+#define SPACES  "        "  /* must be at least TABSTOP spaces long */
+#define SPLAT   '.'
+
+#define NOCHOP 0
+#define CHOP   1
+
 /* just for information:
 US-ASCII control characters <32 which are not defined in Unicode standard
 =00	U+0000	NULL
@@ -125,6 +132,7 @@ extern CONST char * HText_getServer NOPARAMS;
 extern CONST char * HText_getOwner NOPARAMS;
 extern CONST char * HText_getContentBase NOPARAMS;
 extern CONST char * HText_getContentLocation NOPARAMS;
+extern CONST char * HText_getMessageID NOPARAMS;
 extern CONST char * HText_getRevTitle NOPARAMS;
 #ifdef USE_HASH
 extern CONST char * HText_getStyle NOPARAMS;
@@ -248,7 +256,7 @@ extern BOOL HText_AreDifferent PARAMS((
 	HTParentAnchor *	anchor,
 	CONST char *		full_address));
 
-extern void HText_ExtEditForm PARAMS((
+extern int HText_ExtEditForm PARAMS((
 	struct link *	form_link));
 
 #endif /* LYGRIDTEXT_H */
diff --git a/src/HTAlert.c b/src/HTAlert.c
index e36fbf66..dc5626a2 100644
--- a/src/HTAlert.c
+++ b/src/HTAlert.c
@@ -46,13 +46,16 @@ PUBLIC void HTAlwaysAlert ARGS2(
 	    fprintf(((TRACE) ? stdout : stderr),
 		    "%s %s!\n",
 		    extra_prefix, Msg);
+	    fflush(stdout);
+	    sleep(AlertSecs);
 	} else {
 	    fprintf(((TRACE) ? stdout : stderr),
 		    ALERT_FORMAT,
 		    (Msg == 0) ? "" : Msg);
+	    fflush(stdout);
+	    sleep(AlertSecs);
+	    fprintf(((TRACE) ? stdout : stderr), "\n");
 	}
-	fflush(stdout);
-	sleep(AlertSecs);
 	CTRACE(tfp, "\nAlert!: %s\n\n", Msg);
 	CTRACE_FLUSH(tfp);
     }
diff --git a/src/HTInit.c b/src/HTInit.c
index e9a963b0..c4319235 100644
--- a/src/HTInit.c
+++ b/src/HTInit.c
@@ -504,6 +504,8 @@ PRIVATE int RememberTestResult ARGS3(
 	    return -1;
 	case RTR_add:
 	    cur = calloc(1, sizeof(struct cmdlist_s));
+	    if (cur == NULL)
+		outofmem(__FILE__, "RememberTestResult");
 	    cur->next = cmdlist;
 	    cur->cmd = (char *)malloc(strlen(cmd) + 1);
 	    if(cur->cmd)
diff --git a/src/LYCgi.c b/src/LYCgi.c
index b2864c68..aaf69043 100644
--- a/src/LYCgi.c
+++ b/src/LYCgi.c
@@ -42,6 +42,7 @@
 #include <GridText.h>
 #include <LYCgi.h>
 #include <LYSignal.h>
+#include <LYStrings.h>
 #include <LYLocal.h>
 
 #include <LYLeaks.h>
@@ -70,17 +71,6 @@ PRIVATE void add_environment_value PARAMS((char *env_value));
 
 #define PERROR(msg) CTRACE(tfp, "LYNXCGI: %s: %s\n", msg, LYStrerror(errno))
 
-#ifdef HAVE_STRERROR
-#define LYStrerror(n) strerror(n)
-#else
-PRIVATE char *LYStrerror ARGS1(int, code)
-{
-    static char temp[80];
-    sprintf(temp, "System errno is %d.\r\n", code);
-    return temp;
-}
-#endif /* HAVE_STRERROR */
-
 PRIVATE void free_alloced_lynxcgi NOARGS
 {
     void *ptr;
diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c
index bb5e8224..d4df1e23 100644
--- a/src/LYCharUtils.c
+++ b/src/LYCharUtils.c
@@ -3827,3 +3827,130 @@ PUBLIC BOOLEAN LYCheckForCSI ARGS2(
     StrAllocCopy(*url, anchor->address);
     return TRUE;
 }
+
+/*
+**  This function is called from the SGML parser to look at comments
+**  and see whether we should collect some info from them.  Currently
+**  it only looks for comments with Message-Id and Subject info, in the
+**  exact form generated by MHonArc for archived mailing list.  If found,
+**  the info is stored in the document's HTParentAnchor.  It can later be
+**  used for generating a mail response.
+**
+**  We are extra picky here because there isn't any official definition
+**  for these kinds of comments - we might (and still can) misinterpret
+**  arbitrary comments as something they aren't.
+**
+**  If something doesn't look right, for example invalid characters, the
+**  strings are not stored.  Mail responses will use something else as
+**  the subject, probably the document URL, and will not have an
+**  In-Reply-To header.
+**
+**  All this is a hack - to do this the right way, mailing list archivers
+**  would have to agree on some better mechanism to make this kind of info
+**  from original mail headers available, for example using LINK.  - kw
+*/
+PUBLIC BOOLEAN LYCommentHacks ARGS2(
+	HTParentAnchor *,	anchor,
+	CONST char *,		comment)
+{
+    CONST char *cp = comment;
+    size_t len;
+
+    if (comment == NULL)
+	return FALSE;
+
+    if (!(anchor && anchor->address))
+	return FALSE;
+
+    if (strncmp(comment, "!--X-Message-Id: ", 17) == 0) {
+	char *messageid = NULL;
+	char *p;
+	for (cp = comment+17; *cp; cp++) {
+	    if ((unsigned char)*cp >= 127 || !isgraph((unsigned char)*cp)) {
+		break;
+	    }
+	}
+	if (strcmp(cp, " --")) {
+	    return FALSE;
+	}
+	cp = comment + 17;
+	StrAllocCopy(messageid, cp);
+	/* This should be ok - message-id should only contain 7-bit ASCII */
+	if (!LYUCFullyTranslateString(&messageid, 0, 0, NO, NO, YES, st_URL))
+	    return FALSE;
+	for (p = messageid; *p; p++) {
+	    if ((unsigned char)*p >= 127 || !isgraph((unsigned char)*p)) {
+		break;
+	    }
+	}
+	if (strcmp(p, " --")) {
+	    FREE(messageid);
+	    return FALSE;
+	}
+	if ((p = strchr(messageid, '@')) == NULL || p[1] == '\0') {
+	    FREE(messageid);
+	    return FALSE;
+	}
+	p = messageid;
+	if ((len = strlen(p)) >= 8 && !strcmp(&p[len-3], " --")) {
+	    p[len-3] = '\0';
+	} else {
+	    FREE(messageid);
+	    return FALSE;
+	}
+	if (HTAnchor_setMessageID(anchor, messageid)) {
+	    FREE(messageid);
+	    return TRUE;
+	} else {
+	    FREE(messageid);
+	    return FALSE;
+	}
+    }
+    if (strncmp(comment, "!--X-Subject: ", 14) == 0) {
+	char *subject = NULL;
+	char *p;
+	for (cp = comment+14; *cp; cp++) {
+	    if ((unsigned char)*cp >= 127 || !isprint((unsigned char)*cp)) {
+		return FALSE;
+	    }
+	}
+	cp = comment + 14;
+	StrAllocCopy(subject, cp);
+	/* @@@
+	 * This may not be the right thing for the subject - but mail
+	 * subjects shouldn't contain 8-bit characters in raw form anyway.
+	 * We have to unescape character entities, since that's what MHonArc
+	 * seems to generate.  But if after that there are 8-bit characters
+	 * the string is rejected.  We would probably not know correctly
+	 * what charset to assume anyway - the mail sender's can differ from
+	 * the archive's.  And the code for sending mail cannot deal well
+	 * with 8-bit characters - we should not put them in the Subject
+	 * header in raw form, but don't have MIME encoding implemented.
+	 * Someone may want to do more about this...  - kw
+	 */
+	if (!LYUCFullyTranslateString(&subject, 0, 0, NO, YES, NO, st_HTML))
+	    return FALSE;
+	for (p = subject; *p; p++) {
+	    if ((unsigned char)*p >= 127 || !isprint((unsigned char)*p)) {
+		FREE(subject);
+		return FALSE;
+	    }
+	}
+	p = subject;
+	if ((len = strlen(p)) >= 4 && !strcmp(&p[len-3], " --")) {
+	    p[len-3] = '\0';
+	} else {
+	    FREE(subject);
+	    return FALSE;
+	}
+	if (HTAnchor_setSubject(anchor, subject)) {
+	    FREE(subject);
+	    return TRUE;
+	} else {
+	    FREE(subject);
+	    return FALSE;
+	}
+    }
+
+    return FALSE;
+}
diff --git a/src/LYCookie.c b/src/LYCookie.c
index 04a9a6fc..12c9f260 100644
--- a/src/LYCookie.c
+++ b/src/LYCookie.c
@@ -414,6 +414,7 @@ PRIVATE void store_cookie ARGS3(
 	else
 #endif
 	    de->bv = QUERY_USER;
+	de->invcheck_bv = QUERY_USER; /* should this go here? */
 	cookie_list = de->cookie_list = HTList_new();
 	StrAllocCopy(de->domain, co->domain);
 	HTList_addObject(domain_list, de);
@@ -2004,7 +2005,7 @@ PUBLIC void LYLoadCookies ARGS1 (
 	 *  COOKIE_FLAG_EXPIRES_SET  It must have had an explicit
 	 *			     expiration originally, otherwise
 	 *			     it would not be in the file.
-	 *  COOKIE_FLAG_DOMAN_SET,   We don't know whether these were
+	 *  COOKIE_FLAG_DOMAIN_SET,  We don't know whether these were
 	 *   COOKIE_FLAG_PATH_SET    explicit or implicit, but this
 	 *			     only matters for sending version 1
 	 *			     cookies; the cookies read from the
@@ -2617,8 +2618,11 @@ PUBLIC void cookie_add_acceptlist ARGS1(
     char *strsmall = NULL;
     int isexisting = FALSE;
 
+    if (str == NULL)
+	outofmem(__FILE__, "cookie_add_acceptlist");
+
     /*
-     * Is this the first cookie we're handling?  If so, initialize
+     * Is this the first domain we're handling?  If so, initialize
      * domain_list.
      */
 
@@ -2635,8 +2639,8 @@ PUBLIC void cookie_add_acceptlist ARGS1(
     while ((strsmall = LYstrsep(str, ",")) != 0) {
 
 	/*
-	 * Check the list of existing cookies to see if this is a
-	 * re-setting of an already existing cookie -- if so, just
+	 * Check the list of existing domains to see if this is a
+	 * re-setting of an already existing domains -- if so, just
 	 * change the behavior, if not, create a new domain entry.
 	 */
 
@@ -2693,8 +2697,11 @@ PUBLIC void cookie_add_rejectlist ARGS1(
     char *strsmall = NULL;
     int isexisting = FALSE;
 
+    if (str == NULL)
+	outofmem(__FILE__, "cookie_add_rejectlist");
+
     /*
-     * Is this the first cookie we're handling?  If so, initialize
+     * Is this the first domain we're handling?  If so, initialize
      * domain_list.
      */
 
@@ -2711,8 +2718,8 @@ PUBLIC void cookie_add_rejectlist ARGS1(
     while ((strsmall = LYstrsep(str, ",")) != 0) {
 
 	/*
-	 * Check the list of existing cookies to see if this is a
-	 * re-setting of an already existing cookie -- if so, just
+	 * Check the list of existing domains to see if this is a
+	 * re-setting of an already existing domains -- if so, just
 	 * change the behavior, if not, create a new domain entry.
 	 */
 
@@ -2748,6 +2755,82 @@ PUBLIC void cookie_add_rejectlist ARGS1(
     FREE(rstr);
 }
 
+/*      cookie_set_invcheck
+**      -------------------
+**
+**   Is passed a comma-delimited string of domains and a particular
+**   behaviour to set their invcheck_bv to. - BJP
+*/
+
+PUBLIC void cookie_set_invcheck ARGS2(
+	char *, 	domains,
+        invcheck_behaviour,		setting)
+{
+    domain_entry *de = NULL;
+    domain_entry *de2 = NULL;
+    HTList *hl = NULL;
+    char **str = (char **)calloc(1, sizeof(domains));
+    char *dstr = NULL;
+    char *strsmall = NULL;
+    int isexisting = FALSE;
+
+    if (str == NULL)
+	outofmem(__FILE__, "cookie_set_invcheck");
+
+    /*
+     * Is this the first cookie we're handling?  If so, initialize
+     * domain_list.
+     */
+
+    if (domain_list == NULL) {
+	atexit(LYCookieJar_free);
+	domain_list = HTList_new();
+	total_cookies = 0;
+    }
+
+    StrAllocCopy(dstr, domains);
+
+    *str = dstr;
+
+    while ((strsmall = LYstrsep(str, ",")) != 0) {
+
+	/*
+	 * Check the list of existing cookies to see if this is a
+	 * re-setting of an already existing cookie -- if so, just
+	 * change the behavior, if not, create a new domain entry.
+	 */
+	for (hl = domain_list; hl != NULL; hl = hl->next) {
+	    de2 = (domain_entry *)hl->object;
+	    if ((de2 != NULL && de2->domain != NULL)
+	     && !strcmp(strsmall, de2->domain)) {
+		isexisting = TRUE;
+		break;
+	    } else {
+		isexisting = FALSE;
+	    }
+	}
+
+	if (!isexisting) {
+	    de = (domain_entry *)calloc(1, sizeof(domain_entry));
+
+	    if (de == NULL)
+		outofmem(__FILE__, "cookie_set_invcheck");
+
+	    de->invcheck_bv = setting;
+
+	    StrAllocCopy(de->domain, strsmall);
+	    de->cookie_list = HTList_new();
+	    HTList_addObject(domain_list, de);
+	} else {
+	    de2->invcheck_bv = setting;
+	}
+    }
+
+    FREE(str);
+    FREE(strsmall);
+    FREE(dstr);
+}
+
 #ifdef GLOBALDEF_IS_MACRO
 #define _LYCOOKIE_C_GLOBALDEF_1_INIT { "LYNXCOOKIE",LYHandleCookies,0}
 GLOBALDEF (HTProtocol,LYLynxCookies,_LYCOOKIE_C_GLOBALDEF_1_INIT);
diff --git a/src/LYCookie.h b/src/LYCookie.h
index 62caa88a..6f406287 100644
--- a/src/LYCookie.h
+++ b/src/LYCookie.h
@@ -4,6 +4,19 @@
 #include <HTUtils.h>
 #include <HTList.h>
 
+typedef enum {ACCEPT_ALWAYS, REJECT_ALWAYS, QUERY_USER, FROM_FILE} behaviour;
+typedef enum {INVCHECK_QUERY,
+	      INVCHECK_STRICT,
+	      INVCHECK_LOOSE} invcheck_behaviour;
+
+struct _domain_entry {
+    char *	domain;  /* Domain for which these cookies are valid */
+    behaviour	bv;
+    invcheck_behaviour	invcheck_bv;
+    HTList *	cookie_list;
+};
+typedef struct _domain_entry domain_entry;
+
 extern void LYSetCookie PARAMS((
 	CONST char *	SetCookie,
 	CONST char *	SetCookie2,
@@ -21,14 +34,8 @@ extern void cookie_add_acceptlist PARAMS((
 	char *		acceptdomains));
 extern void cookie_add_rejectlist PARAMS((
 	char *		rejectdomains));
-
-typedef enum {ACCEPT_ALWAYS, REJECT_ALWAYS, QUERY_USER, FROM_FILE} behaviour;
-
-struct _domain_entry {
-    char *	domain;  /* Domain for which these cookies are valid */
-    behaviour	bv;
-    HTList *	cookie_list;
-};
-typedef struct _domain_entry domain_entry;
+extern void cookie_set_invcheck PARAMS((
+	char *	 	domains,
+        invcheck_behaviour setting));
 
 #endif /* LYCOOKIES_H */
diff --git a/src/LYForms.c b/src/LYForms.c
index 8f0a0984..4ba50547 100644
--- a/src/LYForms.c
+++ b/src/LYForms.c
@@ -311,9 +311,11 @@ PRIVATE int form_getstr ARGS1(
 		    }
 		    break;
 		case F_TEXT_TYPE:
-		case F_TEXTAREA_TYPE:
 		    statusline(FORM_LINK_TEXT_MESSAGE);
 		    break;
+		case F_TEXTAREA_TYPE:
+		    statusline(FORM_LINK_TEXTAREA_MESSAGE);
+		    break;
 		default:
 		    break;
 	    }
diff --git a/src/LYGetFile.c b/src/LYGetFile.c
index 7ce9a59d..0f55b9b3 100644
--- a/src/LYGetFile.c
+++ b/src/LYGetFile.c
@@ -420,13 +420,24 @@ Try_Redirected_URL:
 		    } else {
 			HTParentAnchor *tmpanchor;
 			CONST char *title;
+			char *tmptitle = NULL;
 
 			title = "";
 			if ((tmpanchor = HTAnchor_parent(
 						HTAnchor_findAddress(&WWWDoc)
-							)) != NULL) {
-			    if (HTAnchor_title(tmpanchor)) {
+							)) != NULL &&
+			    HTAnchor_title(tmpanchor)) {
 				title = HTAnchor_title(tmpanchor);
+			} else if (HTMainAnchor && !LYUserSpecifiedURL) {
+			    title = HTAnchor_subject(HTMainAnchor);
+			    if (title && *title) {
+				if (strncasecomp(title, "Re:", 3)) {
+				    StrAllocCopy(tmptitle, "Re: ");
+				    StrAllocCat(tmptitle, title);
+				    title = tmptitle;
+				}
+			    } else {
+				title = "";
 			    }
 			}
 			cp = (char *)strchr(doc->address,':')+1;
@@ -434,7 +445,10 @@ Try_Redirected_URL:
 				      ((HTMainAnchor && !LYUserSpecifiedURL) ?
 				       (char *)HTMainAnchor->address :
 				       (char *)doc->address),
-				      title);
+				      title,
+				      (HTMainAnchor && !LYUserSpecifiedURL) ?
+				       HTMainAnchor->message_id : NULL);
+			FREE(tmptitle);
 		    }
 		    return(NULLFILE);
 
diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h
index 4000b353..613b5045 100644
--- a/src/LYGlobalDefs.h
+++ b/src/LYGlobalDefs.h
@@ -314,6 +314,9 @@ extern BOOLEAN LYSetCookies;		/* Process Set-Cookie headers?	 */
 extern BOOLEAN LYAcceptAllCookies;      /* accept ALL cookies?           */
 extern char *LYCookieAcceptDomains;     /* domains to accept all cookies */
 extern char *LYCookieRejectDomains;     /* domains to reject all cookies */
+extern char *LYCookieStrictCheckDomains; /* domains to check strictly    */
+extern char *LYCookieLooseCheckDomains; /* domains to check loosely      */
+extern char *LYCookieQueryCheckDomains; /* domains to check w/a query    */
 #ifdef EXP_PERSISTENT_COOKIES
 extern BOOLEAN persistent_cookies;
 extern char *LYCookieFile;              /* file to store cookies in      */
diff --git a/src/LYKeymap.c b/src/LYKeymap.c
index 14625052..3800a879 100644
--- a/src/LYKeymap.c
+++ b/src/LYKeymap.c
@@ -577,7 +577,7 @@ PRIVATE struct rmap revmap[] = {
 { "WHEREIS",		"search within the current document" },
 { "NEXT",		"search for the next occurence" },
 { "COMMENT",		"send a comment to the author of the current document" },
-{ "EDIT",		"edit the current document" },
+{ "EDIT",		"edit the current document or a form's textarea" },
 { "INFO",		"display information on the current document and link" },
 { "PRINT",		"display choices for printing the current document" },
 { "ADD_BOOKMARK",	"add to your personal bookmark list" },
@@ -607,7 +607,7 @@ PRIVATE struct rmap revmap[] = {
 { "SWITCH_DTD",		"switch between two ways of parsing HTML" },
 { "ELGOTO",		"edit the current link's URL or ACTION and go to it" },
 { "CHANGE_LINK",	"force reset of the current link on the page" },
-{ "EDITTEXTAREA",	"use defined external editor to edit the text area" },
+{ "EDITTEXTAREA",	"use an external editor to edit a form's textarea" },
 #ifdef USE_EXTERNALS
 { "EXTERN",		"run external program with url" },
 #endif
diff --git a/src/LYMail.c b/src/LYMail.c
index 5bb717b6..af4b2a6d 100644
--- a/src/LYMail.c
+++ b/src/LYMail.c
@@ -506,7 +506,7 @@ PUBLIC void mailform ARGS4(
 	 *  temporary buffer (i.e., about 500 chars). - BL
 	 */
 	if (strlen(address_ptr1) > 3 &&
-            strlen(address_ptr1) + strlen(mail_adrs) < sizeof(cmd)) {
+	    strlen(address_ptr1) + strlen(mail_adrs) < sizeof(cmd)) {
 	    if (!first) {
 		StrAllocCat(command, ",");
 	    }
@@ -539,7 +539,7 @@ PUBLIC void mailform ARGS4(
 	     *  temporary buffer (i.e., about 500 chars). - BL
 	     */
 	    if (strlen(address_ptr1) > 3 &&
-                strlen(address_ptr1) + strlen(mail_adrs) < sizeof(cmd)) {
+		strlen(address_ptr1) + strlen(mail_adrs) < sizeof(cmd)) {
 		StrAllocCat(command, ",");
 		sprintf(cmd, mail_adrs, address_ptr1);
 		if (isPMDF) {
@@ -800,7 +800,7 @@ PUBLIC void mailmsg ARGS4(
 	 *  temporary buffer (i.e., about 500 chars). - BL
 	 */
 	if (strlen(address) > 3 &&
-            strlen(address) + strlen(mail_adrs) < sizeof(cmd)) {
+	    strlen(address) + strlen(mail_adrs) < sizeof(cmd)) {
 	    if (!first) {
 		StrAllocCat(command, ",");
 	    }
@@ -852,10 +852,11 @@ PUBLIC void mailmsg ARGS4(
 **  reply_by_mail() invokes sendmail on Unix or mail on VMS to send
 **  a comment  from the users to the owner
 */
-PUBLIC void reply_by_mail ARGS3(
+PUBLIC void reply_by_mail ARGS4(
 	char *, 	mail_address,
 	char *, 	filename,
-	CONST char *,	title)
+	CONST char *,	title,
+	CONST char *,	refid)
 {
     char user_input[1000];
     FILE *fd, *fp;
@@ -886,11 +887,6 @@ PUBLIC void reply_by_mail ARGS3(
     char hdrfile[LY_MAXPATH];
     FILE *hfd;
 
-    CTRACE(tfp, "reply_by_mail(\"%s\", \"%s\", \"%s\")\n",
-	mail_address?mail_address:"<nil>",
-	filename?filename:"<nil>",
-	title?title:"<nil>");
-
     if (!strncasecomp(system_mail, "PMDF SEND", 9)) {
 	isPMDF = TRUE;
     }
@@ -900,6 +896,12 @@ PUBLIC void reply_by_mail ARGS3(
     int n;
 #endif /* VMS */
 
+    CTRACE(tfp, "reply_by_mail(\"%s\", \"%s\", \"%s\", \"%s\")\n",
+	mail_address?mail_address:"<nil>",
+	filename?filename:"<nil>",
+	title?title:"<nil>",
+	refid?refid:"<nil>");
+
     term_letter = FALSE;
 
     if (mail_address && *mail_address) {
@@ -1255,15 +1257,21 @@ PUBLIC void reply_by_mail ARGS3(
      */
     StrAllocCat(header, "X-URL: ");
     if (filename && *filename) {
-        StrAllocCat(header, filename);
+	StrAllocCat(header, filename);
     }
     else {
-        StrAllocCat(header, "mailto:");
-        StrAllocCat(header, address);
+	StrAllocCat(header, "mailto:");
+	StrAllocCat(header, address);
     }
     StrAllocCat(header, "\n");
     sprintf(buf, "X-Mailer: Lynx, Version %s\n", LYNX_VERSION);
     StrAllocCat(header, buf);
+
+    if (refid && *refid) {
+	StrAllocCat(header, "In-Reply-To: <");
+	StrAllocCat(header, refid);
+	StrAllocCat(header, ">\n");
+    }
 #endif /* VMS */
 
     /*
@@ -1492,9 +1500,9 @@ PUBLIC void reply_by_mail ARGS3(
 
 #ifdef DOSPATH
     if (*address) {
-        StrAllocCat(header, "To: ");
-        StrAllocCat(header, address);
-        StrAllocCat(header, "\n");
+	StrAllocCat(header, "To: ");
+	StrAllocCat(header, address);
+	StrAllocCat(header, "\n");
     }
 #endif
 
@@ -1769,7 +1777,7 @@ PUBLIC void reply_by_mail ARGS3(
 	 *  temporary buffer (i.e., about 500 chars). - BL
 	 */
 	if (strlen(address_ptr1) > 3 &&
-            strlen(address_ptr1) + strlen(mail_adrs) < sizeof(cmd)) {
+	    strlen(address_ptr1) + strlen(mail_adrs) < sizeof(cmd)) {
 	    if (!first) {
 		StrAllocCat(command, ",");
 	    }
@@ -1802,7 +1810,7 @@ PUBLIC void reply_by_mail ARGS3(
 	     *  temporary buffer (i.e., about 500 chars). - BL
 	     */
 	    if (strlen(address_ptr1) > 3 &&
-                strlen(address_ptr1) + strlen(mail_adrs) < sizeof(cmd)) {
+		strlen(address_ptr1) + strlen(mail_adrs) < sizeof(cmd)) {
 		StrAllocCat(command, ",");
 		sprintf(cmd, mail_adrs, address_ptr1);
 		if (isPMDF) {
diff --git a/src/LYMail.h b/src/LYMail.h
index 3304228a..00728e38 100644
--- a/src/LYMail.h
+++ b/src/LYMail.h
@@ -21,6 +21,7 @@ extern void mailmsg PARAMS((
 extern void reply_by_mail PARAMS((
 	char *		mail_address,
 	char *		filename,
-	CONST char *	title));
+	CONST char *	title,
+	CONST char *	refid));
 
 #endif /* LYMAIL_H */
diff --git a/src/LYMain.c b/src/LYMain.c
index 30a03d65..4bed8652 100644
--- a/src/LYMain.c
+++ b/src/LYMain.c
@@ -341,6 +341,9 @@ PUBLIC BOOLEAN LYSetCookies = SET_COOKIES; /* Process Set-Cookie headers? */
 PUBLIC BOOLEAN LYAcceptAllCookies = ACCEPT_ALL_COOKIES; /* take all cookies? */
 PUBLIC char *LYCookieAcceptDomains = NULL; /* domains to accept all cookies */
 PUBLIC char *LYCookieRejectDomains = NULL; /* domains to reject all cookies */
+PUBLIC char *LYCookieStrictCheckDomains = NULL; /* check strictly  */
+PUBLIC char *LYCookieLooseCheckDomains = NULL;  /* check loosely   */
+PUBLIC char *LYCookieQueryCheckDomains = NULL;  /* check w/a query */
 #ifdef EXP_PERSISTENT_COOKIES
 BOOLEAN persistent_cookies = TRUE;
 PUBLIC char *LYCookieFile = NULL;          /* default cookie file */
@@ -487,6 +490,7 @@ PRIVATE void free_lynx_globals NOARGS
     FREE(URLDomainPrefixes);
     FREE(URLDomainSuffixes);
     FREE(XLoadImageCommand);
+    FREE(lynx_version_putenv_command);
     FREE(LYTraceLogPath);
     FREE(lynx_cfg_file);
 #if defined(USE_HASH)
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index cfddb3f6..0d68c81d 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -269,6 +269,7 @@ int mainloop NOARGS
     BOOLEAN override_LYresubmit_posts = FALSE;
     unsigned int len;
     int i;
+    int n;
 
 #ifdef DIRED_SUPPORT
     char *tp = NULL;
@@ -1449,12 +1450,17 @@ try_again:
 			    statusline(FORM_LINK_RESET_MESSAGE);
 			break;
 		    case F_TEXT_TYPE:
-		    case F_TEXTAREA_TYPE:
 			if (links[curdoc.link].form->disabled == YES)
 			    statusline(FORM_LINK_TEXT_UNM_MSG);
 			else
 			    statusline(FORM_LINK_TEXT_MESSAGE);
 			break;
+		    case F_TEXTAREA_TYPE:
+			if (links[curdoc.link].form->disabled == YES)
+			    statusline(FORM_LINK_TEXT_UNM_MSG);
+			else
+			    statusline(FORM_LINK_TEXTAREA_MESSAGE);
+			break;
 		    }
 		} else {
 		    statusline(NORMAL_LINK_MESSAGE);
@@ -4025,17 +4031,31 @@ if (!LYUseFormsOptions) {
 			 *  The owner_address is a mailto: URL.
 			 */
 			CONST char *kp = HText_getRevTitle();
+			CONST char *id = HText_getMessageID();
+			char *tmptitle = NULL;
+			if (!kp && HTMainAnchor) {
+			    kp = HTAnchor_subject(HTMainAnchor);
+			    if (kp && *kp) {
+				if (strncasecomp(kp, "Re: ", 4)) {
+				    StrAllocCopy(tmptitle, "Re: ");
+				    StrAllocCat(tmptitle, kp);
+				    kp = tmptitle;
+				}
+			    }
+			}
+
 			if (strchr(owner_address,':')!=NULL)
 			     /*
 			      *  Send a reply.	The address is after the colon.
 			      */
 			     reply_by_mail(strchr(owner_address,':')+1,
 					   curdoc.address,
-					   (kp ? kp : ""));
+					   (kp ? kp : ""), id);
 			else
 			    reply_by_mail(owner_address, curdoc.address,
-					  (kp ? kp : ""));
+					  (kp ? kp : ""), id);
 
+			FREE(tmptitle);
 			refresh_screen = TRUE;	/* to force a showpage */
 		   }
 	       }
@@ -4142,6 +4162,28 @@ if (!LYUseFormsOptions) {
 		break;
 	    }
 
+	    /*
+	     *  If we're in a forms TEXTAREA, invoke the editor on it.
+	     */
+	    if (links[curdoc.link].type       == WWW_FORM_LINK_TYPE &&
+		links[curdoc.link].form->type == F_TEXTAREA_TYPE)   {
+	       cmd = LYK_EDIT_TEXTAREA;
+	       goto new_cmd;
+	    }
+
+	    /*
+	     *  If we're in a forms TEXT type, tell user the request
+	     *  is bogus (though in reality, without this trap, if the
+	     *  document with the TEXT field is local, the editor *would*
+	     *  be invoked on the source .html file; eg, the o(ptions)
+	     *  form tempfile).
+	     */
+	    if (links[curdoc.link].type       == WWW_FORM_LINK_TYPE &&
+		links[curdoc.link].form->type == F_TEXT_TYPE)       {
+	       HTUserMsg(CANNOT_EDIT_FIELD);
+	       break;
+	    }
+
 #ifdef DIRED_SUPPORT
 	    /*
 	     *	Allow the user to edit the link rather
@@ -4304,25 +4346,37 @@ if (!LYUseFormsOptions) {
 		break;
 	    }
 
-		/* is curent link part of a textarea */
-	    if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-		links[curdoc.link].form->type == F_TEXTAREA_TYPE) {
+	    /*
+	     *  See if the current link is in a form TEXTAREA.
+	     */
+	    if (links[curdoc.link].type       == WWW_FORM_LINK_TYPE &&
+		links[curdoc.link].form->type == F_TEXTAREA_TYPE)   {
 
 		/* stop screen */
 		stop_curses();
 
-		HText_ExtEditForm (&links[curdoc.link]);
+		n = HText_ExtEditForm (&links[curdoc.link]);
+
+		lines_in_file = HText_getNumOfLines();
+
+		/*
+		 *  TODO: Move cursor "n" lines from the current line to
+		 *        position it on the 1st trailing blank line in
+		 *        the now edited TEXTAREA.  If the target line/
+		 *        anchor requires us to scroll up/down, position
+		 *        the target in the approximate center of the
+		 *        screen.
+		 */
+
+		/* curdoc.link += n;*/	/* works, except for page crossing, */
+					/* damnit; why is nothing ever easy */
 
 		/* start screen */
 		start_curses();
 		refresh_screen = TRUE;
 
-		/*
-		cmd = LYK_REFRESH;
-		goto new_cmd;
-		*/
-
 	    } else {
+
 		HTInfoMsg (NOT_IN_TEXTAREA);
 	    }
 	    break;
diff --git a/src/LYNews.c b/src/LYNews.c
index e7f11d2d..5cfd41db 100644
--- a/src/LYNews.c
+++ b/src/LYNews.c
@@ -25,6 +25,54 @@
 BOOLEAN term_message = FALSE;
 PRIVATE void terminate_message  PARAMS((int sig));
 
+PRIVATE BOOLEAN message_has_content ARGS1(
+    CONST char *,		filename)
+{
+    FILE *fp;
+    char buffer[72];
+    BOOLEAN in_headers = TRUE;
+
+    if (!filename || (fp = fopen(filename, "r")) == NULL) {
+	CTRACE(tfp, "Failed to open file %s for reading!\n",
+	       filename ? filename : "(<null>)");
+	return FALSE;
+    }
+    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
+	char *cp = buffer;
+	char firstnonblank = '\0';
+	if (*cp == '\0') {
+	    break;
+	}
+	for (; *cp; cp++) {
+	    if (*cp == '\n') {
+		break;
+	    } else if (*cp != ' ') {
+		if (!firstnonblank && isgraph((unsigned char)*cp)) {
+		    firstnonblank = *cp;
+		}
+	    }
+	}
+	if (*cp != '\n') {
+	    int c;
+	    while ((c = getc(fp)) != EOF && c != (int)(unsigned char)'\n') {
+		if (!firstnonblank && isgraph((unsigned char)c))
+		    firstnonblank = (char)c;
+	    }
+	}
+	if (firstnonblank && firstnonblank != '>') {
+	    if (!in_headers) {
+		fclose(fp);
+		return TRUE;
+	    }
+	}
+	if (!firstnonblank) {
+	    in_headers = FALSE;
+	}
+    }
+    fclose(fp);
+    return FALSE;
+}
+
 /*
 **  This function is called from HTLoadNews() to have the user
 **  create a file with news headers and a body for posting of
@@ -51,8 +99,10 @@ PUBLIC char *LYNewsPost ARGS2(
     char CJKfile[LY_MAXPATH];
     char *postfile = NULL;
     char *NewsGroups = NULL;
+    char *References = NULL;
     char *org = NULL;
     FILE *fp = NULL;
+    BOOLEAN nonempty = FALSE;
 
     /*
      *  Make sure a non-zero length newspost, newsreply,
@@ -90,7 +140,27 @@ PUBLIC char *LYNewsPost ARGS2(
      *  may also have been hex escaped. - FM
      */
     StrAllocCopy(NewsGroups, newsgroups);
+    if ((cp = strstr(NewsGroups, ";ref="))) {
+	*cp = '\0';
+	cp += 5;
+	if (*cp == '<') {
+	    StrAllocCopy(References, cp);
+	} else {
+	    StrAllocCopy(References, "<");
+	    StrAllocCat(References, cp);
+	    StrAllocCat(References, ">");
+	}
+	HTUnEscape(References);
+	if (!((cp = strchr(References, '@')) && cp > References + 1 &&
+	      isalnum(cp[1]))) {
+	    FREE(References);
+	}
+    }
     HTUnEscape(NewsGroups);
+    if (!*NewsGroups) {
+	LYCloseTempFP(fd);		/* Close the temp file.	*/
+	goto cleanup;
+    }
 
     /*
      *  Allow ^C to cancel the posting,
@@ -121,7 +191,7 @@ PUBLIC char *LYNewsPost ARGS2(
     if (LYgetstr(user_input, VISIBLE,
 		 sizeof(user_input), NORECALL) < 0 ||
 	term_message) {
-        HTInfoMsg(NEWS_POST_CANCELLED);
+	HTInfoMsg(NEWS_POST_CANCELLED);
 	LYCloseTempFP(fd);		/* Close the temp file.	*/
 	scrollok(stdscr, FALSE);	/* Stop scrolling.	*/
 	goto cleanup;
@@ -136,24 +206,24 @@ PUBLIC char *LYNewsPost ARGS2(
     addstr(gettext("\n\n Please provide or edit the Subject: header\n"));
     strcpy(user_input, "Subject: ");
     if ((followup == TRUE && nhist > 0) &&
-        (kp = HText_getTitle()) != NULL) {
+	(kp = HText_getTitle()) != NULL) {
 	/*
 	 *  Add the default subject.
 	 */
 	kp = LYSkipCBlanks(kp);
 	if (strncasecomp(kp, "Re:", 3)) {
-            strcat(user_input, "Re: ");
+	    strcat(user_input, "Re: ");
 	}
-        strcat(user_input, kp);
+	strcat(user_input, kp);
     }
     cp = NULL;
     if (LYgetstr(user_input, VISIBLE,
 		 sizeof(user_input), NORECALL) < 0 ||
 	term_message) {
-        HTInfoMsg(NEWS_POST_CANCELLED);
-        LYCloseTempFP(fd);		/* Close the temp file. */
+	HTInfoMsg(NEWS_POST_CANCELLED);
+	LYCloseTempFP(fd);		/* Close the temp file. */
 	scrollok(stdscr, FALSE);	/* Stop scrolling.	*/
-        goto cleanup;
+	goto cleanup;
     }
     fprintf(fd,"%s\n",user_input);
 
@@ -164,34 +234,37 @@ PUBLIC char *LYNewsPost ARGS2(
     if (((org = getenv("ORGANIZATION")) != NULL) && *org != '\0') {
 	StrAllocCat(cp, org);
     } else if (((org = getenv("NEWS_ORGANIZATION")) != NULL) &&
-    	       *org != '\0') {
+	       *org != '\0') {
 	StrAllocCat(cp, org);
 #ifndef VMS
     } else if ((fp = fopen("/etc/organization", "r")) != NULL) {
 	if (fgets(user_input, sizeof(user_input), fp) != NULL) {
 	    if ((org = strchr(user_input, '\n')) != NULL) {
-	        *org = '\0';
+		*org = '\0';
 	    }
 	    if (user_input[0] != '\0') {
-	        StrAllocCat(cp, user_input);
+		StrAllocCat(cp, user_input);
 	    }
 	}
 	fclose(fp);
 #endif /* !VMS */
     }
     LYstrncpy(user_input, cp, (sizeof(user_input) - 16));
-    FREE(cp); 
+    FREE(cp);
     addstr(gettext("\n\n Please provide or edit the Organization: header\n"));
     if (LYgetstr(user_input, VISIBLE,
 		 sizeof(user_input), NORECALL) < 0 ||
 	term_message) {
-        HTInfoMsg(NEWS_POST_CANCELLED);
-        LYCloseTempFP(fd);		/* Close the temp file. */
+	HTInfoMsg(NEWS_POST_CANCELLED);
+	LYCloseTempFP(fd);		/* Close the temp file. */
 	scrollok(stdscr, FALSE);	/* Stop scrolling.	*/
-        goto cleanup;
+	goto cleanup;
     }
     fprintf(fd, "%s\n", user_input);
 
+    if (References) {
+	fprintf(fd, "References: %s\n", References);
+    }
     /*
      *  Add Newsgroups Summary and Keywords headers.
      */
@@ -201,7 +274,7 @@ PUBLIC char *LYNewsPost ARGS2(
      *  Have the user create the message body.
      */
     if (!no_editor && editor && *editor != '\0') {
-        /*
+	/*
 	 *  Use an external editor.
 	 */
 	char *editor_arg = "";
@@ -213,17 +286,17 @@ PUBLIC char *LYNewsPost ARGS2(
 	    _statusline(INC_ORIG_MSG_PROMPT);
 	    c = 0;
 	    while (TOUPPER(c) != 'Y' && TOUPPER(c) != 'N' &&
-	    	   !term_message && c != 7 && c != 3)
-	        c = LYgetch();
+		   !term_message && c != 7 && c != 3)
+		c = LYgetch();
 	    if (TOUPPER(c) == 'Y')
-	        /*
+		/*
 		 *  The 1 will add the reply ">" in front of every line.
 		 *  We're assuming that if the display character set is
 		 *  Japanese and the document did not have a CJK charset,
 		 *  any non-EUC or non-SJIS 8-bit characters in it where
 		 *  converted to 7-bit equivalents. - FM
 		 */
-	        print_wwwfile_to_fd(fd, 1);
+		print_wwwfile_to_fd(fd, 1);
 	}
 	LYCloseTempFP(fd);		/* Close the temp file. */
 	scrollok(stdscr, FALSE);	/* Stop scrolling.	*/
@@ -245,8 +318,11 @@ PUBLIC char *LYNewsPost ARGS2(
 	} else {
 	    start_curses();
 	}
+
+	nonempty = message_has_content(my_tempfile);
+
     } else {
-        /*
+	/*
 	 *  Use the built in line editior.
 	 */
 	addstr(gettext("\n\n Please enter your message below."));
@@ -254,32 +330,38 @@ PUBLIC char *LYNewsPost ARGS2(
 	addstr(gettext("\n on a line and press enter again."));
 	addstr("\n\n");
 	refresh();
-        *user_input = '\0';
+	*user_input = '\0';
 	if (LYgetstr(user_input, VISIBLE,
-	    	     sizeof(user_input), NORECALL) < 0 ||
+		     sizeof(user_input), NORECALL) < 0 ||
 	    term_message) {
 	    HTInfoMsg(NEWS_POST_CANCELLED);
 	    LYCloseTempFP(fd);		/* Close the temp file.	*/
 	    scrollok(stdscr, FALSE);	/* Stop scrolling.	*/
 	    goto cleanup;
 	}
-	while (!STREQ(user_input,".") && !term_message) { 
+	while (!STREQ(user_input,".") && !term_message) {
 	    addch('\n');
 	    fprintf(fd,"%s\n",user_input);
+	    if (!nonempty && strlen(user_input))
+		nonempty = TRUE;
 	    *user_input = '\0';
 	    if (LYgetstr(user_input, VISIBLE,
-	       		 sizeof(user_input), NORECALL) < 0) {
-	        HTInfoMsg(NEWS_POST_CANCELLED);
-	        LYCloseTempFP(fd);		/* Close the temp file. */
+			 sizeof(user_input), NORECALL) < 0) {
+		HTInfoMsg(NEWS_POST_CANCELLED);
+		LYCloseTempFP(fd);		/* Close the temp file. */
 		scrollok(stdscr, FALSE);	/* Stop scrolling.	*/
-	        goto cleanup;
+		goto cleanup;
 	    }
- 	}
+	}
 	fprintf(fd, "\n");
 	LYCloseTempFP(fd);		/* Close the temp file. */
 	scrollok(stdscr, FALSE);	/* Stop scrolling.	*/
     }
 
+    if (!nonempty) {
+	HTAlert(gettext("Message has no original text!"));
+	goto cleanup;
+    }
     /*
      *  Confirm whether to post, and if so,
      *  whether to append the sig file. - FM
@@ -292,22 +374,22 @@ PUBLIC char *LYNewsPost ARGS2(
 	   !term_message && c != 7   && c != 3)
 	c = LYgetch();
     if (TOUPPER(c) != 'Y') {
-        clear();  /* clear the screen */
+	clear();  /* clear the screen */
 	goto cleanup;
     }
     if ((LynxSigFile != NULL) &&
-        (fp = fopen(LynxSigFile, "r")) != NULL) {
+	(fp = fopen(LynxSigFile, "r")) != NULL) {
 	LYStatusLine = (LYlines - 1);
 	_user_message(APPEND_SIG_FILE, LynxSigFile);
 	c = 0;
-        LYStatusLine = -1;
+	LYStatusLine = -1;
 	while (TOUPPER(c) != 'Y' && TOUPPER(c) != 'N' &&
 	       !term_message && c != 7   && c != 3)
 	    c = LYgetch();
 	if (TOUPPER(c) == 'Y') {
 	    if ((fd = LYAppendToTxtFile (my_tempfile)) != NULL) {
-	        fputs("-- \n", fd);
-	        while (fgets(user_input, sizeof(user_input), fp) != NULL) {
+		fputs("-- \n", fd);
+		while (fgets(user_input, sizeof(user_input), fp) != NULL) {
 		    fputs(user_input, fd);
 		}
 		fclose(fd);
@@ -327,7 +409,7 @@ PUBLIC char *LYNewsPost ARGS2(
     if (CJKfile[0] != '\0') {
 	if ((fd = fopen(my_tempfile, "r")) != NULL) {
 	    while (fgets(user_input, sizeof(user_input), fd) != NULL) {
-	        TO_JIS((unsigned char *)user_input,
+		TO_JIS((unsigned char *)user_input,
 		       (unsigned char *)CJKinput);
 		fputs(CJKinput, fc);
 	    }
@@ -344,7 +426,7 @@ PUBLIC char *LYNewsPost ARGS2(
 	StrAllocCopy(postfile, my_tempfile);
     }
     if (!followup) {
-        /*
+	/*
 	 *  If it's not a followup, the current document
 	 *  most likely is the group listing, so force a
 	 *  to have the article show up in the list after
@@ -353,7 +435,7 @@ PUBLIC char *LYNewsPost ARGS2(
 	 *  do a reload manually on returning to the
 	 *  group listing. - FM
 	 */
-        LYforce_no_cache = TRUE;
+	LYforce_no_cache = TRUE;
     }
     LYStatusLine = (LYlines - 1);
     HTUserMsg(POSTING_TO_NEWS);
@@ -371,6 +453,7 @@ cleanup:
 	LYRemoveTemp(my_tempfile);
     LYRemoveTemp(CJKfile);
     FREE(NewsGroups);
+    FREE(References);
 
     return(postfile);
 }
diff --git a/src/LYPrint.c b/src/LYPrint.c
index 21e0989d..e5b35ae7 100644
--- a/src/LYPrint.c
+++ b/src/LYPrint.c
@@ -483,7 +483,7 @@ PRIVATE void send_file_to_mail ARGS3(
     BOOL use_type;
     CONST char *disp_charset;
     FILE *outfile_fp;
-    char *buffer;
+    char *buffer = NULL;
     char *subject = NULL;
     char user_response[LINESIZE];
     int c;
diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c
index 4eefe938..090cff98 100644
--- a/src/LYReadCFG.c
+++ b/src/LYReadCFG.c
@@ -859,7 +859,10 @@ static Config_Type Config_Table [] =
 #ifdef EXP_PERSISTENT_COOKIES
      PARSE_STR("cookie_file", CONF_STR, LYCookieFile),
 #endif /* EXP_PERSISTENT_COOKIES */
+     PARSE_STR("cookie_loose_invalid_domains", CONF_STR, LYCookieLooseCheckDomains),
+     PARSE_STR("cookie_query_invalid_domains", CONF_STR, LYCookieQueryCheckDomains),
      PARSE_STR("cookie_reject_domains", CONF_STR, LYCookieRejectDomains),
+     PARSE_STR("cookie_strict_invalid_domains", CONF_STR, LYCookieStrictCheckDomains),
      PARSE_ENV("cso_proxy", CONF_ENV, 0 ),
 #ifdef VMS
      PARSE_STR("CSWING_PATH", CONF_STR, LYCSwingPath),
@@ -1210,8 +1213,10 @@ PUBLIC void read_cfg ARGS4(
 		char tmpbuf[MAX_LINE_BUFFER_LEN];
 		sprintf (tmpbuf, "%s=%s", name, value);
 		if ((q->str_value = (char **)calloc(1, sizeof(char **))) != 0) {
-			StrAllocCopy(*(q->str_value), tmpbuf);
-			putenv (*(q->str_value));
+		    StrAllocCopy(*(q->str_value), tmpbuf);
+		    putenv (*(q->str_value));
+		} else {
+		    outofmem(__FILE__, "read_cfg");
 		}
 #endif
 	    }
@@ -1283,6 +1288,8 @@ PUBLIC void read_cfg ARGS4(
      * If any COOKIE_{ACCEPT,REJECT}_DOMAINS have been defined,
      * process them.  These are comma delimited lists of
      * domains. - BJP
+     *
+     * And for query/strict/loose invalid cookie checking. - BJP
      */
 
     if (LYCookieAcceptDomains != NULL) {
@@ -1292,6 +1299,19 @@ PUBLIC void read_cfg ARGS4(
     if (LYCookieRejectDomains != NULL) {
 	cookie_add_rejectlist(LYCookieRejectDomains);
     }
+
+    if (LYCookieStrictCheckDomains != NULL) {
+	cookie_set_invcheck(LYCookieStrictCheckDomains, INVCHECK_STRICT);
+    }
+
+    if (LYCookieLooseCheckDomains != NULL) {
+	cookie_set_invcheck(LYCookieLooseCheckDomains, INVCHECK_LOOSE);
+    }
+
+    if (LYCookieQueryCheckDomains != NULL) {
+	cookie_set_invcheck(LYCookieQueryCheckDomains, INVCHECK_QUERY);
+    }
+
 }
 
 /*
diff --git a/src/LYStrings.c b/src/LYStrings.c
index f7ff73d9..f8d0fe3c 100644
--- a/src/LYStrings.c
+++ b/src/LYStrings.c
@@ -288,6 +288,21 @@ PRIVATE int set_clicked_link ARGS3(
 
 
 /*
+ *  LYstrerror emulates the ANSI strerror() function.
+ */
+#ifdef LYStrerror
+    /* defined as macro in .h file. */
+#else
+PUBLIC char *LYStrerror ARGS1(int, code)
+{
+    static char temp[80];
+    sprintf(temp, "System errno is %d.\r\n", code);
+    return temp;
+}
+#endif /* HAVE_STRERROR */
+
+
+/*
  *  LYstrncpy() terminates strings with a null byte.
  *  Writes a null byte into the n+1 byte of dst.
  */
diff --git a/src/LYStrings.h b/src/LYStrings.h
index e4683b38..7c346fc2 100644
--- a/src/LYStrings.h
+++ b/src/LYStrings.h
@@ -13,6 +13,13 @@ extern int peek_mouse_link NOPARAMS;
 extern int peek_mouse_levent NOPARAMS;
 extern int fancy_mouse PARAMS((WINDOW *win, int row, int *position));
 
+#ifdef HAVE_STRERROR
+#define LYStrerror strerror
+#else
+extern char *LYStrerror PARAMS((
+	int		code));
+#endif /* HAVE_STRERROR */
+
 extern char * LYstrncpy PARAMS((
 	char *		dst,
 	CONST char *	src,
diff --git a/src/LYUtils.c b/src/LYUtils.c
index f68da554..2c9a92a0 100644
--- a/src/LYUtils.c
+++ b/src/LYUtils.c
@@ -2000,6 +2000,43 @@ PUBLIC void noviceline ARGS1(
     return;
 }
 
+#ifdef NSL_FORK
+/*
+ *  Returns the file descriptor from which keyboard input is expected,
+ *  or INVSOC (-1) if not available.
+ *  If need_selectable is true, returns non-INVSOC fd only if select()
+ *  is possible - actually, currently only checks if fd is connected
+ *  to a tty. - kw
+ */
+PUBLIC int LYConsoleInputFD ARGS1(
+    BOOLEAN,		need_selectable)
+{
+    int fd = INVSOC;
+#ifdef USE_SLANG
+    if (!LYCursesON)
+	fd = fileno(stdin);
+#if SLANG_VERSION >= 9919
+    /* SLang_TT_Read_FD introduced in slang 0.99.19, from its changelog:
+     *   SLang_TT_Read_FD variable is now available for unix.  This is the file
+     *   descriptor used by SLang_getkey. */
+    else
+	fd = SLang_TT_Read_FD;
+#endif /* SLANG_VERSION >= 9919 */
+#else  /* !USE_SLANG */
+    fd = fileno(stdin);
+#endif /* !USE_SLANG */
+
+    if (need_selectable && fd != INVSOC) {
+	if (isatty(fd)) {
+	    return fd;
+	} else {
+	    return INVSOC;
+	}
+    }
+    return fd;
+}
+#endif /* NSL_FORK */
+
 PRIVATE int fake_zap = 0;
 
 PUBLIC void LYFakeZap ARGS1(
@@ -2975,6 +3012,8 @@ PUBLIC void change_sug_filename ARGS1(
      *	Rename any temporary files.
      */
     temp = (char *)calloc(1, (strlen(lynx_temp_space) + 60));
+    if (temp == NULL)
+	outofmem(__FILE__, "change_sug_filename");
     cp = wwwName(lynx_temp_space);
     if (LYIsHtmlSep(*cp)) {
 	sprintf(temp, "file://localhost%s%d", cp, (int)getpid());
@@ -4138,8 +4177,6 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
     char *Host = NULL, *HostColon = NULL, *host = NULL;
     char *Path = NULL;
     char *Fragment = NULL;
-    int hoststat;
-    SockA sock;
     BOOLEAN GotHost = FALSE;
     BOOLEAN Startup = (helpfilepath == NULL);
 
@@ -4214,8 +4251,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 	fprintf(stdout, "%s '%s'%s\n", WWW_FIND_MESSAGE, host, FIRST_SEGMENT);
     }
 #ifndef DJGPP
-    sock.sin_port = htons(80);
-    if ((hoststat = HTParseInet(&sock, host)) == 0)
+    if (LYGetHostByName(host) != NULL)
 #else
     if (resolve(host) != 0)
 #endif /* DJGPP */
@@ -4237,7 +4273,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 	FREE(MsgStr);
 	return GotHost;
 #ifndef DJGPP
-    } else if (LYCursesON && (hoststat == HT_INTERRUPTED)) {
+    } else if (LYCursesON && (lynx_nsl_status == HT_INTERRUPTED)) {
 #else /* DJGPP */
     } else if (LYCursesON && HTCheckForInterrupt()) {
 #endif /* DJGPP */
@@ -4336,8 +4372,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 		fprintf(stdout, "%s '%s'%s\n", WWW_FIND_MESSAGE, host, GUESSING_SEGMENT);
 	    }
 #ifndef DJGPP
-	    sock.sin_port = htons(80);
-	    GotHost = ((hoststat = HTParseInet(&sock, host)) == 0);
+	    GotHost = (LYGetHostByName(host) != NULL);
 #else
 	    GotHost = (resolve(host) != 0);
 #endif /* DJGPP */
@@ -4349,7 +4384,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 		 *  Give the user chance to interrupt lookup cycles. - KW
 		 */
 #ifndef DJGPP
-		if (LYCursesON && (hoststat == HT_INTERRUPTED))
+		if (LYCursesON && (lynx_nsl_status == HT_INTERRUPTED))
 #else /* DJGPP */
 		if (LYCursesON && HTCheckForInterrupt())
 #endif /* DJGPP */
@@ -5024,6 +5059,8 @@ PUBLIC void LYAddPathToHome ARGS3(
 	     */
 	    char *temp = (char *)calloc(1,
 					(strlen(home) + strlen(file) + 10));
+	    if (temp == NULL)
+		outofmem(__FILE__, "LYAddPathToHome");
 	    sprintf(temp, "%s%s", HTVMS_wwwName(home), (file + 1));
 	    sprintf(fbuffer, "%.*s",
 		    (fbuffer_size - 1), HTVMS_name("", temp));
@@ -5638,7 +5675,6 @@ PUBLIC FILE *LYOpenTemp ARGS3(
 	CONST char *,	mode)
 {
     FILE *fp = 0;
-    BOOL first = TRUE;
     BOOL txt = TRUE;
     BOOL wrt = 'r';
     LY_TEMP *p;
@@ -5674,19 +5710,15 @@ PUBLIC FILE *LYOpenTemp ARGS3(
 	    fp = LYNewBinFile (result);
 	}
 	/*
-	 * If we get a failure to make a temporary file, double check if the
-	 * directory is writable.
+	 * If we get a failure to make a temporary file, don't bother to try a
+	 * different name unless the failure was because the file already
+	 * exists.
 	 */
-#ifdef W_OK	/* FIXME (need a better test) in fcntl.h or unistd.h */
-	if (first) {
-	    first = FALSE;
-	    if (fp == 0) {
-		*LYPathLeaf(result) = 0;
-		if (*result == 0)
-		    strcpy(result, ".");
-		if (access(result, W_OK) < 0)
-		    return 0;
-	    }
+#ifdef EEXIST	/* FIXME (need a better test) in fcntl.h or unistd.h */
+	if ((fp == 0) && (errno != EEXIST)) {
+	    CTRACE(tfp, "... LYOpenTemp(%s) failed: %s\n",
+		   result, LYStrerror(errno));
+	    return 0;
 	}
 #endif
     } while (fp == 0);
@@ -5696,6 +5728,8 @@ PUBLIC FILE *LYOpenTemp ARGS3(
 	StrAllocCopy((p->name), result);
 	p->file = fp;
 	ly_temp = p;
+    } else {
+	outofmem(__FILE__, "LYOpenTemp");
     }
 
     CTRACE(tfp, "... LYOpenTemp(%s)\n", result);
@@ -5741,6 +5775,8 @@ PUBLIC FILE *LYOpenScratch ARGS2(
 	    StrAllocCopy((p->name), result);
 	    p->file = fp;
 	    ly_temp = p;
+	} else {
+	    outofmem(__FILE__, "LYOpenScratch");
 	}
     }
     CTRACE(tfp, "LYOpenScratch(%s)\n", result);
diff --git a/src/LYUtils.h b/src/LYUtils.h
index 21a2875e..6652e58c 100644
--- a/src/LYUtils.h
+++ b/src/LYUtils.h
@@ -65,6 +65,7 @@ extern char *LYSysShell NOPARAMS;
 extern char *LYgetXDisplay NOPARAMS;
 extern char *strip_trailing_slash PARAMS((char * my_dirname));
 extern char *wwwName PARAMS((CONST char *pathname));
+extern int LYConsoleInputFD PARAMS((BOOLEAN need_selectable));
 extern int HTCheckForInterrupt NOPARAMS;
 extern int LYCheckForProxyURL PARAMS((char *filename));
 extern int LYCopyFile PARAMS((char *src, char *dst));
diff --git a/src/LYrcFile.c b/src/LYrcFile.c
index d3540ec8..af1f9041 100644
--- a/src/LYrcFile.c
+++ b/src/LYrcFile.c
@@ -17,12 +17,24 @@
 #define FNAME_LYNXRC ".lynxrc"
 #endif /* FNAMES_8_3 */
 
+#define FIND_KEYWORD(cp, keyword) \
+    ((cp = LYstrstr(line_buffer, keyword)) != NULL && \
+     (cp - line_buffer) < number_sign)
+
+PRIVATE char *SkipEquals ARGS1(char *, src)
+{
+    char *tmp;
+    if ((tmp = (char *)strchr(src, '=')) != NULL)
+	src = tmp + 1;
+    return LYSkipBlanks(src);
+}
+
 PUBLIC void read_rc NOPARAMS
 {
     char line_buffer[LINESIZE];
     char rcfile[LY_MAXPATH];
     FILE *fp;
-    char *cp, *cp2;
+    char *cp;
     int number_sign;
     char MBM_line[256];
     int  MBM_counter;
@@ -73,24 +85,17 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  File editor.
 	 */
-	if (!system_editor &&
-	    (cp = LYstrstr(line_buffer, "file_editor")) != NULL &&
-	    cp-line_buffer < number_sign) {
+	if (!system_editor && FIND_KEYWORD(cp, "file_editor")) {
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    StrAllocCopy(editor, cp);
 
 	/*
 	 *  Default bookmark file.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "bookmark_file")) != NULL &&
-		    cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "bookmark_file")) {
 
-	    if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 
 	    /*
 	     *  Since this is the "Default Bookmark File", we save it
@@ -104,12 +109,9 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Multiple (sub)bookmark support settings.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "sub_bookmarks")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "sub_bookmarks")) {
 
-	   if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = (cp2 + 1);
-	   cp = LYSkipBlanks(cp);
+	   cp = SkipEquals(cp);
 	   if (!strncasecomp(cp, "standard", 8)) {
 	      LYMultiBookmarks = TRUE;
 	      LYMBMAdvanced = FALSE;
@@ -123,8 +125,7 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Multiple (sub)bookmark definitions and descriptions.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "multi_bookmark")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "multi_bookmark")) {
 
 	    /*
 	     *  Found the root, now cycle through all the
@@ -134,8 +135,7 @@ PUBLIC void read_rc NOPARAMS
 		 MBM_counter <= MBM_V_MAXFILES; MBM_counter++) {
 		sprintf(MBM_line, "multi_bookmark%c", (MBM_counter + 'A'));
 
-		if ((cp = LYstrstr(line_buffer, MBM_line)) != NULL &&
-		    cp-line_buffer < number_sign) {
+		if (FIND_KEYWORD(cp, MBM_line)) {
 		    if ((MBM_cp1 = (char *)strchr(cp, '=')) == NULL) {
 			break;
 		    } else {
@@ -193,13 +193,9 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  FTP/file sorting method.
 	 */
-	} else if ((cp = LYstrstr(line_buffer,
-				  "file_sorting_method")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "file_sorting_method")) {
 
-	   if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	   cp = LYSkipBlanks(cp);
+	   cp = SkipEquals(cp);
 	   if (!strncasecomp(cp, "BY_FILENAME", 11))
 		HTfileSortMethod = FILE_BY_NAME;
 	   else if (!strncasecomp(cp, "BY_TYPE", 7))
@@ -212,25 +208,17 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Personal mail address.
 	 */
-	} else if ((cp = LYstrstr(line_buffer,
-				  "personal_mail_address")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "personal_mail_address")) {
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    StrAllocCopy(personal_mail_address, cp);
 
 	/*
 	 *  Searching type.
 	 */
-	} else if ((cp = LYstrstr(line_buffer,
-				  "case_sensitive_searching")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "case_sensitive_searching")) {
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    if (!strncasecomp(cp, "on", 2))
 		case_sensitive = TRUE;
 	    else
@@ -239,14 +227,11 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Character set.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "character_set")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "character_set")) {
 
 	    int i = 0;
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 
 	    i = UCGetLYhndl_byAnyName(cp); /* by MIME or full name */
 	    if (i < 0)
@@ -257,36 +242,25 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Preferred language.
 	 */
-	} else if ((cp = LYstrstr(line_buffer,
-				  "preferred_language")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "preferred_language")) {
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    StrAllocCopy(language, cp);
 
 	/*
 	 *  Preferred charset.
 	 */
-	} else if ((cp = LYstrstr(line_buffer,
-				  "preferred_charset")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "preferred_charset")) {
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    StrAllocCopy(pref_charset, cp);
 
 	/*
 	 *  VI keys.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "vi_keys")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "vi_keys")) {
 
-	    if ((cp2 = (char * )strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    if (!strncasecomp(cp, "on", 2))
 		vi_keys = TRUE;
 	    else
@@ -295,12 +269,9 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  EMACS keys.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "emacs_keys")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "emacs_keys")) {
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    if (!strncasecomp(cp, "on", 2))
 		emacs_keys = TRUE;
 	    else
@@ -309,12 +280,9 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Show dot files.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "show_dotfiles")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "show_dotfiles")) {
 
-	    if ((cp2 = (char * )strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    if (!strncasecomp(cp, "on", 2))
 		show_dotfiles = TRUE;
 	    else
@@ -323,12 +291,9 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Show color.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "show_color")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "show_color")) {
 
-	    if ((cp2 = (char * )strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    if (!strncasecomp(cp, "always", 6)) {
 		LYrcShowColor = SHOW_COLOR_ALWAYS;
 #if defined(USE_SLANG) || defined(COLOR_CURSES)
@@ -346,12 +311,9 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Select popups.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "select_popups")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "select_popups")) {
 
-	    if ((cp2 = (char * )strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    if (!strncasecomp(cp, "off", 3))
 		LYSelectPopups = FALSE;
 	    else
@@ -360,12 +322,9 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Show cursor.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "show_cursor")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "show_cursor")) {
 
-	    if ((cp2 = (char * )strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    if (!strncasecomp(cp, "off", 3))
 		LYShowCursor = FALSE;
 	    else
@@ -374,12 +333,9 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Keypad mode.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "keypad_mode")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "keypad_mode")) {
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    if (LYstrstr(cp, "LINKS_ARE_NUMBERED"))
 		keypad_mode = LINKS_ARE_NUMBERED;
 	    else if (LYstrstr(cp, "LINKS_AND_FORM_FIELDS_ARE_NUMBERED"))
@@ -391,14 +347,11 @@ PUBLIC void read_rc NOPARAMS
 	 *  Keyboard layout.
 	 */
 #ifdef EXP_KEYBOARD_LAYOUT
-	} else if ((cp = LYstrstr(line_buffer, "kblayout")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "kblayout")) {
 
 	    int i = 0;
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    for (; LYKbLayoutNames[i]; i++) {
 		if (!strcmp(cp, LYKbLayoutNames[i])) {
 		    current_layout = i;
@@ -410,14 +363,11 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Line edit mode.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "lineedit_mode")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "lineedit_mode")) {
 
 	    int i = 0;
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    for (; LYLineeditNames[i]; i++) {
 		if (!strncmp(cp, LYLineeditNames[i], strlen(cp))) {
 		    current_lineedit = i;
@@ -429,12 +379,9 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Directory list style.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "dir_list_style")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "dir_list_style")) {
 
-	    if ((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    if (LYstrstr(cp, "FILES_FIRST") != NULL) {
 		dir_list_style = FILES_FIRST;
 	    } else if (LYstrstr(cp,"DIRECTORIES_FIRST") != NULL) {
@@ -447,12 +394,8 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Accept cookies from all domains?
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "accept_all_cookies")) != NULL &&
-		   cp-line_buffer < number_sign) {
-	    if((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2 + 1;
-	    while (isspace(*cp))
-		cp++; /* get rid of spaces */
+	} else if (FIND_KEYWORD(cp, "accept_all_cookies")) {
+	    cp = SkipEquals(cp);
 	    if (LYstrstr(cp,"TRUE") != NULL) {
 		LYAcceptAllCookies = TRUE;
 	    } else {
@@ -463,49 +406,65 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Accept all cookies from certain domains?
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "cookie_accept_domains"))
-		!= NULL && cp-line_buffer < number_sign) {
-	    if((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2 + 1;
-	    while (isspace(*cp))
-		cp++; /* get rid of spaces */
+	} else if (FIND_KEYWORD(cp, "cookie_accept_domains")) {
+	    cp = SkipEquals(cp);
 	    cookie_add_acceptlist(cp);
+	    if(LYCookieAcceptDomains != NULL) { 
+		StrAllocCat(LYCookieAcceptDomains, ","); 
+	    } 
+	    StrAllocCat(LYCookieAcceptDomains, cp); 
 
 
 	/*
 	 *  Reject all cookies from certain domains?
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "cookie_reject_domains"))
-		!= NULL && cp-line_buffer < number_sign) {
-	    if((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2 + 1;
-	    while (isspace(*cp))
-		cp++; /* get rid of spaces */
+	} else if (FIND_KEYWORD(cp, "cookie_reject_domains")) {
+	    cp = SkipEquals(cp);
 	    cookie_add_rejectlist(cp);
+	    if(LYCookieRejectDomains != NULL) { 
+		StrAllocCat(LYCookieRejectDomains, ","); 
+	    } 
+	    StrAllocCat(LYCookieRejectDomains, cp); 
+
+	/*
+	 *  Cookie domains to perform loose checks?
+	 */
+	} else if (FIND_KEYWORD(cp, "cookie_loose_invalid_domains")) {
+	    cp = SkipEquals(cp);
+	    StrAllocCopy(LYCookieLooseCheckDomains, cp);
+	    cookie_set_invcheck(LYCookieLooseCheckDomains, INVCHECK_LOOSE);
+
+	/*
+	 *  Cookie domains to perform strict checks?
+	 */
+	} else if (FIND_KEYWORD(cp, "cookie_strict_invalid_domains")) {
+	    cp = SkipEquals(cp);
+	    StrAllocCopy(LYCookieStrictCheckDomains, cp);
+	    cookie_set_invcheck(LYCookieStrictCheckDomains, INVCHECK_STRICT);
 
-#ifdef EXP_PERSISTENT_COOKIES
 	/*
-	 *  File to store cookies in.
+	 *  Cookie domains to query user over invalid cookies?
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "cookie_file"))
-		!= NULL && cp-line_buffer < number_sign) {
-	    if((cp2 = (char *)strchr(cp,'=')) != NULL)
-		cp = cp2 + 1;
-	    while (isspace(*cp))
-		cp++; /* get rid of spaces */
+	} else if (FIND_KEYWORD(cp, "cookie_query_invalid_domains")) {
+	    cp = SkipEquals(cp);
+	    StrAllocCopy(LYCookieQueryCheckDomains, cp);
+	    cookie_set_invcheck(LYCookieQueryCheckDomains, INVCHECK_QUERY);
 
+#ifdef EXP_PERSISTENT_COOKIES
+	/*
+	 *  File in which to store persistent cookies. 
+	 */
+	} else if (FIND_KEYWORD(cp, "cookie_file")) {
+	    cp = SkipEquals(cp);
 	    StrAllocCopy(LYCookieFile, cp);
 #endif /* EXP_PERSISTENT_COOKIES */
 
 	/*
 	 *  User mode.
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "user_mode")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "user_mode")) {
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    if (LYstrstr(cp, "ADVANCED") != NULL) {
 		user_mode = ADVANCED_MODE;
 	    } else if (LYstrstr(cp,"INTERMEDIATE") != NULL) {
@@ -518,13 +477,9 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Local execution mode - all links.
 	 */
-	} else if ((cp = LYstrstr(line_buffer,
-				  "run_all_execution_links")) != NULL &&
-		   cp-line_buffer < number_sign) {
+	} else if (FIND_KEYWORD(cp, "run_all_execution_links")) {
 
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	    cp = SkipEquals(cp);
 	    if (!strncasecomp(cp, "on", 2))
 		local_exec = TRUE;
 	     else
@@ -535,11 +490,8 @@ PUBLIC void read_rc NOPARAMS
 	 *  Partial display logic--set the threshold # of lines before
 	 *  Lynx redraws the screen
 	 */
-	} else if ((cp = LYstrstr(line_buffer, "partial_thres")) != NULL &&
-		   cp-line_buffer < number_sign) {
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-	        cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	} else if (FIND_KEYWORD(cp, "partial_thres")) {
+	    cp = SkipEquals(cp);
 	    if (atoi(cp) != 0)
 	        partial_threshold = atoi(cp);
 #endif /* DISP_PARTIAL */
@@ -547,26 +499,16 @@ PUBLIC void read_rc NOPARAMS
 	/*
 	 *  Local execution mode - only links in local files.
 	 */
-	} else if ((cp = LYstrstr(line_buffer,
-			"run_execution_links_on_local_files")) != NULL &&
-		   cp-line_buffer < number_sign) {
-
-	    if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	    cp = LYSkipBlanks(cp);
+	} else if (FIND_KEYWORD(cp, "run_execution_links_on_local_files")) {
+	    cp = SkipEquals(cp);
 	    if (!strncasecomp(cp, "on", 2))
 		local_exec_on_local_files = TRUE;
 	    else
 		local_exec_on_local_files=FALSE;
 #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */
 
-	} else if ((cp = LYstrstr(line_buffer,
-				  "verbose_images")) != NULL &&
-		   cp-line_buffer < number_sign) {
-
-	   if ((cp2 = (char *)strchr(cp, '=')) != NULL)
-		cp = cp2 + 1;
-	   cp = LYSkipBlanks(cp);
+	} else if (FIND_KEYWORD(cp, "verbose_images")) {
+	   cp = SkipEquals(cp);
 	   if (!strncasecomp(cp, "on", 2))
 		verbose_img = 1;
 	   else if (!strncasecomp(cp, "off", 3))
@@ -960,14 +902,29 @@ PUBLIC int save_rc NOPARAMS
 # override any settings made here.  If a single domain is specified in\n\
 # both cookie_accept_domains and in cookie_reject_domains, the rejection\n\
 # will take precedence.\n"));
-    fprintf(fp, "# cookie_accept_domains=\n");
-    fprintf(fp, "# cookie_reject_domains=\n\n");
+    fprintf(fp, "cookie_accept_domains=%s\n", 
+		    (LYCookieAcceptDomains == NULL ? ""  
+		    : LYCookieAcceptDomains)); 
+    fprintf(fp, "cookie_reject_domains=%s\n\n", 
+		    (LYCookieRejectDomains == NULL ? ""  
+		    : LYCookieRejectDomains)); 
+
+
+    fprintf(fp, gettext("\
+# cookie_loose_invalid_domains, cookie_strict_invalid_domains, and\n\
+# cookie_query_invalid_domains control checking incoming cookies'\n\
+# conformance to RFCNNNN.\n\
+# XXX FIXME\n"));
+    fprintf(fp, "cookie_loose_invalid_domains=%s\n",
+	    (LYCookieLooseCheckDomains == NULL) ? ""
+		    : LYCookieLooseCheckDomains);
+    fprintf(fp, "cookie_strict_invalid_domains=%s\n",
+	    (LYCookieStrictCheckDomains == NULL) ? ""
+		    : LYCookieStrictCheckDomains);
+    fprintf(fp, "cookie_query_invalid_domains=%s\n\n",
+	    (LYCookieQueryCheckDomains == NULL) ? ""
+		    : LYCookieQueryCheckDomains);
 
-    /*
-     *  cookie_accept_domains and cookie_reject_domains not set here because
-     *  there's not currently a method on the options menu (maybe later?)
-     *  to set them.
-     */
 
 #ifdef EXP_PERSISTENT_COOKIES
     /*
@@ -980,6 +937,8 @@ PUBLIC int save_rc NOPARAMS
 		(LYCookieFile == NULL ? "~/.lynx_cookies" : LYCookieFile));
 #endif /* EXP_PERSISTENT_COOKIES */
 
+
+
 #if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS)
     /*
      *  Local execution mode - all links.
diff --git a/src/UCdomap.c b/src/UCdomap.c
index 36b8b5de..b9f50f8b 100644
--- a/src/UCdomap.c
+++ b/src/UCdomap.c
@@ -67,6 +67,9 @@
 #include <rfc_suni.h>		/* RFC 1345 w/o Intro	*/
 #include <utf8_uni.h>		/* UNICODE UTF 8	*/
 #include <viscii_uni.h> 	/* Vietnamese (VISCII)	*/
+#include <iso9945_uni.h>	/* Ukrainian Cyrillic (ISO 9945-2) */
+#include <cp866u_uni.h>		/* Ukrainian Cyrillic (866) */
+#include <koi8u_uni.h>		/* Ukrainian Cyrillic (koi8-u */
 #ifdef NOTDEFINED
 #include <mnem_suni.h>
 #endif /* NOTDEFINED */
@@ -2054,6 +2057,9 @@ PUBLIC void UCInit NOARGS
     UC_CHARSET_SETUP_utf_8;		  /* UNICODE UTF-8	  */
     UC_CHARSET_SETUP_mnemonic_ascii_0;	  /* RFC 1345 w/o Intro   */
     UC_CHARSET_SETUP_mnemonic;		  /* RFC 1345 Mnemonic	  */
+    UC_CHARSET_SETUP_iso_9945_2;	  /* Ukrainian Cyrillic (ISO 9945-2) */
+    UC_CHARSET_SETUP_cp866u;		  /* Ukrainian Cyrillic (866) */
+    UC_CHARSET_SETUP_koi8_u;		  /* Ukrainian Cyrillic (koi8-u) */
 #ifdef NOTDEFINED
     UC_CHARSET_SETUP_mnem;
 #endif /* NOTDEFINED */
diff --git a/src/chrtrans/MAKEW32.BAT b/src/chrtrans/MAKEW32.BAT
index 48b26f97..4fe285f4 100644
--- a/src/chrtrans/MAKEW32.BAT
+++ b/src/chrtrans/MAKEW32.BAT
@@ -17,6 +17,7 @@ makeuctb cp852_uni.tbl > cp852_uni.h
 makeuctb cp862_uni.tbl > cp862_uni.h
 makeuctb cp864_uni.tbl > cp864_uni.h
 makeuctb cp866_uni.tbl > cp866_uni.h
+makeuctb cp866u_uni.tbl > cp866u_uni.h
 makeuctb cp869_uni.tbl > cp869_uni.h
 makeuctb def7_uni.tbl  > def7_uni.h
 makeuctb dmcs_uni.tbl > dmcs_uni.h
@@ -32,10 +33,12 @@ makeuctb iso08_uni.tbl > iso08_uni.h
 makeuctb iso09_uni.tbl > iso09_uni.h
 makeuctb iso10_uni.tbl > iso10_uni.h
 makeuctb iso15_uni.tbl > iso15_uni.h 
+makeuctb iso9945_uni.tbl > iso9945_uni.h
 makeuctb koi8r_uni.tbl > koi8r_uni.h
+makeuctb koi8u_uni.tbl > koi8u_uni.h
 makeuctb mac_uni.tbl > mac_uni.h
-makeuctb mnem_suni.tbl > mnem_suni.h
 makeuctb mnem2_suni.tbl > mnem2_suni.h
+makeuctb mnem_suni.tbl > mnem_suni.h
 makeuctb next_uni.tbl > next_uni.h
 makeuctb rfc_suni.tbl > rfc_suni.h
 makeuctb utf8_uni.tbl > utf8_uni.h
diff --git a/src/chrtrans/build-chrtrans.com b/src/chrtrans/build-chrtrans.com
index b0089033..df565522 100644
--- a/src/chrtrans/build-chrtrans.com
+++ b/src/chrtrans/build-chrtrans.com
@@ -114,10 +114,14 @@ $ define/user sys$output 'CHRwhere'iso05_uni.h	!ISO 8859-5 Cyrillic
 $ makeuctb iso05_uni.tbl
 $ define/user sys$output 'CHRwhere'cp866_uni.h	!DosCyrillic (cp866)
 $ makeuctb cp866_uni.tbl
+$ define/user sys$output 'CHRwhere'cp866u_uni.h	!Ukrainian Cyrillic
+$ makeuctb cp866u_uni.tbl
 $ define/user sys$output 'CHRwhere'cp1251_uni.h	!WinCyrillic (cp1251)
 $ makeuctb cp1251_uni.tbl
 $ define/user sys$output 'CHRwhere'koi8r_uni.h	!KOI8-R Cyrillic
 $ makeuctb koi8r_uni.tbl
+$ define/user sys$output 'CHRwhere'koi8u_uni.h	!KOI8-U Ukranian Cyrillic
+$ makeuctb koi8u_uni.tbl
 $ define/user sys$output 'CHRwhere'iso06_uni.h	!ISO 8859-6 Arabic
 $ makeuctb iso06_uni.tbl
 $ define/user sys$output 'CHRwhere'cp864_uni.h	!DosArabic (cp864)
@@ -136,6 +140,8 @@ $ define/user sys$output 'CHRwhere'iso08_uni.h	!ISO 8859-8 Hebrew
 $ makeuctb iso08_uni.tbl
 $ define/user sys$output 'CHRwhere'cp862_uni.h	!DosHebrew (cp862)
 $ makeuctb cp862_uni.tbl
+$ define/user sys$output 'CHRwhere'iso9945_uni.h !Ukranian
+$ makeuctb iso9945_uni.tbl
 $ define/user sys$output 'CHRwhere'cp1255_uni.h	!WinHebrew (cp1255)
 $ makeuctb cp1255_uni.tbl
 $ define/user sys$output 'CHRwhere'iso09_uni.h	!ISO 8859-9 (Latin 5)
diff --git a/src/chrtrans/cp866u_uni.tbl b/src/chrtrans/cp866u_uni.tbl
new file mode 100644
index 00000000..0b14123e
--- /dev/null
+++ b/src/chrtrans/cp866u_uni.tbl
@@ -0,0 +1,158 @@
+#
+#The MIME name of this charset. 
+Mcp866u
+
+#Name as a Display Charset (used on Options screen)
+OUkrainian Cyrillic (cp866u)
+
+#Codepage number
+#?
+
+#
+#    Name:     cp866_DOSCyrillicUkrainian to Unicode table
+#    Unicode version: 2.0
+#    Table version: 2.00
+#    Table format:  Format A
+#    General notes: based on Cyrillic (cp866) table.
+#                   Original file: cp866_uni.tbl (authors: 
+#                           Lori Brownell <loribr@microsoft.com>
+#                           K.D. Chang    <a-kchang@microsoft.com>
+#
+#    Format: Three tab-separated columns
+#        Column #1 is the cp866_DOSCyrillicUkrainian 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_DOSCyrillicUkrainian order
+#
+0x20-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+0490  #CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+0xf3    U+0491  #CYRILLIC SMALL LETTER GHE WITH UPTURN
+0xf4    U+0404  #CYRILLIC CAPITAL LETTER UKRAINIAN IE
+0xf5    U+0454  #CYRILLIC SMALL LETTER UKRAINIAN IE
+0xf6    U+0406  #CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+0xf7    U+0456  #CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+0xf8    U+0407  #CYRILLIC CAPITAL LETTER YI
+0xf9    U+0457  #CYRILLIC SMALL LETTER YI
+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
+
diff --git a/src/chrtrans/iso9945_uni.tbl b/src/chrtrans/iso9945_uni.tbl
new file mode 100644
index 00000000..100ae92c
--- /dev/null
+++ b/src/chrtrans/iso9945_uni.tbl
@@ -0,0 +1,178 @@
+#The MIME name of this charset.
+Miso-9945-2
+
+#Name as a Display Charset (used on Options screen)
+OUkrainian (ISO-9945-2)
+
+#Codepage number
+#?
+
+#
+#	Name:             ISO 9945-2 (1998) to Unicode
+#	Unicode version:  1.0
+#	Table version:    0.1
+#	Table format:     Format A
+#	Date:             16 January 1995
+#	Authors:          Tim Greenwood <greenwood@r2me2.enet.dec.com>
+#                     John H. Jenkins <John_Jenkins@taligent.com>
+#
+#	Copyright (c) 1991-1995 Unicode, Inc.  All Rights reserved.
+#
+#	This file is provided as-is by Unicode, Inc. (The Unicode Consortium).
+#	No claims are made as to fitness for any particular purpose.  No
+#	warranties of any kind are expressed or implied.  The recipient
+#	agrees to determine applicability of information provided.  If this
+#	file has been provided on magnetic media by Unicode, Inc., the sole
+#	remedy for any claim will be exchange of defective media within 90
+#	days of receipt.
+#
+#	Recipient is granted the right to make copies in any form for
+#	internal distribution and to freely use the information supplied
+#	in the creation of products supporting Unicode.  Unicode, Inc.
+#	specifically excludes the right to re-distribute this file directly
+#	to third parties or other organizations whether for profit or not.
+#
+#	General notes:
+#
+#	This table contains the data the Unicode Consortium has on how
+#       ISO 8859-2 (1987) characters map into Unicode.
+#
+#	Format:  Three tab-separated columns
+#		 Column #1 is the ISO 8859-2 code (in hex as 0xXX)
+#		 Column #2 is the Unicode (in hex as 0xXXXX)
+#		 Column #3 the Unicode name (follows a comment sign, '#')
+#
+#	The entries are in ISO 8859-2 order
+#
+#	Any comments or problems, contact <John_Jenkins@taligent.com>
+#
+0x20-0x7e idem
+#
+0x80 U+2500 # BOX DRAWINGS LIGHT HORIZONTAL
+0x81 U+2502 # BOX DRAWINGS LIGHT VERTICAL
+0x82 U+250C # BOX DRAWINGS LIGHT DOWN AND RIGHT
+0x83 U+2510 # BOX DRAWINGS LIGHT DOWN AND LEFT
+0x84 U+2514 # BOX DRAWINGS LIGHT UP AND RIGHT
+0x85 U+2518 # BOX DRAWINGS LIGHT UP AND LEFT
+0x86 U+251C # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+0x87 U+2524 # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+0x88 U+252C # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+0x89 U+2534 # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+0x8A U+253C # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+0x8B U+2580 # UPPER HALF BLOCK
+0x8C U+2584 # LOWER HALF BLOCK
+0x8D U+2588 # FULL BLOCK
+0x8E U+258C # LEFT HALF BLOCK
+0x8F U+2590 # RIGHT HALF BLOCK
+0x90 U+2591 # LIGHT SHADE
+0x91 U+2592 # MEDIUM SHADE
+0x92 U+2593 # DARK SHADE
+0x93 U+201C # LEFT DOUBLE QUOTATION MARK
+0x94 U+25A0 # BLACK SQUARE
+0x95 U+2022 # BULLET
+0x96 U+201D # RIGHT DOUBLE QUOTATION MARK
+0x97 U+2014 # EM DASH
+0x98 U+00AC # NOT SIGN
+0x99 U+2122 # TRADE MARK SIGN
+0x9A U+00A0 # NO-BREAK SPACE
+0x9B U+00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+0x9C U+00AE # REGISTERED SIGN
+0x9D U+00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+0x9E U+00B7 # MIDDLE DOT
+0x9F U+00A4 # CURRENCY SIGN
+0xA0 U+2550 # BOX DRAWINGS DOUBLE HORIZONTAL
+0xA1 U+2551 # BOX DRAWINGS DOUBLE VERTICAL
+0xA2 U+2552 # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+0xA3 U+0451 # CYRILLIC SMALL LETTER IO
+0xA4 U+0454 # CYRILLIC SMALL LETTER UKRAINIAN IE
+0xA5 U+2554 # BOX DRAWINGS DOUBLE DOWN AND RIGHT
+0xA6 U+0456 # CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+0xA7 U+0457 # CYRILLIC SMALL LETTER YI (Ukrainian)
+0xA8 U+2557 # BOX DRAWINGS DOUBLE DOWN AND LEFT
+0xA9 U+2558 # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+0xAA U+2559 # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+0xAB U+255A # BOX DRAWINGS DOUBLE UP AND RIGHT
+0xAC U+255B # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+0xAD U+0491 # CYRILLIC SMALL LETTER GHE WITH UPTURN
+0xAE U+256C # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+0xAF U+255E # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+0xB0 U+255F # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+0xB1 U+2560 # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+0xB2 U+2561 # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+0xB3 U+0401 # CYRILLIC CAPITAL LETTER IO
+0xB4 U+0403 # CYRILLIC CAPITAL LETTER UKRAINIAN IE
+0xB5 U+2563 # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+0xB6 U+0406 # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+0xB7 U+0407 # CYRILLIC CAPITAL LETTER YI (Ukrainian)
+0xB8 U+2566 # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+0xB9 U+2567 # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+0xBA U+2568 # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+0xBB U+2569 # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+0xBC U+256A # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+0xBD U+0490 # CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+0xBE U+255A # BOX DRAWINGS DOUBLE UP AND RIGHT
+0xBF U+00A9 # COPYRIGHT SIGN
+0xC0 U+044E # CYRILLIC SMALL LETTER YU
+0xC1 U+0430 # CYRILLIC SMALL LETTER A
+0xC2 U+0431 # CYRILLIC SMALL LETTER BE
+0xC3 U+0446 # CYRILLIC SMALL LETTER TSE
+0xC4 U+0434 # CYRILLIC SMALL LETTER DE
+0xC5 U+0435 # CYRILLIC SMALL LETTER IE
+0xC6 U+0444 # CYRILLIC SMALL LETTER EF
+0xC7 U+0433 # CYRILLIC SMALL LETTER GHE
+0xC8 U+0445 # CYRILLIC SMALL LETTER HA
+0xC9 U+0438 # CYRILLIC SMALL LETTER I
+0xCA U+0439 # CYRILLIC SMALL LETTER SHORT I
+0xCB U+043A # CYRILLIC SMALL LETTER KA
+0xCC U+043B # CYRILLIC SMALL LETTER EL
+0xCD U+043C # CYRILLIC SMALL LETTER EM
+0xCE U+043D # CYRILLIC SMALL LETTER EN
+0xCF U+043E # CYRILLIC SMALL LETTER O
+0xD0 U+043F # CYRILLIC SMALL LETTER PE
+0xD1 U+044F # CYRILLIC SMALL LETTER YA
+0xD2 U+0440 # CYRILLIC SMALL LETTER ER
+0xD3 U+0441 # CYRILLIC SMALL LETTER ES
+0xD4 U+0442 # CYRILLIC SMALL LETTER TE
+0xD5 U+0443 # CYRILLIC SMALL LETTER U
+0xD6 U+0436 # CYRILLIC SMALL LETTER ZHE
+0xD7 U+0432 # CYRILLIC SMALL LETTER VE
+0xD8 U+044C # CYRILLIC SMALL LETTER SOFT SIGN
+0xD9 U+044B # CYRILLIC SMALL LETTER YERU
+0xDA U+0437 # CYRILLIC SMALL LETTER ZE
+0xDB U+0448 # CYRILLIC SMALL LETTER SHA
+0xDC U+044D # CYRILLIC SMALL LETTER E
+0xDD U+0449 # CYRILLIC SMALL LETTER SHCHA
+0xDE U+0447 # CYRILLIC SMALL LETTER CHE
+0xDF U+044A # CYRILLIC SMALL LETTER HARD SIGN
+0xE0 U+042E # CYRILLIC CAPITAL LETTER YU
+0xE1 U+0410 # CYRILLIC CAPITAL LETTER A
+0xE2 U+0411 # CYRILLIC CAPITAL LETTER BE
+0xE3 U+0426 # CYRILLIC CAPITAL LETTER TSE
+0xE4 U+0414 # CYRILLIC CAPITAL LETTER DE
+0xE5 U+0415 # CYRILLIC CAPITAL LETTER IE
+0xE6 U+0424 # CYRILLIC CAPITAL LETTER EF
+0xE7 U+0413 # CYRILLIC CAPITAL LETTER GHE
+0xE8 U+0425 # CYRILLIC CAPITAL LETTER HA
+0xE9 U+0418 # CYRILLIC CAPITAL LETTER I
+0xEA U+0419 # CYRILLIC CAPITAL LETTER SHORT I
+0xEB U+041A # CYRILLIC CAPITAL LETTER KA
+0xEC U+041B # CYRILLIC CAPITAL LETTER EL
+0xED U+041C # CYRILLIC CAPITAL LETTER EM
+0xEE U+041D # CYRILLIC CAPITAL LETTER EN
+0xEF U+041E # CYRILLIC CAPITAL LETTER O
+0xF0 U+041F # CYRILLIC CAPITAL LETTER PE
+0xF1 U+042F # CYRILLIC CAPITAL LETTER YA
+0xF2 U+0420 # CYRILLIC CAPITAL LETTER ER
+0xF3 U+0421 # CYRILLIC CAPITAL LETTER ES
+0xF4 U+0422 # CYRILLIC CAPITAL LETTER TE
+0xF5 U+0423 # CYRILLIC CAPITAL LETTER U
+0xF6 U+0416 # CYRILLIC CAPITAL LETTER ZHE
+0xF7 U+0412 # CYRILLIC CAPITAL LETTER VE
+0xF8 U+042C # CYRILLIC CAPITAL LETTER SOFT SIGN
+0xF9 U+042B # CYRILLIC CAPITAL LETTER YERU
+0xFA U+0417 # CYRILLIC CAPITAL LETTER ZE
+0xFB U+0428 # CYRILLIC CAPITAL LETTER SHA
+0xFC U+042D # CYRILLIC CAPITAL LETTER E
+0xFD U+0429 # CYRILLIC CAPITAL LETTER SHCHA
+0xFE U+0427 # CYRILLIC CAPITAL LETTER CHE
+0xFF U+042A # CYRILLIC CAPITAL LETTER HARD SIGN
diff --git a/src/chrtrans/koi8u_uni.tbl b/src/chrtrans/koi8u_uni.tbl
new file mode 100644
index 00000000..e3458dba
--- /dev/null
+++ b/src/chrtrans/koi8u_uni.tbl
@@ -0,0 +1,144 @@
+# Options screen name for this character set
+OUkrainian Cyrillic (KOI8-U)
+
+# MIME name for this charset
+Mkoi8-u
+
+#Codepage number
+#?
+
+0x20-0x7f       idem
+# Based on a table received from "Denis V. Dmitrienko" <denis@null.net>
+# (verified against RFC2319).
+# KOI8-U home page: <http://www.net.ua/KOI8-U>
+#
+#hex unicode # description     
+#--- U+---- # ---------------     
+0x80 U+2500 # BOX DRAWINGS  LIGHT HORIZONTAL
+0x81 U+2502 # BOX DRAWINGS  LIGHT VERTICAL
+0x82 U+250C # BOX DRAWINGS  LIGHT DOWN AND RIGHT
+0x83 U+2510 # BOX DRAWINGS  LIGHT DOWN AND LEFT
+0x84 U+2514 # BOX DRAWINGS  LIGHT UP AND RIGHT
+0x85 U+2518 # BOX DRAWINGS  LIGHT UP AND LEFT
+0x86 U+251C # BOX DRAWINGS  LIGHT VERTICAL AND RIGHT
+0x87 U+2524 # BOX DRAWINGS  LIGHT VERTICAL AND LEFT
+0x88 U+252C # BOX DRAWINGS  LIGHT DOWN AND HORIZONTAL
+0x89 U+2534 # BOX DRAWINGS  LIGHT UP AND HORIZONTAL
+0x8A U+253C # BOX DRAWINGS  LIGHT VERTICAL AND HORIZONTAL
+0x8B U+2580 # UPPER HALF BLOCK
+0x8C U+2584 # LOWER HALF BLOCK
+0x8D U+2588 # FULL BLOCK
+0x8E U+258C # LEFT HALF BLOCK
+0x8F U+2590 # RIGHT HALF BLOCK
+0x90 U+2591 # LIGHT SHADE
+0x91 U+2592 # MEDIUM SHADE
+0x92 U+2593 # DARK SHADE
+0x93 U+2320 # TOP HALF INTEGRAL
+0x94 U+25A0 # BLACK SQUARE
+0x95 U+2219 # BULLET OPERATOR
+0x96 U+221A # SQUARE ROOT
+0x97 U+2248 # ALMOST EQUAL TO
+0x98 U+2264 # LESS THAN OR EQUAL TO
+0x99 U+2265 # GREATER THAN OR EQUAL TO
+0x9A U+00A0 # NO-BREAK SPACE
+0x9B U+2321 # BOTTOM HALF INTEGRAL
+0x9C U+00B0 # DEGREE SIGN
+0x9D U+00B2 # SUPERSCRIPT TWO
+0x9E U+00B7 # MIDDLE DOT
+0x9F U+00F7 # DIVISION SIGN
+0xA0 U+2550 # BOX DRAWINGS  DOUBLE HORIZONTAL
+0xA1 U+2551 # BOX DRAWINGS  DOUBLE VERTICAL
+0xA2 U+2552 # BOX DRAWINGS  DOWN SINGLE AND RIGHT DOUBLE
+0xA3 U+0451 # CYRILLIC SMALL LETTER IO
+0xA4 U+0454 # CYRILLIC SMALL LETTER UKRAINIAN IE
+0xA5 U+2554 # BOX DRAWINGS  DOUBLE DOWN AND RIGHT
+0xA6 U+0456 # CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+0xA7 U+0457 # CYRILLIC SMALL LETTER YI (UKRAINIAN)
+0xA8 U+2557 # BOX DRAWINGS  DOUBLE DOWN AND LEFT
+0xA9 U+2558 # BOX DRAWINGS  UP SINGLE AND RIGHT DOUBLE
+0xAA U+2559 # BOX DRAWINGS  UP DOUBLE AND RIGHT SINGLE
+0xAB U+255A # BOX DRAWINGS  DOUBLE UP AND RIGHT
+0xAC U+255B # BOX DRAWINGS  UP SINGLE AND LEFT DOUBLE
+0xAD U+0491 # CYRILLIC SMALL LETTER GHE WITH UPTURN
+0xAE U+255D # BOX DRAWINGS  DOUBLE UP AND LEFT
+0xAF U+255E # BOX DRAWINGS  VERTICAL SINGLE AND RIGHT DOUBLE
+0xB0 U+255F # BOX DRAWINGS  VERTICAL DOUBLE AND RIGHT SINGLE
+0xB1 U+2560 # BOX DRAWINGS  DOUBLE VERTICAL AND RIGHT
+0xB2 U+2561 # BOX DRAWINGS  VERTICAL SINGLE AND LEFT DOUBLE
+0xB3 U+0401 # CYRILLIC CAPITAL LETTER IO
+0xB4 U+0404 # CYRILLIC CAPITAL LETTER UKRAINIAN IE
+0xB5 U+2563 # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+0xB6 U+0406 # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+0xB7 U+0407 # CYRILLIC CAPITAL LETTER YI (UKRAINIAN)
+0xB8 U+2566 # BOX DRAWINGS  DOUBLE DOWN AND HORIZONTAL
+0xB9 U+2567 # BOX DRAWINGS  UP SINGLE AND HORIZONTAL DOUBLE
+0xBA U+2568 # BOX DRAWINGS  UP DOUBLE AND HORIZONTAL SINGLE
+0xBB U+2569 # BOX DRAWINGS  DOUBLE UP AND HORIZONTAL
+0xBC U+256A # BOX DRAWINGS  VERTICAL SINGLE AND HORIZONTAL DOUBLE
+0xBD U+0490 # CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+0xBE U+256C # BOX DRAWINGS  DOUBLE VERTICAL AND HORIZONTAL
+0xBF U+00A9 # COPYRIGHT SIGN
+0xC0 U+044E # CYRILLIC SMALL LETTER YU
+0xC1 U+0430 # CYRILLIC SMALL LETTER A
+0xC2 U+0431 # CYRILLIC SMALL LETTER BE
+0xC3 U+0446 # CYRILLIC SMALL LETTER TSE
+0xC4 U+0434 # CYRILLIC SMALL LETTER DE
+0xC5 U+0435 # CYRILLIC SMALL LETTER IE
+0xC6 U+0444 # CYRILLIC SMALL LETTER EF
+0xC7 U+0433 # CYRILLIC SMALL LETTER GHE
+0xC8 U+0445 # CYRILLIC SMALL LETTER KHA
+0xC9 U+0438 # CYRILLIC SMALL LETTER I
+0xCA U+0439 # CYRILLIC SMALL LETTER SHORT I
+0xCB U+043A # CYRILLIC SMALL LETTER KA
+0xCC U+043B # CYRILLIC SMALL LETTER EL
+0xCD U+043C # CYRILLIC SMALL LETTER EM
+0xCE U+043D # CYRILLIC SMALL LETTER EN
+0xCF U+043E # CYRILLIC SMALL LETTER O
+0xD0 U+043F # CYRILLIC SMALL LETTER PE
+0xD1 U+044F # CYRILLIC SMALL LETTER YA
+0xD2 U+0440 # CYRILLIC SMALL LETTER ER
+0xD3 U+0441 # CYRILLIC SMALL LETTER ES
+0xD4 U+0442 # CYRILLIC SMALL LETTER TE
+0xD5 U+0443 # CYRILLIC SMALL LETTER U
+0xD6 U+0436 # CYRILLIC SMALL LETTER ZHE
+0xD7 U+0432 # CYRILLIC SMALL LETTER VE
+0xD8 U+044C # CYRILLIC SMALL LETTER SOFT SIGN
+0xD9 U+044B # CYRILLIC SMALL LETTER YERU
+0xDA U+0437 # CYRILLIC SMALL LETTER ZE
+0xDB U+0448 # CYRILLIC SMALL LETTER SHA
+0xDC U+044D # CYRILLIC SMALL LETTER E
+0xDD U+0449 # CYRILLIC SMALL LETTER SHCHA
+0xDE U+0447 # CYRILLIC SMALL LETTER CHE
+0xDF U+044A # CYRILLIC SMALL LETTER HARD SIGN
+0xE0 U+042E # CYRILLIC CAPITAL LETTER YU
+0xE1 U+0410 # CYRILLIC CAPITAL LETTER A
+0xE2 U+0411 # CYRILLIC CAPITAL LETTER BE
+0xE3 U+0426 # CYRILLIC CAPITAL LETTER TSE
+0xE4 U+0414 # CYRILLIC CAPITAL LETTER DE
+0xE5 U+0415 # CYRILLIC CAPITAL LETTER IE
+0xE6 U+0424 # CYRILLIC CAPITAL LETTER EF
+0xE7 U+0413 # CYRILLIC CAPITAL LETTER GHE
+0xE8 U+0425 # CYRILLIC CAPITAL LETTER KHA
+0xE9 U+0418 # CYRILLIC CAPITAL LETTER I
+0xEA U+0419 # CYRILLIC CAPITAL LETTER SHORT I
+0xEB U+041A # CYRILLIC CAPITAL LETTER KA
+0xEC U+041B # CYRILLIC CAPITAL LETTER EL
+0xED U+041C # CYRILLIC CAPITAL LETTER EM
+0xEE U+041D # CYRILLIC CAPITAL LETTER EN
+0xEF U+041E # CYRILLIC CAPITAL LETTER O
+0xF0 U+041F # CYRILLIC CAPITAL LETTER PE
+0xF1 U+042F # CYRILLIC CAPITAL LETTER YA
+0xF2 U+0420 # CYRILLIC CAPITAL LETTER ER
+0xF3 U+0421 # CYRILLIC CAPITAL LETTER ES
+0xF4 U+0422 # CYRILLIC CAPITAL LETTER TE
+0xF5 U+0423 # CYRILLIC CAPITAL LETTER U
+0xF6 U+0416 # CYRILLIC CAPITAL LETTER ZHE
+0xF7 U+0412 # CYRILLIC CAPITAL LETTER VE
+0xF8 U+042C # CYRILLIC CAPITAL LETTER SOFT SIGN
+0xF9 U+042B # CYRILLIC CAPITAL LETTER YERU
+0xFA U+0417 # CYRILLIC CAPITAL LETTER ZE
+0xFB U+0428 # CYRILLIC CAPITAL LETTER SHA
+0xFC U+042D # CYRILLIC CAPITAL LETTER E
+0xFD U+0429 # CYRILLIC CAPITAL LETTER SHCHA
+0xFE U+0427 # CYRILLIC CAPITAL LETTER CHE
+0xFF U+042A # CYRILLIC CAPITAL LETTER HARD SIGN
diff --git a/src/chrtrans/makefile.dos b/src/chrtrans/makefile.dos
index 3f99eaa9..bc665212 100644
--- a/src/chrtrans/makefile.dos
+++ b/src/chrtrans/makefile.dos
@@ -42,6 +42,7 @@ TABLES= \
  cp862_uni.h \
  cp864_uni.h \
  cp866_uni.h \
+ cp866u_uni.h \
  cp869_uni.h \
  def7_uni.h \
  dmcs_uni.h \
@@ -57,10 +58,12 @@ TABLES= \
  iso09_uni.h \
  iso10_uni.h \
  iso15_uni.h \
+ iso9945_uni.h \
  koi8r_uni.h \
+ koi8u_uni.h \
  mac_uni.h \
- mnem_suni.h \
  mnem2_suni.h \
+ mnem_suni.h \
  next_uni.h \
  rfc_suni.h \
  utf8_uni.h \
@@ -92,6 +95,7 @@ cp852_uni.h:		cp852_uni.tbl		makeuctb.exe
 cp862_uni.h:		cp862_uni.tbl		makeuctb.exe
 cp864_uni.h:		cp864_uni.tbl		makeuctb.exe
 cp866_uni.h:		cp866_uni.tbl		makeuctb.exe
+cp866u_uni.h:		cp866u_uni.tbl		makeuctb.exe
 cp869_uni.h:		cp869_uni.tbl		makeuctb.exe
 def7_uni.h:		def7_uni.tbl		makeuctb.exe
 dmcs_uni.h:		dmcs_uni.tbl		makeuctb.exe
@@ -107,10 +111,12 @@ iso08_uni.h:		iso08_uni.tbl		makeuctb.exe
 iso09_uni.h:		iso09_uni.tbl		makeuctb.exe
 iso10_uni.h:		iso10_uni.tbl		makeuctb.exe
 iso15_uni.h:		iso15_uni.tbl		makeuctb.exe
+iso9945_uni.h:		iso9945_uni.tbl		makeuctb.exe
 koi8r_uni.h:		koi8r_uni.tbl		makeuctb.exe
+koi8u_uni.h:		koi8u_uni.tbl		makeuctb.exe
 mac_uni.h:		mac_uni.tbl		makeuctb.exe
-mnem_suni.h:		mnem_suni.tbl		makeuctb.exe
 mnem2_suni.h:		mnem2_suni.tbl		makeuctb.exe
+mnem_suni.h:		mnem_suni.tbl		makeuctb.exe
 next_uni.h:		next_uni.tbl		makeuctb.exe
 rfc_suni.h:		rfc_suni.tbl		makeuctb.exe
 utf8_uni.h:		utf8_uni.tbl		makeuctb.exe
diff --git a/src/chrtrans/makefile.in b/src/chrtrans/makefile.in
index ece1dac9..dbcf4782 100644
--- a/src/chrtrans/makefile.in
+++ b/src/chrtrans/makefile.in
@@ -61,6 +61,7 @@ TABLES= \
  cp862_uni.h \
  cp864_uni.h \
  cp866_uni.h \
+ cp866u_uni.h \
  cp869_uni.h \
  def7_uni.h \
  dmcs_uni.h \
@@ -76,10 +77,12 @@ TABLES= \
  iso09_uni.h \
  iso10_uni.h \
  iso15_uni.h \
+ iso9945_uni.h \
  koi8r_uni.h \
+ koi8u_uni.h \
  mac_uni.h \
- mnem_suni.h \
  mnem2_suni.h \
+ mnem_suni.h \
  next_uni.h \
  rfc_suni.h \
  utf8_uni.h \
@@ -124,6 +127,7 @@ cp852_uni.h:		$(srcdir)/cp852_uni.tbl		makeuctb$x
 cp862_uni.h:		$(srcdir)/cp862_uni.tbl		makeuctb$x
 cp864_uni.h:		$(srcdir)/cp864_uni.tbl		makeuctb$x
 cp866_uni.h:		$(srcdir)/cp866_uni.tbl		makeuctb$x
+cp866u_uni.h:		$(srcdir)/cp866u_uni.tbl	makeuctb$x
 cp869_uni.h:		$(srcdir)/cp869_uni.tbl		makeuctb$x
 def7_uni.h:		$(srcdir)/def7_uni.tbl		makeuctb$x
 dmcs_uni.h:		$(srcdir)/dmcs_uni.tbl		makeuctb$x
@@ -139,10 +143,12 @@ iso08_uni.h:		$(srcdir)/iso08_uni.tbl		makeuctb$x
 iso09_uni.h:		$(srcdir)/iso09_uni.tbl		makeuctb$x
 iso10_uni.h:		$(srcdir)/iso10_uni.tbl		makeuctb$x
 iso15_uni.h:		$(srcdir)/iso15_uni.tbl		makeuctb$x
+iso9945_uni.h:		$(srcdir)/iso9945_uni.tbl	makeuctb$x
 koi8r_uni.h:		$(srcdir)/koi8r_uni.tbl		makeuctb$x
+koi8u_uni.h:		$(srcdir)/koi8u_uni.tbl		makeuctb$x
 mac_uni.h:		$(srcdir)/mac_uni.tbl		makeuctb$x
-mnem_suni.h:		$(srcdir)/mnem_suni.tbl		makeuctb$x
 mnem2_suni.h:		$(srcdir)/mnem2_suni.tbl	makeuctb$x
+mnem_suni.h:		$(srcdir)/mnem_suni.tbl		makeuctb$x
 next_uni.h:		$(srcdir)/next_uni.tbl		makeuctb$x
 rfc_suni.h:		$(srcdir)/rfc_suni.tbl		makeuctb$x
 utf8_uni.h:		$(srcdir)/utf8_uni.tbl		makeuctb$x
diff --git a/src/structdump.h b/src/structdump.h
index 876d4576..8b058189 100644
--- a/src/structdump.h
+++ b/src/structdump.h
@@ -9,24 +9,24 @@
 /* usage: DUMPSTRUCT_LINK(link_ptr, "message"); */
 #define   DUMPSTRUCT_LINK(L,X) \
 CTRACE(tfp, "\n" \
-            "KED:     link_ptr=%08x  sizeof=%d  ["X"]\n" \
-            "link       struct {\n" \
-            "           *lname=%08x\n" \
-            "            lname=|%s|\n" \
-            "          *target=%08x\n" \
-            "           target=|%s|\n" \
-            "        *hightext=%08x\n" \
-            "         hightext=|%s|\n" \
-            "       *hightext2=%08x\n" \
-            "        hightext2=|%s|\n" \
-            " hightext2_offset=%d\n"   \
-            "      inUnderline=%1x\n"  \
-            "               lx=%d\n"   \
-            "               ly=%d\n"   \
-            "             type=%d\n"   \
-            "    anchor_number=%d\n"   \
-            "  anchor_line_num=%d\n"   \
-            "            *form=%08x\n" \
+            "KED:     link_ptr=0x%08x  sizeof=%d  ["X"]\n" \
+            "link       struct {\n"      \
+            "           *lname=0x%08x\n" \
+            "            lname=|%s|\n"   \
+            "          *target=0x%08x\n" \
+            "           target=|%s|\n"   \
+            "        *hightext=0x%08x\n" \
+            "         hightext=|%s|\n"   \
+            "       *hightext2=0x%08x\n" \
+            "        hightext2=|%s|\n"   \
+            " hightext2_offset=%d\n"     \
+            "      inUnderline=%1x\n"    \
+            "               lx=%d\n"     \
+            "               ly=%d\n"     \
+            "             type=%d\n"     \
+            "    anchor_number=%d\n"     \
+            "  anchor_line_num=%d\n"     \
+            "            *form=0x%08x\n" \
             "}\n", \
             (L), sizeof(*((L))), \
             (L)->lname, (L)->lname, (L)->target, (L)->target, \
@@ -39,25 +39,25 @@ CTRACE_FLUSH(tfp);
 /* usage: DUMPSTRUCT_ANCHOR(anchor_ptr, "message"); */
 #define   DUMPSTRUCT_ANCHOR(A,X) \
 CTRACE(tfp, "\n" \
-            "KED:   anchor_ptr=%08x  sizeof=%d  ["X"]\n" \
-            "TextAnchor struct {\n"    \
-            "            *next=%08x\n" \
-            "           number=%d\n"   \
-            "            start=%d\n"   \
-            "         line_pos=%d\n"   \
-            "           extent=%d\n"   \
-            "         line_num=%d\n"   \
-            "        *hightext=%08x\n" \
-            "         hightext=|%s|\n" \
-            "       *hightext2=%08x\n" \
-            "        hightext2=|%s|\n" \
-            "  hightext2offset=%d\n"   \
-            "        link_type=%d\n"   \
-            "     *input_field=%08x\n" \
-            "      input_field=|%s|\n" \
-            "      show_anchor=%1x\n"  \
-            "      inUnderline=%1x\n"  \
-            "          *anchor=%08x\n" \
+            "KED:   anchor_ptr=0x%08x  sizeof=%d  ["X"]\n" \
+            "TextAnchor struct {\n"      \
+            "            *next=0x%08x\n" \
+            "           number=%d\n"     \
+            "            start=%d\n"     \
+            "         line_pos=%d\n"     \
+            "           extent=%d\n"     \
+            "         line_num=%d\n"     \
+            "        *hightext=0x%08x\n" \
+            "         hightext=|%s|\n"   \
+            "       *hightext2=0x%08x\n" \
+            "        hightext2=|%s|\n"   \
+            "  hightext2offset=%d\n"     \
+            "        link_type=%d\n"     \
+            "     *input_field=0x%08x\n" \
+            "      input_field=|%s|\n"   \
+            "      show_anchor=%1x\n"    \
+            "      inUnderline=%1x\n"    \
+            "          *anchor=0x%08x\n" \
             "}\n", \
             (A), sizeof(*((A))), \
             (A)->next, (A)->number, (A)->start, (A)->line_pos, \
@@ -72,35 +72,35 @@ CTRACE_FLUSH(tfp);
 /* usage: DUMPSTRUCT_FORM(forminfo_ptr, "message"); */
 #define   DUMPSTRUCT_FORMINFO(F,X) \
 CTRACE(tfp, "\n" \
-            "KED: forminfo_ptr=%08x  sizeof=%d  ["X"]\n" \
-            "FormInfo   struct {\n"    \
-            "            *name=%08x\n" \
-            "             name=|%s|\n" \
-            "           number=%d\n"   \
-            "             type=%d\n"   \
-            "           *value=%08x\n" \
-            "            value=|%s|\n" \
-            "      *orig_value=%08x\n" \
-            "       orig_value=|%s|\n" \
-            "             size=%d\n"   \
-            "        maxlength=%d\n"   \
-            "            group=%d\n"   \
-            "        num_value=%d\n"   \
-            "           hrange=%d\n"   \
-            "           lrange=%d\n"   \
-            "     *select_list=%08x\n" \
-            "    submit_action=|%s|\n" \
-            "    submit_method=%d\n"   \
-            "   submit_enctype=|%s|\n" \
-            "     submit_title=|%s|\n" \
-            "         no_cache=%1x\n"  \
-            "  cp_submit_value=|%s|\n" \
-            "orig_submit_value=|%s|\n" \
-            "           size_l=%d\n"   \
-            "         disabled=%d\n"   \
-            "          name_cs=%d\n"   \
-            "         value_cs=%d\n"   \
-            "        accept_cs=|%s|\n" \
+            "KED: forminfo_ptr=0x%08x  sizeof=%d  ["X"]\n" \
+            "FormInfo   struct {\n"      \
+            "            *name=0x%08x\n" \
+            "             name=|%s|\n"   \
+            "           number=%d\n"     \
+            "             type=%d\n"     \
+            "           *value=0x%08x\n" \
+            "            value=|%s|\n"   \
+            "      *orig_value=0x%08x\n" \
+            "       orig_value=|%s|\n"   \
+            "             size=%d\n"     \
+            "        maxlength=%d\n"     \
+            "            group=%d\n"     \
+            "        num_value=%d\n"     \
+            "           hrange=%d\n"     \
+            "           lrange=%d\n"     \
+            "     *select_list=0x%08x\n" \
+            "    submit_action=|%s|\n"   \
+            "    submit_method=%d\n"     \
+            "   submit_enctype=|%s|\n"   \
+            "     submit_title=|%s|\n"   \
+            "         no_cache=%1x\n"    \
+            "  cp_submit_value=|%s|\n"   \
+            "orig_submit_value=|%s|\n"   \
+            "           size_l=%d\n"     \
+            "         disabled=%d\n"     \
+            "          name_cs=%d\n"     \
+            "         value_cs=%d\n"     \
+            "        accept_cs=|%s|\n"   \
             "}\n", \
             (F), sizeof(*((F))), \
             (F)->name, (F)->name, (F)->number, (F)->type, \
@@ -117,17 +117,17 @@ CTRACE_FLUSH(tfp);
 /* usage: DUMPSTRUCT_LINE(htline_ptr, "message"); */
 #define   DUMPSTRUCT_LINE(L,X) \
 CTRACE(tfp, "\n" \
-            "KED: htline_ptr=%08x  sizeof=%d  ["X"]\n" \
-            "HTLine struct {\n"    \
-            "        *next=%08x\n" \
-            "        *prev=%08x\n" \
-            "       offset=%d\n"   \
-            "         size=%d\n"   \
-            "  split_after=%1x\n"  \
-            "       bullet=%1x\n"  \
-            "nodef U_C_S\n"        \
-            "       data[]=%08x\n" \
-            "         data=|%s|\n" \
+            "KED: htline_ptr=0x%08x  sizeof=%d  ["X"]\n" \
+            "HTLine struct {\n"      \
+            "        *next=0x%08x\n" \
+            "        *prev=0x%08x\n" \
+            "       offset=%d\n"     \
+            "         size=%d\n"     \
+            "  split_after=%1x\n"    \
+            "       bullet=%1x\n"    \
+            "nodef U_C_S\n"          \
+            "       data[]=0x%08x\n" \
+            "         data=|%s|\n"   \
             "}\n", \
             (L), sizeof(*((L))), \
             (L)->next, (L)->prev, (L)->offset, (L)->size, (L)->split_after, \