about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CHANGES984
-rw-r--r--CHANGES2-6732
-rw-r--r--CRAWL.announce20
-rw-r--r--DESC4
-rw-r--r--LYMessages_en.h24
-rw-r--r--Makefile30
-rw-r--r--README13
-rw-r--r--RELEASE_STATEMENT4
-rw-r--r--WWW/Library/Implementation/HTAAFile.c2
-rw-r--r--WWW/Library/Implementation/HTAAUtil.c19
-rw-r--r--WWW/Library/Implementation/HTAccess.c15
-rw-r--r--WWW/Library/Implementation/HTAlert.h14
-rw-r--r--WWW/Library/Implementation/HTAnchor.c108
-rw-r--r--WWW/Library/Implementation/HTAnchor.h69
-rw-r--r--WWW/Library/Implementation/HTFTP.c3
-rw-r--r--WWW/Library/Implementation/HTFile.c72
-rw-r--r--WWW/Library/Implementation/HTFormat.c357
-rw-r--r--WWW/Library/Implementation/HTGroup.c2
-rw-r--r--WWW/Library/Implementation/HTMIME.c216
-rw-r--r--WWW/Library/Implementation/HTMLDTD.c8
-rw-r--r--WWW/Library/Implementation/HTMLDTD.h47
-rw-r--r--WWW/Library/Implementation/HTNews.c80
-rw-r--r--WWW/Library/Implementation/HTParse.c43
-rw-r--r--WWW/Library/Implementation/HTParse.h110
-rw-r--r--WWW/Library/Implementation/HTPasswd.c2
-rw-r--r--WWW/Library/Implementation/HTTCP.c882
-rw-r--r--WWW/Library/Implementation/HTTP.c191
-rw-r--r--WWW/Library/Implementation/SGML.c58
-rw-r--r--WWW/Library/Implementation/tcp.h42
-rw-r--r--WWW/Library/umaxv-m88k/Makefile30
-rw-r--r--about_lynx/about_lynx-dev.html10
-rw-r--r--about_lynx/about_lynx.html19
-rw-r--r--docs/README.html6
-rw-r--r--docs/README.txt4
-rw-r--r--lynx.cfg75
-rw-r--r--lynx.hlp12
-rw-r--r--lynx.man13
-rw-r--r--lynx_help/Lynx_users_guide.html99
-rw-r--r--lynx_help/lynx_help_main.html13
-rw-r--r--lynx_help/lynx_url_support.html33
-rw-r--r--samples/lynx.cfg75
-rw-r--r--src/DefaultStyle.c13
-rw-r--r--src/GridText.c604
-rw-r--r--src/GridText.h9
-rw-r--r--src/HTAlert.c109
-rw-r--r--src/HTAlert.h14
-rw-r--r--src/HTFWriter.c44
-rw-r--r--src/HTInit.c6
-rw-r--r--src/HTML.c294
-rw-r--r--src/LYBookmark.c486
-rw-r--r--src/LYBookmark.h14
-rw-r--r--src/LYCgi.c6
-rw-r--r--src/LYCharUtils.c2
-rw-r--r--src/LYCurses.h23
-rw-r--r--src/LYForms.c597
-rw-r--r--src/LYGetFile.c140
-rw-r--r--src/LYGlobalDefs.h14
-rw-r--r--src/LYHistory.c14
-rw-r--r--src/LYKeymap.c16
-rw-r--r--src/LYKeymap.h1
-rw-r--r--src/LYLocal.c424
-rw-r--r--src/LYLocal.h7
-rw-r--r--src/LYMail.c157
-rw-r--r--src/LYMail.h23
-rw-r--r--src/LYMain.c139
-rw-r--r--src/LYMainLoop.c525
-rw-r--r--src/LYMap.c2
-rw-r--r--src/LYNews.c1
-rw-r--r--src/LYOptions.c668
-rw-r--r--src/LYOptions.h27
-rw-r--r--src/LYPrint.c123
-rw-r--r--src/LYReadCFG.c18
-rw-r--r--src/LYShowInfo.c88
-rw-r--r--src/LYStructs.h9
-rw-r--r--src/LYUtils.c133
-rw-r--r--src/LYUtils.h5
-rw-r--r--src/LYrcFile.c180
-rw-r--r--userdefs.h64
-rw-r--r--utils/inews/Makefile15
-rw-r--r--utils/inews/clientlib.c2
80 files changed, 6612 insertions, 2944 deletions
diff --git a/CHANGES b/CHANGES
index 73c158ab..bdf86c81 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,732 +1,256 @@
---- Rename of Lynx2-5FM and release as Lynx2-6  (02-Sep-1996) ---
-==============================================================================
-09-02-96 ---- Release of Lynx2-6 ----
-* More expansions of the online 'h'elp files. - FM
-* Updated the PROBLEMS file. - FM
-09-01-96
-* More expansions of the online 'h'elp files. - FM
-* Tweaks of list handling. - FM
-* Miscellaneous code cleanups and annotations. - FM
-08-31-96
-* Further updates and expansions of the online 'h'elp files. - FM
-* Tweaks of alignment handling with bad HTML. - FM
-* Added JIS X 0201 Japanese Kana string support. - TA & FM
-08-30-96
-* Further updates and expansions of the online 'h'elp files. - FM
-* Typo fixes in the help and doc files. - LWV
-* Tweaks of ENCTYPE handling for FORM submissions. - FM
-08-29-96
-* Today's distribution is a pre-release of v2.6.  The projected official
-  release date is 09-02-96.
-* Tweaks of numeric character reference handling. - FM
-* Typo fix in LYShowInfo.c. - IC
-08-28-96
-* Added handling of ENCTYPE="application/sgml-form-urlencoded" in FORMs
-  as a directive to use semi-colons instead of ampersands as name=value
-  separators, and to indicate that as the Content-Type for POSTs. - FM
-* Convert ampersands in addresses and link names, and angle-brackets in
-  link names, to SGML entities when creating bookmarks and showinfo ('=')
-  link 'l'ist, client-side-image-map, and history list text/html streams
-  or temporary files. - FM
-* More SGML compliance mods for the handling of attribute values which
-  represent URLs or URL components. - FM
-* Tweaks of form INPUT, TEXTAREA, SELECT and OPTION handling. - FM
-* Check EAGAIN on socket connect or select attempts for all platforms and
-  flavors. - FM
-* Include both <time.h> and <sys/time.h> in tcp.h for AIX.
-* Adding warning and info in the INSTALLATION file and userdefs.h on how
-  to cope with telnetd environment variable spamming for anonymous accounts
-  running Lynx captively. - FM
-08-24-96
-* Enhancements of the History List handling.  Show each link's actual address
-  in addition to the titles, since the actual addresses can't be determined
-  via showinfo or the 'l'ist display, and links in the History List derived
-  from searches can have the same titles but different searchparts or hidden
-  content appended.  If a link in the History List is activated, is still
-  cached, has POST content, and ALWAYS_RESUBMIT_POSTS was configured off (as
-  recommended) and wasn't toggled on via -resubmit_posts, prompt the user
-  whether to resubmit the form (versus retrieve the cached rendition from
-  the previous submission).  We don't bother prompting on PREV_DOC ("back")
-  fetches, and still resubmit forms with POST content whenever their submit
-  buttons are activated, i.e., regardless of whether ALWAYS_RESUBMIT_POSTS
-  has been configured or toggled on. - FM 
-* If a user attempts to add a bookmark while viewing a document returned
-  via a form submission with POST content, and it contains links, offer
-  the current link with it's link name for editing.  Otherwise, display
-  a statusline message that documents from forms with POST content cannot
-  be saved as bookmarks. - FM
-08-23-96
-* Added UP_HALF and DOWN_HALF commands, mapped by default to '(' and ')',
-  for going back or forward half a page in the document.  These are
-  complementary to UP_TWO and DOWN_TWO, for going back or forward two
-  lines (remember to use the 'K'eymap command for a list of all of the
-  keystroke command bindings currently in effect, since they may have
-  been changed via lynx.cfg from the defaults described in the online
-  'H'elp). - FM
-* Made the Control-A and Control-E keys default synonyms for HOME and END,
-  complementary to their use for going to the beginning or end of the line
-  when using the line editor. - FM
-* Don't lose track of source versus present mode on returns from temporary
-  menu files to documents derived from forms with method POST. - FM
-* Ugh, I had deleted one too many lines from HTTP.c when stripping out my
-  SSL hooks for the distribution copy (no wonder the Authorization mods
-  worked fine for me but nobody else 8-). - FM
-08-22-96
-* Added handling of named entities and numeric character references in
-  the values of most of the non-URL attributes (we don't waste overhead
-  doing that for the values of simple attributes, like ALIGN, which have
-  designated strings). - FM
-08-21-96
-* Safely handle named entities and numeric character references in the values
-  of BASE, LINK, HREF, SRC, ACTION, DATA, CODEBASE and CODE attributes, and
-  in the URL field for the CONTENT of META with a "Refresh" HTTP-EQUIV or
-  NAME.  They are converted in relation to the "ISO Latin 1" Character Set
-  array regardless of the selected Character Set (except that nbsp and shy
-  remain 160 and 173), then 8-bit translations are hex escaped (as they
-  should have been in the markup 8-), and ESC is hex escaped or omitted
-  depending on whether a CJK character set has been selected.  There's no
-  way to do it such that the resolved URL always will be valid no matter
-  what yoyos or CGI scripts put in document instances, but this strategy
-  maximizes the chances while making sure no "dangerous" characters, based
-  on the selected Character Set, are ever sent to the screen (it used to be
-  HyperText Markup Language, not HyperGraphic Markup Language 8-)- FM
-* Allow Control-G or a zero-length username or password to act as a cancel
-  of the request (and restoration of the current document) when an http
-  server invokes prompting for Authorization. - FM
-* When using a proxy server, report the target host instead of the proxy
-  in prompts for Authorization. - FM 
-* Show MIME types of files, if known, whenever a download offer is forced,
-  regardless of why it was forced (i.e, not only for mismatches between
-  the document's charset and the selected character set). - FM
-08-20-96
-* Yet more tweaks of MIME header parsing. - FM
-08-19-96
-* Enhancements of the news gateway. - FM
-* Tweaks of Content-Type and charset handling. - FM
-* Tweaks of MIME header parsing. - FM
-08-18-96
-* Tweaks of the news gateway and its documentation. - FM
-08-17-96
-* Added overt (rational 8-) handling of all status codes that might be
-  returned (appropriately or inappropriately 8-) from HTTP/1.1 http
-  servers, and massively annotated the code in HTTP.c. - FM
-* Added parsing in HTMIME.c, and at least trace mode reporting, for all
-  http server reply and entity headers as in the 08-12-96 HTTP/1.1 draft.
-  We should not get many of them, unless we declare ourselves as an HTTP/1.1
-  client and send the appropriate request headers, but they're all available
-  now for use as more HTTP/1.1 features are added. - FM
-08-16-96
-* Added handling of "Pragma: no-cache" or "Cache-Control: no-cache" headers
-  from http servers, and polished up the code for handling them via META
-  directives. - FM
-08-15-96
-* Modified form handling so that Lynx always resubmits forms if their method
-  is POST, even if their content was not changed, when their submit buttons
-  or submitting text input are activated.  Changed the ALWAYS_RESUBMIT_FORMS
-  compilation and configuration definitions, and -resubmit_forms command
-  line toggle, to ALWAYS_RESUBMIT_POSTS, and -resubmit_posts.  When FALSE,
-  you still get the previously returned document from a POSTed form if that
-  document had links which you activated, and then go back with the PREV_DOC
-  command or via the history list.  If set TRUE, the form will be resubmitted
-  under those circumstances as well.  Documents returned by forms with method
-  GET still require use of the RESUBMIT command to resubmit if the forms'
-  content was not changed, and forms with a mailto action still always mail
-  the content on activation of the submit button or submitting text input
-  (no document is returned, so the PREV_DOC command and history list behaviors
-  are irrelevant). - FM
-* Use space to plus conversions for values of submitted form content (Ugh,
-  Lynx has been using %20 all these years!  It worked because they are
-  unescaped to space, anyway. 8-). - FM
-* Polished up and massively annotated the redirection handling code.  If
-  a user approves redirection of a form with POST content, it will not be
-  freed and the submission will not be converted to a contentless GET request
-  unless the status was 303 (See Other).  For 300 (Multiple Choices), the
-  returned document is offered, which should include links with descriptions
-  of their media types.  The returned document (if any) is now displayed for
-  any redirection status code if no Location: header was present, and for
-  unknown 3xx codes (i.e., greater than 305).  If Lynx gets an inappropriate
-  304 (Not Modified), it switches to HEAD mode and displays the status line,
-  and anything else returned by the server, as text/plain.  A 301 (Moved
-  Permanently) will be treated as 302 (Moved Temporarily) for form submissions
-  with POST content.  Otherwise, Lynx will use the new URL for the remainder
-  of the current session (users will have to do a 'r'emove and 'a'dd for their
-  bookmarks themselves, for now).  A 305 (Use Proxy) will not be honored if
-  Lynx is already using a proxy, and instead the returned document will be
-  displayed.  The limit on serial redirections was dropped from the current
-  10 to 5, as recommended in the August 10, 1996 HTTP/1.1 draft. - FM
-08-13-96
-* Mods to accommodate the HTTP/1.1 300 - 305 Redirection status codes, and
-  to require user confirmation for any redirection of POST content. - FM
-* Tweaks of OBJECT handling. - FM
-08-12-96
-* Implemented all aspects of OBJECT that make sense for a text client.
-  Will descend though nested OBJECTs.  Can be used for presenting PRE
-  formatted character-cell versions of images, and appears to handle
-  all likely uses of the SHAPES and USEMAP attributes in OBJECTs.  The
-  pseudo-ALTs for links to non-script DATA values (i.e, the for-GUI
-  sources) when offered as links (e.g., in clickable_images mode), if
-  not a markup-specified string (e.g., based on a TITLE attribute),
-  are (IMAGE) or (OBJECT), based on whether the nature of the source
-  can be inferred from the context, or an explicit TYPE attribute in
-  the OBJECT start tag.  The use of parens instead of square-brackets
-  indicates that the links are for OBJECTs as opposed to IMGs. - FM
-* Tweaks of SELECT and OPTION handling. - FM
-08-09-96
-* Lots more stuff added to the online help files. - FM
-* Added state code in SGML.c to avoid getting tripped up by any single or
-  double quotes in CJK escape sequences that are within single or double
-  quoted attribute values. - TA
-* Restrict resetting the Kanji code flag on white space to Japanese
-  (i.e., not also Chinese, Taipai, or Korean). - TA
-* Added handling of EPLF lines (with local time) for the FTP gateway. -
-  D. J. Bernstein (djb@koobera.math.uic.edu)
-08-08-96
-* Added code for handling captured OBJECT content with the SHAPES
-  attribute equivalently to our handling of FIG, and with USEMAP and/or
-  ISMAP content equivalently to our handling of IMG.
-* Added code for capturing potentially nested container elements that
-  require pre-processing, e.g., OBJECT, and for passing the processed
-  markup back to the SGML parser to be inserted within the ongoing HTML
-  stream.
-* Added CHECK_EAGAIN Makefile definition for non-SVR4 Unix flavors which
-  might need it for socket connect() and select() calls. - FM
-* Tweaks of keyboard input with slang when LYCursesON is FALSE. - FM
-08-06-96
-* Terminate and start a new Accept: header line if the current one will
-  exceed 1 KB (shouldn't be necessary, but otherwise the long lines cause
-  an error for WebSitePro and crash Netscape servers, and perhaps have
-  adversed effects on some other http servers with ill designed code for
-  content negotiation). - FM
-* Give temporary files suffixes matched to the Content-Type for all flavors
-  of Unix and for VMS, not just for NeXT. - FM 
-* Tweak of Location: header parsing in HTTP.c (trim all lead spaces). - FM
-08-05-96
-* More help and documentation updates. - FM
-08-04-96
-* Updated the online help files. - FM
-08-03-96
-* Mods of "user (A)gent" 'o'ption handling.  Also added a "useragent"
-  -restriction, included in the defaults for anonymous accounts.  See
-  the "Lynx options menu" section of the "Lynx Users Guide" via the
-  online 'h'elp for more information. - FM
-* Tweaks of messaging for unsupported URLs. - FM
-* Tweaks of interrupt handling on VMS. - FM
-08-02-96
-* Added handling of Refresh in META tags.  The URL is presented as a link
-  pointed to by a "REFRESH(n sec):" label, where "n" is the seconds
-  parameter from the META tag, and you must activate it yourself, which
-  should enable people using Lynx via a braille interface to examine
-  the initial document before it is refreshed.  The META format is:
-  <META HTTP-EQUIV=refresh CONTENT="n; URL=url"> where "n" can be "0" or
-  a positive integer, and the "; URL=url" field is optional, defaulting
-  to the document's own address.  Netscape's docs say that "url" should
-  be a complete URL, but their client doesn't require it, and so it's
-  users don't reliably use complete URLs.  Lynx therefore resolves "url"
-  versus the document's own address if it is not complete. - FM
-08-01-96
-* Added handling of ENCTYPE="text/plain" for FORMs with a mailto ACTION.
-  The name=value pairs are not hex escaped, and physical newlines instead
-  of '&' separate the pairs, so that the content is readable directly. - FM
-* Added SUBJECT attribute as synonym for TITLE in FORMs (Some clients
-  are using it instead of TITLE for mailto ACTIONs, ugh!). - FM
-* Tweaks of DEL, S, STRIKE, and INS handling. - FM
-* Handle any newline characters in quoted INPUT values. - FM
-* Added news-ncurses and news-slang Makefile targets, and tweaks of headers
-  for sony_news. - Makoto MATSUSHITA (matusita@ics.es.osaka-u.ac.jp)
-07-30-96
-* Finished and incorporated lynx_url_support.html in the online help,
-  and updated lynx_help_main.html. - FM
-* Tweaks of ID attribute handling. - FM
-* Tweaks of the gopher gateway. - FM
-* Updated IBMPC-charsets.announce. - MB
-07-26-96
-* Set the default anonymous account restrictions if Lynx is invoked in
-  the account pointed to by ANONYMOUS_USER, or with the -anonymous switch,
-  before processing any additional command line restrictions, so that any
-  greater restrictions will not drop back to the compilation defaults.
-  Note that the full set of -validate restrictions always are enforced for
-  that switch, i.e., no matter what other switches or compilation options
-  are used, and whether or not the account is anonymous. - FM
-* Implemented handling of the ANONYMOUS_USER definition on VMS (equivalently
-  to it's implementation on Unix). - FM
-* Tweaks of mailto URL handling and setting of the default subject via
-  TITLE attributes. - FM
-* Tweak of the news gateway's handling of the author (From:) field. - FM 
-07-25-96
-* If a server returns redirection without a complete URL indicated, resolve
-  it relative to the original request instead of issuing an error message
-  (this is incorrect behavior, but that's another trashed standard, and
-  Lynx may as well handle the situation as standard-less clients do). - FM
-* Move the NO_JUMPFILE and JUMP_PROMPT definitions to LYMessages_en.h - FM
-* Added code for selective disabling of goto by scheme in anonymous accounts,
-  along lines of patch from Doug Lawson (dlawson@epfl2.epflbalto.org). - FM
-* Ignore any viewer mappings for text/html or text/plain in mailcap
-  files. - FM
-07-22-96
-* Updated ptx target and added ptx-slang. - Alan Coopersmith
-  (alanc@CSUA.Berkeley.EDU)
-* Added all the new elements and attributes from the July 12 HTML 3.2/Cougar
-  DTD, and implemented the new IMG TITLE attribute for use with USEMAP.
-* Added a -startfile_ok switch for allowing a non-http startfile or homepage
-  with -validate, and restored the behavior of not allowing *any* non-http
-  URLs by default.
-07-19-96
-* Treat PLAIN and TYPE="plain" as equivalent in UL tags. - FM
-* Fixed the mispositioning of thinsp in HTMLDTD.c. - FM
-07-18-96
-* Moved the statusline prompt, message, and warning string definitions
-  out of userdefs.h into an LYMessages_en.h header.  See the comments
-  in userdefs.h and LYMessages_en.h for more information. - FM
-* Removed the -lc from the LIBS= list of the snake3 and snake3-slang
-  targets, added a description of the HP/UX 10.10 select() problems
-  and reported (but not yet satisfactory) workarounds in the PROBLEMS
-  file, and a note in the Makefile to read the PROBLEMS file. - FM
-07-17-96
-* Numerous typecasts added for optimized compilations. - FM
-* Tweaks for ISC. - WS
-* Changed make to $(MAKE) and -g to -O for Unix targets (may need
-  tweaking for some flavors 8-). - FM
-* Added news target for SONY NEWS-OS 4.2.1R based on patch from
-  Kazuya 'Sharl' Masuda (masuda@sp.hudson.co.jp) and TA. - FM
-* Fixed typo in LYList.c from yesterday's mods. - FM
-07-16-96
-* Plugged memory leaks associated with temporary file names. - FM
-* Finally figured out what was creating orphan child anchors, and plugged
-  that memory leak in HTAnchor_delete(). - FM
-* Replace <sys/select.h> with <sys/timeb.h> for SCO in tcp.h. - BL
-* Mods to avoid warning about redefinition of signal when building on
-  VMS with old versions of SOCKETSHR (irrelevant, but might worry
-  people who don't know that the warning can be ignored). - FM
-07-15-96
-* Plugged various memory leaks in FORM handling code. - FM
-07-13-96
-* Add the startfile, and homepage if different, to the 'g'oto recall
-  buffer so that they are available for editing in addition to any
-  overtly entered 'g'oto URLs. - FM
-* Changed TRUSTED_URL to ALWAYS_TRUSTED_EXEC for clarity, and plugged
-  memory leaks and some security holes in that code. - FM
-* Fixed typo in code for handling Z compressed files. - FM
-07-12-96
-* Added handling of &thinsp; (&#8201;), and handling of &#8194; as &ensp;,
-  &#8195; as &emsp;, &#8211; as &ndash; or &endash;, &#8212; as &mdash; or
-  &emdash;, and &#8482; as &trade; (treated as &reg; &#174;), based on the
-  Cougar DTD. - FM
-* Increased the line buffer size in HTLoadHTTP() and limited the deflt string
-  length in HTPrompt() to avoid possibilities of buffer overruns. - FM
-07-11-96
-* Block access to file: URLs via network served files or bookmarks in
-  addition to 'g'oto entries when -restrictions=file_url is set (one of
-  the default restrictions for -anonymous). - FM
-* Extended compressed file handling to the ftp gateway and local files.
-  If you ACTIVATE the link instead of overtly invoking a 'd'ownload, and
-  the path with the gz or Z stripped maps to a displayable Content-Type or
-  one for which you have a viewer or helper app, the file will be treated
-  as if it had a Content-Encoding: header indicating the compression (i.e.,
-  uncompressed and displayed or passed to the viewer or helper app). - FM
-* Mods to send http servers an Accept-Encoding: header indicating gzip and
-  compress, and to block inclusion of our new, internal www/compressed MIME
-  type in the Accept: header list. - FM
-* Changed the names of the lex_buffer and lex_lines globals to HTlex_buffer
-  and HTlex_lines in case name conflicts are causing segmentation faults on
-  linux for long usernames in authorization requests, and changed all
-  malloc()'s to calloc()'s in that code in case there's an initialization
-  glitch I don't yet see. - FM
-07-09-96
-* Use the username and password of an -auth= command line argument only
-  for the first realm that requests authorization, so they don't preclude
-  access to other realms later in any interactive session that might have
-  a different username and/or password, and handle inclusion of only a
-  username or only a password in the -auth= argument. - FM
-* Tweaks of memory leak plugs in authorization handling functions (hopefully
-  now avoiding segmentation faults on linux 8-). - FM
-* Include -lc in the first position of the LIBS= list for snake3 targets.
-  - Donald S. Teiser <dsteis01@homer.louisville.edu)
-* Enhancements of Makefile. - LWV
-07-07-96
-* Tweaks of code for uncompressing on the fly.  Will now force a download
-  offer without uncompressing if there is no presentation mapping for the
-  Content-Type. - FM
-* Retain blank lines within TEXTAREA content (but not trailing blanks). - DT
-07-07-96
-* Added functions for uncompressing and handling documents which have
-  Content-Encoding headers that indicate "x-gzip", "gzip", "x-compress",
-  or "compress" (instead of forcing a download offer).  The files are
-  not uncompressed if they were fetched via the 'd'ownload command.
-  Note, however, that if you activate a link for a compressed image or
-  other binary file, and don't have a viewer or helper app mapped for it,
-  it will already have been uncompressed before a D)ownload or C)ancel
-  offer can be made, so use the 'd'ownload command directly if it is
-  your intention to download such files.  Note also that on VMS "gzip -d"
-  is used for both gz and Z uncompression.  See the INSTALLATION file for
-  info on getting the VMS port of gzip. - FM
-07-06-96
-* Allow any startfile and homepage in -validate mode even if they are not
-  http URLs. - FM
-* Made all the 'o'ptions menu statusline prompts and informational messages
-  strings that can be defined in userdefs.h for different languages. - FM
-* Mods to send one Accept header as a comma-separated list instead of a
-  series of individual Accept header statements. - FM
-07-05-96
-* Added NO_FILE_REFERER configuration symbol and -nofilereferer switch
-  for disabling transmissions of Referer headers for any file URLs (is
-  a subset of what NO_REFERER_HEADER and -noreferer disable). - FM
-* Tweaks to facilitate additions of security-related patches. - FM
-07-04-96
-* Added NEWS_CHUNK_SIZE and NEWS_MAX_CHUNK configuration symbols and
-  -newschunksize and -newsmaxchunk switches for regulating the chunking
-  of news article listings.  See comments in lynx.cfg for explanation. - FM
-07-02-96
-* Tweaks of URL_DOMAIN_PREFIXES and URL_DOMAIN_SUFFIXES handling (was
-  doing double scheme prefixing under some circumstances). - FM
-* Fixed problem of potential crashes with bad HTML which lacks any
-  OPTION tags in SELECT containers (Yes, HTML that bad is really out
-  there! 8-). - FM
-* Fixed problem of potential infinite loop in HText_endAppend() for documents
-  that contain nothing but SCRIPTs and empty OBJECT containers (as in the
-  Microsoft ActiveX demos). -FM
-07-01-96
-* Added circular recall buffer for paths used as the second argument in
-  'd'ownload and 'p'rint menu commands.  Use the up- and down-arrow keys
-  to access then at the statusline prompt, equivalently to the recalls for
-  previous 'g'oto URLs, 'j'ump shortcuts, and ISINDEX or WHEREIS search
-  queries. - FM
-* Modified the LYMail.c functions to work as intended with both curses
-  and slang (through v0.9-33) on both Unix and VMS. - FM
-06-30-96
-* Changed yesterday's symbols to URL_DOMAIN_PREFIXES and URL_DOMAIN_SUFFIXES
-  and added code to guess the scheme based on the first field of the domain
-  name (e.g., gopher.wfbr.edu will become gopher://gopher.wfbr.edu instead
-  an http://host URL).  Note also that a partial host string can contain a
-  dot within it and still be tested with prefixes and suffixes if the DNS
-  lookup fails with the host string as entered (e.g., cc.ukans will become
-  http://www.cc.ukans.edu), and only dots at the end or beginning of the
-  partial host string will block prepending or appending, respectively, of
-  items from the prefix or suffix lists (e.g., ftp.foo. will block use of
-  items from the prefix list, but permit tests from the suffix list, and
-  will become ftp://ftp.foo.dom if the ftp.foo.dom lookup succeeds). - FM
-06-29-96
-* Added HTTP_DOMAIN_PREFIXES and HTTP_DOMAIN_SUFFIXES in userdefs.h and
-  lynx.cfg for defining lists and setting the order of domain name prefixes
-  and suffixes to use when creating http:// URLs from command line and
-  'g'oto arguments which are not already URLs and cannot be opened via a
-  file://localhost URL (see 05-30-96 entry). - FM
-06-28-96
-* Tweaks of MIME header handling. - FM
-06-27-96
-* Do not send a referer header for links obtained from the history list,
-  bookmark file, or jumps file. - FM
-* Made sorts by name case-sensitive in ftp and file listings. - FM
-* Added osf-slang make target. - FM
-* Enable ^C (SIGINT) interrupts during spawns on Unix (^C and ^Y interrupts
-  were already being enabled for VMS ). - FM
-* Fixed glitch in WHEREIS search handling. - Michael Barabanov
-  (baraban@luz.cs.nmt.edu)
-06-26-96
-* Tweaks of ftp gateway for VM/CMS servers based on feedback from PG. - FM
-* More tweaks of 'o'ptions menu and DISPLAY handling. - FM
-* Tweaks for builds with WIN_TCP on VMS. - FM
-06-24-96
-* Modified 'o'ptions menu handling to allow NULLing of strings which were
-  set at startup.  Note that if you NULL (or set) the DISPLAY variable,
-  Lynx configured itself for X/Motif or not based on whether it was set
-  (or NULL) at startup, and you need to restart Lynx to really change the
-  configuration for 'd'ownload forces versus X/Motif viewer spawns. - FM
-* More tweaks of language code, to make the HTCJK enum checks more
-  portable. - FM
-06-23-96
-* Set up handling of nested DIV tags with ALIGN attributes (and CENTER,
-  which is treated as DIV ALIGN="center"). - FM
-* Removed INSERT, ALIAS and MH from the DTD, and their associated code
-  from HTML.c and GridText.c. - FM
-06-22-96
-* Tweaks of character set handling. - FM
-* Added function for graphic boxing of popups with curses on VMS. - FM
-06-21-96
-* Mods to translate CJK escape sequences and take Kanji into account when
-  handling statusline() messages.  That's in effect if a CJK character set
-  is selected, and regardless of the raw or CJK mode setting, because the
-  strings are coming from definitions in userdefs.h, not the document that
-  is being rendered or displayed. - FM
-* Added more statusline() string definitions in userdefs.h. - FM
-* Ignore a server's Content-Encoding header if it inappropriately indicates
-  "8bit" or "7bit" (should be indicated a compression scheme). - FM
-* Mods to use charset strings as in the 07-Jun-1996 HTTP/1.1 draft, and to
-  check for those as well as their common synonyms. - FM
-* Mods to revive clearok() functionality with the slang 0.99-33 library
-  (need it for Kanji handling and for VMS), and to deal with the definition
-  conflicts for the (poorly added) TRUE and FALSE definitions in the new
-  slang library's SLcurses.h. - FM
-06-20-96
-* Added handling of the SFS file system on VM ftp servers, tested on
-  ftp://ubvm.cc.buffalo.edu/ (be sure to escape the colons if you use SFS
-  paths, e.g., ftp://ubvm.cc.buffalo.edu/vmsysu%3alistserv.webshare) - FM
-* More memory management enhancements and leak plugs. - FM
-* Added -DUNIX and -DSCO to the sco and sco5 libwww targets. - BL
-06-17-96
-* Added handling of &shy;, &#173;, and 8-bit 173 for ISO-Latin-1 documents,
-  as a soft hyphen for all of the character sets. - FM
-* Polished up and massively annotated the new character set handling
-  code. - FM
-* Made all the dummy libwww headers in WWW/Library/Implementation
-  compatible with the new, actually used, headers in /src. - FM
-* Fixed some bad ifdef-ing for statusline string definitions which
-  were added to userdefs.h. - FM
-06-15-96
-* Added many more userdefs.h definitions for statusline() and HTAlert()
-  messages. - FM
-* Tweaks of ALT string handling when they are used as forced link names
-  for USEMAP, AREA, IMG, EMBED or APPLET sources. - FM 
-* Oops, hadn't put the new HTML.h in the zip. - FM
-* Fixed casing typo for HTCJK.h inclusion in HTMIME.c. - LWV
-06-14-96
-* Updated the help files, lynx.man and lynx.hlp concerning the character
-  set handling. - FM
-* Changed the -jpn switch to a generic -raw switch, and the LYK_JPN_TOGGLE
-  ('@') to a generic LYK_RAW_TOGGLE.  The toggling also can be done via
-  the 'o'ptions menu, in conjunction with selecting character sets.  See
-  the comments about CHARACTER_SET in userdefs.h and lynx.cfg for more
-  information.  The toggle determines whether raw 8-bit characters in the
-  document are assumed to be ISO-8859-1, and therefore translated for the
-  non-"ISO Latin 1" character sets based on their LYCharSets.c arrays, or
-  are assumed to match the character set (e.g, 8-bit ISO-8859-2 when the
-  "ISO Latin 2" set is selected, or Kanji when a CJK set is selected) and
-  therefore processed raw.  Use raw or CJK mode when you know the charset
-  of the document is a match to your selected character set, but no header
-  or suffix has indicated that the charset is not ISO-8859-1. Be careful
-  about this when "Other ISO Latin" is selected, since the document could
-  be, e.g., ISO-8859-3, but you are using, e.g., ISO-8859-5. - FM
-* Added "Other ISO Latin", "Chinese", "Japanese (EUC)", "Japanese (SJIS)",
-  "Korean", and "Taipei (Big5)", character sets, which presently translate
-  8-bit ISO-8859-1 named and numeric entities to 7-bit approximations, and
-  added a default "CHARACTER_SET" definition in userdefs.h, complementary
-  to that in lynx.cfg. - FM
-* Worked in the expanded CJK (Chinese, Japanese, Korean) escape sequence and
-  Kanji handling from Takuya ASADA's June 11, 1996 Lynx2-5CJK (available in
-  ftp://ftp.three-a.co.jp/pub/www/lynx). - FM
-06-11-96
-* Tweak of the ftp gateway to handle Reflection Unix emulation servers. - FM
-* Made lynx_version_putenv_command a global so we can free it at exit
-  via free_lynx_globals() in LYMain.c. - FM
-06-10-96
-* Convert a 0xFFFF value from slang in LYgetch() to 7 (^G) to cancel
-  whatever called it, instead of exiting on error. - FM
-* Tweaks of Makefile to use symbolic, $(include) and $(lib) paths with
-  ncurses for convex, NeXT and sun4, and for SOCKSLIB. - LWV 
-* Tweaks of mail editor handling based on patch from Arne Riiber
-  (riiber@systek.no). - FM
-06-09-96
-* Had overdone it plugging memory leaks and was freeing the proxy, news
-  server, and lynx version variables too soon. - FM
-06-07-96
-* Moved the Kanji handling variables into HText structure elements to make
-  the GridText.c functions reentrant for them, and added code for regulating
-  them via charset parameters in server headers or META tags.  The recognized
-  parameters are EUC-JP, Shift-JIS, ISO-2022-JP, ISO-2022-JP-2, and EUC-KR.
-  E.g., a META with:
-       	HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=Shift-JIS"
-  will set up handling of the document as Shift-JIS. - FM
-* Made handling of Kanji more reliable when SJIS is the default, based
-  on the strategy in Takuya ASADA's Japanized Lynx2-4-2. - FM
-* K&Rized the Ichikawa ISO-2022-JP MIME header handling functions and added
-  them to HTMIME.c, together with Takuya ASADA's (asada@three-a.co.jp)
-  function for guessing whether an escape has been lost and filling it in,
-  and use them for checking news headers. - FM
-* Retry DCL spawns without the TRUSTED flag if it was included and we
-  got back an INVARG status. - Robert C. Gray (gray@cyberodyssey.com)
-06-06-96
-* Plugged lots of memory leaks. - FM
-* Handle colons in code for expanding host names and prepending http://
-  (e.g., wfbr:8002 will become http://www.wfbr.edu:8002/). - FM
-* More tweaks of character conversions. - FM
-* Block crashes if illegal markup such as Anchors are present in the
-  OPTION strings for SELECT. - FM
-06-04-96
-* Mods of entity and end tag handling in SGML.c and LYCharUtils.c. - FM
-* Tweaks of make target for sun4-slang. - NHE
-06-03-96
-* More tweaks of the ftp gateway. - FM
-* More anti-crash protections for bad HTML. - FM
-* Tweaks of LYCharUtils.c and SGML.c. - KW
-* Enclose the username for rlogin URLs in double-quotes on VMS to preserve
-  mixed casing if present. - Robert C. Gray (gray@cyberodyssey.com)
-06-02-96
-* Made DEFAULT_CACHE_SIZE and DEFAULT_VIRTUAL_MEMORY_SIZE configurable via
-  lynx.cfg. - FM
-* Added comments in HTFTP.c to make more clear some of the counterintuitive
-  things being done, and why. - FM
-* Oops, had left my ISSPACE() debugging macro in HTFTP.c yesterday.  Is
-  now back to isspace(). - FM
-06-01-96
-* Added support for ;type=I (or A or D) to specify Image or ASCII transfer 
-  modes, or a Directory, in ftp URLs. - FM
-* Added support for VM/CMS ftp servers.  Note that 'd'ownloaded text files
-  will have CRLF as line terminators, due to their use of ASCII records
-  (tested on ftp://pucc.princeton.edu/anonymou.376). - FM
-* Added support for use of a tilde on Unix ftp servers to indicate that you
-  want a listing of the user's login directory instead of the root (i.e.,
-  ftp://user@host/~ or ftp://user@host/~username will cause Lynx to attempt
-  a listing of the translated ~ or ~username).  Paths can be appended (e.g.,
-  ftp://user@host/~/subdirectory).  This should not be used with anonymous
-  ftp, or in public documents.  It yields the behavior on Unix or Unix-like
-  ftp servers which should occur without the tilde, based on RFC 1738.  Note
-  that the valid behavior involving use of %2f is implemented for VMS (see
-  the 12-20-95 entry, below), but the behavior for Unix and Unix-like ftp
-  servers emulates Lynx's Unix DIRED_SUPPORT. - FM
-* Mods of CSO/PH gateway to deal with discontinuous field name tokens
-  (e.g., "NYU fax" instead of "NYU_fax"). - FM
-* More fixes for the putenv_command pointer in LYMain.c. - CC
-* Add curly braces to the current hack for mininizing reversals of
-  trace messages with slang. - KW
-05-30-96
-* Modified the http:// prepending code to try expanded host names if the
-  the first (or only) element does not contain a dot and is not a known
-  host name.  Will first try it as www.host.com, then www.host.edu, then
-  www.host.net, then www.host.org, e.g., wfbr/dir/lynx will become an
-  http://www.wfbr.edu/dir/lynx URL. - FM
-* Added handling of MSDOS_SERVER ftp server type (tested on ftp.hayes.com)
-  and corrected WINDOWS_NT_SERVER handling (tested on ftp.boca.org). - FM
-* Reset any modified, non-HT-LEFT styles in HTML_free() if they were not
-  reset in HTML_end_element() due to missing end tags. - FM
-* Initialize the putenv_command pointer in LYMain.c. - Christophe Colle
-  (colle@krtkg1.rug.ac.be)
-* Include LYLocal.h in LYCgi.c. - Carl Hansen (hansen@best.com)
-05-28-96
-* Made all mainloop() statusline() message strings definitions in userdefs.h
-  for easier modification to other languages (we'll move them to a catalog
-  someday 8-). - FM
-* Added string definitions in userdefs.h for statusline messages identifying
-  active or DISABLED radio buttons. - FM
-* More tweaks of character conversions.  Note that numeric entities with
-  values greater than 255 are displayed as text, until we are able to
-  handle them as Unicode.  - FM
-* Implemented ID handling for BDO. - FM
-05-27-96
-* Added nested handling of Q, so that it alternates between double-quotes
-  and single-quotes, with directionality of start and end single-quotes
-  (should someday check the LANG and DIR attributes, and character set,
-  to use other quoting conventions if appropriate). - FM
-* Use [DEL: ... :DEL] labeling to indicate DEL content, and [INS: ... :INS]
-  labeling to indicate INS, S, and STRIKE content. - FM
-* Added ID handling for ABBREV, ACRONYM, AU, AUTHOR, BIG, DEL, INS, Q, S,
-  SMALL, SUB, SUP and SPAN. - FM
-* Added code to clear the screen of any trace messages directed to the
-  screen, once the full page has been created. - FM
-* Added code to minimize slang's casting of trace messages as reverse when
-  directed to the screen instead of a file. - FM
-05-26-96
-* More tweaks of character conversions. - FM
-* Added submit_enctype elements to the forms structures as will be needed to
-  implement INPUTS with TYPE="file" (someday 8-), and set disabled for FORM
-  fields if the ENCTYPE is multipart/form-data, until we can handle that
-  (someday 8-), so the user won't fill out the FORM pointlessly. - FM
-* Made the third argument of SLang_init_tty() 1 so that '\n' will be treated
-  as CRLF when trace messages are sent to the screen instead of to a file.
-  Might cause problems with the slang screen management functions, but
-  doesn't seem to according to KW. - FM
-05-25-96
-* Mods to pass 8-bit control characters entered via the line editor.  They
-  should be assumed to be valid if the user entered them, and could indeed
-  be valid for Japanese and Russian. - FM
-* Check for a NULL return value from initscr() on Unix. - Geert Jan de Groot
-  (GeertJan.deGroot@ripe.net)
-* Tweaks of character conversions, and of 8-bit character handling with
-  slang. - Klaus Weide (kweide@tezcat.com)
-* Added TRUSTED_URL for specifying lynxexec and lynxprog URLs which always
-  are permitted, based on patches from David Drum (david@more.net). - FM
-05-21-96
-* Made the LOCAL_DOMAIN symbol configurable via lynx.cfg. - FM
-* Added descriptions of the quality (q=) and maxbytes (mxb=) parameters
-  in the sample mailcap file. - FM
-* Added a maxbytes element to the libwww presentation and converter
-  structures, and code for specifying a maximum for mailcap entries via
-  a semi-colon-separated mxb=value field, where "value" is a positive
-  integer (e.g., ; mxb=1000000).  The default is 0, meaning no maximum.
-  If the value exceeds 0, a maxbytes parameter will be appended in the
-  Accept: header for the Content-Type. - FM
-05-20-96
-* Added code for specifying a quality parameter for mailcap entries via
-  a semi-colon-separated q=value field, where "value" is a floating point
-  number (e.g., ; q=0.002), and for appending the quality parameters in
-  Accept: headers if the values are less than 1.0. - FM
-* Treat screen width as 80 for the startup page when doing traversals with
-  a slang-build Lynx to prevent a crash. - FM
-05-19-96
-* Mods in HTML.c to make resolving of local file URLs more efficient. - FM
-* Tweaks of Makefile for slang. - Ed Doolittle (dolittle@math.toronto.edu)
-05-18-96
-* Added FRAME elements and attributes to the DTD, and code for creating
-  links to the SRCs. - FM
-* Added numerous sanity checks for valid but inappropriate combinations
-  of attributes based on the HTML 3.2 DTD.
-05-17-96
-* Added support for TYPE and VALUE attributes of LIs in OLs.  TYPEs
-  are equivalent to those for OL, and VALUE is equivalent to START
-  or SEQNUM for OL.  See the 11-28-95, 10-17-95, 09-19-95 and 09-04-95
-  entries in this file.  If a TYPE is changed via an LI, the change
-  persists for subsequent LIs of that OL.  The VALUE set for an LI
-  similarly increments for subsequent LIs in that OL. - FM
-05-16-96
-* Made SGML_character() in SGML.c fully reentrant. - FM
-* Set up capturing of marked sections, and DOCTYPE, ELEMENT, ATTLIST and
-  ENTITY declarations in SGML.c.  Lynx doesn't do anything with them yet,
-  besides reporting them in trace mode, but they at least won't create
-  garbage in the display if they start being used for the "next generation"
-  of clients. - FM
-* Set up base code for CSIs (Client Side Includes, homologous to SSIs).
-  See the comments for LYDoCSI() in LYUtils.c.  It should be moved to a
-  separate module if someone wants to work on CSIs seriously.  LYDoCSI()
-  is called from SGML.c if the document was obtained via a file URL on
-  the local host and has comments that begin with "!--#". - FM
-05-15-96
-* Add a MIME charset parameter to POST Content-Type headers if it's not
-  ISO-8859-1 or US-ASCII and the server included the parameter when it
-  sent the form (but don't do it simply on the basis of the user's current
-  character set, because if the server didn't include the parameter, it's
-  CGI script probably won't parse the client header either, and will return
-  an error instead of processing the form submission). - FM
-05-14-96
-* Tweaks for Unixware and addition of a unixware-slang Makefile target based
-  on patches from Thanh Ma (tma@encore.com). - FM
-* Tweaks for SCO and addition of an sco5 Makefile target based on patches
-  from Bela Lubkin (filbo@armory.com). - FM
-* Include ;q=0.001 for the wildcard (*/*) Accept header. - FM
-05-13-96
-* Added support for a host field in news URLs, analogous to that for nntp
-  URLs.  Though illegal according to the current RFCs, discussions with a
-  W3C member about this Netscapism indicate that Lynx may as well support
-  it now, rather than continue failing when it is encountered. - FM
-05-12-96
-* Added an explicit GetYX definition for slang in LYForms.c. - FM
-05-11-96
-* Eliminated the NCURSESINCDIR compilation symbol and added NCURSESHEADER,
-  so the default now is to seek ncurses/curses.h and -DNCURSESHEADER invokes
-  a seek for the (now obsolete 8-) ncurses.h. - FM
-* Added an explicit GetYX definition for slang in LYStrings.c (now avoids
-  reference to stdscr). - FM
-* Mods in tcp.h for TCPWARE builds on VMS with DECC. - FM
-05-08-96
-* Fixed typo in Makefile entry for linux. - LWV
-05-07-96
-* Added LYPassHighCTRL boolean for passing normally illegal 8-bit control
-  characters, and set it TRUE when the KOI8-R character set is selected
-  (note that they also are passed when Japanese character support is
-  toggled ON). - FM
-05-06-96
-* Mods in SGML.c to handle "<URL:" as text instead of an unknown tag. - FM
-05-05-96
-* Added typecasts of the third arguments for the getsockname() and
-  accept() calls in HTFTP.c to void pointers, to avoid conflicts with
-  their declarations as int versus unsigned int across platforms and
-  flavors. - FM
-* Renamed the for-VMS opendir(), readdir() and closedir() to HTVMSopendir(),
-  HTVMSreaddir() and HTVMSclosedir(), and the for-UCX ioctl() to HTioctl(),
-  to avoid possible conflicts with their additions to newer versions of
-  VMS and UCX. - FM
-05-04-96
-* Fixed typo which was placing a space instead of a slash between the
-  User-Agent name and version. - Tim Rowley (tor@cs.brown.edu)
+11-30-96
+* Added the ability to set the advanced mode for multiple bookmarks from
+  the options menu and save the defaults in the .lynxrc file - HL
+* Various typo corrections including one which kept LYMainLoop.c from
+  compiling under unix when DIRED_SUPPORT was defined. - HL
+11-29-96
+* Numerous additional refinements and enhancements of the multiple bookmark
+  support.  Added support for REFRESH and PREV_DOC in the options and bookmark
+  menus, and NEXT_PAGE, PREV_PAGE, and ACTIVATE in the bookmark menus or
+  prompts.  Expanded the anchor and document structures to keep track of
+  different bookmark files in conjunction with VIEW_BOOKMARK, ADD_BOOKMARK,
+  and DEL_BOOKMARK commands, to restore the proper bookmark files on reloads
+  (overt, or because the cache was dumped for subsequent documents accessed
+  via bookmark links), and in conjunction with security-related restrictions.
+  Multiple bookmark support can be regulated via MULTI_BOOKMARK_SUPPORT,
+  BLOCK_MULTI_BOOKMARKS and ADVANCED_MULTI_BOOKMARKS symbols in userdefs.h
+  (or as SITE_DEFS in the Makefile) and lynx.cfg.  The multiple bookmark
+  support can be blocked via a -restrictions=multibook command line switch,
+  which is also set for -anonymous and -validate.  Prompting or display of
+  the bookmark file selection menu occurs only if bookmark files in addition
+  to the startup default have been defined (via the B)ookmark command in the
+  'o'ptions menu, if mu(L)ti bookmarks has been turned on; the setting and
+  definitions can be saved in the .lynxrc file).  Plugged memory leaks in
+  the previous implementation of multiple bookmark support.  Added code for
+  inserting the current description and filepath for each bookmark file
+  dynamically during rendering. - FM
+* Another tweak of attribute order in HTMLDTD.c. - KW
+11-28-96
+* Tweaked multiple bookmark support to fix an error which was causing a
+  crash on some systems and incorrect behavior on others - HL
+* Tweaked editing of multiple bookmark filenames to correct shifting of 
+  screen between multiple pages - HL
+11-26-96
+* Added support for setting the rendering of SELECT OPTIONs as popup menus
+  versus radio button lists via the 'o'ptions menu, and saving the default
+  in the RC file.  Changed NO_SELECT_POPUPS to USE_SELECT_POPUPS in lynx.cfg
+  and userdefs.h.  The -popup switch still overrides everything. - FM
+* Added multiple bookmark support along the lines of the patch from Filip M.
+  Gieszczykiewicz (filipg@paranoia.com), plus numerous enhancements of the
+  'o'ptions menu and bookmark handling. - FM
+* Tweaks of attribute orders in HTMLDTD.h and HTMLDTD.c. - KW
+11-25-96
+* Updated the "Lynx Enhanced Pages" links to the new "Lynx links"
+  (http://www.crl.com/~subir/lynx.html) throughout the help, docs,
+  and code. - FM 
+11-24-96
+* Modified the ENCTYPE="multipart/form-data" handling to indicate the
+  Content-Type with charset parameter, when known, within each part
+  rather than in the main Content-Type header. - FM
+* Corrected typo in HTNews.c. - FM
+* Added support for setting the suggested filename in 'd'ownload and
+  'p'rint options based on the Content-Disposition header if it included
+  the string  file; filename=name.suffix  in its value.  Can be used by
+  CGI scripts to set the suggested filename for saves to disk, downloads
+  or mailings of the script's reply body, so it won't be the last symbolic
+  element in the path field of the form's ACTION (which is normally the
+  the script, itself, or a PATH_INFO element, and thus misleading). - FM 
+* Tweaks of change_sug_filename() in LYUtils.c for better handling of
+  gzipped files on VMS. - FM
+11-23-96
+* Added reporting of the Server, Date and Last-Modified headers, if present
+  in server replies, to the showinfo ('=') display. - FM
+* Added the ability to store the NO_SELECT_POPUPS in the .lynxrc, but the
+  .lynxrc must be edited manually until the options handling is converted
+  to a form-like interface that accommodates more options.  For now, select
+  'O'ptions and write out the options with '>' to create a block in .lynxrc
+  with an explanation of the switch.  The switch is "select_popups" and
+  can have the values of "on", "off", or nothing.  If nothing, the default
+  set in userdefs.h or lynx.cfg will persist.  Otherwise, "on" will set use
+  of popups and "off" will set use of radio buttons as the default.  The
+  startup default always can be toggled via the -popup switch. - HL & FM
+* Corrected a couple of typos in the help files. - HL
+11-22-96
+* Added support for WHEREIS ('/') and 'n'ext searches within SELECT popups.
+  The buffering for 'n'ext is separate from that in the main loop (i.e.,
+  for non-form field document searches), but all previously entered search
+  strings are still combined into a circular buffer and can be accessed via
+  the up-arrow or down-arrow keys at the prompt for a search string.  The
+  searches within popup menus do not yield highlighting of the search string,
+  but simply positioning of the cursor on successive options which contain
+  the search string. - FM
+* Added support for all of the navigation commands within SELECT popup
+  windows, including HOME, END, UP_TWO, DOWN_TWO, UP_HALF and DOWN_HALF,
+  in addition to the single line and paging navigation commands. - FM
+* Added support for the REFRESH command within SELECT popup windows. - FM
+* Tweak of hookless snews handling. - FM
+11-21-96
+* Added handling of forms with ENCTYPE="multipart/form-data".  Note that
+  we still don't support INPUTs with TYPE="file" or TYPE="range", and
+  thus still set the DISABLED attribute for all fields in the form if
+  either of those two TYPEs are present in it. - FM
+* Tweak of -mime_header handling. - FM
+* Typo fixes of comments in HTML.c. - Albert S Woodhull
+  (aswNS@hamp.hampshire.edu)
+11-20-96
+* Added a NO_SELECT_POPUPS compilation (userdefs.h) and configuration
+  (lynx.cfg) definition, normally set FALSE.  If set TRUE, single-choice
+  SELECT blocks (i.e., ones without the MULTIPLE attribute) will be handled
+  as a list of radio buttons instead of via a popup window.  Also added a
+  -popup command line switch for toggling the compilation or configuration
+  setting. - FM
+11-18-96
+* Tweak of LYFindEndOfComment() in LYCharUtils.c. - Brian Borowski
+  (brianb@braille.uwo.ca)
+11-17-96
+* Added links to the lynx-dev hypertext archive at FLORA in the online
+  'h'elp. - FM
+* Tweaks of my_spawn() in LYLocal.c. - KW
+11-16-96
+* Added support for use of the 'd'ownload command on TYPE="submit" and
+  TYPE="image" submit buttons.  You still must use the History Page for
+  TYPE="text" INPUT fields that also act as submit buttons by virtue of
+  being the only non-hidden field, because the 'd'ownload command key
+  could be a text entry into the field, and thus must be treated as
+  such. - FM 
+11-15-96
+* Mods of HTFormat.c and HTTP.c for better handling of unexpected server
+  disconnects. - FM
+11-13-96
+* Wind down the element stack on EOF if any unclosed tags were received. - FM
+* Fixed typos in the HTMLDTD.c BODYTEXT definitions. - FM
+11-10-96
+* More tweaks of hook-less snews handling. - FM
+* Changed the default STARTFILE to http://lynx.browser.org/ and the default
+  HELPFILE to the v2.6 set at NYU in userdefs.h and lynx.cfg. - FM
+* New function HTUnEscapeSome() in HTParse.c for unescaping selected
+  characters in a string.. - KW
+* Numerous changes to make DIRED_SUPPORT work as intended, to use the
+  library's HTList functions and macros for managing the list of tagged
+  file URLs, and to keep track of proper levels of URL escaping so that
+  unusual filenames which contain #% etc. are handled properly.  Can now
+  edit, move, etc. Abc%25252525def.html, #xy#~, etc. - KW
+11-09-96
+* Treat 301 or 302 redirection of a POST as 303 when the Lynx process is
+  non-interactive, rather than rejecting the redirection, since 303 is
+  still most likely what the CGI script actually intends (will still
+  prompt if the process is interactive). - FM
+* Added parsing and trace mode reporting of Content-Disposition headers
+  in HTMIME.c (should be used, someday, to set the suggested file name
+  for disk saves and downloads based on any filename=foo.blah field). - FM
+* Further mods of HTNews.c to facilitate use of Lynx without SSL-hooks
+  in conjunction with an SSL-capable daemon/proxy for snews URLs that
+  returns NNTP streams for Lynx itself to convert into HTML, instead
+  of already converted streams as from a standard proxy. - TZ & FM
+11-08-96
+* Changed information returned by "-version" in LYMain.c to point to
+  lynx.browser.org and added a date to the copyright info. - HL
+11-07-96
+* Mods of HTNews.c to facilitate use of Lynx without SSL-hooks in
+  conjunction with an SSL-capable daemon/proxy for snews URLs. - TZ
+11-05-96
+* Typo fixes in HTMIME.c. - KW
+* Tweak of NSL_FORK mods. - FM
+11-04-96
+* Tweaks of host parsing when a password and/or username is present
+  in override_proxy() of HTAccess.c. - FM
+* Tweaks of the UNDERSCORES and STARS macro setup and useage to avoid
+  possible crashes for FORMs with long values. - FM
+* Worked in Tom Zerucha's (tz@execpc.com) code for fork-based name
+  server lookups that can be 'z'apped.  May not yet be portable to
+  all flavors of Unix.  Add -DNSL_FORK to your SITE_LYDEFS to try
+  it. - FM
+11-02-96
+* Fixed typo in HTAlert.h. - FM
+* Cleaned up HTTCP.c code, simplified some of its spaghetti
+  ifdef'ing, and worked in mods to bypass connection confirmations
+  when Lynx is SOCKSified and the socks_flag is set. - FM
+* Added recognition and acceptance of text/x-sgml and text/sgml
+  MIME types (all that I've encountered thus far work fine with
+  Lynx, though it doesn't yet interpret marked sections). - FM
+* Added socket function prototypes for MultiNet in tcp.h. - FM
+* Mods to facilitate application of the SSL patches (after some
+  corrections in the patches to keep HTLoadHTTP re-entrant, make
+  CONNECT work as intended again, and eliminate memory leaks in
+  the SSLeay adaption) - FM
+* Adding info about -DNO_TTYTYPE in top level Makefile. - FM
+* Use clrtoeol() in LYOptions.c to ensure that no terminals which use
+  reverse video for standout() will have trailing reverse fields on
+  edits of option vaules. - DK
+* Offer user@host instead of WebMaster@host for the 'c'omment command
+  if the path for the URL begins with a tilde and there is no
+  LINK REV="made" present. - FM
+* Tweaks of inews Makefile and clientlib.c. - Christopher R. Maden
+  (crm@ebt.com)
+* Check nhist before attempting a DIRED_SUPPORT directory listing in
+  LYShowInfo.c. - KW
+10-21-96
+* Offer WebMaster@host for the 'c'omment command if no LINK REV="made"
+  was present in a text/html document, and save a known owner URL when
+  toggling to source ('\') so that the 'c'omment command can still be
+  used with that owner's (mailto or homepage) URL, but the source can
+  be included in the comment, as would be desireable (instead of a bad
+  rendering) when sending a comment about bad HTML in the document. - FM
+10-20-96
+* Added code for traversing the pseudo-documents created for client-side
+  image MAPs.  See the updated CRAWL.announce for more information. - FM
+10-19-96
+* Added definitions in LYCurses.h relating curses function calls to slang
+  functions or emulations for compatibility with new versions of slang,
+  based on patch from John E. Davis (davis@space.mit.edu). - FM
+* Added unescaping of the full address fields in mailto URLs or ACTIONs,
+  and improved the reliability of the parsing of the subject header from
+  the ?searchpart Netscapism when present. - FM
+* Give user option to use 303-like coversion of POST to GET in confirmation
+  requests for redirection of POSTs, base on patches from Drazen Kacar
+  (dave@fly.cc.fer.hr). - FM
+* Tweaks of POST content submissions in HTTP.c, based on patch from
+  KW. - FM
+* Fixed EOF checks in HTAAFile.c, HTGroup.c and HTPasswd.c, and improved
+  host address parsing in HTTCP.c, based on patches from Larry Schwimmer
+  (schwim@cyclone.stanford.edu) and Klaus Weide (kweide@tezcat.com). - FM
+* Added targets for umaxv and umaxv-slang for Encore's UMAXV - Thanh Ma
+  (tma@encore.com)
+10-16-96
+* Send the rendering of decompressed files to stdout with -dump, don't
+  spawn a viewer under any circumstances if -dump was used instead of
+  -source for Content-Types that are not text/html, and remove the
+  temporary decompressed files before exiting with -dump or -source. - FM
+* Properly handle TYPE="radio" versus TYPE="checkbox" INPUTs with NULL
+  or zero-length VALUEs. - FM
+* Added a continuation line token for the netbsd-ncurses target - HL
+* Fixed a typo in HTMIME.c in the trace output - HL
+* Block predictable buffer overrun in GridText.c if a page has more
+  than MAXLINKS links in it. - FM
+10-01-96
+* Add a Mime-Version header to the other headers in LYPrint.c so that the
+  09-20-96 mods for mailing source do what they were intended to do. :) -
+  Hamish MacEwan (macewanh@diatp.dia.govt.nz)
+09-20-96
+* Add a BASE tag to the tops of HTML source files, a la Netscape, when
+  mailing or downloading, and don't worry, for now, if that creates
+  technically invalid HTML (since Lynx copes with it as of the 09-15-96
+  mods 8-). - FM
+* Include Content-Type, Content-Location and Content-Base headers when
+  mailing HTML source on Unix. - FM
+* Use .txt versus .html suffixes when submitting rendered versus HTML source
+  temporary files to VMS MAIL, so that transports such as PMDF will indicate
+  the appropriate Content-Type. - FM
+09-17-96
+* Handle illegally positioned BASE tags. - FM
+* Tweak of Q nesting level checks. - Pawel Wiecek
+  (coven@i17linuxb.ists.pwr.wroc.pl)
+* Fixed typo in HTMIME.c for parsing of Pragma header. - Wilson Cheung
+  (wcheung@netcom.com)
+* Added parsing of Set-Cookie header in HTMIME.c (see IETF ID
+  http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-mgmt-03.txt
+  for info on how to implement it's use). - FM
+* Fixed typo in LYMainLoop.c for display of error message when up arrow is
+  pressed at the top of a document. - Hiram Lester, Jr. (hwlester@pobox.com)
+09-16-96
+* Use standard ls -l parsing of LIST output for Windows_NT ftp servers in
+  Lynx v2.6 as in v2.5. - FM
 
---- STARTING  2.5FM ---
---- Rename of Lynx2-4-FM and release as Lynx2-5  (02-May-1996) ---
-    (see CHANGES2-5, CHANGES2-4 and CHANGES2-3)
+--- Rename of Lynx2-5FM and release as Lynx2-6  (02-Sep-1996) ---
+    (see CHANGES2-6, CHANGES2-5, CHANGES2-4 and CHANGES2-3)
 ==============================================================================
diff --git a/CHANGES2-6 b/CHANGES2-6
new file mode 100644
index 00000000..73c158ab
--- /dev/null
+++ b/CHANGES2-6
@@ -0,0 +1,732 @@
+--- Rename of Lynx2-5FM and release as Lynx2-6  (02-Sep-1996) ---
+==============================================================================
+09-02-96 ---- Release of Lynx2-6 ----
+* More expansions of the online 'h'elp files. - FM
+* Updated the PROBLEMS file. - FM
+09-01-96
+* More expansions of the online 'h'elp files. - FM
+* Tweaks of list handling. - FM
+* Miscellaneous code cleanups and annotations. - FM
+08-31-96
+* Further updates and expansions of the online 'h'elp files. - FM
+* Tweaks of alignment handling with bad HTML. - FM
+* Added JIS X 0201 Japanese Kana string support. - TA & FM
+08-30-96
+* Further updates and expansions of the online 'h'elp files. - FM
+* Typo fixes in the help and doc files. - LWV
+* Tweaks of ENCTYPE handling for FORM submissions. - FM
+08-29-96
+* Today's distribution is a pre-release of v2.6.  The projected official
+  release date is 09-02-96.
+* Tweaks of numeric character reference handling. - FM
+* Typo fix in LYShowInfo.c. - IC
+08-28-96
+* Added handling of ENCTYPE="application/sgml-form-urlencoded" in FORMs
+  as a directive to use semi-colons instead of ampersands as name=value
+  separators, and to indicate that as the Content-Type for POSTs. - FM
+* Convert ampersands in addresses and link names, and angle-brackets in
+  link names, to SGML entities when creating bookmarks and showinfo ('=')
+  link 'l'ist, client-side-image-map, and history list text/html streams
+  or temporary files. - FM
+* More SGML compliance mods for the handling of attribute values which
+  represent URLs or URL components. - FM
+* Tweaks of form INPUT, TEXTAREA, SELECT and OPTION handling. - FM
+* Check EAGAIN on socket connect or select attempts for all platforms and
+  flavors. - FM
+* Include both <time.h> and <sys/time.h> in tcp.h for AIX.
+* Adding warning and info in the INSTALLATION file and userdefs.h on how
+  to cope with telnetd environment variable spamming for anonymous accounts
+  running Lynx captively. - FM
+08-24-96
+* Enhancements of the History List handling.  Show each link's actual address
+  in addition to the titles, since the actual addresses can't be determined
+  via showinfo or the 'l'ist display, and links in the History List derived
+  from searches can have the same titles but different searchparts or hidden
+  content appended.  If a link in the History List is activated, is still
+  cached, has POST content, and ALWAYS_RESUBMIT_POSTS was configured off (as
+  recommended) and wasn't toggled on via -resubmit_posts, prompt the user
+  whether to resubmit the form (versus retrieve the cached rendition from
+  the previous submission).  We don't bother prompting on PREV_DOC ("back")
+  fetches, and still resubmit forms with POST content whenever their submit
+  buttons are activated, i.e., regardless of whether ALWAYS_RESUBMIT_POSTS
+  has been configured or toggled on. - FM 
+* If a user attempts to add a bookmark while viewing a document returned
+  via a form submission with POST content, and it contains links, offer
+  the current link with it's link name for editing.  Otherwise, display
+  a statusline message that documents from forms with POST content cannot
+  be saved as bookmarks. - FM
+08-23-96
+* Added UP_HALF and DOWN_HALF commands, mapped by default to '(' and ')',
+  for going back or forward half a page in the document.  These are
+  complementary to UP_TWO and DOWN_TWO, for going back or forward two
+  lines (remember to use the 'K'eymap command for a list of all of the
+  keystroke command bindings currently in effect, since they may have
+  been changed via lynx.cfg from the defaults described in the online
+  'H'elp). - FM
+* Made the Control-A and Control-E keys default synonyms for HOME and END,
+  complementary to their use for going to the beginning or end of the line
+  when using the line editor. - FM
+* Don't lose track of source versus present mode on returns from temporary
+  menu files to documents derived from forms with method POST. - FM
+* Ugh, I had deleted one too many lines from HTTP.c when stripping out my
+  SSL hooks for the distribution copy (no wonder the Authorization mods
+  worked fine for me but nobody else 8-). - FM
+08-22-96
+* Added handling of named entities and numeric character references in
+  the values of most of the non-URL attributes (we don't waste overhead
+  doing that for the values of simple attributes, like ALIGN, which have
+  designated strings). - FM
+08-21-96
+* Safely handle named entities and numeric character references in the values
+  of BASE, LINK, HREF, SRC, ACTION, DATA, CODEBASE and CODE attributes, and
+  in the URL field for the CONTENT of META with a "Refresh" HTTP-EQUIV or
+  NAME.  They are converted in relation to the "ISO Latin 1" Character Set
+  array regardless of the selected Character Set (except that nbsp and shy
+  remain 160 and 173), then 8-bit translations are hex escaped (as they
+  should have been in the markup 8-), and ESC is hex escaped or omitted
+  depending on whether a CJK character set has been selected.  There's no
+  way to do it such that the resolved URL always will be valid no matter
+  what yoyos or CGI scripts put in document instances, but this strategy
+  maximizes the chances while making sure no "dangerous" characters, based
+  on the selected Character Set, are ever sent to the screen (it used to be
+  HyperText Markup Language, not HyperGraphic Markup Language 8-)- FM
+* Allow Control-G or a zero-length username or password to act as a cancel
+  of the request (and restoration of the current document) when an http
+  server invokes prompting for Authorization. - FM
+* When using a proxy server, report the target host instead of the proxy
+  in prompts for Authorization. - FM 
+* Show MIME types of files, if known, whenever a download offer is forced,
+  regardless of why it was forced (i.e, not only for mismatches between
+  the document's charset and the selected character set). - FM
+08-20-96
+* Yet more tweaks of MIME header parsing. - FM
+08-19-96
+* Enhancements of the news gateway. - FM
+* Tweaks of Content-Type and charset handling. - FM
+* Tweaks of MIME header parsing. - FM
+08-18-96
+* Tweaks of the news gateway and its documentation. - FM
+08-17-96
+* Added overt (rational 8-) handling of all status codes that might be
+  returned (appropriately or inappropriately 8-) from HTTP/1.1 http
+  servers, and massively annotated the code in HTTP.c. - FM
+* Added parsing in HTMIME.c, and at least trace mode reporting, for all
+  http server reply and entity headers as in the 08-12-96 HTTP/1.1 draft.
+  We should not get many of them, unless we declare ourselves as an HTTP/1.1
+  client and send the appropriate request headers, but they're all available
+  now for use as more HTTP/1.1 features are added. - FM
+08-16-96
+* Added handling of "Pragma: no-cache" or "Cache-Control: no-cache" headers
+  from http servers, and polished up the code for handling them via META
+  directives. - FM
+08-15-96
+* Modified form handling so that Lynx always resubmits forms if their method
+  is POST, even if their content was not changed, when their submit buttons
+  or submitting text input are activated.  Changed the ALWAYS_RESUBMIT_FORMS
+  compilation and configuration definitions, and -resubmit_forms command
+  line toggle, to ALWAYS_RESUBMIT_POSTS, and -resubmit_posts.  When FALSE,
+  you still get the previously returned document from a POSTed form if that
+  document had links which you activated, and then go back with the PREV_DOC
+  command or via the history list.  If set TRUE, the form will be resubmitted
+  under those circumstances as well.  Documents returned by forms with method
+  GET still require use of the RESUBMIT command to resubmit if the forms'
+  content was not changed, and forms with a mailto action still always mail
+  the content on activation of the submit button or submitting text input
+  (no document is returned, so the PREV_DOC command and history list behaviors
+  are irrelevant). - FM
+* Use space to plus conversions for values of submitted form content (Ugh,
+  Lynx has been using %20 all these years!  It worked because they are
+  unescaped to space, anyway. 8-). - FM
+* Polished up and massively annotated the redirection handling code.  If
+  a user approves redirection of a form with POST content, it will not be
+  freed and the submission will not be converted to a contentless GET request
+  unless the status was 303 (See Other).  For 300 (Multiple Choices), the
+  returned document is offered, which should include links with descriptions
+  of their media types.  The returned document (if any) is now displayed for
+  any redirection status code if no Location: header was present, and for
+  unknown 3xx codes (i.e., greater than 305).  If Lynx gets an inappropriate
+  304 (Not Modified), it switches to HEAD mode and displays the status line,
+  and anything else returned by the server, as text/plain.  A 301 (Moved
+  Permanently) will be treated as 302 (Moved Temporarily) for form submissions
+  with POST content.  Otherwise, Lynx will use the new URL for the remainder
+  of the current session (users will have to do a 'r'emove and 'a'dd for their
+  bookmarks themselves, for now).  A 305 (Use Proxy) will not be honored if
+  Lynx is already using a proxy, and instead the returned document will be
+  displayed.  The limit on serial redirections was dropped from the current
+  10 to 5, as recommended in the August 10, 1996 HTTP/1.1 draft. - FM
+08-13-96
+* Mods to accommodate the HTTP/1.1 300 - 305 Redirection status codes, and
+  to require user confirmation for any redirection of POST content. - FM
+* Tweaks of OBJECT handling. - FM
+08-12-96
+* Implemented all aspects of OBJECT that make sense for a text client.
+  Will descend though nested OBJECTs.  Can be used for presenting PRE
+  formatted character-cell versions of images, and appears to handle
+  all likely uses of the SHAPES and USEMAP attributes in OBJECTs.  The
+  pseudo-ALTs for links to non-script DATA values (i.e, the for-GUI
+  sources) when offered as links (e.g., in clickable_images mode), if
+  not a markup-specified string (e.g., based on a TITLE attribute),
+  are (IMAGE) or (OBJECT), based on whether the nature of the source
+  can be inferred from the context, or an explicit TYPE attribute in
+  the OBJECT start tag.  The use of parens instead of square-brackets
+  indicates that the links are for OBJECTs as opposed to IMGs. - FM
+* Tweaks of SELECT and OPTION handling. - FM
+08-09-96
+* Lots more stuff added to the online help files. - FM
+* Added state code in SGML.c to avoid getting tripped up by any single or
+  double quotes in CJK escape sequences that are within single or double
+  quoted attribute values. - TA
+* Restrict resetting the Kanji code flag on white space to Japanese
+  (i.e., not also Chinese, Taipai, or Korean). - TA
+* Added handling of EPLF lines (with local time) for the FTP gateway. -
+  D. J. Bernstein (djb@koobera.math.uic.edu)
+08-08-96
+* Added code for handling captured OBJECT content with the SHAPES
+  attribute equivalently to our handling of FIG, and with USEMAP and/or
+  ISMAP content equivalently to our handling of IMG.
+* Added code for capturing potentially nested container elements that
+  require pre-processing, e.g., OBJECT, and for passing the processed
+  markup back to the SGML parser to be inserted within the ongoing HTML
+  stream.
+* Added CHECK_EAGAIN Makefile definition for non-SVR4 Unix flavors which
+  might need it for socket connect() and select() calls. - FM
+* Tweaks of keyboard input with slang when LYCursesON is FALSE. - FM
+08-06-96
+* Terminate and start a new Accept: header line if the current one will
+  exceed 1 KB (shouldn't be necessary, but otherwise the long lines cause
+  an error for WebSitePro and crash Netscape servers, and perhaps have
+  adversed effects on some other http servers with ill designed code for
+  content negotiation). - FM
+* Give temporary files suffixes matched to the Content-Type for all flavors
+  of Unix and for VMS, not just for NeXT. - FM 
+* Tweak of Location: header parsing in HTTP.c (trim all lead spaces). - FM
+08-05-96
+* More help and documentation updates. - FM
+08-04-96
+* Updated the online help files. - FM
+08-03-96
+* Mods of "user (A)gent" 'o'ption handling.  Also added a "useragent"
+  -restriction, included in the defaults for anonymous accounts.  See
+  the "Lynx options menu" section of the "Lynx Users Guide" via the
+  online 'h'elp for more information. - FM
+* Tweaks of messaging for unsupported URLs. - FM
+* Tweaks of interrupt handling on VMS. - FM
+08-02-96
+* Added handling of Refresh in META tags.  The URL is presented as a link
+  pointed to by a "REFRESH(n sec):" label, where "n" is the seconds
+  parameter from the META tag, and you must activate it yourself, which
+  should enable people using Lynx via a braille interface to examine
+  the initial document before it is refreshed.  The META format is:
+  <META HTTP-EQUIV=refresh CONTENT="n; URL=url"> where "n" can be "0" or
+  a positive integer, and the "; URL=url" field is optional, defaulting
+  to the document's own address.  Netscape's docs say that "url" should
+  be a complete URL, but their client doesn't require it, and so it's
+  users don't reliably use complete URLs.  Lynx therefore resolves "url"
+  versus the document's own address if it is not complete. - FM
+08-01-96
+* Added handling of ENCTYPE="text/plain" for FORMs with a mailto ACTION.
+  The name=value pairs are not hex escaped, and physical newlines instead
+  of '&' separate the pairs, so that the content is readable directly. - FM
+* Added SUBJECT attribute as synonym for TITLE in FORMs (Some clients
+  are using it instead of TITLE for mailto ACTIONs, ugh!). - FM
+* Tweaks of DEL, S, STRIKE, and INS handling. - FM
+* Handle any newline characters in quoted INPUT values. - FM
+* Added news-ncurses and news-slang Makefile targets, and tweaks of headers
+  for sony_news. - Makoto MATSUSHITA (matusita@ics.es.osaka-u.ac.jp)
+07-30-96
+* Finished and incorporated lynx_url_support.html in the online help,
+  and updated lynx_help_main.html. - FM
+* Tweaks of ID attribute handling. - FM
+* Tweaks of the gopher gateway. - FM
+* Updated IBMPC-charsets.announce. - MB
+07-26-96
+* Set the default anonymous account restrictions if Lynx is invoked in
+  the account pointed to by ANONYMOUS_USER, or with the -anonymous switch,
+  before processing any additional command line restrictions, so that any
+  greater restrictions will not drop back to the compilation defaults.
+  Note that the full set of -validate restrictions always are enforced for
+  that switch, i.e., no matter what other switches or compilation options
+  are used, and whether or not the account is anonymous. - FM
+* Implemented handling of the ANONYMOUS_USER definition on VMS (equivalently
+  to it's implementation on Unix). - FM
+* Tweaks of mailto URL handling and setting of the default subject via
+  TITLE attributes. - FM
+* Tweak of the news gateway's handling of the author (From:) field. - FM 
+07-25-96
+* If a server returns redirection without a complete URL indicated, resolve
+  it relative to the original request instead of issuing an error message
+  (this is incorrect behavior, but that's another trashed standard, and
+  Lynx may as well handle the situation as standard-less clients do). - FM
+* Move the NO_JUMPFILE and JUMP_PROMPT definitions to LYMessages_en.h - FM
+* Added code for selective disabling of goto by scheme in anonymous accounts,
+  along lines of patch from Doug Lawson (dlawson@epfl2.epflbalto.org). - FM
+* Ignore any viewer mappings for text/html or text/plain in mailcap
+  files. - FM
+07-22-96
+* Updated ptx target and added ptx-slang. - Alan Coopersmith
+  (alanc@CSUA.Berkeley.EDU)
+* Added all the new elements and attributes from the July 12 HTML 3.2/Cougar
+  DTD, and implemented the new IMG TITLE attribute for use with USEMAP.
+* Added a -startfile_ok switch for allowing a non-http startfile or homepage
+  with -validate, and restored the behavior of not allowing *any* non-http
+  URLs by default.
+07-19-96
+* Treat PLAIN and TYPE="plain" as equivalent in UL tags. - FM
+* Fixed the mispositioning of thinsp in HTMLDTD.c. - FM
+07-18-96
+* Moved the statusline prompt, message, and warning string definitions
+  out of userdefs.h into an LYMessages_en.h header.  See the comments
+  in userdefs.h and LYMessages_en.h for more information. - FM
+* Removed the -lc from the LIBS= list of the snake3 and snake3-slang
+  targets, added a description of the HP/UX 10.10 select() problems
+  and reported (but not yet satisfactory) workarounds in the PROBLEMS
+  file, and a note in the Makefile to read the PROBLEMS file. - FM
+07-17-96
+* Numerous typecasts added for optimized compilations. - FM
+* Tweaks for ISC. - WS
+* Changed make to $(MAKE) and -g to -O for Unix targets (may need
+  tweaking for some flavors 8-). - FM
+* Added news target for SONY NEWS-OS 4.2.1R based on patch from
+  Kazuya 'Sharl' Masuda (masuda@sp.hudson.co.jp) and TA. - FM
+* Fixed typo in LYList.c from yesterday's mods. - FM
+07-16-96
+* Plugged memory leaks associated with temporary file names. - FM
+* Finally figured out what was creating orphan child anchors, and plugged
+  that memory leak in HTAnchor_delete(). - FM
+* Replace <sys/select.h> with <sys/timeb.h> for SCO in tcp.h. - BL
+* Mods to avoid warning about redefinition of signal when building on
+  VMS with old versions of SOCKETSHR (irrelevant, but might worry
+  people who don't know that the warning can be ignored). - FM
+07-15-96
+* Plugged various memory leaks in FORM handling code. - FM
+07-13-96
+* Add the startfile, and homepage if different, to the 'g'oto recall
+  buffer so that they are available for editing in addition to any
+  overtly entered 'g'oto URLs. - FM
+* Changed TRUSTED_URL to ALWAYS_TRUSTED_EXEC for clarity, and plugged
+  memory leaks and some security holes in that code. - FM
+* Fixed typo in code for handling Z compressed files. - FM
+07-12-96
+* Added handling of &thinsp; (&#8201;), and handling of &#8194; as &ensp;,
+  &#8195; as &emsp;, &#8211; as &ndash; or &endash;, &#8212; as &mdash; or
+  &emdash;, and &#8482; as &trade; (treated as &reg; &#174;), based on the
+  Cougar DTD. - FM
+* Increased the line buffer size in HTLoadHTTP() and limited the deflt string
+  length in HTPrompt() to avoid possibilities of buffer overruns. - FM
+07-11-96
+* Block access to file: URLs via network served files or bookmarks in
+  addition to 'g'oto entries when -restrictions=file_url is set (one of
+  the default restrictions for -anonymous). - FM
+* Extended compressed file handling to the ftp gateway and local files.
+  If you ACTIVATE the link instead of overtly invoking a 'd'ownload, and
+  the path with the gz or Z stripped maps to a displayable Content-Type or
+  one for which you have a viewer or helper app, the file will be treated
+  as if it had a Content-Encoding: header indicating the compression (i.e.,
+  uncompressed and displayed or passed to the viewer or helper app). - FM
+* Mods to send http servers an Accept-Encoding: header indicating gzip and
+  compress, and to block inclusion of our new, internal www/compressed MIME
+  type in the Accept: header list. - FM
+* Changed the names of the lex_buffer and lex_lines globals to HTlex_buffer
+  and HTlex_lines in case name conflicts are causing segmentation faults on
+  linux for long usernames in authorization requests, and changed all
+  malloc()'s to calloc()'s in that code in case there's an initialization
+  glitch I don't yet see. - FM
+07-09-96
+* Use the username and password of an -auth= command line argument only
+  for the first realm that requests authorization, so they don't preclude
+  access to other realms later in any interactive session that might have
+  a different username and/or password, and handle inclusion of only a
+  username or only a password in the -auth= argument. - FM
+* Tweaks of memory leak plugs in authorization handling functions (hopefully
+  now avoiding segmentation faults on linux 8-). - FM
+* Include -lc in the first position of the LIBS= list for snake3 targets.
+  - Donald S. Teiser <dsteis01@homer.louisville.edu)
+* Enhancements of Makefile. - LWV
+07-07-96
+* Tweaks of code for uncompressing on the fly.  Will now force a download
+  offer without uncompressing if there is no presentation mapping for the
+  Content-Type. - FM
+* Retain blank lines within TEXTAREA content (but not trailing blanks). - DT
+07-07-96
+* Added functions for uncompressing and handling documents which have
+  Content-Encoding headers that indicate "x-gzip", "gzip", "x-compress",
+  or "compress" (instead of forcing a download offer).  The files are
+  not uncompressed if they were fetched via the 'd'ownload command.
+  Note, however, that if you activate a link for a compressed image or
+  other binary file, and don't have a viewer or helper app mapped for it,
+  it will already have been uncompressed before a D)ownload or C)ancel
+  offer can be made, so use the 'd'ownload command directly if it is
+  your intention to download such files.  Note also that on VMS "gzip -d"
+  is used for both gz and Z uncompression.  See the INSTALLATION file for
+  info on getting the VMS port of gzip. - FM
+07-06-96
+* Allow any startfile and homepage in -validate mode even if they are not
+  http URLs. - FM
+* Made all the 'o'ptions menu statusline prompts and informational messages
+  strings that can be defined in userdefs.h for different languages. - FM
+* Mods to send one Accept header as a comma-separated list instead of a
+  series of individual Accept header statements. - FM
+07-05-96
+* Added NO_FILE_REFERER configuration symbol and -nofilereferer switch
+  for disabling transmissions of Referer headers for any file URLs (is
+  a subset of what NO_REFERER_HEADER and -noreferer disable). - FM
+* Tweaks to facilitate additions of security-related patches. - FM
+07-04-96
+* Added NEWS_CHUNK_SIZE and NEWS_MAX_CHUNK configuration symbols and
+  -newschunksize and -newsmaxchunk switches for regulating the chunking
+  of news article listings.  See comments in lynx.cfg for explanation. - FM
+07-02-96
+* Tweaks of URL_DOMAIN_PREFIXES and URL_DOMAIN_SUFFIXES handling (was
+  doing double scheme prefixing under some circumstances). - FM
+* Fixed problem of potential crashes with bad HTML which lacks any
+  OPTION tags in SELECT containers (Yes, HTML that bad is really out
+  there! 8-). - FM
+* Fixed problem of potential infinite loop in HText_endAppend() for documents
+  that contain nothing but SCRIPTs and empty OBJECT containers (as in the
+  Microsoft ActiveX demos). -FM
+07-01-96
+* Added circular recall buffer for paths used as the second argument in
+  'd'ownload and 'p'rint menu commands.  Use the up- and down-arrow keys
+  to access then at the statusline prompt, equivalently to the recalls for
+  previous 'g'oto URLs, 'j'ump shortcuts, and ISINDEX or WHEREIS search
+  queries. - FM
+* Modified the LYMail.c functions to work as intended with both curses
+  and slang (through v0.9-33) on both Unix and VMS. - FM
+06-30-96
+* Changed yesterday's symbols to URL_DOMAIN_PREFIXES and URL_DOMAIN_SUFFIXES
+  and added code to guess the scheme based on the first field of the domain
+  name (e.g., gopher.wfbr.edu will become gopher://gopher.wfbr.edu instead
+  an http://host URL).  Note also that a partial host string can contain a
+  dot within it and still be tested with prefixes and suffixes if the DNS
+  lookup fails with the host string as entered (e.g., cc.ukans will become
+  http://www.cc.ukans.edu), and only dots at the end or beginning of the
+  partial host string will block prepending or appending, respectively, of
+  items from the prefix or suffix lists (e.g., ftp.foo. will block use of
+  items from the prefix list, but permit tests from the suffix list, and
+  will become ftp://ftp.foo.dom if the ftp.foo.dom lookup succeeds). - FM
+06-29-96
+* Added HTTP_DOMAIN_PREFIXES and HTTP_DOMAIN_SUFFIXES in userdefs.h and
+  lynx.cfg for defining lists and setting the order of domain name prefixes
+  and suffixes to use when creating http:// URLs from command line and
+  'g'oto arguments which are not already URLs and cannot be opened via a
+  file://localhost URL (see 05-30-96 entry). - FM
+06-28-96
+* Tweaks of MIME header handling. - FM
+06-27-96
+* Do not send a referer header for links obtained from the history list,
+  bookmark file, or jumps file. - FM
+* Made sorts by name case-sensitive in ftp and file listings. - FM
+* Added osf-slang make target. - FM
+* Enable ^C (SIGINT) interrupts during spawns on Unix (^C and ^Y interrupts
+  were already being enabled for VMS ). - FM
+* Fixed glitch in WHEREIS search handling. - Michael Barabanov
+  (baraban@luz.cs.nmt.edu)
+06-26-96
+* Tweaks of ftp gateway for VM/CMS servers based on feedback from PG. - FM
+* More tweaks of 'o'ptions menu and DISPLAY handling. - FM
+* Tweaks for builds with WIN_TCP on VMS. - FM
+06-24-96
+* Modified 'o'ptions menu handling to allow NULLing of strings which were
+  set at startup.  Note that if you NULL (or set) the DISPLAY variable,
+  Lynx configured itself for X/Motif or not based on whether it was set
+  (or NULL) at startup, and you need to restart Lynx to really change the
+  configuration for 'd'ownload forces versus X/Motif viewer spawns. - FM
+* More tweaks of language code, to make the HTCJK enum checks more
+  portable. - FM
+06-23-96
+* Set up handling of nested DIV tags with ALIGN attributes (and CENTER,
+  which is treated as DIV ALIGN="center"). - FM
+* Removed INSERT, ALIAS and MH from the DTD, and their associated code
+  from HTML.c and GridText.c. - FM
+06-22-96
+* Tweaks of character set handling. - FM
+* Added function for graphic boxing of popups with curses on VMS. - FM
+06-21-96
+* Mods to translate CJK escape sequences and take Kanji into account when
+  handling statusline() messages.  That's in effect if a CJK character set
+  is selected, and regardless of the raw or CJK mode setting, because the
+  strings are coming from definitions in userdefs.h, not the document that
+  is being rendered or displayed. - FM
+* Added more statusline() string definitions in userdefs.h. - FM
+* Ignore a server's Content-Encoding header if it inappropriately indicates
+  "8bit" or "7bit" (should be indicated a compression scheme). - FM
+* Mods to use charset strings as in the 07-Jun-1996 HTTP/1.1 draft, and to
+  check for those as well as their common synonyms. - FM
+* Mods to revive clearok() functionality with the slang 0.99-33 library
+  (need it for Kanji handling and for VMS), and to deal with the definition
+  conflicts for the (poorly added) TRUE and FALSE definitions in the new
+  slang library's SLcurses.h. - FM
+06-20-96
+* Added handling of the SFS file system on VM ftp servers, tested on
+  ftp://ubvm.cc.buffalo.edu/ (be sure to escape the colons if you use SFS
+  paths, e.g., ftp://ubvm.cc.buffalo.edu/vmsysu%3alistserv.webshare) - FM
+* More memory management enhancements and leak plugs. - FM
+* Added -DUNIX and -DSCO to the sco and sco5 libwww targets. - BL
+06-17-96
+* Added handling of &shy;, &#173;, and 8-bit 173 for ISO-Latin-1 documents,
+  as a soft hyphen for all of the character sets. - FM
+* Polished up and massively annotated the new character set handling
+  code. - FM
+* Made all the dummy libwww headers in WWW/Library/Implementation
+  compatible with the new, actually used, headers in /src. - FM
+* Fixed some bad ifdef-ing for statusline string definitions which
+  were added to userdefs.h. - FM
+06-15-96
+* Added many more userdefs.h definitions for statusline() and HTAlert()
+  messages. - FM
+* Tweaks of ALT string handling when they are used as forced link names
+  for USEMAP, AREA, IMG, EMBED or APPLET sources. - FM 
+* Oops, hadn't put the new HTML.h in the zip. - FM
+* Fixed casing typo for HTCJK.h inclusion in HTMIME.c. - LWV
+06-14-96
+* Updated the help files, lynx.man and lynx.hlp concerning the character
+  set handling. - FM
+* Changed the -jpn switch to a generic -raw switch, and the LYK_JPN_TOGGLE
+  ('@') to a generic LYK_RAW_TOGGLE.  The toggling also can be done via
+  the 'o'ptions menu, in conjunction with selecting character sets.  See
+  the comments about CHARACTER_SET in userdefs.h and lynx.cfg for more
+  information.  The toggle determines whether raw 8-bit characters in the
+  document are assumed to be ISO-8859-1, and therefore translated for the
+  non-"ISO Latin 1" character sets based on their LYCharSets.c arrays, or
+  are assumed to match the character set (e.g, 8-bit ISO-8859-2 when the
+  "ISO Latin 2" set is selected, or Kanji when a CJK set is selected) and
+  therefore processed raw.  Use raw or CJK mode when you know the charset
+  of the document is a match to your selected character set, but no header
+  or suffix has indicated that the charset is not ISO-8859-1. Be careful
+  about this when "Other ISO Latin" is selected, since the document could
+  be, e.g., ISO-8859-3, but you are using, e.g., ISO-8859-5. - FM
+* Added "Other ISO Latin", "Chinese", "Japanese (EUC)", "Japanese (SJIS)",
+  "Korean", and "Taipei (Big5)", character sets, which presently translate
+  8-bit ISO-8859-1 named and numeric entities to 7-bit approximations, and
+  added a default "CHARACTER_SET" definition in userdefs.h, complementary
+  to that in lynx.cfg. - FM
+* Worked in the expanded CJK (Chinese, Japanese, Korean) escape sequence and
+  Kanji handling from Takuya ASADA's June 11, 1996 Lynx2-5CJK (available in
+  ftp://ftp.three-a.co.jp/pub/www/lynx). - FM
+06-11-96
+* Tweak of the ftp gateway to handle Reflection Unix emulation servers. - FM
+* Made lynx_version_putenv_command a global so we can free it at exit
+  via free_lynx_globals() in LYMain.c. - FM
+06-10-96
+* Convert a 0xFFFF value from slang in LYgetch() to 7 (^G) to cancel
+  whatever called it, instead of exiting on error. - FM
+* Tweaks of Makefile to use symbolic, $(include) and $(lib) paths with
+  ncurses for convex, NeXT and sun4, and for SOCKSLIB. - LWV 
+* Tweaks of mail editor handling based on patch from Arne Riiber
+  (riiber@systek.no). - FM
+06-09-96
+* Had overdone it plugging memory leaks and was freeing the proxy, news
+  server, and lynx version variables too soon. - FM
+06-07-96
+* Moved the Kanji handling variables into HText structure elements to make
+  the GridText.c functions reentrant for them, and added code for regulating
+  them via charset parameters in server headers or META tags.  The recognized
+  parameters are EUC-JP, Shift-JIS, ISO-2022-JP, ISO-2022-JP-2, and EUC-KR.
+  E.g., a META with:
+       	HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=Shift-JIS"
+  will set up handling of the document as Shift-JIS. - FM
+* Made handling of Kanji more reliable when SJIS is the default, based
+  on the strategy in Takuya ASADA's Japanized Lynx2-4-2. - FM
+* K&Rized the Ichikawa ISO-2022-JP MIME header handling functions and added
+  them to HTMIME.c, together with Takuya ASADA's (asada@three-a.co.jp)
+  function for guessing whether an escape has been lost and filling it in,
+  and use them for checking news headers. - FM
+* Retry DCL spawns without the TRUSTED flag if it was included and we
+  got back an INVARG status. - Robert C. Gray (gray@cyberodyssey.com)
+06-06-96
+* Plugged lots of memory leaks. - FM
+* Handle colons in code for expanding host names and prepending http://
+  (e.g., wfbr:8002 will become http://www.wfbr.edu:8002/). - FM
+* More tweaks of character conversions. - FM
+* Block crashes if illegal markup such as Anchors are present in the
+  OPTION strings for SELECT. - FM
+06-04-96
+* Mods of entity and end tag handling in SGML.c and LYCharUtils.c. - FM
+* Tweaks of make target for sun4-slang. - NHE
+06-03-96
+* More tweaks of the ftp gateway. - FM
+* More anti-crash protections for bad HTML. - FM
+* Tweaks of LYCharUtils.c and SGML.c. - KW
+* Enclose the username for rlogin URLs in double-quotes on VMS to preserve
+  mixed casing if present. - Robert C. Gray (gray@cyberodyssey.com)
+06-02-96
+* Made DEFAULT_CACHE_SIZE and DEFAULT_VIRTUAL_MEMORY_SIZE configurable via
+  lynx.cfg. - FM
+* Added comments in HTFTP.c to make more clear some of the counterintuitive
+  things being done, and why. - FM
+* Oops, had left my ISSPACE() debugging macro in HTFTP.c yesterday.  Is
+  now back to isspace(). - FM
+06-01-96
+* Added support for ;type=I (or A or D) to specify Image or ASCII transfer 
+  modes, or a Directory, in ftp URLs. - FM
+* Added support for VM/CMS ftp servers.  Note that 'd'ownloaded text files
+  will have CRLF as line terminators, due to their use of ASCII records
+  (tested on ftp://pucc.princeton.edu/anonymou.376). - FM
+* Added support for use of a tilde on Unix ftp servers to indicate that you
+  want a listing of the user's login directory instead of the root (i.e.,
+  ftp://user@host/~ or ftp://user@host/~username will cause Lynx to attempt
+  a listing of the translated ~ or ~username).  Paths can be appended (e.g.,
+  ftp://user@host/~/subdirectory).  This should not be used with anonymous
+  ftp, or in public documents.  It yields the behavior on Unix or Unix-like
+  ftp servers which should occur without the tilde, based on RFC 1738.  Note
+  that the valid behavior involving use of %2f is implemented for VMS (see
+  the 12-20-95 entry, below), but the behavior for Unix and Unix-like ftp
+  servers emulates Lynx's Unix DIRED_SUPPORT. - FM
+* Mods of CSO/PH gateway to deal with discontinuous field name tokens
+  (e.g., "NYU fax" instead of "NYU_fax"). - FM
+* More fixes for the putenv_command pointer in LYMain.c. - CC
+* Add curly braces to the current hack for mininizing reversals of
+  trace messages with slang. - KW
+05-30-96
+* Modified the http:// prepending code to try expanded host names if the
+  the first (or only) element does not contain a dot and is not a known
+  host name.  Will first try it as www.host.com, then www.host.edu, then
+  www.host.net, then www.host.org, e.g., wfbr/dir/lynx will become an
+  http://www.wfbr.edu/dir/lynx URL. - FM
+* Added handling of MSDOS_SERVER ftp server type (tested on ftp.hayes.com)
+  and corrected WINDOWS_NT_SERVER handling (tested on ftp.boca.org). - FM
+* Reset any modified, non-HT-LEFT styles in HTML_free() if they were not
+  reset in HTML_end_element() due to missing end tags. - FM
+* Initialize the putenv_command pointer in LYMain.c. - Christophe Colle
+  (colle@krtkg1.rug.ac.be)
+* Include LYLocal.h in LYCgi.c. - Carl Hansen (hansen@best.com)
+05-28-96
+* Made all mainloop() statusline() message strings definitions in userdefs.h
+  for easier modification to other languages (we'll move them to a catalog
+  someday 8-). - FM
+* Added string definitions in userdefs.h for statusline messages identifying
+  active or DISABLED radio buttons. - FM
+* More tweaks of character conversions.  Note that numeric entities with
+  values greater than 255 are displayed as text, until we are able to
+  handle them as Unicode.  - FM
+* Implemented ID handling for BDO. - FM
+05-27-96
+* Added nested handling of Q, so that it alternates between double-quotes
+  and single-quotes, with directionality of start and end single-quotes
+  (should someday check the LANG and DIR attributes, and character set,
+  to use other quoting conventions if appropriate). - FM
+* Use [DEL: ... :DEL] labeling to indicate DEL content, and [INS: ... :INS]
+  labeling to indicate INS, S, and STRIKE content. - FM
+* Added ID handling for ABBREV, ACRONYM, AU, AUTHOR, BIG, DEL, INS, Q, S,
+  SMALL, SUB, SUP and SPAN. - FM
+* Added code to clear the screen of any trace messages directed to the
+  screen, once the full page has been created. - FM
+* Added code to minimize slang's casting of trace messages as reverse when
+  directed to the screen instead of a file. - FM
+05-26-96
+* More tweaks of character conversions. - FM
+* Added submit_enctype elements to the forms structures as will be needed to
+  implement INPUTS with TYPE="file" (someday 8-), and set disabled for FORM
+  fields if the ENCTYPE is multipart/form-data, until we can handle that
+  (someday 8-), so the user won't fill out the FORM pointlessly. - FM
+* Made the third argument of SLang_init_tty() 1 so that '\n' will be treated
+  as CRLF when trace messages are sent to the screen instead of to a file.
+  Might cause problems with the slang screen management functions, but
+  doesn't seem to according to KW. - FM
+05-25-96
+* Mods to pass 8-bit control characters entered via the line editor.  They
+  should be assumed to be valid if the user entered them, and could indeed
+  be valid for Japanese and Russian. - FM
+* Check for a NULL return value from initscr() on Unix. - Geert Jan de Groot
+  (GeertJan.deGroot@ripe.net)
+* Tweaks of character conversions, and of 8-bit character handling with
+  slang. - Klaus Weide (kweide@tezcat.com)
+* Added TRUSTED_URL for specifying lynxexec and lynxprog URLs which always
+  are permitted, based on patches from David Drum (david@more.net). - FM
+05-21-96
+* Made the LOCAL_DOMAIN symbol configurable via lynx.cfg. - FM
+* Added descriptions of the quality (q=) and maxbytes (mxb=) parameters
+  in the sample mailcap file. - FM
+* Added a maxbytes element to the libwww presentation and converter
+  structures, and code for specifying a maximum for mailcap entries via
+  a semi-colon-separated mxb=value field, where "value" is a positive
+  integer (e.g., ; mxb=1000000).  The default is 0, meaning no maximum.
+  If the value exceeds 0, a maxbytes parameter will be appended in the
+  Accept: header for the Content-Type. - FM
+05-20-96
+* Added code for specifying a quality parameter for mailcap entries via
+  a semi-colon-separated q=value field, where "value" is a floating point
+  number (e.g., ; q=0.002), and for appending the quality parameters in
+  Accept: headers if the values are less than 1.0. - FM
+* Treat screen width as 80 for the startup page when doing traversals with
+  a slang-build Lynx to prevent a crash. - FM
+05-19-96
+* Mods in HTML.c to make resolving of local file URLs more efficient. - FM
+* Tweaks of Makefile for slang. - Ed Doolittle (dolittle@math.toronto.edu)
+05-18-96
+* Added FRAME elements and attributes to the DTD, and code for creating
+  links to the SRCs. - FM
+* Added numerous sanity checks for valid but inappropriate combinations
+  of attributes based on the HTML 3.2 DTD.
+05-17-96
+* Added support for TYPE and VALUE attributes of LIs in OLs.  TYPEs
+  are equivalent to those for OL, and VALUE is equivalent to START
+  or SEQNUM for OL.  See the 11-28-95, 10-17-95, 09-19-95 and 09-04-95
+  entries in this file.  If a TYPE is changed via an LI, the change
+  persists for subsequent LIs of that OL.  The VALUE set for an LI
+  similarly increments for subsequent LIs in that OL. - FM
+05-16-96
+* Made SGML_character() in SGML.c fully reentrant. - FM
+* Set up capturing of marked sections, and DOCTYPE, ELEMENT, ATTLIST and
+  ENTITY declarations in SGML.c.  Lynx doesn't do anything with them yet,
+  besides reporting them in trace mode, but they at least won't create
+  garbage in the display if they start being used for the "next generation"
+  of clients. - FM
+* Set up base code for CSIs (Client Side Includes, homologous to SSIs).
+  See the comments for LYDoCSI() in LYUtils.c.  It should be moved to a
+  separate module if someone wants to work on CSIs seriously.  LYDoCSI()
+  is called from SGML.c if the document was obtained via a file URL on
+  the local host and has comments that begin with "!--#". - FM
+05-15-96
+* Add a MIME charset parameter to POST Content-Type headers if it's not
+  ISO-8859-1 or US-ASCII and the server included the parameter when it
+  sent the form (but don't do it simply on the basis of the user's current
+  character set, because if the server didn't include the parameter, it's
+  CGI script probably won't parse the client header either, and will return
+  an error instead of processing the form submission). - FM
+05-14-96
+* Tweaks for Unixware and addition of a unixware-slang Makefile target based
+  on patches from Thanh Ma (tma@encore.com). - FM
+* Tweaks for SCO and addition of an sco5 Makefile target based on patches
+  from Bela Lubkin (filbo@armory.com). - FM
+* Include ;q=0.001 for the wildcard (*/*) Accept header. - FM
+05-13-96
+* Added support for a host field in news URLs, analogous to that for nntp
+  URLs.  Though illegal according to the current RFCs, discussions with a
+  W3C member about this Netscapism indicate that Lynx may as well support
+  it now, rather than continue failing when it is encountered. - FM
+05-12-96
+* Added an explicit GetYX definition for slang in LYForms.c. - FM
+05-11-96
+* Eliminated the NCURSESINCDIR compilation symbol and added NCURSESHEADER,
+  so the default now is to seek ncurses/curses.h and -DNCURSESHEADER invokes
+  a seek for the (now obsolete 8-) ncurses.h. - FM
+* Added an explicit GetYX definition for slang in LYStrings.c (now avoids
+  reference to stdscr). - FM
+* Mods in tcp.h for TCPWARE builds on VMS with DECC. - FM
+05-08-96
+* Fixed typo in Makefile entry for linux. - LWV
+05-07-96
+* Added LYPassHighCTRL boolean for passing normally illegal 8-bit control
+  characters, and set it TRUE when the KOI8-R character set is selected
+  (note that they also are passed when Japanese character support is
+  toggled ON). - FM
+05-06-96
+* Mods in SGML.c to handle "<URL:" as text instead of an unknown tag. - FM
+05-05-96
+* Added typecasts of the third arguments for the getsockname() and
+  accept() calls in HTFTP.c to void pointers, to avoid conflicts with
+  their declarations as int versus unsigned int across platforms and
+  flavors. - FM
+* Renamed the for-VMS opendir(), readdir() and closedir() to HTVMSopendir(),
+  HTVMSreaddir() and HTVMSclosedir(), and the for-UCX ioctl() to HTioctl(),
+  to avoid possible conflicts with their additions to newer versions of
+  VMS and UCX. - FM
+05-04-96
+* Fixed typo which was placing a space instead of a slash between the
+  User-Agent name and version. - Tim Rowley (tor@cs.brown.edu)
+
+--- STARTING  2.5FM ---
+--- Rename of Lynx2-4-FM and release as Lynx2-5  (02-May-1996) ---
+    (see CHANGES2-5, CHANGES2-4 and CHANGES2-3)
+==============================================================================
diff --git a/CRAWL.announce b/CRAWL.announce
index eb3f4a43..e734bcba 100644
--- a/CRAWL.announce
+++ b/CRAWL.announce
@@ -19,7 +19,9 @@ Added switches are:
                   startfile or WWW_HOME.
 
   -realm	  Further restrict http links to ones in the same realm
-                  as the startpage (e.g., http://host/~user/).
+                  (having a matching base URI) as the startpage (e.g.,
+		  http://host/~user/ will restrict the traversal to that
+		  user's public html tree).
 
   -crawl          With [-traversal] outputs each unique hypertext page
                   as an lnk###########.dat file in the format specified
@@ -49,7 +51,10 @@ TRAVERSE_FILE (traverse.dat):
                   traversed again (important if runs are started and 
                   stopped).  Placing an entry in this file BEFORE the
                   run will block traversal of that URL.  Unlike reject.dat
-                  a final * has no effect (see below).
+                  a final * has no effect (see below).  Note that Lynx
+		  internal client-side image MAP URLs will be included in
+		  this file (e.g., LYNXIMGMAP:http://server/foo.html#map1),
+		  in addition to the "real" (external) http URLs.
 
 TRAVERSE_FOUND_FILE (traverse2.dat):
                   Contains a list of all URLs that were traversed, in the
@@ -58,6 +63,11 @@ TRAVERSE_FOUND_FILE (traverse2.dat):
                   (separated from the URLs by TABs)  A URL and TITLE may be
                   present in this list many times.  To simplify the list,
                   on VMS use:  sort/nodups traverse2.dat;1 ;2
+		  Note that the URLs and TITLEs of the Lynx internal
+		  client-side image MAP pseudo-documents will not be
+		  included in this file, though "traversed", but only the
+		  http URLs and TITLEs derived from the MAP's AREA tag
+		  HREFs that were traversed.
 
 TRAVERSE_REJECT_FILE (reject.dat):
                   Contains a list of URLs that have been rejected from the
@@ -111,5 +121,11 @@ lnk########.dat   Numbered output files containing the contents of traversed
 		  numbered links but not the References list, include the
 		  -nolist switch as well.
 
+		  Note that any client-side image MAP pseudo documents
+		  that were "traversed" will not have lnk########.dat
+		  output files created for them, but output files will
+		  be created for "real" documents that were traversed
+		  based on the HREFs of the MAP's AREA tags.
+
 This functionality is still under development.  Feedback and suggestions
 are welcome.
diff --git a/DESC b/DESC
index fde1e3f7..04ad3e97 100644
--- a/DESC
+++ b/DESC
@@ -1,6 +1,6 @@
 Lynx is a distributed hypertext browser with full World Wide Web
-capabilities.  See the "Lynx Enhanced Pages":
-	<URL:http://www.nyu.edu/pages/wsn/subir/lynx.html>
+capabilities.  See "Lynx Information":
+	<URL:http://lynx.browser.org/>
 for information and collections of hyperlinks concerning Lynx.
 
 A listserv list exists for the distribution of Lynx related
diff --git a/LYMessages_en.h b/LYMessages_en.h
index f9fef9bd..eb30bcd4 100644
--- a/LYMessages_en.h
+++ b/LYMessages_en.h
@@ -2,7 +2,7 @@
  * Lynx - Hypertext navigation system
  *
  *   (c) Copyright 1992, 1993, 1994 University of Kansas
- *	 1996: GNU General Public License
+ *	 1995, 1996: GNU General Public License
  */
 #ifndef LYMESSAGES_EN_H
 #define LYMESSAGES_EN_H
@@ -13,9 +13,9 @@
  * modify them to make them more appropriate for you site, and/or
  * to use other languages.  Links to collections of alternate
  * definitions, developed by the Lynx User Community, are maintained
- * in the Lynx Enhanced Pages:
+ * in Lynx links:
  *
- *    http://www.nyu.edu/pages/wsn/subir/lynx.html
+ *    http://www.crl.com/~subir/lynx.html
  *
  * You can substitute one of those as LYMessages_en.h, or modify
  * the header inclusion statement in your userdefs.h to include
@@ -148,6 +148,7 @@
 #define SPAWNING_DISABLED "Spawning is currently disabled."
 #define DOWNLOAD_DISABLED "The 'd'ownload command is currently disabled."
 #define NO_DOWNLOAD_INPUT "You cannot download a input field."
+#define NO_DOWNLOAD_MAILTO_ACTION "Form has a mailto action!  Cannot download."
 #define NO_DOWNLOAD_PRINT_OP "You cannot download a printing option."
 #define NO_DOWNLOAD_UPLOAD_OP "You cannot download an upload option."
 #define NO_DOWNLOAD_PERMIT_OP "You cannot download an permit option."
@@ -305,6 +306,7 @@
  "Not a searchable indexed document -- press '/' to search for a text string"
 #define NO_OWNER \
  "No owner is defined for this file so you cannot send a comment"
+#define NO_OWNER_USE "No owner is defined. Use %s? [N] "
 #define CONFIRM_COMMENT "Do you wish to send a comment? [N]"
 #define MAIL_DISALLOWED "Mail is disallowed so you cannot send a comment"
 #define EDIT_DISABLED "The 'e'dit command is currently disabled."
@@ -437,7 +439,7 @@
  "You are not allowed to change the bookmark file!"
 #define DOTFILE_ACCESS_DISABLED "Access to dot files is disabled!"
 #define UA_COPYRIGHT_WARNING \
- "WARNING: Misrepresentaton of the User-Agent may be a copyright violation!"
+ "WARNING: Misrepresentation of the User-Agent may be a copyright violation!"
 #define CHANGE_OF_SETTING_DISALLOWED \
  "You are not allowed to change this setting."
 #define SAVING_OPTIONS "Saving Options..."
@@ -450,6 +452,20 @@
 #define ERROR_UNCOMPRESSING_TEMP "Error uncompressing temporary file!"
 #define UNSUPPORTED_URL_SCHEME "Unsupported URL scheme!"
 #define UNSUPPORTED_DATA_URL "Unsupported data: URL!  Use SHOWINFO, for now."
+#define	SERVER_ASKED_FOR_REDIRECTION \
+ "Server asked for redirection of POST content to"
+#define	PROCEED_GET_CANCEL "P)roceed, use G)ET or C)ancel "
+#define	ADVANCED_POST_REDIRECT \
+ "Redirection of POST content. P)roceed, see U)RL, use G)ET or C)ancel"
+#define	LOCATION_HEADER "Location: "
+#define STRING_NOT_FOUND "'%s' not found!"
+#define MULTIBOOKMARKS_DEFAULT "Default Bookmark File"
+#define MULTIBOOKMARKS_SAVE "Select destination or ^G to Cancel: "
+#define MULTIBOOKMARKS_SMALL "Screen too small! (8x35 min)"
+#define MULTIBOOKMARKS_MOVE "'[' previous, ']' next screen"
+#define MULTIBOOKMARKS_SELF \
+ "Reproduce L)ink in this bookmark file or C)ancel? (l,c): "
+#define MULTIBOOKMARKS_DISALLOWED "Multiple bookmark support is not available."
 
 #ifdef DIRED_SUPPORT
 #define DIRED_NOVICELINE \
diff --git a/Makefile b/Makefile
index 90575145..d220eb13 100644
--- a/Makefile
+++ b/Makefile
@@ -234,6 +234,8 @@ all:
 	@echo "decstation -- for DEC Ultrix (same as ultrix)"
 	@echo "ultrix-slang     -- for DEC Ultrix and color slang package"
 	@echo "decstation-slang -- for DEC Ultrix and color slang (same as ultrix-slang)"
+	@echo "umaxv   -- for Encore's UMAXV (SVR3.x) "
+	@echo "umaxv-slang   -- for Encore's UMAXV and color slang package"
 	@echo "unixware   -- for Novell's Unixware"
 	@echo "univell    -- for Novell's Unixware"
 	@echo "unixware-slang -- for Unixware and color slang package"
@@ -259,10 +261,10 @@ DIR_DEFS = $(DIRED_SUPPORT) $(DIRED_ARCHIVE) $(DIRED_TAR) $(DIRED_ZIP) $(DIRED_G
 #SITE_LIBS= # Your libraries here (remove the "#")
 
 # Set SITE_LYDEFS to one or more of the defines for the WWW Library:
-SITE_LYDEFS = $(DIR_LYDEFS) # Your defines here (remove the "#")
+SITE_LYDEFS = $(DIR_LYDEFS) # Your defines here
 
 # Set SITE_DEFS to one or more of the defines for lynx below:
-SITE_DEFS = $(DIR_DEFS) # Your defines here (remove the "#")
+SITE_DEFS = $(DIR_DEFS) # Your defines here
 
 # if you are compiling on a previously unsupported system, modify
 # this generic entry!!
@@ -288,6 +290,8 @@ SITE_DEFS = $(DIR_DEFS) # Your defines here (remove the "#")
 # -DSHORTENED_RBIND  For a SOCKSified lynx with the short version of Rbind.
 # -DNO_UNISTD_H    if you don't have <unistd.h>
 # -DNOPORT         if you must use PASV instead of PORT for FTP
+# -DNO_TTYTYPE	   if your system lacks a ttytype variable
+# -DNSL_FORK	   For fork-based name server lookups that can be 'z'apped.
 #
 # if you are linking to freeWAIS-0.202 or older, you should define this
 # in MCFLAGS (SITE_DEFS)
@@ -419,7 +423,7 @@ netbsd-ncurses:
 	cd WWW/Library/netbsd; $(MAKE) LYFLAGS="$(SITE_LYDEFS)"
 	cd src; $(MAKE) all CC="cc" MCFLAGS="-O -DFANCY_CURSES -DNCURSES -DUNIX \
 		-DNO_KEYPAD -DNO_CUSERID -I../$(WWWINC) $(SITE_DEFS) \
-		-I/usr/include/ncurses"
+		-I/usr/include/ncurses" \
 		LIBS="-lncurses -lcompat -ltermcap \
 		$(WAISLIB) $(SOCKSLIB) $(SITE_LIBS)" \
 		WWWLIB="../WWW/Library/netbsd/libwww.a"
@@ -542,6 +546,26 @@ ptx2:
 		$(WAISLIB) $(SOCKSLIB) $(SITE_LIBS)" \
 		WWWLIB="../WWW/Library/ptx/libwww.a"
 
+# Contributed by Thanh Ma (tma@encore.com).
+umaxv:
+	cd WWW/Library/umaxv-m88k; $(MAKE) LYFLAGS="$(SITE_LYDEFS)"
+	cd src; $(MAKE) all CC="cc" MCFLAGS="-O -DFANCY_CURSES -DUNIX \
+		-D_SYSV3 -DHAVE_TERMIOS -DUSE_DIRENT -DNO_UTMP \
+		-I../$(WWWINC) $(SITE_DEFS)" \
+		LIBS="-lcurses \
+		$(WAISLIB) $(SOCKSLIB) $(SITE_LIBS)" \
+		WWWLIB="../WWW/Library/umaxv-m88k/libwww.a"
+
+# Contributed by Thanh Ma (tma@encore.com).
+umaxv-slang:
+	cd WWW/Library/umaxv-m88k; $(MAKE) LYFLAGS="$(SITE_LYDEFS)"
+	cd src; $(MAKE) all CC="cc" MCFLAGS="-O -DUSE_SLANG -DUNIX \
+		-D_SYSV3 -DHAVE_TERMIOS -DUSE_DIRENT -DNO_UTMP \
+		-I../$(WWWINC) $(SITE_DEFS)" \
+		LIBS="$(WAISLIB) $(SOCKSLIB) $(SITE_LIBS)" \
+		WWWLIB="../WWW/Library/umaxv-m88k/libwww.a" \
+		SLANGLIB="$(SLANGLIB) -lslang -lm" SLANGINC="$(SLANGINC)"
+
 unixware:
 	cd WWW/Library/svr4; $(MAKE) LYFLAGS="-DNO_BCOPY -DUNIXWARE \
 		$(SITE_LYDEFS)"
diff --git a/README b/README
index 56c54ef7..d0bda757 100644
--- a/README
+++ b/README
@@ -20,8 +20,8 @@ WHAT IS LYNX?
    a single LAN.
    
    For information about Lynx, including new updates, go to the
-   			Lynx Enhanced Pages
-   	<URL:http://www.nyu.edu/pages/wsn/subir/lynx.html>.
+   			"Lynx links"
+   	<URL:http://www.crl.com/~subir/lynx.html>.
    
    Lynx is distributed under the GNU General Public License without
    restrictions on usage or redistribution, and is supported by the
@@ -67,10 +67,11 @@ INSTALLING LYNX
    
 PROBLEMS
 
-   If you experience problems installing or compiling Lynx, there is a
-   mailing list called lynx-dev which is frequented by Lynx experts. To
-   subscribe to lynx-dev, send email to majordomo@sig.net with only the
-   following message in the body:
+   If you experience problems installing or compiling Lynx, please read
+   the PROBLEMS file located in the source distribution. If your problem
+   is not addressed there, there is a mailing list called lynx-dev which
+   is frequented by Lynx experts. To subscribe to lynx-dev, send email to
+   majordomo@sig.net with only the following message in the body: 
    
       SUBSCRIBE LYNX-DEV address
 
diff --git a/RELEASE_STATEMENT b/RELEASE_STATEMENT
index fecd6769..e660d46f 100644
--- a/RELEASE_STATEMENT
+++ b/RELEASE_STATEMENT
@@ -9,8 +9,8 @@ subdirectory of the distribution.
 
 	Links to the current sources and support materials for Lynx
 are maintained in the:
-			 "Lynx Enhanced Pages"
-	<URL:http://www.nyu.edu/pages/wsn/subir/lynx.html>
+			 "Lynx links"
+	<URL:http://www.crl.com/~subir/lynx.html>
 
 	Version 2.6 is an official release of the Lynx2-5FM code set
 through September 2, 1996.
diff --git a/WWW/Library/Implementation/HTAAFile.c b/WWW/Library/Implementation/HTAAFile.c
index 15c2d547..a55b2f89 100644
--- a/WWW/Library/Implementation/HTAAFile.c
+++ b/WWW/Library/Implementation/HTAAFile.c
@@ -188,7 +188,7 @@ PUBLIC int HTAAFile_readList ARGS3(FILE *,	fp,
 				   int,		max_len)
 {
     char *item = NULL;
-    char terminator;
+    int terminator;
     int cnt = 0;
 
     do {
diff --git a/WWW/Library/Implementation/HTAAUtil.c b/WWW/Library/Implementation/HTAAUtil.c
index c1af8c24..512a0d0d 100644
--- a/WWW/Library/Implementation/HTAAUtil.c
+++ b/WWW/Library/Implementation/HTAAUtil.c
@@ -52,15 +52,6 @@
 #include "HTTCP.h"
 #include "HTAlert.h"
 
-#ifdef USE_SSL
-#ifdef VMS
-#include "[-.-.-.refssl]ssl.h"
-#else
-#include "../../../refssl/ssl.h"
-#endif /* VMS */
-PRIVATE SSLHandle * ssl_handle=NULL;	/* The SSL handle */
-#endif /* USE_SSL */
-
 #include "LYLeaks.h"
 
 /* PUBLIC						HTAAScheme_enum()
@@ -526,9 +517,6 @@ PUBLIC void HTAA_setupReader ARGS4(char *,	start_of_headers,
 	end_pointer = start_pointer;
     }
     in_soc = soc;
-#ifdef USE_SSL
-    ssl_handle = (SSLHandle *)handle;
-#endif /* USE_SSL */
 }
 
 
@@ -573,14 +561,7 @@ PUBLIC char *HTAA_getUnfoldedLine NOARGS
 	/* Reading from socket */
 
 	if (start_pointer >= end_pointer) {/*Read the next block and continue*/
-#ifdef USE_SSL
-	    if (ssl_handle)
-	        count = SSL_Read(ssl_handle, buffer, BUFFER_SIZE);
-	    else
-	        count = NETREAD(in_soc, buffer, BUFFER_SIZE);
-#else
 	    count = NETREAD(in_soc, buffer, BUFFER_SIZE);
-#endif /* USE_SSL */
 	    if (count <= 0) {
 		in_soc = -1;
 		return line;
diff --git a/WWW/Library/Implementation/HTAccess.c b/WWW/Library/Implementation/HTAccess.c
index 1d9725f5..330e40e0 100644
--- a/WWW/Library/Implementation/HTAccess.c
+++ b/WWW/Library/Implementation/HTAccess.c
@@ -193,7 +193,9 @@ PRIVATE BOOL override_proxy ARGS1(CONST char *, addr)
 {
     CONST char * no_proxy = getenv("no_proxy");
     char * p = NULL;
+    char * at = NULL;
     char * host = NULL;
+    char * Host = NULL;
     char * access = NULL;
     int port = 0;
     int h_len = 0;
@@ -220,14 +222,15 @@ PRIVATE BOOL override_proxy ARGS1(CONST char *, addr)
         FREE(host);
 	return NO;
     }
+    Host = (((at = strchr(host, '@')) != NULL) ? (at+1) : host);
 
     if((access = HTParse(addr, "", PARSE_ACCESS))) {
         if (0==strcmp("file", access) &&
-	    (0==strcmp(host, "localhost") ||
+	    (0==strcmp(Host, "localhost") ||
 #ifdef VMS
-             0==strcasecomp(host, HTHostName())))
+             0==strcasecomp(Host, HTHostName())))
 #else
-             0==strcmp(host, HTHostName())))
+             0==strcmp(Host, HTHostName())))
 #endif /* VMS */
         {
 	    FREE(host);
@@ -242,7 +245,7 @@ PRIVATE BOOL override_proxy ARGS1(CONST char *, addr)
         return NO;
     }
 
-    if (NULL != (p = strchr(host, ':'))) {	/* Port specified */
+    if (NULL != (p = strrchr(Host, ':'))) {	/* Port specified */
         *p++ = 0;                   		/* Chop off port */
         port = atoi(p);
     } else {					/* Use default port */
@@ -263,7 +266,7 @@ PRIVATE BOOL override_proxy ARGS1(CONST char *, addr)
     }
     if (!port)
         port = 80;                  /* Default */
-    h_len = strlen(host);
+    h_len = strlen(Host);
 
     while (*no_proxy) {
         CONST char * end;
@@ -290,7 +293,7 @@ PRIVATE BOOL override_proxy ARGS1(CONST char *, addr)
 
         if ((!templ_port || templ_port == port)  &&
             (t_len > 0  &&  t_len <= h_len  &&
-             !strncmp(host + h_len - t_len, no_proxy, t_len))) {
+             !strncmp(Host + h_len - t_len, no_proxy, t_len))) {
             FREE(host);
             return YES;
         }
diff --git a/WWW/Library/Implementation/HTAlert.h b/WWW/Library/Implementation/HTAlert.h
index 8ce0be53..dc470cfd 100644
--- a/WWW/Library/Implementation/HTAlert.h
+++ b/WWW/Library/Implementation/HTAlert.h
@@ -81,6 +81,20 @@ extern void HTPromptUsernameAndPassword PARAMS((
 	char **		username,
 	char **		password));
 
+
+/*      Confirm redirection of POST		HTConfirmPostRedirect()
+**
+** On entry,
+**      redirecting_url             is the Location.
+**
+** On exit,
+**      Returns 0 on cancel,
+**	  1 for redirect of POST with content,
+**	303 for redirect as GET without content
+*/
+extern int HTConfirmPostRedirect PARAMS((
+	CONST char *	redirecting_url));
+
 /*
 
     */
diff --git a/WWW/Library/Implementation/HTAnchor.c b/WWW/Library/Implementation/HTAnchor.c
index 3172f1a2..a206f70f 100644
--- a/WWW/Library/Implementation/HTAnchor.c
+++ b/WWW/Library/Implementation/HTAnchor.c
@@ -65,21 +65,30 @@ PRIVATE HTList **adult_table = 0;  /* Point to table of lists of all parents */
 **	consistency, we insist that you furnish more information about the
 **	anchor you are creating : use newWithParent or newWithAddress.
 */
-
 PRIVATE HTParentAnchor * HTParentAnchor_new NOARGS
 {
     HTParentAnchor *newAnchor = 
        (HTParentAnchor *)calloc(1, sizeof(HTParentAnchor));  /* zero-filled */
     newAnchor->parent = newAnchor;
+    newAnchor->bookmark = NULL;		/* Bookmark filename. - FM */
     newAnchor->isISMAPScript = FALSE;	/* Lynx appends ?0,0 if TRUE. - FM */
     newAnchor->isHEAD = FALSE;		/* HEAD request if TRUE. - FM */
     newAnchor->FileCache = NULL;	/* Path to a disk-cached copy. - FM */
+    newAnchor->SugFname = NULL;		/* Suggested filename. - FM */
+    newAnchor->RevTitle = NULL;		/* TITLE for a LINK with REV. - FM */
     newAnchor->cache_control = NULL;	/* Cache-Control. - FM */
     newAnchor->no_cache = FALSE;	/* no-cache? - FM */
     newAnchor->content_type = NULL;	/* Content-Type. - FM */
     newAnchor->content_language = NULL;	/* Content-Language. - FM */
     newAnchor->content_encoding = NULL;	/* Compression algorith. - FM */
-    newAnchor->RevTitle = NULL;		/* TITLE for a LINK with REV. - FM */
+    newAnchor->content_base = NULL;	/* Content-Base. - FM */
+    newAnchor->content_disposition = NULL; /* Content-Disposition. - FM */
+    newAnchor->content_location = NULL;	/* Content-Location. - FM */
+    newAnchor->content_md5 = NULL;	/* Content-MD5. - FM */
+    newAnchor->date = NULL;		/* Date. - FM */
+    newAnchor->expires = NULL;		/* Expires. - FM */
+    newAnchor->last_modified = NULL;	/* Last-Modified. - FM */
+    newAnchor->server = NULL;		/* Server. - FM */
     return newAnchor;
 }
 
@@ -99,7 +108,6 @@ PRIVATE HTChildAnchor * HTChildAnchor_new NOARGS
 **	returns	YES if the strings are equivalent ignoring case
 **		NO if they differ in more than  their case.
 */
-
 PRIVATE BOOL HTEquivalent ARGS2(
 	CONST char *,	s,
 	CONST char *,	t)
@@ -127,7 +135,6 @@ PRIVATE BOOL HTEquivalent ARGS2(
 **	returns	YES if the strings are identical or both NULL
 **		NO if they differ.
 */
-
 PRIVATE BOOL HTIdentical ARGS2(
 	CONST char *,	s,
 	CONST char *,	t)
@@ -152,7 +159,6 @@ PRIVATE BOOL HTIdentical ARGS2(
 **	Me one is for a new anchor being edited into an existing
 **	document. The parent anchor must already exist.
 */
-
 PUBLIC HTChildAnchor * HTAnchor_findChild ARGS2(
 	HTParentAnchor *,	parent,
 	CONST char *,		tag)
@@ -225,6 +231,7 @@ PUBLIC HTChildAnchor * HTAnchor_findChildAndLink ARGS4(
         parsed_doc.address = HTParse(href, relative_to, PARSE_ALL);
         parsed_doc.post_data = NULL;
         parsed_doc.post_content_type = NULL;
+        parsed_doc.bookmark = NULL;
         parsed_doc.isHEAD = FALSE;
         dest = HTAnchor_findAddress(&parsed_doc);
 
@@ -274,7 +281,6 @@ PRIVATE void free_adult_table NOARGS
 **	Note: You are not guaranteed a new anchor -- you might get an old one,
 **	like with fonts.
 */
-
 PUBLIC HTAnchor * HTAnchor_findAddress ARGS1(
 	CONST DocAddress *,	newdoc)
 {
@@ -297,6 +303,7 @@ PUBLIC HTAnchor * HTAnchor_findAddress ARGS1(
 		PARSE_ACCESS | PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION);
         parsed_doc.post_data = newdoc->post_data;
         parsed_doc.post_content_type = newdoc->post_content_type;
+        parsed_doc.bookmark = newdoc->bookmark;
         parsed_doc.isHEAD = newdoc->isHEAD;
 
         foundParent = (HTParentAnchor *) HTAnchor_findAddress (&parsed_doc);
@@ -337,12 +344,13 @@ PUBLIC HTAnchor * HTAnchor_findAddress ARGS1(
 #ifdef CASE_INSENSITIVE_ANCHORS
             if (HTEquivalent(foundAnchor->address, newdoc->address) &&
 	        HTEquivalent(foundAnchor->post_data, newdoc->post_data) &&
-	        foundAnchor->isHEAD == newdoc->isHEAD) {
+	        foundAnchor->isHEAD == newdoc->isHEAD)
 #else
             if (HTIdentical(foundAnchor->address, newdoc->address) &&
 	        HTIdentical(foundAnchor->post_data, newdoc->post_data) &&
-	        foundAnchor->isHEAD == newdoc->isHEAD) {
+	        foundAnchor->isHEAD == newdoc->isHEAD)
 #endif /* CASE_INSENSITIVE_ANCHORS */
+	    {
 	        if (TRACE)
 		    fprintf(stderr,
 		    	    "Anchor %p with address `%s' already exists.\n",
@@ -365,6 +373,8 @@ PUBLIC HTAnchor * HTAnchor_findAddress ARGS1(
         if (newdoc->post_content_type)
 	    StrAllocCopy(foundAnchor->post_content_type,
 	    		 newdoc->post_content_type);
+        if (newdoc->bookmark)
+	    StrAllocCopy(foundAnchor->bookmark, newdoc->bookmark);
         foundAnchor->isHEAD = newdoc->isHEAD;
         HTList_addObject (adults, foundAnchor);
         return (HTAnchor *) foundAnchor;
@@ -381,7 +391,6 @@ PUBLIC HTAnchor * HTAnchor_findAddress ARGS1(
 **	We also try to delete the targets whose documents are not loaded.
 **	If this anchor's source list is empty, we delete it and its children.
 */
-
 PRIVATE void deleteLinks ARGS1(
 	HTAnchor *,	me)
 {
@@ -609,6 +618,7 @@ PUBLIC BOOL HTAnchor_delete ARGS1(
     FREE(me->physical);
     FREE(me->post_data);
     FREE(me->post_content_type);
+    FREE(me->bookmark);
     FREE(me->owner);
     FREE(me->RevTitle);
     if (me->FileCache) {
@@ -619,11 +629,20 @@ PUBLIC BOOL HTAnchor_delete ARGS1(
 	}
 	FREE(me->FileCache);
     }
+    FREE(me->SugFname);
     FREE(me->cache_control);
     FREE(me->content_type);
     FREE(me->content_language);
     FREE(me->content_encoding);
-
+    FREE(me->content_base);
+    FREE(me->content_disposition);
+    FREE(me->content_location);
+    FREE(me->content_md5);
+    FREE(me->date);
+    FREE(me->expires);
+    FREE(me->last_modified);
+    FREE(me->server);
+ 
     /*
      *  Remove ourselves from the hash table's list.
      */
@@ -662,7 +681,6 @@ PUBLIC BOOL HTAnchor_delete ARGS1(
 **	This is to ensure that an anchor which might have already existed
 **	is put in the correct order as we load the document.
 */
-
 PUBLIC void HTAnchor_makeLastChild ARGS1(
 	HTChildAnchor *,	me)
 {
@@ -676,7 +694,6 @@ PUBLIC void HTAnchor_makeLastChild ARGS1(
 /*	Data access functions
 **	---------------------
 */
-
 PUBLIC HTParentAnchor * HTAnchor_parent ARGS1(
 	HTAnchor *,	me)
 {
@@ -775,12 +792,12 @@ PUBLIC BOOL HTAnchor_hasChildren ARGS1(
     return me ? ! HTList_isEmpty(me->children) : NO;
 }
 
-/*	Title handling
+/*	Title handling.
 */
 PUBLIC CONST char * HTAnchor_title ARGS1(
 	HTParentAnchor *,	me)
 {
-    return me ? me->title : 0;
+    return me ? me->title : NULL;
 }
 
 PUBLIC void HTAnchor_setTitle ARGS2(
@@ -817,12 +834,28 @@ PUBLIC void HTAnchor_appendTitle ARGS2(
     }
 }
 
-/*	Owner handling
+/*	Bookmark handling.
+*/
+PUBLIC CONST char * HTAnchor_bookmark ARGS1(
+	HTParentAnchor *,	me)
+{
+    return me ? me->bookmark : NULL;
+}
+
+PUBLIC void HTAnchor_setBookmark ARGS2(
+	HTParentAnchor *,	me,
+	CONST char *,		bookmark)
+{
+    if (me)
+        StrAllocCopy(me->bookmark, bookmark);
+}
+
+/*	Owner handling.
 */
 PUBLIC CONST char * HTAnchor_owner ARGS1(
 	HTParentAnchor *,	me)
 {
-    return (me ? me->owner : 0);
+    return (me ? me->owner : NULL);
 }
 
 PUBLIC void HTAnchor_setOwner ARGS2(
@@ -834,12 +867,12 @@ PUBLIC void HTAnchor_setOwner ARGS2(
     }
 }
 
-/*      TITLE handling in LINKs with REV="made" or REV="owner"
+/*      TITLE handling in LINKs with REV="made" or REV="owner". - FM
 */
 PUBLIC CONST char * HTAnchor_RevTitle ARGS1(
 	HTParentAnchor *,	me)
 {
-    return (me ? me->RevTitle : 0);
+    return (me ? me->RevTitle : NULL);
 }
 
 PUBLIC void HTAnchor_setRevTitle ARGS2(
@@ -859,10 +892,43 @@ PUBLIC void HTAnchor_setRevTitle ARGS2(
     }
 }
 
+/*	Suggested filename handling. - FM
+**	(will be loaded if we had a Content-disposition
+**	 header with file; filename=name.suffix)
+*/
+PUBLIC CONST char * HTAnchor_SugFname ARGS1(
+	HTParentAnchor *,	me)
+{
+    return me ? me->SugFname : NULL;
+}
+
+/*	Last-Modified header handling. - FM
+*/
+PUBLIC CONST char * HTAnchor_last_modified ARGS1(
+	HTParentAnchor *,	me)
+{
+    return me ? me->last_modified : NULL;
+}
+
+/*	Date header handling. - FM
+*/
+PUBLIC CONST char * HTAnchor_date ARGS1(
+	HTParentAnchor *,	me)
+{
+    return me ? me->date : NULL;
+}
+
+/*	Server header handling. - FM
+*/
+PUBLIC CONST char * HTAnchor_server ARGS1(
+	HTParentAnchor *,	me)
+{
+    return me ? me->server : NULL;
+}
+
 /*	Link me Anchor to another given one
 **	-------------------------------------
 */
-
 PUBLIC BOOL HTAnchor_link ARGS3(
 	HTAnchor *,	source,
 	HTAnchor *,	destination,
@@ -896,7 +962,6 @@ PUBLIC BOOL HTAnchor_link ARGS3(
 /*	Manipulation of links
 **	---------------------
 */
-
 PUBLIC HTAnchor * HTAnchor_followMainLink ARGS1(
 	HTAnchor *,	me)
 {
@@ -952,7 +1017,6 @@ PUBLIC BOOL HTAnchor_makeMainLink ARGS2(
 /*	Methods List
 **	------------
 */
-
 PUBLIC HTList * HTAnchor_methods ARGS1(
 	HTParentAnchor *,	me)
 {
@@ -965,7 +1029,6 @@ PUBLIC HTList * HTAnchor_methods ARGS1(
 /*	Protocol
 **	--------
 */
-
 PUBLIC void * HTAnchor_protocol ARGS1(
 	HTParentAnchor *,	me)
 {
@@ -982,7 +1045,6 @@ PUBLIC void HTAnchor_setProtocol ARGS2(
 /*	Physical Address
 **	----------------
 */
-
 PUBLIC char * HTAnchor_physical ARGS1(
 	HTParentAnchor *,	me)
 {
diff --git a/WWW/Library/Implementation/HTAnchor.h b/WWW/Library/Implementation/HTAnchor.h
index e9a137cb..92bf6716 100644
--- a/WWW/Library/Implementation/HTAnchor.h
+++ b/WWW/Library/Implementation/HTAnchor.h
@@ -84,8 +84,9 @@ struct _HTParentAnchor {
   HTList *      sources;        /* List of anchors pointing to this, if any */
   HyperDoc *    document;       /* The document within which this is an anchor */
   char *        address;        /* Absolute address of this node */
-  char *	post_data;      /* posting data */
-  char * 	post_content_type;  /* type of post data */
+  char *	post_data;      /* Posting data */
+  char * 	post_content_type;  /* Type of post data */
+  char *	bookmark;	/* Bookmark filname */
   HTFormat      format;         /* Pointer to node format descriptor */
   char *	charset;	/* Pointer to character set (kludge, for now */
   BOOL          isIndex;        /* Acceptance of a keyword search */
@@ -102,11 +103,20 @@ struct _HTParentAnchor {
   BOOL		isISMAPScript;	/* Script for clickable image map */
   BOOL		isHEAD;		/* Document is headers from a HEAD request */
   char *	FileCache;	/* Path to a disk-cached copy */
+  char *	SugFname;	/* Suggested filename */
   char *	cache_control;	/* Cache-Control */
   BOOL		no_cache;	/* Cache-Control, Pragma or META "no-cache"? */
-  char *	content_type;	/* Content-Type */
-  char *	content_language;   /* Content-Language */
-  char *	content_encoding;   /* Compression algorithm */
+  char *	content_type;		/* Content-Type */
+  char *	content_language;	/* Content-Language */
+  char *	content_encoding;	/* Compression algorithm */
+  char *	content_base;		/* Content-Base */
+  char *	content_disposition;	/* Content-Dispositon */
+  char *	content_location;	/* Content-Location */
+  char *	content_md5;		/* Content-MD5 */
+  char *	date;			/* Date */
+  char *	expires;		/* Expires */
+  char *	last_modified;		/* Last-Modified */
+  char *	server;			/* Server */
 };
 
 typedef struct {
@@ -128,6 +138,7 @@ typedef struct _DocAddress {
     char * address;
     char * post_data;
     char * post_content_type;
+    char * bookmark;
     BOOL   isHEAD;
 } DocAddress;
 
@@ -263,7 +274,7 @@ extern BOOL HTAnchor_hasChildren
      (HTParentAnchor *me)
      );
 
-/*      Title handling
+/*      Title handling.
 */
 extern CONST char * HTAnchor_title
   PARAMS(
@@ -280,7 +291,19 @@ extern void HTAnchor_appendTitle
      (HTParentAnchor *me, CONST char * title)
      );
 
-/*      Owner handling
+/*	Bookmark handling.
+*/
+extern CONST char * HTAnchor_bookmark
+  PARAMS(
+	(HTParentAnchor * me)
+	);
+
+extern void HTAnchor_setBookmark
+  PARAMS(
+	(HTParentAnchor *me, CONST char * bookmark)
+	);
+
+/*      Owner handling.
 */
 extern CONST char * HTAnchor_owner
   PARAMS(
@@ -292,7 +315,7 @@ extern void HTAnchor_setOwner
      (HTParentAnchor *me, CONST char * owner)
      );
 
-/*      TITLE handling in LINKs with REV="made" or REV="owner"
+/*      TITLE handling in LINKs with REV="made" or REV="owner". - FM
 */
 extern CONST char * HTAnchor_RevTitle
   PARAMS(
@@ -304,6 +327,36 @@ extern void HTAnchor_setRevTitle
      (HTParentAnchor *me, CONST char * title)
      );
 
+/*	Suggested filename handling. - FM
+**	(will be loaded if we had a Content-disposition
+**	 header with file; filename=name.suffix)
+*/
+extern CONST char * HTAnchor_SugFname
+  PARAMS(
+     (HTParentAnchor *me)
+     );
+
+/*	Last-Modified header handling. - FM
+*/
+extern CONST char * HTAnchor_last_modified
+  PARAMS(
+     (HTParentAnchor *me)
+     );
+
+/*	Date header handling. - FM
+*/
+extern CONST char * HTAnchor_date
+  PARAMS(
+     (HTParentAnchor *me)
+     );
+
+/*	Server header handling. - FM
+*/
+extern CONST char * HTAnchor_server
+  PARAMS(
+     (HTParentAnchor *me)
+     );
+
 /*      Link this Anchor to another given one
 **      -------------------------------------
 */
diff --git a/WWW/Library/Implementation/HTFTP.c b/WWW/Library/Implementation/HTFTP.c
index 9d19610f..27d929f7 100644
--- a/WWW/Library/Implementation/HTFTP.c
+++ b/WWW/Library/Implementation/HTFTP.c
@@ -1887,6 +1887,7 @@ PRIVATE EntryInfo * parse_dir_entry ARGS2(
         case PETER_LEWIS_SERVER:
         case MACHTEN_SERVER:
 	case MSDOS_SERVER:
+        case WINDOWS_NT_SERVER:
 	    /*
 	    **  Check for EPLF output (local times).
 	    */
@@ -2004,6 +2005,7 @@ PRIVATE EntryInfo * parse_dir_entry ARGS2(
 	    */
 	    break;
 
+#ifdef NOTDEFINED
         case WINDOWS_NT_SERVER:
             /*
 	    **  Interpret and edit LIST output from MS_WINDOWS server
@@ -2024,6 +2026,7 @@ PRIVATE EntryInfo * parse_dir_entry ARGS2(
 	    **  Goto the bottom and get real type.
 	    */
 	    break;
+#endif /* NOTDEFINED */
 
         case CMS_SERVER:
 	  {
diff --git a/WWW/Library/Implementation/HTFile.c b/WWW/Library/Implementation/HTFile.c
index 9148f5d1..a41f0526 100644
--- a/WWW/Library/Implementation/HTFile.c
+++ b/WWW/Library/Implementation/HTFile.c
@@ -997,8 +997,16 @@ PUBLIC void HTDirEntry ARGS3(
 	CONST char *,	tail,
 	CONST char *,	entry)
 {
-    char * relative;
-    char * escaped = HTEscape(entry, URL_XPALPHAS);
+    char * relative = NULL;
+    char * escaped = NULL;
+
+    if (0 == strcmp(entry,"../"))
+        /*
+	 *  Undo slash appending for anchor creation.
+	 */
+	StrAllocCopy(escaped,"..");
+    else
+	escaped = HTEscape(entry, URL_XPALPHAS);
 
 
     if (tail == NULL || *tail == '\0') {
@@ -1006,7 +1014,7 @@ PUBLIC void HTDirEntry ARGS3(
         HTStartAnchor(target, NULL, escaped);
     } else {
         /* If empty tail, gives absolute ref below */
-        relative = (char*) malloc(strlen(tail) + strlen(escaped)+2);
+        relative = (char*)malloc(strlen(tail) + strlen(escaped)+2);
         if (relative == NULL)
 	    outofmem(__FILE__, "DirRead");
         sprintf(relative, "%s/%s", tail, escaped);
@@ -1038,6 +1046,7 @@ PUBLIC void HTDirTitles ARGS2(
 		TOUPPER(*(cp+6)) == 'I')
 		*cp = '\0';
 	}
+	cp = NULL;
     }
     current = strrchr(path, '/');	/* last part or "" */
 
@@ -1056,7 +1065,7 @@ PUBLIC void HTDirTitles ARGS2(
 	  FREE(cp);
       }
 #else 
-      StrAllocCopy(printable, (current + 1));
+      StrAllocCopy(printable, (current ? current + 1 : ""));
 #endif /* DIRED_SUPPORT */
 
       START(HTML_HEAD);
@@ -1100,9 +1109,10 @@ PUBLIC void HTDirTitles ARGS2(
      */
 
     if (current && current[1]) {   /* was a slash AND something else too */
-        char * parent;
-	char * relative;
-	*current++ = 0;
+        char * parent = NULL;
+	char * relative = NULL;
+
+	*current++ = '\0';
         parent = strrchr(path, '/');  /* penultimate slash */
 
 	if ((parent && 0 == strncasecomp(parent, "/%2F", 4)) ||
@@ -1126,10 +1136,36 @@ PUBLIC void HTDirTitles ARGS2(
 	     *  HTVMSBrowseDir().
 	     */
 	    extern BOOLEAN LYisLocalFile PARAMS((char *logical));
-	    DIR  * dp=NULL;
+	    DIR  * dp = NULL;
 
 	    if (LYisLocalFile(logical)) {
-	        if ((dp = opendir(relative)) == NULL) {
+		/*
+		 *  We need an absolute file path for the opendir.
+		 *  We also need to unescape for this test.
+		 *  Don't worry about %2F now, they presumably have been
+		 *  dealt with above, and shouldn't appear for local
+		 *  files anyway...  Assume OS / filesystem will just
+		 *  ignore superfluous slashes. - KW
+		 */
+		char * fullparentpath = NULL;
+
+		/*
+		 *  Path has been shortened above
+		 */
+		StrAllocCopy(fullparentpath, path);
+
+		/*
+		 *  Guard against weirdness.
+		 */
+		if (0 == strcmp(current,"..")) {
+		    StrAllocCat(fullparentpath,"/../..");
+		} else if (0 == strcmp(current,".")) {
+		    StrAllocCat(fullparentpath,"/..");
+		}
+
+		HTUnEscape(fullparentpath);
+	        if ((dp = opendir(fullparentpath)) == NULL) {
+	            FREE(fullparentpath);
 	            FREE(logical);
 	            FREE(relative);
 	            FREE(path);
@@ -1137,6 +1173,7 @@ PUBLIC void HTDirTitles ARGS2(
 		}
 		if (dp)
 	    	    closedir(dp);
+		FREE(fullparentpath);
 	    }
 	}
 #endif /* !VMS */
@@ -1151,10 +1188,16 @@ PUBLIC void HTDirTitles ARGS2(
 #ifdef DIRED_SUPPORT
 	   if (dir_list_style == MIXED_STYLE) {
 	      PUTS("../");
-	   } else {
-#else
-	   {
+	   } else
 #endif /* DIRED_SUPPORT */
+	   if ((0 == strcmp(current,".")) ||
+	       (0 == strcmp(current,".."))) {
+	       /*
+	        *  Should not happen, but if it does.
+		*  at least avoid giving misleading info. - KW
+		*/
+	       PUTS("..");
+	   } else {
 	      char * printable = NULL;
 	      StrAllocCopy(printable, parent + 1);
 	      HTUnEscape(printable);
@@ -1588,7 +1631,7 @@ forget_multi:
 		    while ((dirbuf = readdir(dp))!=0)
 		    {
 			/* while there are directory entries to be read */
-		        HTBTElement * dirname = NULL;
+		        char * dirname = NULL;
 			extern BOOLEAN no_dotfiles, show_dotfiles;
 
 		        if (dirbuf->d_ino == 0)
@@ -1607,8 +1650,7 @@ forget_multi:
 			     * begins with '.' */
 			    continue;
 
-			dirname = (HTBTElement *)malloc(
-					strlen(dirbuf->d_name) + 4);
+			dirname = (char *)malloc(strlen(dirbuf->d_name) + 4);
 			if (dirname == NULL)
 			    outofmem(__FILE__,"DirRead");
 			StrAllocCopy(tmpfilename,localname);
diff --git a/WWW/Library/Implementation/HTFormat.c b/WWW/Library/Implementation/HTFormat.c
index f25d36b3..75b60f39 100644
--- a/WWW/Library/Implementation/HTFormat.c
+++ b/WWW/Library/Implementation/HTFormat.c
@@ -11,7 +11,6 @@
 **
 */
 
-
 #include "HTUtils.h"
 #include "tcp.h"
 
@@ -30,10 +29,9 @@ PUBLIC int loading_length= -1;
 #define PRESENT_POSTSCRIPT "open %s; /bin/rm -f %s\n"
 #else
 #define PRESENT_POSTSCRIPT "(ghostview %s ; /bin/rm -f %s)&\n"	
-	/* Full pathname would be better! */
-#endif
-#endif
-
+			   /* Full pathname would be better! */
+#endif /* NeXT */
+#endif /* unix */
 
 #include "HTML.h"
 #include "HTMLDTD.h"
@@ -65,7 +63,7 @@ struct _HTStream {
       CONST HTStreamClass*	isa;
       /* ... */
 };
-#endif
+#endif /* ORIGINAL */
 
 /* this version used by the NetToText stream */
 struct _HTStream {
@@ -74,11 +72,9 @@ struct _HTStream {
 	HTStream * 		sink;
 };
 
-
 /*	Presentation methods
 **	--------------------
 */
-
 PUBLIC  HTList * HTPresentations = NULL;
 PUBLIC  HTPresentation * default_presentation = NULL;
 
@@ -129,7 +125,6 @@ PUBLIC void HTSetPresentation ARGS6(
     }
 }
 
-
 /*	Define a built-in function for a content-type
 **	---------------------------------------------
 */
@@ -201,7 +196,6 @@ PRIVATE void HTFreePresentations NOARGS
     HTPresentations = NULL;
 }
 
-
 /*	File buffering
 **	--------------
 **
@@ -216,7 +210,6 @@ PRIVATE char * input_pointer;
 PRIVATE char * input_limit;
 PRIVATE int input_file_number;
 
-
 /*	Set up the buffering
 **
 **	These routines are public because they are in fact needed by
@@ -236,21 +229,22 @@ PUBLIC char HTGetCharacter NOARGS
     interrupted_in_htgetcharacter = 0;
     do {
 	if (input_pointer >= input_limit) {
-	    int status = NETREAD(
-		    input_file_number, input_buffer, INPUT_BUFFER_SIZE);
+	    int status = NETREAD(input_file_number,
+	    			 input_buffer, INPUT_BUFFER_SIZE);
 	    if (status <= 0) {
-		if (status == 0) return (char)EOF;
-		if (status == HT_INTERRUPTED)
-                {
-                  if (TRACE)
-                    fprintf (stderr,
-			     "HTFormat: Interrupted in HTGetCharacter\n");
-                  interrupted_in_htgetcharacter = 1;
-                  return (char)EOF;
+		if (status == 0)
+		    return (char)EOF;
+		if (status == HT_INTERRUPTED) {
+                    if (TRACE)
+                        fprintf(stderr,
+			        "HTFormat: Interrupted in HTGetCharacter\n");
+                    interrupted_in_htgetcharacter = 1;
+                    return (char)EOF;
                 }
-		if (TRACE) fprintf(stderr,
-		    "HTFormat: File read error %d\n", status);
-		return (char)EOF; /* -1 is returned by UCX at end of HTTP link */
+		if (TRACE)
+		    fprintf(stderr, "HTFormat: File read error %d\n", status);
+		return (char)EOF; /* -1 is returned by UCX
+				     at end of HTTP link */
 	    }
 	    input_pointer = input_buffer;
 	    input_limit = input_buffer + status;
@@ -267,12 +261,12 @@ PUBLIC int HTOutputBinary ARGS2( int, 		input,
 				  FILE *, 	output)
 {
     do {
-	    int status = NETREAD(
-		    input, input_buffer, INPUT_BUFFER_SIZE);
+	    int status = NETREAD(input, input_buffer, INPUT_BUFFER_SIZE);
 	    if (status <= 0) {
-		if (status == 0) return 0;
-		if (TRACE) fprintf(stderr,
-		    "HTFormat: File read error %d\n", status);
+		if (status == 0)
+		    return 0;
+		if (TRACE)
+		    fprintf(stderr, "HTFormat: File read error %d\n", status);
 		return 2;			/* Error */
 	    }
 	    fwrite(input_buffer, sizeof(char), status, output);
@@ -287,21 +281,20 @@ PRIVATE int half_match ARGS2(char *,trial_type, char *,target)
     char *cp=strchr(trial_type,'/');
 
     /* if no '/' or no '*' */
-    if(!cp || *(cp+1) != '*')
+    if (!cp || *(cp+1) != '*')
 	return 0;
 
-    if(TRACE)
+    if (TRACE)
 	fprintf(stderr,"HTFormat: comparing %s and %s for half match\n",
 						      trial_type, target);
 
 	/* main type matches */
-    if(!strncmp(trial_type, target, (cp-trial_type)-1)) 
+    if (!strncmp(trial_type, target, (cp-trial_type)-1)) 
 	return 1;
 
     return 0;
 }
 
-
 /*		Create a filter stack
 **		---------------------
 **
@@ -320,20 +313,21 @@ PUBLIC HTStream * HTStreamStack ARGS4(
 {
     HTAtom * wildcard = HTAtom_for("*");
 
-    if (TRACE) fprintf(stderr,
-    	"HTFormat: Constructing stream stack for %s to %s\n",
-	HTAtom_name(rep_in),	
-	HTAtom_name(rep_out));
+    if (TRACE)
+        fprintf(stderr,
+		"HTFormat: Constructing stream stack for %s to %s\n",
+		HTAtom_name(rep_in), HTAtom_name(rep_out));
 		
-       /* don't return on WWW_SOURCE some people might like
-        * to make use of the source!!!!  LJM
-        */
-     /* if (rep_out == WWW_SOURCE ||
-       		rep_out == rep_in) return sink;  LJM */
+    /* don't return on WWW_SOURCE some people might like
+     * to make use of the source!!!!  LJM
+     *//*
+    if (rep_out == WWW_SOURCE || rep_out == rep_in)
+	return sink;  LJM */
 
-     if(rep_out == rep_in) return sink;
+    if (rep_out == rep_in)
+        return sink;
 
-	/* don't do anymore do it in the Lynx code at startup LJM */
+    /* don't do anymore do it in the Lynx code at startup LJM */
     /* if (!HTPresentations) HTFormatInit(); */	/* set up the list */
     
     {
@@ -345,46 +339,52 @@ PUBLIC HTStream * HTStreamStack ARGS4(
 			*last_default_match=0,
 			*strong_subtype_wildcard_match=0;
 
-	for(i=0; i<n; i++) {
+	for (i = 0; i < n; i++) {
 	    pres = (HTPresentation *)HTList_objectAt(HTPresentations, i);
 	    if (pres->rep == rep_in) {
 	        if (pres->rep_out == rep_out) {
-		    if(TRACE)
-			fprintf(stderr,"StreamStack: found exact match: %s\n",HTAtom_name(pres->rep));
+		    if (TRACE)
+			fprintf(stderr,
+				"StreamStack: found exact match: %s\n",
+				HTAtom_name(pres->rep));
 	    	    return (*pres->converter)(pres, anchor, sink);
 
 		} else if (pres->rep_out == wildcard) {
-		    if(!strong_wildcard_match)
+		    if (!strong_wildcard_match)
 		        strong_wildcard_match = pres;
 		    /* otherwise use the first one */
-		    if(TRACE)
-			fprintf(stderr,"StreamStack: found strong wildcard match: %s\n",HTAtom_name(pres->rep));
+		    if (TRACE)
+			fprintf(stderr,
+			     "StreamStack: found strong wildcard match: %s\n",
+				HTAtom_name(pres->rep));
 		}
 
-	    } else if(half_match(HTAtom_name(pres->rep),
-						HTAtom_name(rep_in))) {
-		
+	    } else if (half_match(HTAtom_name(pres->rep),
+					      HTAtom_name(rep_in))) {
 	        if (pres->rep_out == rep_out) {
-		    if(!strong_subtype_wildcard_match)
-		       strong_subtype_wildcard_match = pres;
+		    if (!strong_subtype_wildcard_match)
+		        strong_subtype_wildcard_match = pres;
 		    /* otherwise use the first one */
-		    if(TRACE)
-			fprintf(stderr,"StreamStack: found strong subtype wildcard match: %s\n",HTAtom_name(pres->rep));
+		    if (TRACE)
+			fprintf(stderr,
+		     "StreamStack: found strong subtype wildcard match: %s\n",
+				HTAtom_name(pres->rep));
 		}
 	    }
 
 	    if (pres->rep == WWW_SOURCE) {
-		if(pres->rep_out == rep_out) {
-		    if(!weak_wildcard_match)
+		if (pres->rep_out == rep_out) {
+		    if (!weak_wildcard_match)
 		        weak_wildcard_match = pres;
 		    /* otherwise use the first one */
-		    if(TRACE)
-			fprintf(stderr,"StreamStack: found weak wildcard match: %s\n",HTAtom_name(pres->rep_out));
-
+		    if (TRACE)
+			fprintf(stderr,
+			    "StreamStack: found weak wildcard match: %s\n",
+				HTAtom_name(pres->rep_out));
 		}
-		if(pres->rep_out == wildcard) {
-		    if(!last_default_match)
-		        last_default_match = pres;
+		if (pres->rep_out == wildcard) {
+		    if (!last_default_match)
+		         last_default_match = pres;
 		    /* otherwise use the first one */
 		}
 	    }
@@ -396,20 +396,20 @@ PUBLIC HTStream * HTStreamStack ARGS4(
 		last_default_match;
 	
 	if (match) {
-		HTPresentation temp;
-		temp = *match;			/* Specific instance */
-		temp.rep = rep_in;		/* yuk */
-		temp.rep_out = rep_out;		/* yuk */
-		if(TRACE)
-		    fprintf(stderr,"StreamStack: Using %s\n",HTAtom_name(temp.rep_out));
-		return (*match->converter)(&temp, anchor, sink);
+	    HTPresentation temp;
+	    temp = *match;		/* Specific instance */
+	    temp.rep = rep_in;		/* yuk */
+	    temp.rep_out = rep_out;	/* yuk */
+	    if (TRACE)
+		fprintf(stderr,
+			"StreamStack: Using %s\n", HTAtom_name(temp.rep_out));
+	    return (*match->converter)(&temp, anchor, sink);
         }
     }
 
     return NULL;
 }
 	
-
 /*		Find the cost of a filter stack
 **		-------------------------------
 **
@@ -426,26 +426,25 @@ PUBLIC float HTStackValue ARGS4(
 {
     HTAtom * wildcard = HTAtom_for("*");
 
-    if (TRACE) fprintf(stderr,
-    	"HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
-	HTAtom_name(rep_in),	initial_value,
-	HTAtom_name(rep_out));
+    if (TRACE)
+        fprintf(stderr,
+    		"HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
+		HTAtom_name(rep_in), initial_value, HTAtom_name(rep_out));
 		
-    if (rep_out == WWW_SOURCE ||
-    	rep_out == rep_in) return 0.0;
+    if (rep_out == WWW_SOURCE || rep_out == rep_in)
+        return 0.0;
 
-	/* don't do anymore do it in the Lynx code at startup LJM */
+    /* don't do anymore do it in the Lynx code at startup LJM */
     /* if (!HTPresentations) HTFormatInit(); */	/* set up the list */
     
     {
 	int n = HTList_count(HTPresentations);
 	int i;
 	HTPresentation * pres;
-	for(i=0; i<n; i++) {
+	for (i = 0; i < n; i++) {
 	    pres = (HTPresentation *)HTList_objectAt(HTPresentations, i);
-	    if (pres->rep == rep_in && (
-	    		pres->rep_out == rep_out ||
-			pres->rep_out == wildcard)) {
+	    if (pres->rep == rep_in &&
+	        (pres->rep_out == rep_out || pres->rep_out == wildcard)) {
 	        float value = initial_value * pres->quality;
 		if (HTMaxSecs != 0.0)
 		    value = value - (length*pres->secs_per_byte + pres->secs)
@@ -459,7 +458,6 @@ PUBLIC float HTStackValue ARGS4(
 
 }
 	
-
 /*	Push data from a socket down a stream
 **	-------------------------------------
 **
@@ -471,7 +469,6 @@ PUBLIC float HTStackValue ARGS4(
 **   when the format is textual.
 **
 */
-
 PUBLIC int HTCopy ARGS3(
 	int,			file_number,
 	void*,			handle,
@@ -479,7 +476,7 @@ PUBLIC int HTCopy ARGS3(
 {
     HTStreamClass targetClass;    
     char line[256];
-    int bytes=0;
+    int bytes = 0;
     int rv = 0;
     char * msg;
 
@@ -490,17 +487,16 @@ PUBLIC int HTCopy ARGS3(
         msg = "Read %d of %d bytes of data.";
 
     
-/*	Push the data down the stream
-**
-*/
+    /*  Push the data down the stream
+    */
     targetClass = *(sink->isa);	/* Copy pointers to procedures */
     
     /*	Push binary from socket down sink
     **
-    **		This operation could be put into a main event loop
+    **  This operation could be put into a main event loop
     */
-    for(;;) {
-        int status;
+    for (;;) {
+	int status;
 	extern char LYCancelDownload;
 
 	if (LYCancelDownload) {
@@ -510,62 +506,76 @@ PUBLIC int HTCopy ARGS3(
 	    goto finished;
 	}
 
-        if (HTCheckForInterrupt())
-          {
-            _HTProgress ("Data transfer interrupted.");
-            (*targetClass._abort)(sink, NULL);
-	    if(bytes)
-                rv = HT_INTERRUPTED;
+	if (HTCheckForInterrupt()) {
+	    _HTProgress ("Data transfer interrupted.");
+	    (*targetClass._abort)(sink, NULL);
+	    if (bytes)
+	        rv = HT_INTERRUPTED;
 	    else
 		rv = -1;
 	    goto finished;
-          }
-
+        }
 
         status = NETREAD(file_number, input_buffer, INPUT_BUFFER_SIZE);
 
 	if (status <= 0) {
-	    if (status == 0) 
-	      break;
-	    else if (status == HT_INTERRUPTED)
-              {
-                _HTProgress ("Data transfer interrupted.");
-                (*targetClass._abort)(sink, NULL);
-	        if(bytes)
-                    rv = HT_INTERRUPTED;
-	        else
+	    if (status == 0) {
+	        break;
+	    } else if (status == HT_INTERRUPTED) {
+	        _HTProgress ("Data transfer interrupted.");
+		(*targetClass._abort)(sink, NULL);
+		if (bytes)
+		    rv = HT_INTERRUPTED;
+		else
 		    rv = -1;
-	        goto finished;
-              }
-	    else if (SOCKET_ERRNO == ENOTCONN || SOCKET_ERRNO == ECONNRESET 
-						   || SOCKET_ERRNO == EPIPE)
-              {
-                /* Arrrrgh, HTTP 0/1 compability problem, maybe. */
-		rv = -2;
-	        goto finished;
-              }
-            break;
+		goto finished;
+	    } else if (SOCKET_ERRNO == ENOTCONN ||
+	    	       SOCKET_ERRNO == ECONNRESET ||
+		       SOCKET_ERRNO == EPIPE) {
+                /*
+		 *  Arrrrgh, HTTP 0/1 compability problem, maybe.
+		 */
+		if (bytes <= 0) {
+		    /*
+		     *  Don't have any data, so let the calling
+		     *  function decide what to do about it. - FM
+		     */
+		    rv = -2;
+	            goto finished;
+		} else {
+		   /*
+		    *  Treat what we've gotten already
+		    *  as the complete transmission. - FM
+		    */
+		   if (TRACE)
+		       fprintf(stderr,
+	    "HTCopy: Unexpected server disconnect. Treating as completed.\n");
+		   status = 0;
+		   break;
+		}
+	    }
+	    break;
 	}
 
 #ifdef NOT_ASCII
 	{
 	    char * p;
-	    for(p = input_buffer; p < input_buffer+status; p++) {
+	    for (p = input_buffer; p < input_buffer+status; p++) {
 		*p = FROMASCII(*p);
 	    }
 	}
-#endif
+#endif /* NOT_ASCII */
 
 	(*targetClass.put_block)(sink, input_buffer, status);
 
 	bytes += status;
-        sprintf(line, msg, bytes, loading_length);
-        HTProgress(line);
+	sprintf(line, msg, bytes, loading_length);
+	HTProgress(line);
 
     } /* next bufferload */
 
     _HTProgress("Data transfer complete");
-    NETCLOSE(file_number);
+    (void)NETCLOSE(file_number);
     rv = HT_LOADED;
 
 finished:
@@ -574,8 +584,6 @@ finished:
 	
 }
 
-
-
 /*	Push data from a file pointer down a stream
 **	-------------------------------------
 **
@@ -590,20 +598,22 @@ PUBLIC void HTFileCopy ARGS2(
 {
     HTStreamClass targetClass;    
     
-/*	Push the data down the stream
-**
-*/
+    /*  Push the data down the stream
+    */
     targetClass = *(sink->isa);	/* Copy pointers to procedures */
-    
+
     /*	Push binary from socket down sink
     */
-    for(;;) {
-	int status = fread(
-	       input_buffer, 1, INPUT_BUFFER_SIZE, fp);
+    for (;;) {
+	int status = fread(input_buffer, 1, INPUT_BUFFER_SIZE, fp);
+
 	if (status == 0) { /* EOF or error */
-	    if (ferror(fp) == 0) break;
-	    if (TRACE) fprintf(stderr,
-		"HTFormat: Read error, read returns %d\n", ferror(fp));
+	    if (ferror(fp) == 0)
+	        break;
+	    if (TRACE)
+	        fprintf(stderr,
+			"HTFormat: Read error, read returns %d\n",
+			ferror(fp));
 	    break;
 	}
 	(*targetClass.put_block)(sink, input_buffer, status);
@@ -611,9 +621,6 @@ PUBLIC void HTFileCopy ARGS2(
 	
 }
 
-
-
-
 /*	Push data from a socket down a stream STRIPPING CR
 **	--------------------------------------------------
 **
@@ -630,28 +637,26 @@ PUBLIC void HTCopyNoCR ARGS2(
 	HTStream*,		sink)
 {
     HTStreamClass targetClass;    
-    
-/*	Push the data, ignoring CRLF, down the stream
-**
-*/
+    char character;
+
+    /*  Push the data, ignoring CRLF, down the stream
+    */
     targetClass = *(sink->isa);	/* Copy pointers to procedures */
 
-/*	Push text from telnet socket down sink
-**
-**	@@@@@ To push strings could be faster? (especially is we
-**	cheat and don't ignore CR! :-}
-*/  
+    /*  Push text from telnet socket down sink
+    **
+    **  @@@@@ To push strings could be faster? (especially is we
+    **  cheat and don't ignore CR! :-}
+    */  
     HTInitInput(file_number);
-    for(;;) {
-	char character;
+    for (;;) {
 	character = HTGetCharacter();
-	if (character == (char)EOF) break;
+	if (character == (char)EOF)
+	    break;
 	(*targetClass.put_character)(sink, character);           
     }
 }
 
-
-
 /*	Parse a socket given format and file number
 **
 **   This routine is responsible for creating and PRESENTING any
@@ -674,9 +679,7 @@ PUBLIC int HTParseSocket ARGS5(
     int rv;
     extern char LYCancelDownload;
 
-    stream = HTStreamStack(rep_in,
-			format_out,
-	 		sink , anchor);
+    stream = HTStreamStack(rep_in, format_out, sink, anchor);
     
     if (!stream) {
         char buffer[1024];	/* @@@@@@@@ */
@@ -686,13 +689,14 @@ PUBLIC int HTParseSocket ARGS5(
 	}
 	sprintf(buffer, "Sorry, can't convert from %s to %s.",
 	        HTAtom_name(rep_in), HTAtom_name(format_out));
-	if (TRACE) fprintf(stderr, "HTFormat: %s\n", buffer);
+	if (TRACE)
+	    fprintf(stderr, "HTFormat: %s\n", buffer);
         return HTLoadError(sink, 501, buffer); /* returns -501 */
     }
     
-/*
-**	Push the data, don't worry about CRLF we can strip them later.
-*/
+    /*
+    ** Push the data, don't worry about CRLF we can strip them later.
+    */
     targetClass = *(stream->isa);	/* Copy pointers to procedures */
     rv = HTCopy(file_number, NULL, stream);
     if (rv != -1 && rv != HT_INTERRUPTED)
@@ -701,8 +705,6 @@ PUBLIC int HTParseSocket ARGS5(
     return rv; /* full: HT_LOADED;  partial: HT_INTERRUPTED;  no bytes: -1 */
 }
 
-
-
 /*	Parse a file given format and file pointer
 **
 **   This routine is responsible for creating and PRESENTING any
@@ -736,17 +738,17 @@ PUBLIC int HTParseFile ARGS5(
 	}
 	sprintf(buffer, "Sorry, can't convert from %s to %s.",
 		HTAtom_name(rep_in), HTAtom_name(format_out));
-	if (TRACE) fprintf(stderr, "HTFormat(in HTParseFile): %s\n", buffer);
+	if (TRACE)
+	    fprintf(stderr, "HTFormat(in HTParseFile): %s\n", buffer);
         return HTLoadError(sink, 501, buffer);
     }
     
-/*	Push the data down the stream
-**
-**
-**   @@  Bug:  This decision ought to be made based on "encoding"
-**   rather than on content-type.  @@@  When we handle encoding.
-**   The current method smells anyway.
-*/
+    /*  Push the data down the stream
+    **
+    **  @@  Bug:  This decision ought to be made based on "encoding"
+    **  rather than on content-type.  @@@  When we handle encoding.
+    **  The current method smells anyway.
+    */
     targetClass = *(stream->isa);	/* Copy pointers to procedures */
     HTFileCopy(fp, stream);
     (*targetClass._free)(stream);
@@ -754,7 +756,6 @@ PUBLIC int HTParseFile ARGS5(
     return HT_LOADED;
 }
 
-
 /*	Converter stream: Network Telnet to internal character text
 **	-----------------------------------------------------------
 **
@@ -765,12 +766,11 @@ PUBLIC int HTParseFile ARGS5(
 **	C representation of a new line.
 */
 
-
 PRIVATE void NetToText_put_character ARGS2(HTStream *, me, char, net_char)
 {
     char c = FROMASCII(net_char);
     if (me->had_cr) {
-        if (c==LF) {
+        if (c == LF) {
 	    me->sink->isa->put_character(me->sink, '\n');	/* Newline */
 	    me->had_cr = NO;
 	    return;
@@ -778,7 +778,7 @@ PRIVATE void NetToText_put_character ARGS2(HTStream *, me, char, net_char)
 	    me->sink->isa->put_character(me->sink, CR);	/* leftover */
 	}
     }
-    me->had_cr = (c==CR);
+    me->had_cr = (c == CR);
     if (!me->had_cr)
 	me->sink->isa->put_character(me->sink, c);		/* normal */
 }
@@ -787,14 +787,16 @@ PRIVATE void NetToText_put_string ARGS2(HTStream *, me, CONST char *, s)
 {
     CONST char * p;
 
-    for (p=s; *p; p++)
+    for (p = s; *p; p++)
         NetToText_put_character(me, *p);
 }
 
 PRIVATE void NetToText_put_block ARGS3(HTStream *, me, CONST char*, s, int, l)
 {
     CONST char * p;
-    for(p=s; p<(s+l); p++) NetToText_put_character(me, *p);
+
+    for (p = s; p < (s+l); p++)
+        NetToText_put_character(me, *p);
 }
 
 PRIVATE void NetToText_free ARGS1(HTStream *, me)
@@ -825,6 +827,7 @@ PRIVATE HTStreamClass NetToTextClass = {
 PUBLIC HTStream * HTNetToText ARGS1(HTStream *, sink)
 {
     HTStream* me = (HTStream*)malloc(sizeof(*me));
+
     if (me == NULL)
         outofmem(__FILE__, "NetToText");
     me->isa = &NetToTextClass;
diff --git a/WWW/Library/Implementation/HTGroup.c b/WWW/Library/Implementation/HTGroup.c
index e281a578..c7abb13e 100644
--- a/WWW/Library/Implementation/HTGroup.c
+++ b/WWW/Library/Implementation/HTGroup.c
@@ -76,7 +76,7 @@ PRIVATE void syntax_error ARGS3(FILE *,	 fp,
 {
     char buffer[41];
     int cnt = 0;
-    char ch;
+    int ch;
 
     while ((ch = getc(fp)) != EOF  &&  ch != '\n')
 	if (cnt < 40) buffer[cnt++] = ch;
diff --git a/WWW/Library/Implementation/HTMIME.c b/WWW/Library/Implementation/HTMIME.c
index 313c34b9..96e6ffb4 100644
--- a/WWW/Library/Implementation/HTMIME.c
+++ b/WWW/Library/Implementation/HTMIME.c
@@ -49,6 +49,7 @@ typedef enum _MIME_state {
 	miCONNECTION,
 	miCONTENT_,
 	miCONTENT_BASE,
+	miCONTENT_DISPOSITION,
 	miCONTENT_ENCODING,
 	miCONTENT_FEATURES,
 	miCONTENT_L,
@@ -75,7 +76,10 @@ typedef enum _MIME_state {
 	miPROXY_AUTHENTICATE,
 	miPUBLIC,
 	miRETRY_AFTER,
+	miS,
+	miSE,
 	miSERVER,
+	miSET_COOKIE,
 	miT,
 	miTITLE,
 	miTRANSFER_ENCODING,
@@ -227,7 +231,7 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
 	    me->state = miCHECK;
 	    if (TRACE)
 	        fprintf(stderr,
-	 "HTMIME: Got 'S' at beginning of line, checking for 'eep-alive:'\n");
+	 "HTMIME: Got 'K' at beginning of line, checking for 'eep-alive:'\n");
 	    break;
 
 	case 'l':
@@ -258,12 +262,10 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
 
 	case 's':
 	case 'S':
-	    me->check_pointer = "erver:";
-	    me->if_ok = miSERVER;
-	    me->state = miCHECK;
+	    me->state = miS;
 	    if (TRACE)
-	        fprintf(stderr,
-	      "HTMIME: Got 'S' at beginning of line, checking for 'erver'\n");
+	        fprintf (stderr,
+		       "HTMIME: Got 'S' at beginning of line, state now S\n");
 	    break;
 
 	case 't':
@@ -535,12 +537,12 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
         switch (c) {
         case 'l':
         case 'L':
-	    me->check_pointer = "low:";
+	    me->check_pointer = "ow:";
 	    me->if_ok = miALLOW;
 	    me->state = miCHECK;
 	    if (TRACE)
 	        fprintf(stderr,
-		      "HTMIME: Was AL, found L, checking for 'low:'\n");
+		      "HTMIME: Was AL, found L, checking for 'ow:'\n");
 	    break;
 
 	case 't':
@@ -629,12 +631,12 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
         switch (c) {
         case 'n':
         case 'N':
-	    me->check_pointer = "nection:";
+	    me->check_pointer = "ection:";
 	    me->if_ok = miCONNECTION;
 	    me->state = miCHECK;
 	    if (TRACE)
 	        fprintf(stderr,
-		      "HTMIME: Was CON, found N, checking for 'nection:'\n");
+		      "HTMIME: Was CON, found N, checking for 'ection:'\n");
 	    break;
 
 	case 't':
@@ -740,12 +742,12 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
 	case 'R':
 	    me->state = miPR;
 	    if (TRACE)
-	        fprintf(stderr, "HTMIME: Was P, found O, state now PR'\n");
+	        fprintf(stderr, "HTMIME: Was P, found R, state now PR'\n");
 	    break;
 
  	case 'u':
 	case 'U':
-	    me->check_pointer = "lic:";
+	    me->check_pointer = "blic:";
 	    me->if_ok = miPUBLIC;
 	    me->state = miCHECK;
 	    if (TRACE)
@@ -768,12 +770,12 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
         switch (c) {
 	case 'a':
 	case 'A':
-	    me->check_pointer = "agma:";
+	    me->check_pointer = "gma:";
 	    me->if_ok = miPRAGMA;
 	    me->state = miCHECK;
 	    if (TRACE)
 	        fprintf(stderr,
-			"HTMIME: Was PR, found A, checking for 'agma'\n");
+			"HTMIME: Was PR, found A, checking for 'gma'\n");
 	    break;
 
 	case 'o':
@@ -797,6 +799,59 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
 	} /* switch on character */
 	break;
 
+    case miS:				/* Check for 'e' */
+        switch (c) {
+	case 'e':
+	case 'E':
+	    me->state = miSE;
+	    if (TRACE)
+	        fprintf(stderr, "HTMIME: Was S, found E, state now SE'\n");
+	    break;
+
+	default:
+	    if (TRACE)
+	        fprintf(stderr,
+		   "HTMIME: Bad character `%c' found where `%s' expected\n",
+		        c, "'e'");
+	    goto bad_field_name;
+	    break;
+
+	} /* switch on character */
+	break;
+
+    case miSE:				/* Check for 'r' or 't' */
+        switch (c) {
+	case 'r':
+	case 'R':
+	    me->check_pointer = "ver:";
+	    me->if_ok = miSERVER;
+	    me->state = miCHECK;
+	    if (TRACE)
+	        fprintf(stderr,
+			"HTMIME: Was SE, found R, checking for 'ver'\n");
+	    break;
+
+	case 't':
+	case 'T':
+	    me->check_pointer = "-cookie:";
+	    me->if_ok = miSET_COOKIE;
+	    me->state = miCHECK;
+	    if (TRACE)
+	        fprintf(stderr,
+		 "HTMIME: Was SE, found T, checking for '-cookie'\n");
+	    break;
+
+	default:
+	    if (TRACE)
+	        fprintf(stderr,
+		   "HTMIME: Bad character `%c' found where `%s' expected\n",
+		        c, "'r' or 't'");
+	    goto bad_field_name;
+	    break;
+
+	} /* switch on character */
+	break;
+
     case miT:				/* Check for 'i' or 'r' */
         switch (c) {
  	case 'i':
@@ -957,6 +1012,16 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
 		      "HTMIME: Was CONTENT_, found B, checking for 'ase:'\n");
 	    break;
 
+        case 'd':
+        case 'D':
+	    me->check_pointer = "isposition:";
+	    me->if_ok = miCONTENT_DISPOSITION;
+	    me->state = miCHECK;
+	    if (TRACE)
+	        fprintf(stderr,
+		"HTMIME: Was CONTENT_, found D, checking for 'isposition:'\n");
+	    break;
+
         case 'e':
         case 'E':
 	    me->check_pointer = "ncoding:";
@@ -1101,6 +1166,7 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
     case miCOOKIE:
     case miCONNECTION:
     case miCONTENT_BASE:
+    case miCONTENT_DISPOSITION:
     case miCONTENT_ENCODING:
     case miCONTENT_FEATURES:
     case miCONTENT_LANGUAGE:
@@ -1122,6 +1188,7 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
     case miPUBLIC:
     case miRETRY_AFTER:
     case miSERVER:
+    case miSET_COOKIE:
     case miTITLE:
     case miTRANSFER_ENCODING:
     case miUPGRADE:
@@ -1183,6 +1250,8 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
                     fprintf(stderr,
 		    	    "HTMIME: PICKED UP Cache-Control: '%s'\n",
 			    me->value);
+		if (!(me->value && *me->value))
+		    break;
 		/*
 		**  Convert to lowercase and indicate in anchor. - FM
 		*/
@@ -1212,6 +1281,49 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
                     fprintf(stderr,
 		    	    "HTMIME: PICKED UP Content-Base: '%s'\n",
 			    me->value);
+		if (!(me->value && *me->value))
+		    break;
+		/*
+		**  Indicate in anchor. - FM
+		*/
+		StrAllocCopy(me->anchor->content_base, me->value);
+                break;
+	    case miCONTENT_DISPOSITION:
+                if (TRACE)
+                    fprintf(stderr,
+		    	    "HTMIME: PICKED UP Content-Disposition: '%s'\n",
+			    me->value);
+		if (!(me->value && *me->value))
+		    break;
+		/*
+		**  Indicate in anchor. - FM
+		*/
+		StrAllocCopy(me->anchor->content_disposition, me->value);
+		/*
+		**  If it includes file; filename=name.suffix
+		**  load the me->SugFname element. - FM
+		*/
+		cp = me->anchor->content_disposition;
+		while (*cp != '\0' && strncasecomp(cp, "file;", 5))
+		    cp++;
+		if (*cp != '\0') {
+		    cp += 5;
+		    while (*cp != '\0' && WHITE(*cp))
+		        cp++;
+		    if (*cp != '\0') {
+		        while (*cp != '\0' && strncasecomp(cp, "filename=", 9))
+			    cp++;
+			if (*cp != '\0') {
+			    StrAllocCopy(me->anchor->SugFname, (cp + 9));
+			    cp = me->anchor->SugFname;
+			    while (*cp != '\0' && !WHITE(*cp))
+				cp++;
+			    *cp = '\0';
+			    if (*me->anchor->SugFname == '\0')
+			        FREE(me->anchor->SugFname);
+			}
+		    }
+		}
                 break;
             case miCONTENT_ENCODING:
                 if (TRACE)
@@ -1256,6 +1368,8 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
                     fprintf(stderr,
 		    	    "HTMIME: PICKED UP Content-Language: '%s'\n",
 			    me->value);
+		if (!(me->value && *me->value))
+		    break;
 		/*
 		**  Convert to lowercase and indicate in anchor. - FM
 		*/
@@ -1264,12 +1378,23 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
 		StrAllocCopy(me->anchor->content_language, me->value);
                 break;
 	    case miCONTENT_LENGTH:
+                if (TRACE)
+                    fprintf(stderr,
+                            "HTMIME: PICKED UP Content-Length: '%s'\n",
+                            me->value);
+		if (!(me->value && *me->value))
+		    break;
+		/*
+		**  Convert to integer and indicate in anchor. - FM
+		*/
                 me->content_length = atoi(me->value);
-                /* This is TEMPORARY. */
+                /*
+		**  This is TEMPORARY.
+		*/
                 loading_length = me->content_length;
                 if (TRACE)
                     fprintf(stderr,
-                            "HTMIME: PICKED UP Content-Length: '%d'\n",
+                            "        Converted to integer: '%d'\n",
                             me->content_length);
                 break;
 	    case miCONTENT_LOCATION:
@@ -1277,12 +1402,24 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
                     fprintf(stderr,
 		    	    "HTMIME: PICKED UP Content-Location: '%s'\n",
 			    me->value);
+		if (!(me->value && *me->value))
+		    break;
+		/*
+		**  Indicate in anchor. - FM
+		*/
+		StrAllocCopy(me->anchor->content_location, me->value);
                 break;
 	    case miCONTENT_MD5:
                 if (TRACE)
                     fprintf(stderr,
 		    	    "HTMIME: PICKED UP Content-MD5: '%s'\n",
 			    me->value);
+		if (!(me->value && *me->value))
+		    break;
+		/*
+		**  Indicate in anchor. - FM
+		*/
+		StrAllocCopy(me->anchor->content_md5, me->value);
                 break;
 	    case miCONTENT_RANGE:
                 if (TRACE)
@@ -1295,6 +1432,8 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
                     fprintf(stderr,
 			"HTMIME: PICKED UP Content-Transfer-Encoding: '%s'\n",
                             me->value);
+		if (!(me->value && *me->value))
+		    break;
 		/*
 		**  Force the Content-Transfer-Encoding value
 		**  to all lower case. - FM
@@ -1308,6 +1447,8 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
                     fprintf(stderr,
 		    	    "HTMIME: PICKED UP Content-Type: '%s'\n",
 			    me->value);
+		if (!(me->value && *me->value))
+		    break;
 		/*
 		**  Force the Content-Type value to all
 		**  lower case and strip spaces. - FM
@@ -1325,6 +1466,12 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
                     fprintf(stderr,
 		    	    "HTMIME: PICKED UP Date: '%s'\n",
 			    me->value);
+		if (!(me->value && *me->value))
+		    break;
+		/*
+		**  Indicate in anchor. - FM
+		*/
+		StrAllocCopy(me->anchor->date, me->value);
                 break;
 	    case miETAG:
                 if (TRACE)
@@ -1337,6 +1484,12 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
                     fprintf(stderr,
 		    	    "HTMIME: PICKED UP Expires: '%s'\n",
 			    me->value);
+		if (!(me->value && *me->value))
+		    break;
+		/*
+		**  Indicate in anchor. - FM
+		*/
+		StrAllocCopy(me->anchor->expires, me->value);
                 break;
 	    case miKEEP_ALIVE:
                 if (TRACE)
@@ -1349,6 +1502,12 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
                     fprintf(stderr,
 		    	    "HTMIME: PICKED UP Last-Modified: '%s'\n",
 			    me->value);
+		if (!(me->value && *me->value))
+		    break;
+		/*
+		**  Indicate in anchor. - FM
+		*/
+		StrAllocCopy(me->anchor->last_modified, me->value);
                 break;
 	    case miLINK:
                 if (TRACE)
@@ -1367,6 +1526,8 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
                     fprintf(stderr,
                             "HTMIME: PICKED UP Pragma: '%s'\n",
 			    me->value);
+		if (!(me->value && *me->value))
+		    break;
 		/*
 		 *  Check whether to set no_cache for the anchor. - FM
 		 */
@@ -1396,6 +1557,18 @@ PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
                     fprintf(stderr,
                             "HTMIME: PICKED UP Server: '%s'\n",
 			    me->value);
+		if (!(me->value && *me->value))
+		    break;
+		/*
+		**  Indicate in anchor. - FM
+		*/
+		StrAllocCopy(me->anchor->server, me->value);
+                break;
+	    case miSET_COOKIE:
+                if (TRACE)
+                    fprintf(stderr,
+                            "HTMIME: PICKED UP Set-Cookie: '%s'\n",
+			    me->value);
                 break;
 	    case miTITLE:
                 if (TRACE)
@@ -1579,9 +1752,18 @@ PUBLIC HTStream* HTMIMEConvert ARGS3(
     me->anchor	=	anchor;
     me->anchor->no_cache = FALSE;
     FREE(me->anchor->cache_control);
+    FREE(me->anchor->SugFname);
     FREE(me->anchor->charset);
     FREE(me->anchor->content_language);
     FREE(me->anchor->content_encoding);
+    FREE(me->anchor->content_base);
+    FREE(me->anchor->content_disposition);
+    FREE(me->anchor->content_location);
+    FREE(me->anchor->content_md5);
+    FREE(me->anchor->date);
+    FREE(me->anchor->expires);
+    FREE(me->anchor->last_modified);
+    FREE(me->anchor->server);
     me->target	= 	NULL;
     me->state	=	miBEGINNING_OF_LINE;
     /*
@@ -1919,7 +2101,7 @@ PUBLIC int HTrjis ARGS2(
 */
 /*
  * RJIS ( Recover JIS code from broken file )
- * $Header: /usr/build/VCS/lynx/WWW/Library/Implementation/RCS/HTMIME.c,v 1.1 1996/09/02 00:21:10 tom Exp $
+ * @Header: rjis.c,v 0.2 92/09/04 takahasi Exp @
  * Copyright (C) 1992 1994
  * Hironobu Takahashi (takahasi@tiny.or.jp)
  *
diff --git a/WWW/Library/Implementation/HTMLDTD.c b/WWW/Library/Implementation/HTMLDTD.c
index 3a982b2f..403c79f1 100644
--- a/WWW/Library/Implementation/HTMLDTD.c
+++ b/WWW/Library/Implementation/HTMLDTD.c
@@ -249,9 +249,9 @@ static attr body_attr[] = {			/* BODY attributes */
 	{ "ID" },
 	{ "LANG" },
 	{ "LINK" },
-	{ "STYLE" },
 	{ "ONLOAD" },
 	{ "ONUNLOAD" },
+	{ "STYLE" },
 	{ "TEXT" },
 	{ "VLINK" },
 	{ 0 } /* Terminate list */
@@ -600,8 +600,8 @@ static attr list_attr[] = {			/* LI attributes */
 	{ "ID" },
 	{ "LANG" },
 	{ "MD" },
-	{ "SRC" },
 	{ "SKIP" },
+	{ "SRC" },
 	{ "STYLE" },
 	{ "TYPE" },
 	{ "VALUE" },
@@ -747,10 +747,10 @@ static attr param_attr[] = {			/* PARAM attribures */
 	{ "ACCEPT-ENCODING" },
 	{ "CLASS" },
 	{ "CLEAR" },
+	{ "DATA" },
 	{ "DIR" },
 	{ "ID" },
 	{ "LANG" },
-	{ "DATA" },
 	{ "NAME" },
 	{ "OBJECT" },
 	{ "REF" },
@@ -774,8 +774,8 @@ static attr script_attr[] = {			/* SCRIPT attribures */
 	{ "NAME" },
 	{ "SCRIPTENGINE" },
 	{ "SRC" },
-	{ "TYPE" },
 	{ "STYLE" },
+	{ "TYPE" },
 	{ 0 }	/* Terminate list */
 };
 
diff --git a/WWW/Library/Implementation/HTMLDTD.h b/WWW/Library/Implementation/HTMLDTD.h
index a176e59b..aad12417 100644
--- a/WWW/Library/Implementation/HTMLDTD.h
+++ b/WWW/Library/Implementation/HTMLDTD.h
@@ -1,11 +1,12 @@
-/*                                               The HTML DTD -- software interface in libwww
+/*                               The HTML DTD -- software interface in libwww
                               HTML DTD - SOFTWARE INTERFACE
                                              
-   SGML purists should excuse the use of the term "DTD" in this file to represent
-   DTD-related information which is not exactly a DTD itself.
+   SGML purists should excuse the use of the term "DTD" in this file to
+   represent DTD-related information which is not exactly a DTD itself.
    
-   The C modular structure doesn't work very well here, as the dtd is partly in the .h and
-   partly in the .c which are not very independent.  Tant pis.
+   The C modular structure doesn't work very well here, as the dtd is
+   partly in the .h and partly in the .c which are not very independent.
+   Tant pis.
    
  */
 #ifndef HTMLDTD_H
@@ -252,20 +253,20 @@ Attribute numbers
 #define HTML_BQ_STYLE           6
 #define HTML_BQ_ATTRIBUTES      7
 
-#define HTML_BODYTEXT_CLASS     1
-#define HTML_BODYTEXT_CLEAR     2
-#define HTML_BODYTEXT_DATA      3
-#define HTML_BODYTEXT_DIR       4
-#define HTML_BODYTEXT_ID        5
-#define HTML_BODYTEXT_LANG      6
-#define HTML_BODYTEXT_NAME      7
-#define HTML_BODYTEXT_OBJECT    8
-#define HTML_BODYTEXT_REF       9
-#define HTML_BODYTEXT_STYLE    10
-#define HTML_BODYTEXT_TYPE     11
-#define HTML_BODYTEXT_VALUE    12
-#define HTML_BODYTEXT_VALUETYPE  13
-#define HTML_BODYTEXT_ATTRIBUTES 14
+#define HTML_BODYTEXT_CLASS     0
+#define HTML_BODYTEXT_CLEAR     1
+#define HTML_BODYTEXT_DATA      2
+#define HTML_BODYTEXT_DIR       3
+#define HTML_BODYTEXT_ID        4
+#define HTML_BODYTEXT_LANG      5
+#define HTML_BODYTEXT_NAME      6
+#define HTML_BODYTEXT_OBJECT    7
+#define HTML_BODYTEXT_REF       8
+#define HTML_BODYTEXT_STYLE     9
+#define HTML_BODYTEXT_TYPE     10
+#define HTML_BODYTEXT_VALUE    11
+#define HTML_BODYTEXT_VALUETYPE  12
+#define HTML_BODYTEXT_ATTRIBUTES 13
 
 #define HTML_BODY_ALINK         0
 #define HTML_BODY_BACKGROUND    1
@@ -555,8 +556,8 @@ Attribute numbers
 #define HTML_LI_ID              4
 #define HTML_LI_LANG            5
 #define HTML_LI_MD              6
-#define HTML_LI_SRC             7
-#define HTML_LI_SKIP            8
+#define HTML_LI_SKIP            7
+#define HTML_LI_SRC             8
 #define HTML_LI_STYLE           9
 #define HTML_LI_TYPE           10
 #define HTML_LI_VALUE          11
@@ -671,8 +672,8 @@ Attribute numbers
 #define HTML_P_DIR              3
 #define HTML_P_ID               4
 #define HTML_P_LANG             5
-#define HTML_P_STYLE            6
-#define HTML_P_NOWRAP           7
+#define HTML_P_NOWRAP           6
+#define HTML_P_STYLE            7
 #define HTML_P_ATTRIBUTES       8
 
 #define HTML_PARAM_ACCEPT       0
diff --git a/WWW/Library/Implementation/HTNews.c b/WWW/Library/Implementation/HTNews.c
index 7eeb7c2a..73406922 100644
--- a/WWW/Library/Implementation/HTNews.c
+++ b/WWW/Library/Implementation/HTNews.c
@@ -38,8 +38,9 @@ PUBLIC int HTNewsMaxChunk = 40;	/* Largest number of articles in one window */
 #define SERVER_FILE "/usr/local/lib/rn/server"
 #endif
 
-#define NEWS_NETREAD   NETREAD
 #define NEWS_NETWRITE  NETWRITE
+#define NEWS_NETCLOSE  NETCLOSE
+#define NEXT_CHAR HTGetCharacter()
 			
 #include <ctype.h>
 
@@ -57,7 +58,6 @@ struct _HTStructured {
 	/* ... */
 };
 
-#define NEXT_CHAR HTGetCharacter()
 #define LINE_LENGTH 512			/* Maximum length of line of ARTICLE etc */
 #define GROUP_NAME_LENGTH	256	/* Maximum length of group name */
 extern BOOLEAN scan_for_buried_news_references;
@@ -184,7 +184,7 @@ PRIVATE int response ARGS1(CONST char *,command)
 	if (status < 0){
 	    if (TRACE) fprintf(stderr,
 	        "HTNews: Unable to send command. Disconnecting.\n");
-	    NETCLOSE(s);
+	    NEWS_NETCLOSE(s);
 	    s = -1;
 	    return status;
 	} /* if bad status */
@@ -202,7 +202,7 @@ PRIVATE int response ARGS1(CONST char *,command)
 	if ((ch = *(p-1)) == (char)EOF) {
 	    if (TRACE) fprintf(stderr,
 	    	"HTNews: EOF on read, closing socket %d\n", s);
-	    NETCLOSE(s);	/* End of file, close socket */
+	    NEWS_NETCLOSE(s);	/* End of file, close socket */
 	    return s = -1;	/* End of file on response */
 	}
     } /* Loop over characters */
@@ -453,7 +453,7 @@ PRIVATE void abort_socket NOARGS
     if (TRACE)
         fprintf(stderr,
 	        "HTNews: EOF on read, closing socket %d\n", s);
-    NETCLOSE(s);	/* End of file, close socket */
+    NEWS_NETCLOSE(s);	/* End of file, close socket */
     PUTS("Network Error: connection lost");
     PUTC('\n');
     s = -1;		/* End of file on response */
@@ -1308,6 +1308,7 @@ PUBLIC int HTLoadNews ARGS4(
 	HTStream*,		stream)
 {
     char command[260];			/* The whole command */
+    char proxycmd[260];			/* The proxy command */
     char groupName[GROUP_NAME_LENGTH];	/* Just the group name */
     int status;				/* tcp return */
     int retries;			/* A count of how hard we have tried */ 
@@ -1342,8 +1343,8 @@ PUBLIC int HTLoadNews ARGS4(
     **  	xxxxx			News group (no "@")
     **  	group/n1-n2		Articles n1 to n2 in group
     */
-	group_wanted = (strchr(arg, '@')==0) && (strchr(arg, '*')==0);
-	list_wanted  = (strchr(arg, '@')==0) && (strchr(arg, '*')!=0);
+	group_wanted = (strchr(arg, '@') == NULL) && (strchr(arg, '*') == NULL);
+	list_wanted  = (strchr(arg, '@') == NULL) && (strchr(arg, '*') != NULL);
 
 	/* p1 = HTParse(arg, "", PARSE_PATH | PARSE_PUNCTUATION); */
 	/*
@@ -1361,19 +1362,19 @@ PUBLIC int HTLoadNews ARGS4(
 	  }
 	  if (!(cp = HTParse(arg, "", PARSE_HOST)) || *cp == '\0') {
 	      if (s >= 0 && NewsHost && strcasecomp(NewsHost, HTNewsHost)) {
-	          NETCLOSE(s);
+	          NEWS_NETCLOSE(s);
 		  s = -1;
 	      }
 	      StrAllocCopy(NewsHost, HTNewsHost);
 	  } else {
 	      if (s >= 0 && NewsHost && strcasecomp(NewsHost, cp)) {
-	          NETCLOSE(s);
+	          NEWS_NETCLOSE(s);
 		  s = -1;
 	      }
 	      StrAllocCopy(NewsHost, cp);
 	  }
 	  FREE(cp);
-	  sprintf(command, "nntp://%s/", NewsHost);
+	  sprintf(command, "nntp://%.250s/", NewsHost);
 	  StrAllocCopy(NewsHREF, command);
 	}
 	else if (!strncasecomp(arg, "snews:", 6)) {
@@ -1390,30 +1391,60 @@ PUBLIC int HTLoadNews ARGS4(
 	  }
 	  if (!(cp = HTParse(arg, "", PARSE_HOST)) || *cp == '\0') {
 	      if (s >= 0 && NewsHost && strcasecomp(NewsHost, HTNewsHost)) {
-	          NETCLOSE(s);
+	          NEWS_NETCLOSE(s);
 		  s = -1;
 	      }
 	      StrAllocCopy(NewsHost, HTNewsHost);
 	  } else {
 	      if (s >= 0 && NewsHost && strcasecomp(NewsHost, cp)) {
-	          NETCLOSE(s);
+	          NEWS_NETCLOSE(s);
 		  s = -1;
 	      }
 	      StrAllocCopy(NewsHost, cp);
 	  }
 	  FREE(cp);
-	  sprintf(command, "news://%s/", NewsHost);
+	  sprintf(command, "news://%.250s/", NewsHost);
 	  StrAllocCopy(NewsHREF, command);
-	}
-	else {
+	} else {
 	  p1 = arg + 5;  /* Skip "news:" prefix */
 	  if (s >= 0 && NewsHost && strcasecomp(NewsHost, HTNewsHost)) {
-	      NETCLOSE(s);
+	      NEWS_NETCLOSE(s);
 	      s = -1;
 	  }
 	  StrAllocCopy(NewsHost, HTNewsHost);
 	  StrAllocCopy(NewsHREF, "news:");
 	}
+
+	/*
+	 *  Set up any proxy for snews URLs that returns NNTP
+	 *  responses for Lynx to convert to HTML, instead of
+	 *  doing the conversion itself. - TZ & FM
+	 */
+	proxycmd[0] = '\0';
+ 	if (!strncasecomp (p1, "snews://", 8)) {
+	  if ((cp = strchr((p1+8), '/')) != NULL)
+	    *cp = '\0';
+	  sprintf(command, "%.258s/", p1);
+	  StrAllocCopy(NewsHREF, command);
+	  sprintf(proxycmd, "GET %.250s%c%c%c%c", p1, CR, LF, CR, LF);
+	  if ((cp == NULL) || *(cp+1) == '\0') {
+	      p1 = "*";
+	      group_wanted = FALSE;
+	      list_wanted = TRUE;
+	  } else {
+	      p1 = (cp+1);
+	  }
+	  if (cp != NULL)
+	      *cp = '/';
+	  if (TRACE)
+	      fprintf(stderr,
+	      	      "HTNews: Proxy command is '%.*s'\n",
+		      (strlen(proxycmd) - 4), proxycmd);
+	}
+
+	/*
+	 *  Set up command for a listing or article request. - FM
+	 */
 	if (list_wanted) {
 	    strcpy(command, "LIST NEWSGROUPS");
 	} else if (group_wanted) {
@@ -1453,10 +1484,12 @@ PUBLIC int HTLoadNews ARGS4(
 
         {
 	    char * p = command + strlen(command);
+	    /*
+	     *  Teminate command with CRLF, as in RFC 977.
+	     */
 	    *p++ = CR;		/* Macros to be correct on Mac */
 	    *p++ = LF;
 	    *p++ = 0;
-	    /* strcat(command, "\r\n");	*/	/* CR LF, as in rfc 977 */
 	}
 	StrAllocCopy(ListArg, p1);
     } /* scope of p1 */
@@ -1509,7 +1542,7 @@ PUBLIC int HTLoadNews ARGS4(
             }
 	    if (status < 0) {
 		char message[256];
-	        NETCLOSE(s);
+	        NEWS_NETCLOSE(s);
 		s = -1;
 		if (TRACE)
 		    fprintf(stderr,
@@ -1526,9 +1559,16 @@ PUBLIC int HTLoadNews ARGS4(
 		    fprintf(stderr, "HTNews: Connected to news host %s.\n",
 				    NewsHost);
 		HTInitInput(s);		/* set up buffering */
+		if (proxycmd[0]) {
+		    status = NEWS_NETWRITE(s, proxycmd, strlen(proxycmd));
+		    if (TRACE)
+		        fprintf(stderr,
+			     "HTNews: Proxy command returned status '%d'.\n",
+				status);
+		}
 		if ((response(NULL) / 100) != 2) {
 			char message[BIG];
-			NETCLOSE(s);
+			NEWS_NETCLOSE(s);
 			s = -1;
 			if (retries < 1)
 			    continue;
@@ -1576,7 +1616,7 @@ Send_NNTP_command:
 	        HTAlert(response_text);
 	    else
 	        _HTProgress(response_text);
-	    NETCLOSE(s);
+	    NEWS_NETCLOSE(s);
 	    s = -1;
 	    /*
 	     *  Message might be a leftover "Timeout-disconnected",
diff --git a/WWW/Library/Implementation/HTParse.c b/WWW/Library/Implementation/HTParse.c
index 463488f7..5c455a65 100644
--- a/WWW/Library/Implementation/HTParse.c
+++ b/WWW/Library/Implementation/HTParse.c
@@ -585,6 +585,10 @@ PUBLIC char * HTUnEscape ARGS1(
 {
     char * p = str;
     char * q = str;
+
+    if (!(p && *p))
+        return str;
+
     while (*p) {
         if (*p == HEX_ESCAPE) {
 	    p++;
@@ -603,4 +607,43 @@ PUBLIC char * HTUnEscape ARGS1(
     
 } /* HTUnEscape */
 
+/*		Decode some %xx escaped characters	      HTUnEscapeSome()
+**		----------------------------------	      Klaus Weide
+**							    (kweide@tezcat.com)
+**	This function takes a pointer to a string in which some
+**	characters may have been encoded in %xy form, where xy is
+**	the acsii hex code for character 16x+y, and a pointer to
+**	a second string containing one or more characters which
+**	should be unescaped if escaped in the first string.
+**	The first string is converted in place, as it will never grow.
+*/
+PUBLIC char * HTUnEscapeSome ARGS2(
+	char *,		str,
+        CONST char *,	do_trans)
+{
+    char * p = str;
+    char * q = str;
+    char testcode;
+
+    if (!(p && *p) || !(do_trans && *do_trans))
+        return str;
+
+    while (*p) {
+        if (*p == HEX_ESCAPE &&
+	    p[1] && p[2] &&	/* tests shouldn't be needed, but.. */
+	    isxdigit((unsigned char)p[1]) &&
+	    isxdigit((unsigned char)p[2]) &&
+	    (testcode = from_hex(p[1])*16 + from_hex(p[2])) && /* %00 no good*/
+	    strchr(do_trans, testcode)) { /* it's one of the ones we want */
+	    *q++ = FROMASCII(testcode); 
+	    p += 3;
+	} else {
+	    *q++ = *p++; 
+	}
+    }
+    
+    *q++ = '\0';
+    return str;
+    
+} /* HTUnEscapeSome */
 
diff --git a/WWW/Library/Implementation/HTParse.h b/WWW/Library/Implementation/HTParse.h
index 669837c2..30cb74f5 100644
--- a/WWW/Library/Implementation/HTParse.h
+++ b/WWW/Library/Implementation/HTParse.h
@@ -1,9 +1,10 @@
-/*                                                   HTParse:  URL parsing in the WWW Library
-                                         HTPARSE
-                                             
-   This module of the WWW library contains code to parse URLs and various related things.
+/*                                   HTParse:  URL parsing in the WWW Library
+				HTPARSE
+
+   This module of the WWW library contains code to parse URLs and various
+   related things.
    Implemented by HTParse.c .
-   
+
  */
 #ifndef HTPARSE_H
 #define HTPARSE_H
@@ -14,9 +15,9 @@
 
 /*
 
-   The following are flag bits which may be ORed together to form a number to give the
-   'wanted' argument to HTParse.
-   
+   The following are flag bits which may be ORed together to form a number to
+   give the 'wanted' argument to HTParse.
+
  */
 #define PARSE_ACCESS            16
 #define PARSE_HOST               8
@@ -30,21 +31,21 @@
 
 HTParse:  Parse a URL relative to another URL
 
-   This returns those parts of a name which are given (and requested) substituting bits
-   from the related name where necessary.
-   
+   This returns those parts of a name which are given (and requested)
+   substituting bits from the related name where necessary.
+
   ON ENTRY
-  
+
   aName                   A filename given
-                         
+
   relatedName             A name relative to which aName is to be parsed
-                         
+
   wanted                  A mask for the bits which are wanted.
-                         
+
   ON EXIT,
-  
+
   returns                 A pointer to a malloc'd string which MUST BE FREED
-                         
+
  */
 
 extern char * HTParse PARAMS((
@@ -58,11 +59,11 @@ extern char * HTParse PARAMS((
 HTStrip: Strip white space off a string
 
   ON EXIT
-  
+
    Return value points to first non-white character, or to 0 if none.
-   
+
    All trailing white space is OVERWRITTEN with zero.
-   
+
  */
 extern char * HTStrip PARAMS((
 	char *		s));
@@ -71,11 +72,11 @@ extern char * HTStrip PARAMS((
 
 HTSimplify: Simplify a UTL
 
-   A URL is allowed to contain the seqeunce xxx/../ which may be replaced by "" , and the
-   seqeunce "/./" which may be replaced by "/". Simplification helps us recognize
-   duplicate filenames. It doesn't deal with soft links, though. The new (shorter)
-   filename overwrites the old.
-   
+   A URL is allowed to contain the seqeunce xxx/../ which may be replaced by
+   "" , and the seqeunce "/./" which may be replaced by "/". Simplification
+   helps us recognize duplicate filenames. It doesn't deal with soft links,
+   though. The new (shorter) filename overwrites the old.
+
  */
 /*
 **      Thus,   /etc/junk/../fred       becomes /etc/fred
@@ -89,19 +90,20 @@ extern void HTSimplify PARAMS((
 
 HTRelative:  Make Relative (Partial) URL
 
-   This function creates and returns a string which gives an expression of one address as
-   related to another. Where there is no relation, an absolute address is retured.
-   
+   This function creates and returns a string which gives an expression of one
+   address as related to another. Where there is no relation, an absolute
+   address is retured.
+
   ON ENTRY,
-  
+
    Both names must be absolute, fully qualified names of nodes (no anchor bits)
-   
+
   ON EXIT,
-  
-   The return result points to a newly allocated name which, if parsed by HTParse relative
-   to relatedName, will yield aName. The caller is responsible for freeing the resulting
-   name later.
-   
+
+   The return result points to a newly allocated name which, if parsed by
+   HTParse relative to relatedName, will yield aName. The caller is
+   responsible for freeing the resulting name later.
+
  */
 extern char * HTRelative PARAMS((
 	CONST char *	aName,
@@ -112,10 +114,11 @@ extern char * HTRelative PARAMS((
 
 HTEscape:  Encode unacceptable characters in string
 
-   This funtion takes a string containing any sequence of ASCII characters, and returns a
-   malloced string containing the same infromation but with all "unacceptable" characters
-   represented in the form %xy where X and Y are two hex digits.
-   
+   This function takes a string containing any sequence of ASCII characters,
+   and returns a malloced string containing the same infromation but with all
+   "unacceptable" characters represented in the form %xy where X and Y are two
+   hex digits.
+
  */
 extern char * HTEscape PARAMS((
 	CONST char *	str,
@@ -128,8 +131,9 @@ extern char * HTEscapeSP PARAMS((
 
 /*
 
-   The following are valid mask values. The terms are the BNF names in the URL document.
-   
+   The following are valid mask values. The terms are the BNF names in the URL
+   document.
+
  */
 #define URL_XALPHAS     (unsigned char) 1
 #define URL_XPALPHAS    (unsigned char) 2
@@ -140,15 +144,31 @@ extern char * HTEscapeSP PARAMS((
 
 HTUnEscape: Decode %xx escaped characters
 
-   This function takes a pointer to a string in which character smay have been encoded in
-   %xy form, where xy is the acsii hex code for character 16x+y. The string is converted
-   in place, as it will never grow.
-   
+   This function takes a pointer to a string in which character smay have been
+   encoded in %xy form, where xy is the acsii hex code for character 16x+y.
+   The string is converted in place, as it will never grow.
+
  */
 extern char * HTUnEscape PARAMS((
 	char *		str));
 
 
+/*
+
+HTUnEscapeSome: Decode some %xx escaped characters - KW
+
+   This function takes a pointer to a string in which some characters may have
+   been encoded in %xy form, where xy is the acsii hex code for character
+   16x+y, and a pointer to a second string containing one or more characters
+   which should be unescaped if escaped in the first string.
+   The first string is converted in place, as it will never grow.
+
+ */
+extern char * HTUnEscapeSome PARAMS((
+	char *		str,
+	CONST char *	do_trans));
+
+
 #endif  /* HTPARSE_H */
 
 
diff --git a/WWW/Library/Implementation/HTPasswd.c b/WWW/Library/Implementation/HTPasswd.c
index 58ae62c8..e08bfbeb 100644
--- a/WWW/Library/Implementation/HTPasswd.c
+++ b/WWW/Library/Implementation/HTPasswd.c
@@ -218,7 +218,7 @@ PUBLIC int HTAAFile_readPasswdRec ARGS3(FILE *, fp,
 					char *, out_username,
 					char *, out_password)
 {
-    char terminator;
+    int terminator;
     
     terminator = HTAAFile_readField(fp, out_username, MAX_USERNAME_LEN);
 
diff --git a/WWW/Library/Implementation/HTTCP.c b/WWW/Library/Implementation/HTTCP.c
index 45d8a979..2ea6906c 100644
--- a/WWW/Library/Implementation/HTTCP.c
+++ b/WWW/Library/Implementation/HTTCP.c
@@ -23,6 +23,11 @@
 #include "HTParse.h"
 #include "HTAlert.h"
 
+#ifdef NSL_FORK
+#include <signal.h>
+#include <sys/wait.h>
+#endif /* NSL_FORM */
+ 
 #define FREE(x) if (x) {free(x); x = NULL;}
 
 extern int HTCheckForInterrupt NOPARAMS;
@@ -48,7 +53,7 @@ PUBLIC int BSDselect PARAMS((int nfds, fd_set * readfds, fd_set * writefds,
 #define HTInetStatus		HTInStat
 #define HTInetString 		HTInStri
 #define HTParseInet		HTPaInet
-#endif
+#endif /* SHORT_NAMES */
 
 #ifndef FD_SETSIZE
 #if defined(UCX) || defined(SOCKETSHR_TCP) || defined(CMU_TCP)
@@ -56,17 +61,15 @@ PUBLIC int BSDselect PARAMS((int nfds, fd_set * readfds, fd_set * writefds,
 #else
 #define FD_SETSIZE 256
 #endif /* Limit # sockets to 32 for UCX, BSN - also SOCKETSHR and CMU, AH */
-#endif
+#endif /* FD_SETSIZE */
 
 /*	Module-Wide variables
 */
-
 PRIVATE char *hostname = NULL;		/* The name of this host */
 
 
 /*	PUBLIC VARIABLES
 */
-
 #ifdef SOCKS
 extern BOOLEAN socks_flag;
 PUBLIC unsigned long socks_bind_remoteAddr; /* for long Rbind */
@@ -122,60 +125,52 @@ extern int sys_nerr;
 #define IOC_OUT (int)0x40000000
 extern int vaxc$get_sdc(), sys$qiow();
 
-PUBLIC int HTioctl ARGS3
-	(int,		d, 
+PUBLIC int HTioctl ARGS3(
+	int,		d, 
 	int,		request,
 	int *,		argp)
 {
-  int sdc, status;
-  unsigned short fun, iosb[4];
-  char *p5, *p6;
-  struct comm
-    {
-      int command;
-      char *addr;
+    int sdc, status;
+    unsigned short fun, iosb[4];
+    char *p5, *p6;
+    struct comm {
+        int command;
+        char *addr;
     } ioctl_comm;
-  struct it2
-    {
-      unsigned short len;
-      unsigned short opt;
-      struct comm *addr;
+    struct it2 {
+        unsigned short len;
+        unsigned short opt;
+        struct comm *addr;
     } ioctl_desc;
-  if ((sdc = vaxc$get_sdc (d)) == 0)
-    {
-      errno = EBADF;
-      return -1;
-    }
-  ioctl_desc.opt  = UCX$C_IOCTL;
-  ioctl_desc.len  = sizeof(struct comm);
-  ioctl_desc.addr = &ioctl_comm;
-  if (request & IOC_OUT)
-    {
-      fun = IO$_SENSEMODE;
-      p5 = 0;
-      p6 = (char *)&ioctl_desc;
+
+    if ((sdc = vaxc$get_sdc (d)) == 0) {
+        errno = EBADF;
+        return -1;
     }
-  else
-    {
-      fun = IO$_SETMODE;
-      p5 = (char *)&ioctl_desc;
-      p6 = 0;
+    ioctl_desc.opt  = UCX$C_IOCTL;
+    ioctl_desc.len  = sizeof(struct comm);
+    ioctl_desc.addr = &ioctl_comm;
+    if (request & IOC_OUT) {
+        fun = IO$_SENSEMODE;
+        p5 = 0;
+        p6 = (char *)&ioctl_desc;
+    } else {
+        fun = IO$_SETMODE;
+        p5 = (char *)&ioctl_desc;
+        p6 = 0;
     }
-  ioctl_comm.command = request;
-  ioctl_comm.addr = (char *)argp;
-  status = sys$qiow (0, sdc, fun, iosb, 0, 0,
-    0, 0, 0, 0, p5, p6);
-  if (!(status & 01))
-    {
-      errno = status;
-      return -1;
+    ioctl_comm.command = request;
+    ioctl_comm.addr = (char *)argp;
+    status = sys$qiow (0, sdc, fun, iosb, 0, 0, 0, 0, 0, 0, p5, p6);
+    if (!(status & 01)) {
+        errno = status;
+        return -1;
     }
-  if (!(iosb[0] & 01))
-    {
-      errno = iosb[0];
-      return -1;
+    if (!(iosb[0] & 01)) {
+        errno = iosb[0];
+        return -1;
     }
-  return 0;
+    return 0;
 }
 #endif /* VMS && UCX */
 
@@ -188,50 +183,52 @@ PUBLIC int HTInetStatus ARGS1(
 {
 #ifdef VMS
 #ifdef MULTINET
-            SOCKET_ERRNO = vmserrno;
+    SOCKET_ERRNO = vmserrno;
 #endif /* MULTINET */
 #endif /* VMS */
 
     CTRACE(tfp,
     	"TCP: Error %d in `SOCKET_ERRNO' after call to %s() failed.\n\t%s\n",
-	SOCKET_ERRNO,  where, /* third arg is transport/platform specific */
-
+	   SOCKET_ERRNO,  where,
+	   /* third arg is transport/platform specific */
 #ifdef VM
-	    "(Error number not translated)");	/* What Is the VM equiv? */
+	   "(Error number not translated)");	/* What Is the VM equiv? */
 #define ER_NO_TRANS_DONE
 #endif /* VM */
 
 #ifdef VMS
 #ifdef MULTINET
-            vms_errno_string());
+           vms_errno_string());
 #else
-	    ((SOCKET_ERRNO > 0 && SOCKET_ERRNO <= 65) ?
-	     strerror(SOCKET_ERRNO) : "(Error number not translated)"));
+	   ((SOCKET_ERRNO > 0 && SOCKET_ERRNO <= 65) ?
+	    strerror(SOCKET_ERRNO) : "(Error number not translated)"));
 #endif /* MULTINET */
 #define ER_NO_TRANS_DONE
 #endif /* VMS */
 
 #if defined(NeXT) || defined(THINK_C)
-	    strerror(SOCKET_ERRNO));
+	   strerror(SOCKET_ERRNO));
 #define ER_NO_TRANS_DONE
 #endif /* NeXT || THINK_C */
 
 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(BSDI)
-	    strerror(SOCKET_ERRNO));
+	   strerror(SOCKET_ERRNO));
 #define ER_NO_TRANS_DONE
 #endif /* __NetBSD__ || __FreeBSD__ || BSDI */
 
 #ifndef ER_NO_TRANS_DONE
-	    (SOCKET_ERRNO < sys_nerr ?
-	     sys_errlist[SOCKET_ERRNO] : "Unknown error" ));
+	   (SOCKET_ERRNO < sys_nerr ?
+	    sys_errlist[SOCKET_ERRNO] : "Unknown error" ));
 #endif /* !ER_NO_TRANS_DONE */
 
 #ifdef VMS
 #ifndef MULTINET
     CTRACE(tfp,
-    	"         Unix error number (SOCKET_ERRNO) = %ld dec\n", SOCKET_ERRNO);
+    	   "         Unix error number (SOCKET_ERRNO) = %ld dec\n",
+	   SOCKET_ERRNO);
     CTRACE(tfp,
-    	"         VMS error (vaxc$errno)    = %lx hex\n", vaxc$errno);
+    	   "         VMS error (vaxc$errno)    = %lx hex\n",
+	   vaxc$errno);
 #endif /* MULTINET */
 #endif /* VMS */
 
@@ -267,16 +264,17 @@ PUBLIC unsigned int HTCardinal ARGS3
 	char **,	pp,
 	unsigned int,	max_value)
 {
-    int   n;
-    if ( (**pp<'0') || (**pp>'9')) {	    /* Null string is error */
+    int n;
+    if ((**pp<'0') || (**pp>'9')) {	    /* Null string is error */
 	*pstatus = -3;  /* No number where one expeceted */
 	return 0;
     }
 
-    n=0;
-    while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
+    n = 0;
+    while ((**pp >= '0') && (**pp <= '9'))
+        n = n*10 + *((*pp)++) - '0';
 
-    if (n>max_value) {
+    if (n > max_value) {
 	*pstatus = -4;  /* Cardinal outside range */
 	return 0;
     }
@@ -326,6 +324,7 @@ PUBLIC int HTParseInet ARGS2(
 {
     char *port;
     char *host = NULL;
+    int dotcount_ip = 0;	/* for dotted decimal IP addr */
     struct hostent  *phost;	/* Pointer to host - See netdb.h */
 
     if (!str) {
@@ -359,9 +358,9 @@ PUBLIC int HTParseInet ARGS2(
 	    struct servent * serv = getservbyname(port, (char*)0);
 	    if (serv) sin->sin_port = serv->s_port;
 	    else if (TRACE) fprintf(stderr, "TCP: Unknown service %s\n", port);
-#endif
+#endif /* SUPPRESS */
 	}
-      }
+    }
 
 #ifdef DECNET
     /* read Decnet node name. @@ Should know about DECnet addresses, but it's
@@ -377,26 +376,45 @@ PUBLIC int HTParseInet ARGS2(
 
 #else  /* parse Internet host */
 
+    if (*host >= '0' && *host <= '9') {   /* Test for numeric node address: */
+	char *strptr = host;
+	while (*strptr) {
+	    if (*strptr == '.')
+		dotcount_ip++;
+	    else if (!isdigit(*strptr))
+		break;
+	    strptr++;
+	}
+	if (*strptr)		/* found non-numeric, assume domain name */
+	    dotcount_ip = 0;
+    }
+
 /*	Parse host number if present.
 */  
-    if (*host >= '0' && *host <= '9') {   /* Numeric node address: */
+    if (dotcount_ip == 3) {   /* Numeric node address: */
 #ifdef DGUX_OLD
 	sin->sin_addr.s_addr = inet_addr(host).s_addr;	/* See arpa/inet.h */
 #else
+#ifdef GUSI
+	sin->sin_addr = inet_addr(host);		/* See netinet/in.h */
+#else
 	sin->sin_addr.s_addr = inet_addr(host);		/* See arpa/inet.h */
+#endif /* GUSI */
 #endif /* DGUX_OLD */
 	FREE(host);
 
     } else {		    /* Alphanumeric node name: */
 #ifdef MVS	/* Oustanding problem with crash in MVS gethostbyname */
-	if(TRACE)
+	if (TRACE)
 	    fprintf(stderr, "HTTCP: Calling gethostbyname(%s)\n", host);
-#endif
-	phost=gethostbyname(host);	/* See netdb.h */
+#endif /* MVS */
+
+#ifndef NSL_FORK
+	phost = gethostbyname(host);	/* See netdb.h */
 #ifdef MVS
-	if(TRACE)
+	if (TRACE)
 	    fprintf(stderr, "HTTCP: gethostbyname() returned %d\n", phost);
-#endif
+#endif /* MVS */
 	if (!phost) {
 	    if (TRACE)
 	        fprintf(stderr, 
@@ -418,6 +436,95 @@ PUBLIC int HTParseInet ARGS2(
 #else
 	memcpy((void *)&sin->sin_addr, phost->h_addr, phost->h_length);
 #endif /* VMS && CMU_TCP */
+
+#else /* NSL_FORK */
+	/*
+	 *  Start block for fork-based gethostbyname() with
+	 *  checks for interrupts. - Tom Zerucha (tz@execpc.com)
+	 */
+	{ 
+	    /*
+	     *  pipe, child pid, status buffers
+	     */
+	    int pfd[2], fpid, cstat, cst1;
+
+	    pipe(pfd);
+
+	    if ((fpid = fork()) == 0 ) {
+		/* 
+		 *  child - for the long call
+		 */
+		phost = gethostbyname(host);
+		cst1 = 0;
+		/*
+		 *  return value (or nulls)
+		 */
+		if (phost != NULL)
+		    write(pfd[1], phost->h_addr, phost->h_length);
+		else
+		    write(pfd[1], &cst1, 4);
+		/*
+		 *  return an error code
+		 */
+		_exit(phost == NULL);
+	    }
+
+	    /*
+	     *  (parent) wait until lookup finishes, or interrupt
+	     */
+	    cstat = 0;
+	    while (cstat <= 0) {
+	        /*
+		 *  exit when data sent
+		 */
+		IOCTL(pfd[0], FIONREAD, &cstat);
+		if (cstat > 0)
+		    break;
+		/*
+		 *  exit if child exited
+		 */
+		if (waitpid(fpid, &cst1, WNOHANG) > 0)
+		    break;
+		/*
+		 *  abort if interrupt key pressed
+		 */
+		if (HTCheckForInterrupt()) {
+		    if (TRACE)
+			fprintf (stderr, "*** INTERRUPTED gethostbyname.\n");
+		    kill(fpid , SIGKILL);
+		    FREE(host);
+		    return HT_INTERRUPTED;
+		}
+		/*
+		 *  be nice to the system
+		 */
+		sleep(1);
+	    }
+	    waitpid(fpid, &cst1, WNOHANG);
+	    /*
+	     *  read as much as we can - should be the address
+	     */
+	    IOCTL(pfd[0], FIONREAD, &cstat);
+	    if (cstat < 4)
+	        cstat = read(pfd[0], (void *)&sin->sin_addr , 4);
+	    else
+	        cstat = read(pfd[0], (void *)&sin->sin_addr , cstat);
+	    close(pfd[0]);
+	}
+
+	if (sin->sin_addr.s_addr == 0) {
+	    if (TRACE)
+	        fprintf(stderr, 
+		    "HTTPAccess: Can't find internet node name `%s'.\n",host);
+	      FREE(host);
+	      return -1;
+	}
+#ifdef MVS
+	if (TRACE)
+	    fprintf(stderr, "HTTCP: gethostbyname() returned %d\n", phost);
+#endif /* MVS */
+	FREE(host);
+#endif /* NSL_FORK */
     }
 
     if (TRACE)
@@ -457,10 +564,10 @@ PRIVATE void get_host_details NOARGS
     char name[MAXHOSTNAMELEN+1];	/* The name of this host */
 #ifdef UCX
     char *domain_name;			/* The name of this host domain */
-#endif
+#endif /* UCX */
 #ifdef NEED_HOST_ADDRESS		/* no -- needs name server! */
     struct hostent * phost;		/* Pointer to host -- See netdb.h */
-#endif
+#endif /* NEED_HOST_ADDRESS */
     int namelength = sizeof(name);
     
     if (hostname)
@@ -472,9 +579,9 @@ PRIVATE void get_host_details NOARGS
     /*  UCX doesn't give the complete domain name. get rest from UCX$BIND_DOM
     **  Logical
     */
-    if(strchr(hostname,'.') == NULL) {           /* Not full address */
+    if (strchr(hostname,'.') == NULL) {           /* Not full address */
         domain_name = getenv("UCX$BIND_DOMAIN");
-        if(domain_name != NULL) {
+        if (domain_name != NULL) {
             StrAllocCat(hostname, ".");
             StrAllocCat(hostname, domain_name);
         }
@@ -483,8 +590,8 @@ PRIVATE void get_host_details NOARGS
     CTRACE(tfp, "TCP: Local host name is %s\n", hostname);
 
 #ifndef DECNET  /* Decnet ain't got no damn name server 8#OO */
-#ifdef NEED_HOST_ADDRESS		 /* no -- needs name server! */
-    phost=gethostbyname(name);		 /* See netdb.h */
+#ifdef NEED_HOST_ADDRESS		/* no -- needs name server! */
+    phost = gethostbyname(name);	/* See netdb.h */
     if (!phost) {
 	if (TRACE) fprintf(stderr, 
 		"TCP: Can't find my own internet node address for `%s'!!\n",
@@ -517,320 +624,284 @@ PUBLIC int HTDoConnect ARGS4(
 	int,		default_port, 
 	int *,		s)
 {
-  struct sockaddr_in soc_address;
-  struct sockaddr_in *sin = &soc_address;
-  int status;
-  char *line = NULL;
-
-  /* Set up defaults: */
-  sin->sin_family = AF_INET;
-  sin->sin_port = htons(default_port);
-
-  /* Get node name and optional port number: */
-  {
-    char *p1 = HTParse(url, "", PARSE_HOST);
-    char *at_sign;
-    char *host = NULL;
+    struct sockaddr_in soc_address;
+    struct sockaddr_in *sin = &soc_address;
     int status;
+    char *line = NULL;
 
-    /* if there's an @ then use the stuff after it as a hostname */
-    if((at_sign = strchr(p1,'@')) != NULL)
-	StrAllocCopy(host, at_sign+1);
-    else
-	StrAllocCopy(host, p1);
-
-    line = (char *)malloc(strlen(host) + strlen(protocol) + 128);
-    if (line == NULL)
-        outofmem(__FILE__, "HTDoConnect");
-    sprintf (line, "Looking up %s.", host);
-    _HTProgress (line);
-
-    status = HTParseInet(sin, host);
-    if (status)
-      {
-        sprintf (line, "Unable to locate remote host %s.", host);
-        _HTProgress(line);
-        FREE(p1);
-	FREE(host);
-	FREE(line);
-        return HT_NO_DATA;
-      }
+    /* Set up defaults: */
+    sin->sin_family = AF_INET;
+    sin->sin_port = htons(default_port);
+
+    /* Get node name and optional port number: */
+    {
+        char *p1 = HTParse(url, "", PARSE_HOST);
+        char *at_sign;
+        char *host = NULL;
+        int status;
+
+        /* if there's an @ then use the stuff after it as a hostname */
+        if ((at_sign = strchr(p1,'@')) != NULL)
+	    StrAllocCopy(host, at_sign+1);
+        else
+	    StrAllocCopy(host, p1);
+
+        line = (char *)malloc(strlen(host) + strlen(protocol) + 128);
+        if (line == NULL)
+            outofmem(__FILE__, "HTDoConnect");
+        sprintf (line, "Looking up %s.", host);
+        _HTProgress (line);
+
+        status = HTParseInet(sin, host);
+        if (status) {
+            sprintf (line, "Unable to locate remote host %s.", host);
+            _HTProgress(line);
+            FREE(p1);
+	    FREE(host);
+	    FREE(line);
+            return HT_NO_DATA;
+        }
 
-    sprintf (line, "Making %s connection to %s.", protocol, host);
-    _HTProgress (line);
-    FREE(p1);
-    FREE(host);
-  }
+        sprintf (line, "Making %s connection to %s.", protocol, host);
+        _HTProgress (line);
+        FREE(p1);
+        FREE(host);
+    }
 
-  /* Now, let's get a socket set up from the server for the data: */
-  *s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    /*  Now, let's get a socket set up from the server for the data: */
+    *s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
-   if (*s == -1)
-     {
+    if (*s == -1) {
 	HTAlert("socket failed.");
 	FREE(line);
 	return HT_NO_DATA;
-     }
+    }
    
-  /*
-   * Make the socket non-blocking, so the connect can be canceled.
-   * This means that when we issue the connect we should NOT
-   * have to wait for the accept on the other end.
-   */
-#if !defined(NO_IOCTL)
-  {
-    int ret;
-    int val = 1;
- 
-    ret = IOCTL(*s, FIONBIO, &val);
-    if (ret == -1)
-      {
-        sprintf (line, "Could not make connection non-blocking.");
-        _HTProgress(line);
-      }
-  }
-#endif /* not NO_IOCTL */
-#if defined(USE_FCNTL)
-  {
-    int ret;
-
-    ret = fcntl(*s, F_SETFL, O_NONBLOCK);
-    if (ret == -1)
-      {
-        sprintf (line, "Could not make connection non-blocking.");
-        _HTProgress(line);
-      }
-  }
+#if !defined(NO_IOCTL) || defined(USE_FCNTL)
+    /*
+     *  Make the socket non-blocking, so the connect can be canceled.
+     *  This means that when we issue the connect we should NOT
+     *  have to wait for the accept on the other end.
+     */
+    {
+#ifdef USE_FCNTL
+        int ret = fcntl(*s, F_SETFL, O_NONBLOCK);
+#else
+        int val = 1;
+        int ret = IOCTL(*s, FIONBIO, &val);
 #endif /* USE_FCNTL */
+        if (ret == -1)
+            _HTProgress("Could not make connection non-blocking.");
+#endif /* !NO_IOCTL || USE_FCNTL */
+    }
 
-  /*
-   * Issue the connect.  Since the server can't do an instantaneous accept
-   * and we are non-blocking, this will almost certainly return a negative
-   * status.
-   */
+    /*
+     *  Issue the connect.  Since the server can't do an instantaneous
+     *  accept and we are non-blocking, this will almost certainly return
+     *  a negative status.
+     */
 #ifdef SOCKS
-  if (socks_flag) {
-      status = Rconnect(*s, (struct sockaddr*)&soc_address,
-      			sizeof(soc_address));
-      socks_bind_remoteAddr = soc_address.sin_addr.s_addr; /* for long Rbind */
-  }
-  else
+    if (socks_flag) {
+        status = Rconnect(*s, (struct sockaddr*)&soc_address,
+      			  sizeof(soc_address));
+	/*  For long Rbind. */
+        socks_bind_remoteAddr = soc_address.sin_addr.s_addr;
+    } else
 #endif /* SOCKS */
-  status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));
-
-  /*
-   * According to the Sun man page for connect:
-   *     EINPROGRESS         The socket is non-blocking and the  con-
-   *                         nection cannot be completed immediately.
-   *                         It is possible to select(2) for  comple-
-   *                         tion  by  selecting the socket for writ-
-   *                         ing.
-   * According to the Motorola SVR4 man page for connect:
-   *     EAGAIN              The socket is non-blocking and the  con-
-   *                         nection cannot be completed immediately.
-   *                         It is possible to select for  completion
-   *                         by  selecting  the  socket  for writing.
-   *                         However, this is only  possible  if  the
-   *                         socket  STREAMS  module  is  the topmost
-   *                         module on  the  protocol  stack  with  a
-   *                         write  service  procedure.  This will be
-   *                         the normal case.
-   */
-  if ((status < 0) &&
-      (SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EAGAIN))
-    {
-      struct timeval timeout;
-      int ret;
-      int tries=0;
-
-      ret = 0;
-      while (ret <= 0)
-        {
-          fd_set writefds;
-
-	  /*
-	   *  Protect against an infinite loop.
-	   */
-	  if (tries++ >= 180000) {
-	      HTAlert("Connection failed for 180,000 tries.");
-	      FREE(line);
- 	      return HT_NO_DATA;
-	  }
-
-	  timeout.tv_sec = 0;
-	  timeout.tv_usec = 100000;
-          FD_ZERO(&writefds);
-          FD_SET(*s, &writefds);
+    status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));
+    /*
+     *  According to the Sun man page for connect:
+     *     EINPROGRESS         The socket is non-blocking and the  con-
+     *                         nection cannot be completed immediately.
+     *                         It is possible to select(2) for  comple-
+     *                         tion  by  selecting the socket for writ-
+     *                         ing.
+     *  According to the Motorola SVR4 man page for connect:
+     *     EAGAIN              The socket is non-blocking and the  con-
+     *                         nection cannot be completed immediately.
+     *                         It is possible to select for  completion
+     *                         by  selecting  the  socket  for writing.
+     *                         However, this is only  possible  if  the
+     *                         socket  STREAMS  module  is  the topmost
+     *                         module on  the  protocol  stack  with  a
+     *                         write  service  procedure.  This will be
+     *                         the normal case.
+     */
+    if ((status < 0) &&
+        (SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EAGAIN)) {
+        struct timeval timeout;
+        int ret;
+        int tries=0;
+
+        ret = 0;
+        while (ret <= 0) {
+            fd_set writefds;
+
+	    /*
+	     *  Protect against an infinite loop.
+	     */
+	    if (tries++ >= 180000) {
+	        HTAlert("Connection failed for 180,000 tries.");
+	        FREE(line);
+ 	        return HT_NO_DATA;
+	    }
+
+	    timeout.tv_sec = 0;
+	    timeout.tv_usec = 100000;
+            FD_ZERO(&writefds);
+            FD_SET(*s, &writefds);
 #ifdef SOCKS
-	  if (socks_flag)
-              ret = Rselect(FD_SETSIZE, NULL,
-	      		    (void *)&writefds, NULL, &timeout);
-	  else
+	    if (socks_flag)
+                ret = Rselect(FD_SETSIZE, NULL,
+	      		      (void *)&writefds, NULL, &timeout);
+	    else
 #endif /* SOCKS */
-          ret = select(FD_SETSIZE, NULL, (void *)&writefds, NULL, &timeout);
-          /*
-           * Again according to the Sun and Motorola man pagse for connect:
-           *     EALREADY            The socket is non-blocking and a  previ-
-           *                         ous  connection attempt has not yet been
-           *                         completed.
-           * Thus if the SOCKET_ERRNO is NOT EALREADY we have a real error, and
-           * should break out here and return that error.
-           * Otherwise if it is EALREADY keep on trying to complete the
-           * connection.
-           */
-          if ((ret < 0) && (SOCKET_ERRNO != EALREADY))
-            {
-              status = ret;
-              break;
-            }
-          else if (ret > 0)
-            {
-              /*
-               * Extra check here for connection success, if we try to connect
-               * again, and get EISCONN, it means we have a successful
-               * connection.
-               */
+            ret = select(FD_SETSIZE, NULL, (void *)&writefds, NULL, &timeout);
+            /*
+             *  Again according to the Sun and Motorola man pagse for connect:
+             *     EALREADY            The socket is non-blocking and a  previ-
+             *                         ous  connection attempt has not yet been
+             *                         completed.
+             *  Thus if the SOCKET_ERRNO is NOT EALREADY we have a real error,
+             *  and should break out here and return that error.
+             *  Otherwise if it is EALREADY keep on trying to complete the
+             *  connection.
+             */
+            if ((ret < 0) && (SOCKET_ERRNO != EALREADY)) {
+                status = ret;
+                break;
+            } else if (ret > 0) {
+                /*
+                 *  Extra check here for connection success, if we try to
+                 *  connect again, and get EISCONN, it means we have a
+                 *  successful connection.  But don't check with SOCKS.
+                 */
 #ifdef SOCKS
-	      if (socks_flag)
-                  status = Rconnect(*s, (struct sockaddr*)&soc_address,
-                                    sizeof(soc_address));
-	      else
+	        if (socks_flag) {
+	            status = 0;
+	        } else {
 #endif /* SOCKS */
-              status = connect(*s, (struct sockaddr*)&soc_address,
-                               sizeof(soc_address));
-#ifndef UCX
-              if ((status < 0)&&(SOCKET_ERRNO == EISCONN))
+                status = connect(*s, (struct sockaddr*)&soc_address,
+                                 sizeof(soc_address));
+#ifdef UCX
+	        /*
+	         *  A UCX feature: Instead of returning EISCONN
+	         *		 UCX returns EADDRINUSE.
+	         *  Test for this status also.
+	         */
+                if ((status < 0) && ((SOCKET_ERRNO == EISCONN) ||
+				     (SOCKET_ERRNO == EADDRINUSE)))
 #else
-/*
- * A UCX feature: Instead of returning EISCONN UCX returns EADDRINUSE.
- * Test for this status also.
- */
-              if ((status < 0)&&((SOCKET_ERRNO == EISCONN) ||
-				 (SOCKET_ERRNO == EADDRINUSE)))
-#endif /* VMS, UCX, BSN */
+                if ((status < 0) && (SOCKET_ERRNO == EISCONN))
+#endif /* UCX */
                 {
-                  status = 0;
+                    status = 0;
                 }
 
-	      if (status && (SOCKET_ERRNO == EALREADY))  /* new stuff LJM */
-		  ret=0; /* keep going */
-	      else
-                  break;
-            }
-          /*
-           * The select says we aren't ready yet.  Try to connect again to
-	   * make sure.  If we don't get EALREADY or EISCONN, something has
-	   * gone wrong.  Break out and report it.
-	   *
-           * For some reason, SVR4 returns EAGAIN here instead of EALREADY,
-           * even though the man page says it should be EALREADY.
-	   *
-	   * For some reason, UCX pre 3 apparently returns errno = 18242
-	   * instead the EALREADY or EISCONN values.
-           */
-          else
-            {
+	        if (status && (SOCKET_ERRNO == EALREADY)) /* new stuff LJM */
+		    ret = 0; /* keep going */
+	        else
+                    break;
+#ifdef SOCKS
+	        }
+#endif /* SOCKS */
+            } 
 #ifdef SOCKS
-	      if (socks_flag)
-                  status = Rconnect(*s, (struct sockaddr*)&soc_address,
-                                    sizeof(soc_address));
-	      else
+	    else if (!socks_flag)
+#else
+            else
 #endif /* SOCKS */
-              status = connect(*s, (struct sockaddr*)&soc_address,
+            {
+		/*
+		 *  The select says we aren't ready yet.  Try to connect
+		 *  again to make sure.  If we don't get EALREADY or EISCONN,
+		 *  something has gone wrong.  Break out and report it.
+		 *
+		 *  For some reason, SVR4 returns EAGAIN here instead of
+		 *  EALREADY, even though the man page says it should be
+		 *  EALREADY.
+		 *
+		 *  For some reason, UCX pre 3 apparently returns
+		 *  errno = 18242 instead the EALREADY or EISCONN.
+		 */
+                status = connect(*s, (struct sockaddr*)&soc_address,
                                  sizeof(soc_address));
-              if ((status < 0) &&
-	          (SOCKET_ERRNO != EALREADY && SOCKET_ERRNO != EAGAIN) &&
+                if ((status < 0) &&
+	            (SOCKET_ERRNO != EALREADY && SOCKET_ERRNO != EAGAIN) &&
 #ifdef UCX
-		  (SOCKET_ERRNO != 18242) &&
+		    (SOCKET_ERRNO != 18242) &&
 #endif /* UCX */
-		  (SOCKET_ERRNO != EISCONN))
-                {
-                  break;
+		    (SOCKET_ERRNO != EISCONN)) {
+                    break;
                 }
             }
-          if(HTCheckForInterrupt())
-            {
-              if (TRACE)
-                fprintf (stderr, "*** INTERRUPTED in middle of connect.\n");
-              status = HT_INTERRUPTED;
-              SOCKET_ERRNO = EINTR;
-              break;
+            if (HTCheckForInterrupt()) {
+                if (TRACE)
+                    fprintf(stderr, "*** INTERRUPTED in middle of connect.\n");
+                status = HT_INTERRUPTED;
+                SOCKET_ERRNO = EINTR;
+                break;
             }
         }
     }
 
-  /*
-   * Make the socket blocking again on good connect
-   */
-  if (status >= 0)
-    {
-#if !defined(NO_IOCTL)
-      int ret;
-      int val = 0;
-
-      ret = IOCTL(*s, FIONBIO, &val);
-      if (ret == -1)
-        {
-          sprintf (line, "Could not restore socket to blocking.");
-          _HTProgress(line);
-        }
-#endif /* not NO_IOCTL */
-#if defined(USE_FCNTL)
-  {
-    int ret;
-
-    ret = fcntl(*s, F_SETFL, 0);
-    if (ret == -1)
-      {
-        sprintf (line, "Could not restore socket to blocking.");
-        _HTProgress(line);
-      }
-  }
-#endif /* USE_FCNTL */
-    }
-  /*
-   * Else the connect attempt failed or was interrupted.
-   * so close up the socket.
-   */
-  else
-    {
+    if (status < 0) {
+        /*
+         *  The connect attempt failed or was interrupted,
+         *  so close up the socket.
+         */
         NETCLOSE(*s);
     }
+#if !defined(NO_IOCTL) || defined(USE_FCNTL)
+    else {
+        /*
+	 *  Make the socket blocking again on good connect.
+	 */
+#ifdef USE_FCNTL
+        int ret = fcntl(*s, F_SETFL, 0);
+#else 
+        int val = 0;
+        int ret = IOCTL(*s, FIONBIO, &val);
+#endif /* USE_FCNTL */
+        if (ret == -1)
+            _HTProgress("Could not restore socket to blocking.");
+    }
+#endif /* !NO_IOCTL || USE_FCNTL */
 
-  FREE(line);
-  return status;
+    FREE(line);
+    return status;
 }
 
-/* This is so interruptible reads can be implemented cleanly. */
+/*
+**  This is so interruptible reads can be implemented cleanly.
+*/
 PUBLIC int HTDoRead ARGS3(
 	int,		fildes,
 	void *,		buf,
 	unsigned,	nbyte)
 {
-  int ready, ret;
-  fd_set readfds;
-  struct timeval timeout;
-  int tries=0;
+    int ready, ret;
+    fd_set readfds;
+    struct timeval timeout;
+    int tries=0;
 #ifdef UCX
-  int nb;
+    int nb;
 #endif /* UCX, BSN */
 
-  if (fildes <= 0)
-      return -1;
+    if (fildes <= 0)
+        return -1;
 
-  if (HTCheckForInterrupt())
-    {
+    if (HTCheckForInterrupt()) {
         SOCKET_ERRNO = EINTR;
         return (HT_INTERRUPTED);
     }
 
 #if !defined(NO_IOCTL)
-  ready = 0;
+    ready = 0;
 #else
-  ready = 1;
+    ready = 1;
 #endif /* bypass for NO_IOCTL */
-  while (!ready)
-    {
+    while (!ready) {
 	/*
 	 *  Protect against an infinite loop.
 	 */
@@ -850,37 +921,36 @@ PUBLIC int HTDoRead ARGS3(
 	else
 #endif /* SOCKS */
         ret = select(FD_SETSIZE, (void *)&readfds, NULL, NULL, &timeout);
-        if (ret < 0)
-          {
-                return -1;
-          }
-        else if (ret > 0)
-          {
-                ready = 1;
-          }
-        else if(HTCheckForInterrupt())
-          {
-       	        SOCKET_ERRNO = EINTR;
-                return HT_INTERRUPTED;
-          }
+        if (ret < 0) {
+            return -1;
+        } else if (ret > 0) {
+            ready = 1;
+        } else if (HTCheckForInterrupt()) {
+       	    SOCKET_ERRNO = EINTR;
+            return HT_INTERRUPTED;
+        }
     }
 
 #if !defined(UCX) || !defined(VAXC)
-  return SOCKET_READ (fildes, buf, nbyte);
-#else                           /* VAXC and UCX problem only */
-  errno = vaxc$errno = 0;
-  nb = SOCKET_READ (fildes, buf, nbyte);
-  CTRACE(tfp, "Read - nb,errno,vaxc$errno: %d %d %d\n", nb,errno,vaxc$errno);
-  if ((nb <= 0) && TRACE)
-     perror ("HTTCP.C:HTDoRead:read");          /* RJF */
-  /*
-   * An errno value of EPIPE and nb < 0 indicates end-of-file on VAXC
-   */
-  if ((nb <= 0) && (errno == EPIPE)) {
-       nb = 0;
-       errno = 0;
-  }
-  return nb;
+    return SOCKET_READ (fildes, buf, nbyte);
+#else
+    /*
+     *  VAXC and UCX problem only.
+     */
+    errno = vaxc$errno = 0;
+    nb = SOCKET_READ (fildes, buf, nbyte);
+    CTRACE(tfp,
+    	   "Read - nb,errno,vaxc$errno: %d %d %d\n", nb,errno,vaxc$errno);
+    if ((nb <= 0) && TRACE)
+        perror ("HTTCP.C:HTDoRead:read");          /* RJF */
+    /*
+     *  An errno value of EPIPE and nb < 0 indicates end-of-file on VAXC.
+     */
+    if ((nb <= 0) && (errno == EPIPE)) {
+        nb = 0;
+        errno = 0;
+    }
+    return nb;
 #endif /* UCX, BSN */
 }
 
@@ -914,42 +984,50 @@ PUBLIC int HTDoRead ARGS3(
 #include <sys/time.h>
 #include <sys/select.h>
 
-
-PUBLIC int BSDselect ARGS5 (int,nfds, fd_set *,readfds,fd_set *,writefds,
-	 		    fd_set *,exceptfds, struct timeval *,timeout)
+PUBLIC int BSDselect ARGS5(
+	int,			nfds,
+	fd_set *,		readfds,
+	fd_set *,		writefds,
+	fd_set *,		exceptfds,
+	struct timeval *,	timeout)
 {
-	int		rval,
-			i;
+    int rval,
+    i;
 
 #ifdef SOCKS
-	if (socks_flag)
-	    rval = Rselect(nfds, readfds, writefds, exceptfds, timeout);
-	else
+    if (socks_flag)
+	rval = Rselect(nfds, readfds, writefds, exceptfds, timeout);
+    else
 #endif /* SOCKS */
-	rval = select(nfds, readfds, writefds, exceptfds, timeout);
-
-	switch(rval) {
-		case -1:	return(rval);
-					break;
-
-		case 0:		if(readfds != NULL)
-						FD_ZERO(readfds);
-					if(writefds != NULL)
-						FD_ZERO(writefds);
-					if(exceptfds != NULL)
-						FD_ZERO(exceptfds);
-
-					return(rval);
-					break;
-
-		default:	for(i=0, rval=0; i < nfds; i++) {
-		if((readfds != NULL) && FD_ISSET(i, readfds)) rval++;
-		if((writefds != NULL) && FD_ISSET(i, writefds)) rval++;
-		if((exceptfds != NULL) && FD_ISSET(i, exceptfds)) rval++;
-
-					}
-					return(rval);
-		}
+    rval = select(nfds, readfds, writefds, exceptfds, timeout);
+
+    switch (rval) {
+	case -1:
+	    return(rval);
+	    break;
+
+	case 0:
+	    if (readfds != NULL)
+		FD_ZERO(readfds);
+	    if (writefds != NULL)
+		FD_ZERO(writefds);
+	    if (exceptfds != NULL)
+		FD_ZERO(exceptfds);
+	    return(rval);
+	    break;
+
+	default:
+	    for (i = 0, rval = 0; i < nfds; i++) {
+		if ((readfds != NULL) && FD_ISSET(i, readfds))
+		    rval++;
+		if ((writefds != NULL) && FD_ISSET(i, writefds))
+		    rval++;
+		if ((exceptfds != NULL) && FD_ISSET(i, exceptfds))
+		    rval++;
+
+	    }
+	    return(rval);
+    }
 /* Should never get here */
 }
 #endif /* SVR4_BSDSELECT */
diff --git a/WWW/Library/Implementation/HTTP.c b/WWW/Library/Implementation/HTTP.c
index 10a484f6..ed77809e 100644
--- a/WWW/Library/Implementation/HTTP.c
+++ b/WWW/Library/Implementation/HTTP.c
@@ -16,9 +16,6 @@
 #define HTTPS_PORT  443
 #define SNEWS_PORT  563
 
-#define HTTP_NETREAD   NETREAD
-#define HTTP_NETWRITE  NETWRITE
-
 #define INIT_LINE_SIZE		1024	/* Start with line buffer this big */
 #define LINE_EXTEND_THRESH	256	/* Minimum read size */
 #define VERSION_LENGTH 		20	/* for returned protocol version */
@@ -68,6 +65,10 @@ extern BOOL dump_output_immediately;  /* TRUE if no interactive user */
 extern char * HTLoadedDocumentURL NOPARAMS;
 extern int HTCheckForInterrupt NOPARAMS;
 
+#define HTTP_NETREAD(a, b, c, d)   NETREAD(a, b, c)
+#define HTTP_NETWRITE(a, b, c, d)  NETWRITE(a, b, c)
+#define HTTP_NETCLOSE(a, b)  (void)NETCLOSE(a)
+
 
 /*		Load Document from HTTP Server			HTLoadHTTP()
 **		==============================
@@ -119,6 +120,8 @@ PUBLIC int HTLoadHTTP ARGS4 (
   int already_retrying = 0;
   int len = 0;
 
+  void * handle = NULL;
+
   if (anAnchor->isHEAD)
       do_head = TRUE;
   else if (anAnchor->post_data)
@@ -405,15 +408,16 @@ PUBLIC int HTLoadHTTP ARGS4 (
     {
       if (TRACE)
           fprintf (stderr, "HTTP: Doing post, content-type '%s'\n",
-                   anAnchor->post_content_type);
+                   anAnchor->post_content_type ? anAnchor->post_content_type
+		   			       : "lose");
       sprintf (line, "Content-type: %s%c%c",
                anAnchor->post_content_type ? anAnchor->post_content_type 
-							: "lose", CR, LF);
+					   : "lose", CR, LF);
       StrAllocCat(command, line);
       {
         int content_length;
         if (!anAnchor->post_data)
-          content_length = 4; /* 4 == "lose" :-) */
+          content_length = 0;
         else
           content_length = strlen (anAnchor->post_data);
         sprintf (line, "Content-length: %d%c%c",
@@ -421,12 +425,12 @@ PUBLIC int HTLoadHTTP ARGS4 (
         StrAllocCat(command, line);
       }
 
-      StrAllocCat(command, crlf);	/* Blank line means "end" */
+      StrAllocCat(command, crlf);	/* Blank line means "end" of headers */
 
       StrAllocCat(command, anAnchor->post_data);
     }
-
-  StrAllocCat(command, crlf);	/* Blank line means "end" */
+  else
+      StrAllocCat(command, crlf);	/* Blank line means "end" of headers */
 
   if (TRACE)
       fprintf (stderr, "Writing:\n%s----------------------------------\n",
@@ -434,7 +438,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
 
   _HTProgress ("Sending HTTP request.");
 
-  status = HTTP_NETWRITE(s, command, (int)strlen(command));
+  status = HTTP_NETWRITE(s, command, (int)strlen(command), handle);
   FREE(command);
   if (status <= 0) 
     {
@@ -455,7 +459,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
                 fprintf (stderr, 
                  "HTTP: BONZO ON WRITE Trying again with HTTP0 request.\n");
             _HTProgress ("Retrying as HTTP0 request.");
-            (void)NETCLOSE(s);
+            HTTP_NETCLOSE(s, handle);
             extensions = NO;
             already_retrying = 1;
             goto try_again;
@@ -465,7 +469,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
           if (TRACE)
               fprintf (stderr,
 	   "HTTP: Hit unexpected network WRITE error; aborting connection.\n");
-          (void)NETCLOSE(s);
+          HTTP_NETCLOSE(s, handle);
           status = -1;
           HTAlert("Unexpected network write error; connection aborted.");
           goto done;
@@ -500,7 +504,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
             fprintf (stderr, "HTTP: Trying to read %d\n",
                      buffer_length - length - 1);
         status = HTTP_NETREAD(s, line_buffer + length,
-                              buffer_length - length - 1);
+                              buffer_length - length - 1, handle);
         if (TRACE)
             fprintf (stderr, "HTTP: Read %d\n", status);
         if (status <= 0)
@@ -524,7 +528,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
                 if (TRACE)
                     fprintf (stderr,
 		    	"HTTP: BONZO Trying again with HTTP0 request.\n");
-                (void)NETCLOSE(s);
+                HTTP_NETCLOSE(s, handle);
                 FREE(line_buffer);
                 FREE(line_kept_clean);
 
@@ -540,7 +544,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
   "HTTP: Hit unexpected network read error; aborting connection; status %d.\n",
 			   status);
                 HTAlert("Unexpected network read error; connection aborted.");
-                (void)NETCLOSE(s);
+                HTTP_NETCLOSE(s, handle);
                 status = -1;
                 goto clean_up;
               }
@@ -609,7 +613,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
       already_retrying = 1;
       if (TRACE)
           fprintf(stderr, "HTTP: close socket %d to retry with HTTP0\n", s);
-      (void)NETCLOSE(s);
+      HTTP_NETCLOSE(s, handle);
       /* print a progress message */
       _HTProgress ("Retrying as HTTP0 request.");
       goto try_again;
@@ -755,7 +759,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
 		 *  document. - FM
 		 */
 	        HTAlert(line_buffer);
-                (void)NETCLOSE(s);
+                HTTP_NETCLOSE(s, handle);
 	        status = HT_NO_DATA;
 	        goto done;
 		break;
@@ -873,7 +877,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
 		   *  Don't redirect POST content without approval
 		   *  from an interactive user. - FM
 		   */
-		  (void)NETCLOSE(s);
+		  HTTP_NETCLOSE(s, handle);
 		  status = -1;
 		  HTAlert(
 		       "Redirection of POST content requires user approval.");
@@ -887,11 +891,12 @@ PUBLIC int HTLoadHTTP ARGS4 (
 	       *  any, and then close the connection. - FM
 	       */
 	      while ((status = HTTP_NETREAD(s, line_buffer,
-	      				    INIT_LINE_SIZE)) > 0) {
+	      				    INIT_LINE_SIZE,
+					    handle)) > 0) {
 	          line_buffer[status] = '\0';
 		  StrAllocCat(line_kept_clean, line_buffer);
 	      }
-	      (void)NETCLOSE(s);
+	      HTTP_NETCLOSE(s, handle);
               if (status == HT_INTERRUPTED) {
 		  /*
 		   *  Impatient user. - FM
@@ -1014,22 +1019,37 @@ PUBLIC int HTLoadHTTP ARGS4 (
 			}
 			/*
 			 *  Make sure the user wants to redirect
-			 *  the POST content. - FM
+			 *  the POST content, or treat as GET - FM & DK
 			 */
-			if (!HTConfirm(
-				"Redirection for POST content. Proceed?")) {
-			    doing_redirect = 0;
-			    FREE(redirecting_url);
-			    status = HT_NO_DATA;
-			    goto clean_up;
-			}
-			/*
-			 *  Set the flag to retain the POST content
-			 *  and go back to check out the URL. - FM
-			 */
-			redirect_post_content = TRUE;
-		        status = HT_REDIRECTING;
-		        goto clean_up;
+			switch (HTConfirmPostRedirect(redirecting_url)) {
+			    /*
+			     *  User failed to confirm.
+			     *  Abort the fetch.
+			     */
+			    case 0:
+			        doing_redirect = 0;
+				FREE(redirecting_url);
+				status = HT_NO_DATA;
+				goto clean_up;
+				      
+			    /*
+			     *  User wants to treat as GET with no content.
+			     *  Go back to check out the URL.
+			     */
+			    case 303:
+				status = HT_REDIRECTING;
+				goto clean_up;
+
+			    /*
+			     *  Set the flag to retain the POST
+			     *  content and go back to check out
+			     *  the URL. - FM
+			     */
+			    default:
+				status = HT_REDIRECTING;
+				redirect_post_content = TRUE;
+				goto clean_up;
+  			}
 		    }
 	            break;
 	        } else {
@@ -1070,11 +1090,12 @@ PUBLIC int HTLoadHTTP ARGS4 (
 		 *  Otherwise, issue a statusline message and
 		 *  restore the current document.  - FM
 		 */
-		if (HTAA_shouldRetryWithAuth(start_of_data, length, NULL, s)) 
+		if (HTAA_shouldRetryWithAuth(start_of_data, length,
+					     (void *)handle, s))
                   {
  		    extern char *authentication_info[2];
 
-                    (void)NETCLOSE(s);
+                    HTTP_NETCLOSE(s, handle);
                     if (dump_output_immediately && !authentication_info[0]) {
                         fprintf(stderr,
 		      		"HTTP: Access authorization required.\n");
@@ -1100,7 +1121,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
 		  {
 		    HTAlert(
 	"Can't retry with authorization!  Contact the server's WebMaster.");
-		    (void)NETCLOSE(s);
+		    HTTP_NETCLOSE(s, handle);
                     status = -1;
                     goto clean_up;
 		  }
@@ -1115,7 +1136,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
 		 */
 	        HTAlert(
 		 "Proxy Authentication Required.  Sorry, not yet supported.");
-                (void)NETCLOSE(s);
+                HTTP_NETCLOSE(s, handle);
 	        status = HT_NO_DATA;
 	        goto done;
 		break;
@@ -1126,7 +1147,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
 		 *  and restore the current document. - FM
 		 */
 	        HTAlert(line_buffer);
-                (void)NETCLOSE(s);
+                HTTP_NETCLOSE(s, handle);
 	        status = HT_NO_DATA;
 	        goto done;
 		break;
@@ -1154,7 +1175,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
 		 */
 		HTAlert(line_buffer);
 		if (traversal) {
-		    (void)NETCLOSE(s);
+		    HTTP_NETCLOSE(s, handle);
 		    status = -1;
 		    goto clean_up;
 		}
@@ -1187,7 +1208,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
             HTAlert("Unknown status reply from server!");
 	    HTAlert(line_buffer);
 	    if (traversal) {
-		(void)NETCLOSE(s);
+		HTTP_NETCLOSE(s, handle);
 		status = -1;
 		goto clean_up;
 	    }
@@ -1213,7 +1234,7 @@ PUBLIC int HTLoadHTTP ARGS4 (
     {
       char buffer[1024];	/* @@@@@@@@ */
 
-      (void)NETCLOSE(s);
+      HTTP_NETCLOSE(s, handle);
       sprintf(buffer, "Sorry, no known way of converting %s to %s.",
               HTAtom_name(format_in), HTAtom_name(format_out));
       _HTProgress (buffer);
@@ -1225,61 +1246,69 @@ PUBLIC int HTLoadHTTP ARGS4 (
   (*target->isa->put_block)(target, start_of_data, length);
 
   /* Go pull the bulk of the data down. */
-  rv = HTCopy(s, NULL, target);
+  rv = HTCopy(s, (void *)handle, target);
 
-  if (rv == -1)
-    {
-      /* Intentional interrupt before data were received, not an error */
+  if (rv == -1) {
+      /*
+       *  Intentional interrupt before data were received, not an error
+       */
       /* (*target->isa->_abort)(target, NULL); */ /* already done in HTCopy */
       status = HT_INTERRUPTED;
-      (void)NETCLOSE(s);
+      HTTP_NETCLOSE(s, handle);
       goto clean_up;
-    }
-  if (rv == -2 && !already_retrying && !do_post)
-    { 
-      /* Aw hell, a REAL error, maybe cuz it's a dumb HTTP0 server */
-      if (TRACE)
-          fprintf (stderr, "HTTP: Trying again with HTTP0 request.\n");
-      /* May as well consider it an interrupt -- right? */
+  }
+
+  if (rv == -2) { 
+      /*
+       *  Aw hell, a REAL error, maybe cuz it's a dumb HTTP0 server
+       */
       (*target->isa->_abort)(target, NULL);
-      (void)NETCLOSE(s);
-      FREE(line_buffer);
-      FREE(line_kept_clean);
-      extensions = NO;
-      already_retrying = 1;
-      _HTProgress ("Retrying as HTTP0 request.");
-      goto try_again;
-    }
+      HTTP_NETCLOSE(s, handle);
+      if (!already_retrying && !do_post) {
+          if (TRACE)
+              fprintf (stderr, "HTTP: Trying again with HTTP0 request.\n");
+          /*
+           *  May as well consider it an interrupt -- right?
+           */
+          FREE(line_buffer);
+          FREE(line_kept_clean);
+          extensions = NO;
+          already_retrying = 1;
+          _HTProgress ("Retrying as HTTP0 request.");
+          goto try_again;
+      } else {
+          status = HT_NO_DATA;
+	  goto clean_up;
+      }
+  }
 
   /* 
-   * Close socket if partial transmission (was freed on abort)
-   * Free if complete transmission (socket was closed before return)
+   *  Free if complete transmission (socket was closed before return).
+   *  Close socket if partial transmission (was freed on abort).
    */
-  if (rv == HT_INTERRUPTED)
-    {
-      (void)NETCLOSE(s);
-    }
-  else
+  if (rv != HT_INTERRUPTED) {
       (*target->isa->_free)(target);
+  } else {
+      HTTP_NETCLOSE(s, handle);
+  }
 
-  if (doing_redirect)
-    /*
-     * We already jumped over all this if the "case 3:" code worked
-     * above, but we'll check here as a backup in case it fails. - FM
-     */
-    {
+  if (doing_redirect) {
+      /*
+       *  We already jumped over all this if the "case 3:" code worked
+       *  above, but we'll check here as a backup in case it fails. - FM
+       */
       /* Lou's old comment:  - FM */
       /* OK, now we've got the redirection URL temporarily stored
          in external variable redirecting_url, exported from HTMIME.c,
          since there's no straightforward way to do this in the library
          currently.  Do the right thing. */
       status = HT_REDIRECTING;
-    }
-  else
-    {
-      /* If any data were received, treat as a complete transmission */
+  } else {
+      /*
+       *  If any data were received, treat as a complete transmission
+       */
       status = HT_LOADED;
-    }
+  }
 
   /*	Clean up
    */
diff --git a/WWW/Library/Implementation/SGML.c b/WWW/Library/Implementation/SGML.c
index 9cddd35a..32ba06b8 100644
--- a/WWW/Library/Implementation/SGML.c
+++ b/WWW/Library/Implementation/SGML.c
@@ -468,33 +468,48 @@ PUBLIC HTTag * SGMLFindTag ARGS2(
 
 
 /*	Could check that we are back to bottom of stack! @@  */
-
+/* 	Do check! - FM					     */
+/*							     */
 PUBLIC void SGML_free  ARGS1(
 	HTStream *,	context)
 {
     int i;
     HTElement * cur;
     HTElement * next;
+    HTTag * t;
 
-    (*context->actions->_free)(context->target);
-    HTChunkFree(context->string);
-
-    /* free strings */
-    for (i = 0; i < MAX_ATTRIBUTES; i++) 
-	FREE(context->value[i]);
-
+    /*
+    **  Free the buffers. - FM
+    */
     FREE(context->recover);
-    FREE(context->include);
     FREE(context->url);
     FREE(context->csi);
+    FREE(context->include);
 
-    cur = context->element_stack;
-    while (cur) {
-        next = cur->next;
+    /*
+    **  Wind down stack if any elements are open. - FM
+    */
+    while (context->element_stack) {
+        cur = context->element_stack;
+	t = cur->tag;
+	context->element_stack = cur->next;	/* Remove from stack */
 	FREE(cur);
-	cur = next;
+	(*context->actions->end_element)(context->target,
+		 t - context->dtd->tags, (char **)&context->include);
+	FREE(context->include);
     }
 
+    /*
+    **  Finish off the target. - FM
+    */
+    (*context->actions->_free)(context->target);
+
+    /*
+    **  Free the strings and context structure. - FM
+    */
+    HTChunkFree(context->string);
+    for (i = 0; i < MAX_ATTRIBUTES; i++) 
+	FREE(context->value[i]);
     FREE(context);
 }
 
@@ -504,18 +519,25 @@ PUBLIC void SGML_abort ARGS2(
 {
     int i;
 
+    /*
+    **  Abort the target. - FM
+    */
     (*context->actions->_abort)(context->target, e);
-    HTChunkFree(context->string);
-
-    /* free strings */
-    for (i = 0; i < MAX_ATTRIBUTES; i++) 
-	FREE(context->value[i]);
 
+    /*
+    **  Free the buffers. - FM
+    */
     FREE(context->recover);
     FREE(context->include);
     FREE(context->url);
     FREE(context->csi);
 
+    /*
+    **  Free the strings and context structure. - FM
+    */
+    HTChunkFree(context->string);
+    for (i = 0; i < MAX_ATTRIBUTES; i++) 
+	FREE(context->value[i]);
     FREE(context);
 }
 
diff --git a/WWW/Library/Implementation/tcp.h b/WWW/Library/Implementation/tcp.h
index 2e5ada8d..b67a1510 100644
--- a/WWW/Library/Implementation/tcp.h
+++ b/WWW/Library/Implementation/tcp.h
@@ -76,6 +76,11 @@ typedef struct sockaddr_in SockA;  /* See netinet/in.h */
 #define USE_DIRENT              /* sys V style directory open */
 #endif /* _IBMR2 */
 
+#ifdef _SYSV3
+#include <fcntl.h>
+#include <dirent.h>
+#endif /* _SYSV3 */
+
 /* Solaris. */
 #if defined(sun) && defined(__svr4__) && !defined(USE_DIRENT)
 #define USE_DIRENT              /* sys V style directory open */
@@ -169,6 +174,15 @@ VAX/VMS
 #undef NETWRITE
 #undef IOCTL
 #undef SOCKET_ERRNO
+/*
+**  Remove these socket_foo() prototypes if
+**  MultiNet someday actually does this. - FM
+*/
+extern int socket_read();
+extern int socket_write();
+extern int socket_close();
+extern int socket_ioctl();
+
 #define SOCKET_READ(s,b,l)  ((s)>10 ? socket_read((s),(b),(l)) : \
 				read((s),(b),(l)))
 #define NETWRITE(s,b,l) ((s)>10 ? socket_write((s),(b),(l)) : \
@@ -209,6 +223,23 @@ VAX/VMS
 #define INCLUDES_DONE
 
 #ifdef MULTINET  /* Include from standard Multinet directories */
+/*
+**  Remove these multinet_foo() and associated prototypes
+**  if MultiNet someday actually does this. - FM
+*/
+extern int multinet_accept();
+extern int multinet_bind();
+extern int bzero();
+extern int multinet_connect();
+extern int multinet_gethostname();
+extern int multinet_getsockname();
+extern unsigned short multinet_htons();
+extern unsigned short multinet_ntohs();
+extern int multinet_listen();
+extern int multinet_select();
+extern int multinet_socket();
+extern char *vms_errno_string();
+
 #ifndef __SOCKET_TYPEDEFS
 #define __SOCKET_TYPEDEFS 1
 #endif /* !__SOCKET_TYPEDEFS */
@@ -238,6 +269,17 @@ VAX/VMS
 #include "multinet_root:[multinet.include.arpa]inet.h"
 #include "multinet_root:[multinet.include]netdb.h"
 #include "multinet_root:[multinet.include.sys]ioctl.h"
+/*
+**  Uncomment this if you get compiler messages
+**  about struct timeval having no linkage. - FM
+*/
+/*#define NO_TIMEVAL*/
+#ifdef NO_TIMEVAL
+struct timeval {
+    long tv_sec;		/* seconds since Jan. 1, 1970 */
+    long tv_usec;		/* microseconds */
+};
+#endif /* NO_TIMEVAL */
 #endif /* MULTINET */
 
 
diff --git a/WWW/Library/umaxv-m88k/Makefile b/WWW/Library/umaxv-m88k/Makefile
new file mode 100644
index 00000000..79c323c0
--- /dev/null
+++ b/WWW/Library/umaxv-m88k/Makefile
@@ -0,0 +1,30 @@
+#  Make WWW under unix for a.n.other unix system (bsd)
+#   Use this as a template
+
+# For W3 distribution, machine type for subdirectories
+WWW_MACH = umaxv-m88k
+
+# The ASIS repository's name for the machine we are on
+ASIS_MACH = hardware/os
+
+
+CFLAGS =  -O -DDEBUG -D_SYSV3
+LFLAGS =
+CC = cc
+
+# Directory for installed binary:
+BINDIR = /usr/local/bin
+
+# Where is the W3 object library to be installed (not normally done)?
+LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH)
+
+#_________________ OK if normal W3 distribution
+# Where is the WWW source root?
+WWW = ../..
+
+#  Where should temporary (object) files go?
+WTMP = ../..
+
+
+include $(WWW)/Library/Implementation/CommonMakefile
+
diff --git a/about_lynx/about_lynx-dev.html b/about_lynx/about_lynx-dev.html
index 1eddf968..2261a76d 100644
--- a/about_lynx/about_lynx-dev.html
+++ b/about_lynx/about_lynx-dev.html
@@ -7,8 +7,9 @@
 
 <body>
 <banner>
-[ <a href="http://lynx.cc.ukans.edu/lynx-dev/index.html">Lynx-Dev Archives</a>
-| <a href="about_lynx.html">About Lynx</a> ]
+[ <a href="http://www.flora.org/lynx-dev/html/">FLORA Archives</a> |
+<a href="http://lynx.cc.ukans.edu/lynx-dev/index.html">UKans Archives</a> |
+<a href="about_lynx.html">About Lynx</a> ]
 </banner>
 
 <h1><em>Lynx-Dev Discussion List</em></h1>
@@ -64,7 +65,8 @@ up their mailboxes.
 Archives of messages posted to lynx-dev are now in html format so that
 you can view them using Lynx.
 
-<p>Go to <a href="http://lynx.cc.ukans.edu/lynx-dev/index.html"
->Lynx-Dev Archives</a>.
+<p>Go to the <a href="http://www.flora.org/lynx-dev/html/">FLORA</a> or
+<a href="http://lynx.cc.ukans.edu/lynx-dev/index.html">UKans</a>
+Lynx-Dev Archives.
 </body>
 </html>
diff --git a/about_lynx/about_lynx.html b/about_lynx/about_lynx.html
index 61f4ae4b..f60324d2 100644
--- a/about_lynx/about_lynx.html
+++ b/about_lynx/about_lynx.html
@@ -7,8 +7,9 @@
 
 <BODY>
 <BANNER>
-[ <A HREF="about_lynx-dev.html">About Lynx-Dev</A>
-| <A HREF="http://lynx.cc.ukans.edu/lynx-dev/index.html">Lynx-Dev Archives</A> ]
+[ <A HREF="about_lynx-dev.html">About Lynx-Dev</A> |
+<A HREF="http://www.flora.org/lynx-dev/html/">FLORA Archives</A> |
+<A HREF="http://lynx.cc.ukans.edu/lynx-dev/index.html">UKans Archives</A> ]
 </BANNER>
 
 <h1><em>About Lynx</em></h1>
@@ -82,17 +83,17 @@ had their own hypertext format.
 <H2><A NAME="availability"><EM>Availability</EM></A></H2>
 
 <p>Information on obtaining the most current version of Lynx is
-available via the
-<a href="http://www.nyu.edu/pages/wsn/subir/lynx.html"
->Lynx Enhanced Pages</a>.
+available via <a href="http://www.crl.com/~subir/lynx.html"
+>Lynx links</a>.
 
 <H2><A NAME="lynx-dev_list"><EM>Mailing List</EM></A></H2>
 
 We have a listserv mailing list running for lynx development discussion.
-If you are interested in joining the list, follow this
-<A HREF="about_lynx-dev.html">link</A>.  There is also a link to
-<A HREF="http://lynx.cc.ukans.edu/lynx-dev/index.html"
->archives</A> in html format for this mailing list.
+If you are interested in joining the list, follow this <A
+HREF="about_lynx-dev.html">link</A>.  There also are links to archives
+at <A HREF="http://www.flora.org/lynx-dev/html/">FLORA</A> and <A
+HREF="http://lynx.cc.ukans.edu/lynx-dev/index.html">UKans</A> in html
+format for this mailing list.
 
 </BODY>
 </HTML>
diff --git a/docs/README.html b/docs/README.html
index 722ecafc..4058c422 100644
--- a/docs/README.html
+++ b/docs/README.html
@@ -10,9 +10,9 @@
 
 The Lynx help files are included with the distribution of
 Lynx sources and documentation.  Links to sites which supply
-the distribution are maintained in the
-<a href="http://www.nyu.edu/pages/wsn/subir/lynx.html"
->Lynx Enhanced Pages</a>.
+the distribution are maintained in
+<a href="http://www.crl.com/~subir/lynx.html"
+>Lynx links</a>.
 
 <p>Once you have downloaded and extracted the distribution,
 set HELPFILE in the lynx.cfg as: 
diff --git a/docs/README.txt b/docs/README.txt
index 92dc4578..c04cac6f 100644
--- a/docs/README.txt
+++ b/docs/README.txt
@@ -3,7 +3,7 @@
                                        
    The Lynx help files are included with the distribution of Lynx sources
    and documentation. Links to sites which supply the distribution are
-   maintained in the [1]Lynx Enhanced Pages.
+   maintained in [1]Lynx links.
    
    Once you have downloaded and extracted the distribution, set HELPFILE
    in the lynx.cfg as:
@@ -14,4 +14,4 @@
 
 References
 
-   1. http://www.nyu.edu/pages/wsn/subir/lynx.html
+   1. http://www.crl.com/~subir/lynx.html
diff --git a/lynx.cfg b/lynx.cfg
index 18598d37..4d348b62 100644
--- a/lynx.cfg
+++ b/lynx.cfg
@@ -22,7 +22,7 @@
 #  replace PATH_TO with the complete path to FILENAME
 #  use Unix SHELL syntax and include the device on VMS systems)
 #
-STARTFILE:http://www.nyu.edu/pages/wsn/subir/lynx.html
+STARTFILE:http://lynx.browser.org/
 
 # HELPFILE must be defined as a URL and must have a
 # complete path if local:
@@ -31,10 +31,10 @@ STARTFILE:http://www.nyu.edu/pages/wsn/subir/lynx.html
 #   for this distribution (use SHELL syntax including the device
 #   on VMS systems).
 # The default HELPFILE is:
-# http://www.nyu.edu/pages/wsn/subir/lynx.html
+# http://www.crl.com/~subir/lynx/lynx_help/lynx_help_main.html
 #   This should be changed to the local path.
 #
-HELPFILE:http://www.nyu.edu/pages/wsn/subir/lynx.html
+HELPFILE:http://www.crl.com/~subir/lynx/lynx_help/lynx_help_main.html
 #HELPFILE:file://localhost/PATH_TO/lynx_help/lynx_help_main.html
 
 # DEFAULT_INDEX_FILE is the default file retrieved when the
@@ -489,6 +489,17 @@ CHECKMAIL:FALSE
 #NEWS_CHUNK_SIZE:30
 #NEWS_MAX_CHUNK:40
 
+# If USE_SELECT_POPUPS is set FALSE, Lynx will present a vertical list of
+# radio buttons for the OPTIONs in SELECT blocks which lack the MULTIPLE
+# attribute, instead of using a popup menu.  Note that if the MULTIPLE
+# attribute is present in the SELECT start tag, Lynx always will create a
+# vertical list of checkboxes for the OPTIONs.
+# The default defined here or in userdefs.h can be changed via the 'o'ptions
+# menu and saved in the RC file, and always can be toggled via the -popup
+# command line switch.
+#
+#USE_SELECT_POPUPS:TRUE
+
 # VMS:
 #=====
 # INEWS is the foreign command for the ANU-NEWS client (normally defined
@@ -581,13 +592,57 @@ DEFAULT_KEYPAD_MODE_IS_NUMBERS_AS_ARROWS:TRUE
 #
 CASE_SENSITIVE_ALWAYS_ON:FALSE
 
-# DEFAULT_BOOKMARK_FILE is a default filename for use as a
-# personal bookmark file.  It should start without a slash
-# and will reference a file from the user's home directory.
-# NOTE: A file ending in .html should be used eliminate potential problems
+# DEFAULT_BOOKMARK_FILE is a default filename for use as a personal
+# bookmark file.  It will reference a file from the user's home directory.
+# NOTE that a file ending in .html or other suffix mapped to text/html
+# should be used to ensure it's treatment as HTML.  The built-in default
+# is lynx_bookmarks.html.  On both Unix and VMS, if a subdirectory off of
+# the HOME directory is desired, the path should begin with "./" (e.g.,
+# ./BM/lynx_bookmarks.html), but the subdirectory must already exist.
+# Lynx will create the bookmark file, if it does not already exist, on
+# the first ADD_BOOKMARK attempt if the HOME directory is indicated
+# (i.e., if the definition is just filename.html without any slashes),
+# but requires a pre-existing subdirectory to create the file there.
+# The user can re-define the default bookmark file, as well as a set
+# of sub-bookmark files if multiple bookmark file support is enabled
+# (see below), via the 'o'ptions menu, and can save those definitions
+# in the .lynxrc file. 
 #
 DEFAULT_BOOKMARK_FILE:lynx_bookmarks.html
 
+# If MULTI_BOOKMARK_SUPPORT is set TRUE, and BLOCK_MULTI_BOOKMARKS (see
+# below) is FALSE, and sub-bookmarks exist, all bookmark-operations will
+# first prompt the user to select an active sub-bookmark file or the
+# default bookmark file.  FALSE is the default so that one (the default)
+# bookmark file will be available initially.  The definition here will
+# override that in userdefs.h.  The user can turn on multiple bookmark
+# support via the 'o'ptions menu, and can save that choice as the startup
+# default via the .lynxrc file.   The startup default, however set, can
+# be overridden on the command line via the -restrictions=multibook or
+# the -anonymous or -validate switches.
+#
+#MULTI_BOOKMARK_SUPPORT:FALSE
+
+# If BLOCK_MULTI_BOOKMARKS is set TRUE, multiple bookmark support will
+# be forced off, and cannot to toggled on via the 'o'ptions menu.  The
+# compilation setting is normally FALSE, and can be overridden here.
+# It can also be set via the -restrictions=multibook or the -anonymous
+# or -validate command line switches.
+#
+#BLOCK_MULTI_BOOKMARKS:FALSE
+
+# If ADVANCED_MULTI_BOOKMARKS is set FALSE, the associated prompting
+# feature will be disabled.  When it is TRUE, multiple bookmark support
+# is on, and the user mode is ADVANCED, the VIEW_BOOKMARK command will
+# invoke a statusline prompt at which the user can enter the letter token
+# of the desired bookmark, or '=' to get a menu of available bookmark
+# files.  The menu always is presented in NOVICE or INTERMEDIATE mode.
+# No prompting or menu display occurs if only one (the startup default)
+# bookmark file has been defined (define additional ones via the 'o'ptions
+# menu).  The compilation definition can be overridden here.
+#
+#ADVANCED_MULTI_BOOKMARKS:TRUE
+
 # DEFAULT_USER_MODE sets the default user mode for Lynx users.
 # NOVICE  shows a three line help message at the bottom of the screen
 # INTERMEDIATE  shows normal amount of help (one line)
@@ -1251,7 +1306,7 @@ MINIMAL_COMMENTS:TRUE
 #DIRED_MENU:DIR::Tar and compress:(using GNU gzip):LYNXDIRED://TAR_GZ%p
 
 # Following depends on OK_ZIP
-#DIRED_MENU:DIR::Package and compress:(using zip):LYNXDIRED://ZIP%f
+#DIRED_MENU:DIR::Package and compress:(using zip):LYNXDIRED://ZIP%p
 
 #DIRED_MENU:FILE::Compress:(using Unix compress):LYNXDIRED://COMPRESS%p
 
@@ -1259,9 +1314,9 @@ MINIMAL_COMMENTS:TRUE
 #DIRED_MENU:FILE::Compress:(using gzip):LYNXDIRED://GZIP%p
 
 # Following depends on OK_ZIP
-#DIRED_MENU:FILE::Compress:(using zip):LYNXDIRED://ZIP%f
+#DIRED_MENU:FILE::Compress:(using zip):LYNXDIRED://ZIP%p
 
-#DIRED_MENU:TAG::Move all tagged items to another location.::LYNXDIRED://MOVE_TAGGED
+#DIRED_MENU:TAG::Move all tagged items to another location.::LYNXDIRED://MOVE_TAGGED%d
 #DIRED_MENU:TAG::Remove all tagged files and directories.::LYNXDIRED://REMOVE_TAGGED
 
 # COLORS (only available if compiled with slang)
diff --git a/lynx.hlp b/lynx.hlp
index 10abed1d..5dc2871d 100644
--- a/lynx.hlp
+++ b/lynx.hlp
@@ -75,7 +75,7 @@
        dumps the formatted output of the default document or one specified
        on the command line to standard out.  This can be used in the
        following way:
-           lynx -dump http://www.nyu.edu/pages/wsn/subir/lynx.html
+           lynx -dump http://www.crl.com/~subir/lynx.html
 
   -editor=EDITOR
        enable edit mode using the specified EDITOR. (vi, ed, emacs, etc.)
@@ -180,6 +180,10 @@
   -number_links
        force numbering of links.
 
+  -popup
+       toggles handling of single-choice SELECT options via
+       popup windows or as lists of radio buttons.
+
   -post_data
        send form data from stdin using POST method and dump results.
 
@@ -253,9 +257,11 @@
 
        jump - disable the 'j' (jump) command.
 
-       mail - disable mailing feature.
+       multibook - disallow multiple bookmark files.
+
+       mail - disallow mail.
 
-       news_post - disable USENET News posting.
+       news_post - disallow USENET News posting.
 
        options_save - disallow saving options in .lynxrc.
 
diff --git a/lynx.man b/lynx.man
index 4c011d37..e76fbdef 100644
--- a/lynx.man
+++ b/lynx.man
@@ -102,7 +102,7 @@ set the display variable for X rexec-ed programs.
 dumps the formatted output of the default document or one
 specified on the command line to standard out. 
 This can be used in the following way:
-lynx -dump http://www.nyu.edu/pages/wsn/subir/lynx.html.
+lynx -dump http://www.crl.com/~subir/lynx.html.
 .TP
 .B -editor\fR=\fIEDITOR
 enable edit mode using the specified
@@ -208,6 +208,10 @@ disable the retrieval status messages.
 .B -number_links
 force numbering of links.
 .TP
+.B -popup
+toggles handling of single-choice SELECT options via
+popup windows or as lists of radio buttons.
+.TP
 .B -post_data
 send form data from stdin using POST method and dump results.
 .TP
@@ -303,11 +307,14 @@ your domain (utmp required for selectivity).
 .I jump
 - disable the 'j' (jump) command.
 
+.I multibook
+- disallow multiple bookmarks.
+
 .I mail
-- disable mailing feature.
+- disallow mail.
 
 .I news_post
-- disable USENET News posting.
+- disallow USENET News posting.
 
 .I options_save 
 - disallow saving options in .lynxrc.
diff --git a/lynx_help/Lynx_users_guide.html b/lynx_help/Lynx_users_guide.html
index af4b7efc..ee9b1814 100644
--- a/lynx_help/Lynx_users_guide.html
+++ b/lynx_help/Lynx_users_guide.html
@@ -187,7 +187,7 @@ Here are some sample URLs.
 
 <dl>
    <dt>HTTP  (HyperText Transfer Protocol)
-     	<dd><code>http://www.nyu.edu/pages/wsn/subir/lynx.html</code>
+     	<dd><code>http://www.crl.com/~subir/lynx.html</code>
 
    <dt>Gopher
      	<dd><code>gopher://gopher.micro.umn.edu/11/</code>
@@ -310,7 +310,10 @@ available as configured by your system administrator.
 for an output filename.  All output filename entries are saved in a
 circular buffer, and any previous entries can be retrieved for re-use by
 pressing the <em>up-arrow</em> or <em>down-arrow</em> keys at the prompt.
-[<A HREF="#TOC">ToC</A>]
+
+<p>Note that if you want exact copies of text files without any expansions
+of TAB characters to spaces you should use the <a href="#9">Download</a>
+options. [<A HREF="#TOC">ToC</A>]
 
 <h2><A NAME="8"
 ><em>Viewing the HTML document source and editing documents</em></A></h2>
@@ -365,7 +368,7 @@ kermit and zmodem may be defined in the <em>lynx.cfg</em> file by the
 system administrator.  Downloading the sources of HTML and plain text
 files, instead of toggling to <a href="#8">display the source</a>
 ('<em>\</em>') and then using <a href="#7">Printing</a> options, ensures
-that no modifications of the source (e.g., expansions of tab characters
+that no modifications of the source (e.g., expansions of TAB characters
 to a series of spaces) will occur.
 
 <p>Some options, such as <em>Save to disk</em>, involve prompting for an
@@ -416,7 +419,7 @@ current document's URL and append your query string as a <em>?searchpart</em>
 <p>All search words or strings which you have entered during a Lynx session
 are saved in a circular buffer, and can be retrieved for re-use by pressing
 the <em>up-arrow</em> or <em>down-arrow</em> keys at the prompt for a search
-word or string.  Also, you can use the '<em>n</em>' command to repeated a
+word or string.  Also, you can use the '<em>n</em>'ext command to repeat a
 search with the last-entered search word or phrase, starting from the current
 position in the document.  The word or phrase matches will be highlighted
 throughout the document, but such highlighting will not persist for new
@@ -738,7 +741,7 @@ would any other link.  You can remove a link from the bookmark list by
 pressing the '<em>r</em>' key when positioned on that link.
 [<A HREF="#TOC">ToC</A>]
 
-<h2><a NAME="16"><em>Jump Command</em></a></h2>
+<h2><A NAME="16"><em>Jump Command</em></a></h2>
 
 A feature similar to the Lynx bookmarks is the jump command.  The jump
 command allows you to enter a shortcut name to access a URL.  If the jump
@@ -754,7 +757,7 @@ previous entries can be retrieved for re-use by pressing the
 to set up the jump command for your system and how to define shortcut names.
 [<A HREF="#TOC">ToC</A>]
 
-<h2><a NAME="17"><em>Directory Editing</em></a></h2>
+<h2><A NAME="17"><em>Directory Editing</em></a></h2>
 
 Lynx offers extended DIRED support on Unix (on VMS the more powerful
 CSwing program is recommended for character cell terminals, and can be
@@ -921,7 +924,7 @@ commands.
 	    [<A HREF="#TOC">ToC</A>]
 </dl>
 
-<h2><a name="19"><em>Lynx and HTML Forms</em></a></h2>
+<h2><A NAME="19"><em>Lynx and HTML Forms</em></a></h2>
 
 This section describes the Lynx Forms Interface.  HTML gives document
 providers the ability to create on-line forms which may be filled out
@@ -952,9 +955,16 @@ options from a list, and fields for entering text.
     press  the <em>right-arrow</em> or <em>Return</em> key.  A box with
     a border of asterisks (or line-drawing characters) will pop up with
     the list of possible options listed within the box.  Use the
-    <em>up-arrow</em> and <em>down-arrow</em> keys to move the cursor
-    between options and the <em>right-arrow</em> or <em>Return</em> 
-    key to select an option.
+    <em>up-arrow</em>, <em>down-arrow</em>, <em>page-up</em>,
+    <em>page-down</em>, and other navigation keys to move the cursor
+    among options, and the <em>right-arrow</em> or <em>Return</em> key to
+    select an option.  You also can use the '<em>/</em>' and '<em>n</em>'ext
+    <a href="#11">searching</a> commands for navigating to options which
+    contain particular strings.  <em>NOTE</em> that the popup menu
+    feature can be disabled via compilation and/or configuration options,
+    in which case the options will be converted to a list of radio buttons.
+    The default setting for use of popups or radio button lists can be
+    toggled via the <em>-popup</em> command line switch.
 
 <dt> Text Entry Fields
 <dd>Text entry (INPUT) fields are displayed as a row of underscores the
@@ -993,7 +1003,7 @@ interpreted by the <a href="keystroke_commands/edit_help.html"
 >Line Editor</a> as either text entries or editing commands.  Select a
 button or box when you want to use Lynx keystrokes.
 
-<p>To <a name="submit"><em>submit</em></a> the form press
+<p>To <A name="submit"><em>submit</em></a> the form press
 <em>right-arrow</em> or <em>Return</em> when positioned on the form's
 submit button.  If you've submitted the form previously during the Lynx
 session, have not changed any of the form content, and the METHOD was
@@ -1030,12 +1040,12 @@ submit the form (or to retrieve what was returned from an earlier submission
 if the content was not changed and the METHOD was <em>GET</em>).
 
 <p>Forms can have multiple <em>submit</em> buttons, if they have been
-assigned names in the markup.  In such cases, information about which
+assigned NAMEs in the markup.  In such cases, information about which
 one of the buttons was used to submit the form is included in the form
 content.
 
 <p>Inlined images can be used as submit buttons in forms.  If such
-buttons are assigned names in the markup, for graphic clients they can
+buttons are assigned NAMEs in the markup, for graphic clients they can
 also serve as <a href="#28">image maps</a>, and the x,y coordinates of
 the graphic client's cursor position in the image when it was
 <em>clicked</em> are included in the form content.  Since Lynx cannot
@@ -1043,17 +1053,17 @@ inline the image, and the user could not have moved a cursor from the
 origin for the image, if no alternatives are made available in the
 markup Lynx sends a 0,0 coordinate pair in the form content.  Document
 authors who use images as submit buttons, but have at least some concern
-for text clients and sight-challenged Webizens, should include values for
+for text clients and sight-challenged Webizens, should include VALUEs for
 the buttons in such markup.  Lynx will then display the string assigned
-to the value, as it would for a normal submit button, and will send that
-instead of an artificial 0,0 coordinate pair if that button is named and
+to the VALUE, as it would for a normal submit button, and will send that
+instead of an artificial 0,0 coordinate pair if that button is NAME-ed and
 is used to submit the form.  The script which analyzes the form content
 thus can be made aware whether the submission was by a user with a graphic
 client, or by a user who did not see the image nor make a conscious choice
 within it.
 
 <p>Forms can have <em>hidden</em> INPUT fields, which are not displayed,
-but have names and values included in the content.  These often are used
+but have NAMEs and VALUEs included in the content.  These often are used
 to keep track of information across a series of related form submissions,
 but have the potential for including information about the user that might
 be considered to represent an invasion of privacy.  NOTE, in this regard,
@@ -1083,7 +1093,7 @@ the <em>GET</em> METHOD causes the encoded form content to be appended
 as a <em>?searchpart</em> for the form's ACTION, and if such URLs are used
 in <em>text/html</em> documents or bookmark files without conversion
 of the ampersands to SGML character references (<em>&amp;amp;</em> or
-<em>&amp;#38;</em>), their being followed by form field names which might
+<em>&amp;#38;</em>), their being followed by form field NAMEs which might
 correspond to SGML entities could lead to corruption of the intended URL.
 
 <p>NOTE, in this regard, that Lynx converts ampersands to <em>&amp;amp;</em>
@@ -1094,14 +1104,24 @@ and which thus have the content appended as a <em>?searchpart</em>, but not
 if the METHOD was <em>POST</em>, because the content would be lost and the
 link thus would be invalid.
 
-<p>Lynx does not yet support <em>ENCTYPE="multipart/form-data"</em> for
-sending form content with name=value pairs encoded as multipart sections
-with individual MIME headers and terminators.  If the FORM tag indicates
-that ENCTYPE, Lynx will render and display the form fields, but will treat
-them as having the <em>DISABLED</em> attribute, so that they can't be
-submitted with an inappropriate encoding. [<A HREF="#TOC">ToC</A>]
-
-<h2><a name="20"><em>Lynx and HTML Tables</em></a></h2>
+<p>Lynx supports <em>ENCTYPE="multipart/form-data"</em> for sending form
+content with name=value pairs encoded as multipart sections with individual
+MIME headers and boundaries.  However, Lynx does not yet support INPUTs
+with <em>TYPE=&quot;file&quot;</em> or <em>TYPE=&quot;range&quot;</em> and
+will set the <em>DISABLED</em> attribute for all of the form's fields if
+any INPUTs with either of those two TYPEs are present, so that the form
+can't be submitted.  Otherwise, Lynx will submit the form with the multipart
+ENCTYPE.
+
+<p>A <em>Content-Disposition:&nbsp;file;&nbsp;filename=name.suffix</em>
+header can be used by CGI scripts to set the suggested filename offered
+by Lynx for '<em>d</em>'ownload and '<em>p</em>'rint menu options to save
+or mail the body returned by the script following submission of a FORM.
+Otherwise, Lynx uses the last symbolic element in the path for the FORM's
+ACTION, which is normally the script, itself, or a PATH_INFO field, and
+thus might be misleading. [<A HREF="#TOC">ToC</A>]
+
+<h2><A NAME="20"><em>Lynx and HTML Tables</em></a></h2>
 
 HTML includes markup for creating <em>tables</em> structured as arrays of
 cells aligned by columns and rows on the displayed page.
@@ -1125,7 +1145,7 @@ href="#21">HTML Tabs</a>.  An example <em>table</em> using <em>TAB</em>
 elements is included in the test subdirectory of the Lynx distribution.
 [<A HREF="#TOC">ToC</A>]
 
-<h2><a name="21"><em>Lynx and HTML Tabs</em></a></h2>
+<h2><A NAME="21"><em>Lynx and HTML Tabs</em></a></h2>
 
 Lynx implements the <a
 href="http://www.w3.org/pub/WWW/MarkUp/html3/Contents.html">HTML 3.0</a>
@@ -1147,7 +1167,7 @@ support it.  Toggle to display of <a href="#8">source</a> and <a
 href="#11">search</a> for <em>&lt;tab</em> to examine the use of TAB markup
 in these documents. [<A HREF="#TOC">ToC</A>]
 
-<h2><a name="22"><em>Lynx and HTML Frames</em></a></h2>
+<h2><A NAME="22"><em>Lynx and HTML Frames</em></a></h2>
 
 Some implementations of HTML include markup, primarily designed for graphic
 clients, that is intended to create an array of simultaneously displayed,
@@ -1167,7 +1187,7 @@ one has the substantive material (if there is any), or you can try each
 of those links to see if anything worthwhile is returned.
 [<A HREF="#TOC">ToC</A>]
 
-<h2><a name="23"><em>Lynx and HTML Banners</em></a></h2>
+<h2><A NAME="23"><em>Lynx and HTML Banners</em></a></h2>
 
 Some implementations of HTML markup include provisions for creating a
 non-scrolling window to be positioned at the top of each page, containing
@@ -1199,7 +1219,7 @@ MicroSoft MARQUEE tag as a synonym for BANNER (i.e., presenting it's
 markup as a static <em>banner</em>, without any horizontal scrolling of
 its content). [<A HREF="#TOC">ToC</A>]
 
-<h2><a name="24"><em>Lynx and HTML Footnotes</em></a></h2>
+<h2><A NAME="24"><em>Lynx and HTML Footnotes</em></a></h2>
 
 Lynx implements the <a
 href="http://www.w3.org/pub/WWW/MarkUp/html3/Contents.html">HTML 3.0</a>
@@ -1223,7 +1243,7 @@ you can return to your previous position in the document by pressing the
 markup that is valid in the BODY of the document.
 [<A HREF="#TOC">ToC</A>]
 
-<h2><a name="25"><em>Lynx and HTML Notes</em></a></h2>
+<h2><A NAME="25"><em>Lynx and HTML Notes</em></a></h2>
 
 Lynx implements the <a
 href="http://www.w3.org/pub/WWW/MarkUp/html3/Contents.html">HTML 3.0</a>
@@ -1247,7 +1267,7 @@ It will <em>degrade gracefully</em> for WWW browsers which do not support
 NOTE, except for recognition of the ID attribute as a named <em>A</em>nchor.
 [<A HREF="#TOC">ToC</A>]
 
-<h2><a name="26"><em>Lynx and HTML Lists</em></a></h2>
+<h2><A NAME="26"><em>Lynx and HTML Lists</em></a></h2>
 
 Lynx implements the <a
 href="http://www.w3.org/pub/WWW/MarkUp/html3/Contents.html">HTML 3.0</a>
@@ -1307,7 +1327,7 @@ blocks.  For DL blocks, double spacing will be used to separate the DT and
 DD elements unless the COMPACT attribute has been specified.
 [<A HREF="#TOC">ToC</A>]
 
-<h2><a name="27"><em>Lynx and HTML Quotes</em></a></h2>
+<h2><A NAME="27"><em>Lynx and HTML Quotes</em></a></h2>
 
 The <a
 href="http://www.w3.org/pub/WWW/MarkUp/html3/Contents.html">HTML 3.0</a> and
@@ -1333,7 +1353,7 @@ line.
 <p>Any ID attributes in BLOCKQUOTE, BQ or Q elements will be treated as
 named <em>A</em>nchors. [<A HREF="#TOC">ToC</A>]
 
-<h2><a name="28"><em>Lynx and Client-Side-Image-Maps</em></a></h2>
+<h2><A NAME="28"><em>Lynx and Client-Side-Image-Maps</em></a></h2>
 
 HTML includes markup, designed primarily for graphic clients, that treats
 inlined images as maps, such that areas of the image within which a mouse
@@ -1394,7 +1414,7 @@ OBJECT tags with the USEMAP and/or ISMAP attributes equivalently to
 its handling of IMG tags with <em>client-side-image-maps</em> and/or
 <em>server-side-image-maps</em>. [<A HREF="#TOC">ToC</A>]
 
-<h2><a name="29"><em>Lynx and Client-Side-Pull</em></a></h2>
+<h2><A NAME="29"><em>Lynx and Client-Side-Pull</em></a></h2>
 
 HTML includes provision for passing instructions to clients via directives
 in META tags, and one such instruction, via the token <em>Refresh</em>,
@@ -1587,6 +1607,9 @@ where
     		<dd>disable the retrieval status messages.
              <dt><code>-number_links</code>
     		<dd>force numbering of links.
+	     <dt><code>-popup</code>
+		<dd>toggles handling of single-choice SELECT options via
+		    popup windows or as lists of radio buttons.
 	     <dt><code>-post_data</code>
 		<dd>properly formatted data for a post form are read in from
 		    stdin and passed to the form. Input is terminated by a
@@ -1804,10 +1827,8 @@ the University of Minnesota, and the later versions of Lynx rely
 on the WWW client library code developed by Tim Berners-Lee (and
 others) and the WWW community.
 
-<p>Information on obtaining the most current version of Lynx is
-available via the
-<a href="http://www.nyu.edu/pages/wsn/subir/lynx.html"
->Lynx Enhanced Pages</a>.
+<p>Information on obtaining the most current version of Lynx is available
+via <a href="http://www.crl.com/~subir/lynx.html">Lynx links</a>.
 
 <p>[<A HREF="#TOC">ToC</A>]
 </body>
diff --git a/lynx_help/lynx_help_main.html b/lynx_help/lynx_help_main.html
index 42fc5275..a9647301 100644
--- a/lynx_help/lynx_help_main.html
+++ b/lynx_help/lynx_help_main.html
@@ -23,12 +23,12 @@
 | <a href="http://www.w3.org/pub/WWW/Addressing/Addressing.html"
 >W3C Help on URLs</a>
 
-<li><a href="../about_lynx/about_lynx-dev.html">About Lynx-Dev</a> |
-    <a href="http://www.access.digex.net/~asgilman/lynx/FAQ/">Lynx FAQ</a>
-
-<li><a href="http://www.nyu.edu/pages/wsn/subir/lynx.html"
->The Lynx Enhanced Pages Index</a>
+<li><a href="http://lynx.browser.org/">Lynx Information</a>
+| <a href="http://www.crl.com/~subir/lynx.html"
+>Lynx links</a>
 
+<li><a href="../about_lynx/about_lynx-dev.html">About Lynx-Dev</a>
+| <a href="http://www.access.digex.net/~asgilman/lynx/FAQ/">Lynx FAQ</a>
 </ul>
 
 <li><a
@@ -44,6 +44,7 @@ href="http://www.w3.org/pub/WWW/MarkUp/html-spec/html-spec_toc.html"
 <ul plain>
 <li><a href="http://www.stonehand.com/doc/"
 >Spyglass/Stonehand Technical Reference</a>
+
 <ul plain>
 <li><a
 href="http://www.stonehand.com/doc/comments.html"
@@ -62,7 +63,6 @@ href="http://www.webtechs.com/html-val-svc/"
 >HTML Primer</a>
 | <a href="http://kuhttp.cc.ukans.edu/lynx_help/HTML_quick.html"
 >HTML Quick Reference Guide</a>
-
 </ul>
 
 <li><a
@@ -82,6 +82,5 @@ href="http://www.w3.org/pub/WWW/TheProject.html"
     <a href="http://guide.Infoseek.com/">Infoseek Guide</a> |
     <a href="http://guaraldi.cs.colostate.edu:2000/">Savvy Search</a> ]
 </ul>
-
 </body>
 </html>
diff --git a/lynx_help/lynx_url_support.html b/lynx_help/lynx_url_support.html
index 8c0ed4f6..dafa3190 100644
--- a/lynx_help/lynx_url_support.html
+++ b/lynx_help/lynx_url_support.html
@@ -81,13 +81,12 @@ technically an instruction rather than part of the URL.  Lynx will treat
 ID attributes as NAME-ed anchors for all tags in the BODY of a document
 which can correspond to positions in the rendering of the document.
 
-<p>The https URL has the same format, but the default port is
-<em>:443</em>.  Patches for support of https URLs and the CONNECT
-procedure are available for qualified recipients via links in the
-<a href="http://www.nyu.edu/pages/wsn/subir/lynx.html">Lynx Enhanced
-Pages</a>.  US Export laws and associated red tape pose severe
-impediments to inclusion of this support in the general distributions
-of freeware WWW clients such as Lynx.  Sorry.
+<p>The https URL has the same format, but the default port is <em>:443</em>.
+Patches for support of https URLs and the CONNECT procedure are available
+for qualified recipients via <a 
+href="http://www.crl.com/~subir/lynx.html">Lynx links</a>.  US Export laws
+and associated red tape pose severe impediments to inclusion of this support
+in the general distributions of freeware WWW clients such as Lynx.  Sorry.
 <HR WIDTH="100%">
 
 <H2><a name="telnet"
@@ -259,16 +258,16 @@ the hit list.
 The news and nntp URLs are handled by Lynx as specified in RFC1738, but
 for compatibility with other clients, Lynx allows inclusion of host and
 port fields in news URLs, which properly should be used <em>only</em> in
-nntp URLs.  If not included in news URLs, Lynx will use the nntp server
-pointed to by the NNTPSERVER environment variable or configuration symbol
-(see lynx.cfg), with default port <em>:119</em>.  A host field must be
-included in nntp URLs, and the port field is optional with the same default.
-Patches for support of snews URLs are available to qualified recipients via
-links in the <a
-href="http://www.nyu.edu/pages/wsn/subir/lynx.html"
->Lynx Enhanced Pages</a> but cannot be included in the general
-distribution (sorry, see <a href="#http">http and https</a>).
-The formats are:<BR>
+nntp and snews URLs.  If not included in news URLs, Lynx will use the nntp
+server pointed to by the NNTPSERVER environment variable or configuration
+symbol (see lynx.cfg), with default port <em>:119</em>.  A host field must
+be included in nntp URLs, and the port field is optional with the same
+default.  Patches for support of snews URLs are available to qualified
+recipients via <a href="http://www.crl.com/~subir/lynx.html">Lynx links</a>
+but cannot be included in the general distribution (sorry, see <a
+href="#http">http and https</a>).
+
+<p>The formats are:<BR>
 <tab indent="12"><em>news:newsgroup</em> <tab
 id="ng">(retrieves list of messages in newsgroup)<BR>
 <tab indent="12"><em>news:messageID</em> <tab
diff --git a/samples/lynx.cfg b/samples/lynx.cfg
index 18598d37..4d348b62 100644
--- a/samples/lynx.cfg
+++ b/samples/lynx.cfg
@@ -22,7 +22,7 @@
 #  replace PATH_TO with the complete path to FILENAME
 #  use Unix SHELL syntax and include the device on VMS systems)
 #
-STARTFILE:http://www.nyu.edu/pages/wsn/subir/lynx.html
+STARTFILE:http://lynx.browser.org/
 
 # HELPFILE must be defined as a URL and must have a
 # complete path if local:
@@ -31,10 +31,10 @@ STARTFILE:http://www.nyu.edu/pages/wsn/subir/lynx.html
 #   for this distribution (use SHELL syntax including the device
 #   on VMS systems).
 # The default HELPFILE is:
-# http://www.nyu.edu/pages/wsn/subir/lynx.html
+# http://www.crl.com/~subir/lynx/lynx_help/lynx_help_main.html
 #   This should be changed to the local path.
 #
-HELPFILE:http://www.nyu.edu/pages/wsn/subir/lynx.html
+HELPFILE:http://www.crl.com/~subir/lynx/lynx_help/lynx_help_main.html
 #HELPFILE:file://localhost/PATH_TO/lynx_help/lynx_help_main.html
 
 # DEFAULT_INDEX_FILE is the default file retrieved when the
@@ -489,6 +489,17 @@ CHECKMAIL:FALSE
 #NEWS_CHUNK_SIZE:30
 #NEWS_MAX_CHUNK:40
 
+# If USE_SELECT_POPUPS is set FALSE, Lynx will present a vertical list of
+# radio buttons for the OPTIONs in SELECT blocks which lack the MULTIPLE
+# attribute, instead of using a popup menu.  Note that if the MULTIPLE
+# attribute is present in the SELECT start tag, Lynx always will create a
+# vertical list of checkboxes for the OPTIONs.
+# The default defined here or in userdefs.h can be changed via the 'o'ptions
+# menu and saved in the RC file, and always can be toggled via the -popup
+# command line switch.
+#
+#USE_SELECT_POPUPS:TRUE
+
 # VMS:
 #=====
 # INEWS is the foreign command for the ANU-NEWS client (normally defined
@@ -581,13 +592,57 @@ DEFAULT_KEYPAD_MODE_IS_NUMBERS_AS_ARROWS:TRUE
 #
 CASE_SENSITIVE_ALWAYS_ON:FALSE
 
-# DEFAULT_BOOKMARK_FILE is a default filename for use as a
-# personal bookmark file.  It should start without a slash
-# and will reference a file from the user's home directory.
-# NOTE: A file ending in .html should be used eliminate potential problems
+# DEFAULT_BOOKMARK_FILE is a default filename for use as a personal
+# bookmark file.  It will reference a file from the user's home directory.
+# NOTE that a file ending in .html or other suffix mapped to text/html
+# should be used to ensure it's treatment as HTML.  The built-in default
+# is lynx_bookmarks.html.  On both Unix and VMS, if a subdirectory off of
+# the HOME directory is desired, the path should begin with "./" (e.g.,
+# ./BM/lynx_bookmarks.html), but the subdirectory must already exist.
+# Lynx will create the bookmark file, if it does not already exist, on
+# the first ADD_BOOKMARK attempt if the HOME directory is indicated
+# (i.e., if the definition is just filename.html without any slashes),
+# but requires a pre-existing subdirectory to create the file there.
+# The user can re-define the default bookmark file, as well as a set
+# of sub-bookmark files if multiple bookmark file support is enabled
+# (see below), via the 'o'ptions menu, and can save those definitions
+# in the .lynxrc file. 
 #
 DEFAULT_BOOKMARK_FILE:lynx_bookmarks.html
 
+# If MULTI_BOOKMARK_SUPPORT is set TRUE, and BLOCK_MULTI_BOOKMARKS (see
+# below) is FALSE, and sub-bookmarks exist, all bookmark-operations will
+# first prompt the user to select an active sub-bookmark file or the
+# default bookmark file.  FALSE is the default so that one (the default)
+# bookmark file will be available initially.  The definition here will
+# override that in userdefs.h.  The user can turn on multiple bookmark
+# support via the 'o'ptions menu, and can save that choice as the startup
+# default via the .lynxrc file.   The startup default, however set, can
+# be overridden on the command line via the -restrictions=multibook or
+# the -anonymous or -validate switches.
+#
+#MULTI_BOOKMARK_SUPPORT:FALSE
+
+# If BLOCK_MULTI_BOOKMARKS is set TRUE, multiple bookmark support will
+# be forced off, and cannot to toggled on via the 'o'ptions menu.  The
+# compilation setting is normally FALSE, and can be overridden here.
+# It can also be set via the -restrictions=multibook or the -anonymous
+# or -validate command line switches.
+#
+#BLOCK_MULTI_BOOKMARKS:FALSE
+
+# If ADVANCED_MULTI_BOOKMARKS is set FALSE, the associated prompting
+# feature will be disabled.  When it is TRUE, multiple bookmark support
+# is on, and the user mode is ADVANCED, the VIEW_BOOKMARK command will
+# invoke a statusline prompt at which the user can enter the letter token
+# of the desired bookmark, or '=' to get a menu of available bookmark
+# files.  The menu always is presented in NOVICE or INTERMEDIATE mode.
+# No prompting or menu display occurs if only one (the startup default)
+# bookmark file has been defined (define additional ones via the 'o'ptions
+# menu).  The compilation definition can be overridden here.
+#
+#ADVANCED_MULTI_BOOKMARKS:TRUE
+
 # DEFAULT_USER_MODE sets the default user mode for Lynx users.
 # NOVICE  shows a three line help message at the bottom of the screen
 # INTERMEDIATE  shows normal amount of help (one line)
@@ -1251,7 +1306,7 @@ MINIMAL_COMMENTS:TRUE
 #DIRED_MENU:DIR::Tar and compress:(using GNU gzip):LYNXDIRED://TAR_GZ%p
 
 # Following depends on OK_ZIP
-#DIRED_MENU:DIR::Package and compress:(using zip):LYNXDIRED://ZIP%f
+#DIRED_MENU:DIR::Package and compress:(using zip):LYNXDIRED://ZIP%p
 
 #DIRED_MENU:FILE::Compress:(using Unix compress):LYNXDIRED://COMPRESS%p
 
@@ -1259,9 +1314,9 @@ MINIMAL_COMMENTS:TRUE
 #DIRED_MENU:FILE::Compress:(using gzip):LYNXDIRED://GZIP%p
 
 # Following depends on OK_ZIP
-#DIRED_MENU:FILE::Compress:(using zip):LYNXDIRED://ZIP%f
+#DIRED_MENU:FILE::Compress:(using zip):LYNXDIRED://ZIP%p
 
-#DIRED_MENU:TAG::Move all tagged items to another location.::LYNXDIRED://MOVE_TAGGED
+#DIRED_MENU:TAG::Move all tagged items to another location.::LYNXDIRED://MOVE_TAGGED%d
 #DIRED_MENU:TAG::Remove all tagged files and directories.::LYNXDIRED://REMOVE_TAGGED
 
 # COLORS (only available if compiled with slang)
diff --git a/src/DefaultStyle.c b/src/DefaultStyle.c
index 1cbe4252..b4ee349a 100644
--- a/src/DefaultStyle.c
+++ b/src/DefaultStyle.c
@@ -277,18 +277,11 @@ PRIVATE HTStyle HTStyleExample = {
 	&HTStyleGlossaryCompact6,  "Example", "XMP",
 	HT_FONT, 1.0, HT_BLACK,		0, 0,
 	0, 0, 0, HT_LEFT,		1, 0,	tabs_8,
-	NO, NO, 1, 1,			0
-};	
-
-PRIVATE HTStyle HTStyleStyle = { /* HTML 3.0 STYLE - FM */
-	&HTStyleExample,  "Style", "STYLE",
-	HT_FONT, 1.0, HT_BLACK,		0, 0,
-	0, 0, 0, HT_LEFT,		1, 0,	tabs_8,
-	NO, NO, 1, 1,			0
+	NO, NO, 0, 0,			0
 };	
 
 PRIVATE HTStyle HTStylePreformatted = {
-	&HTStyleStyle,  	"Preformatted", "PRE",
+	&HTStyleExample,  	"Preformatted", "PRE",
 	HT_FONT, 1.0, HT_BLACK,		0, 0,
 	0, 0, 0, HT_LEFT,		1, 0,	tabs_8,
 	NO, YES, 0, 0,			0
@@ -298,7 +291,7 @@ PRIVATE HTStyle HTStyleListing = {
 	&HTStylePreformatted,  "Listing", "LISTING",
 	HT_FONT, 1.0, HT_BLACK,		0, 0,
 	0, 0, 0, HT_LEFT,		1, 0,	tabs_8,
-	NO, NO, 1, 1,			0 };	
+	NO, NO, 0, 0,			0 };	
 
 PRIVATE HTStyle HTStyleAddress = {
 	&HTStyleListing,  "Address", "ADDRESS",
diff --git a/src/GridText.c b/src/GridText.c
index 2c35304d..e988c7ba 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -68,10 +68,10 @@ PUBLIC char * HTAppVersion = LYNX_VERSION;        /* Application version */
 
 PUBLIC int HTFormNumber = 0;
 PUBLIC int HTFormFields = 0;
-PUBLIC char * HTCurSelectGroup = NULL;		/* form select group name */
-PUBLIC int HTCurSelectGroupType = F_RADIO_TYPE;	/* group type */
-PUBLIC char * HTCurSelectGroupSize = NULL;	/* length of select */
-PRIVATE char * HTCurSelectedOptionValue = NULL;	/* select choice */
+PUBLIC char * HTCurSelectGroup = NULL;		/* Form select group name */
+PUBLIC int HTCurSelectGroupType = F_RADIO_TYPE;	/* Group type */
+PUBLIC char * HTCurSelectGroupSize = NULL;	/* Length of select */
+PRIVATE char * HTCurSelectedOptionValue = NULL;	/* Select choice */
 
 PUBLIC char * checked_box = "[X]";
 PUBLIC char * unchecked_box = "[ ]";
@@ -157,7 +157,8 @@ struct _HText {
 /*
  *  Boring static variable used for moving cursor across
  */
-#define UNDERSCORES(n) (&underscore_string[(MAX_LINE-1) - (n)])
+#define UNDERSCORES(n) \
+ ((n) >= MAX_LINE ? underscore_string : &underscore_string[(MAX_LINE-1)] - (n))
 
 /*
  *	Memory leak fixed.
@@ -192,7 +193,7 @@ PUBLIC HText *	HText_new ARGS1(HTParentAnchor *,anchor)
     int status, VMType=3, VMTotal;
 #endif /* VMS && VAXC && !__DECC */
     HTLine * line = NULL;
-    HText * self = (HText *) calloc(sizeof(*self),1);
+    HText * self = (HText *) calloc(1, sizeof(*self));
     if (!self) return self;
     
 #if defined(VMS) && defined (VAXC) && !defined(__DECC)
@@ -239,7 +240,7 @@ PUBLIC HText *	HText_new ARGS1(HTParentAnchor *,anchor)
 #endif /* VMS && VAXC && !__DECC */
     }
     
-    line = self->last_line = (HTLine *)calloc(sizeof(char),LINE_SIZE(MAX_LINE));
+    line = self->last_line = (HTLine *)calloc(1, LINE_SIZE(MAX_LINE));
     if (line == NULL)
         outofmem(__FILE__, "HText_New");
     line->next = line->prev = line;
@@ -281,14 +282,20 @@ PUBLIC HText *	HText_new ARGS1(HTParentAnchor *,anchor)
      *	Check to see if our underline and star_string need initialization
      *		if the underline is not filled with dots.
      */ 
-    if (underscore_string[0] != '.') { /* Make a line */
+    if (underscore_string[0] != '.') {
         char *p;
-        for (p=underscore_string; p<underscore_string+(MAX_LINE-1); p++)
-            *p = '.';           /* Used for printfs later */
+	/*
+	 * Create and array of dots for the UNDERSCORES macro. - FM
+	 */
+	memset(underscore_string, '.', (MAX_LINE-1));
         underscore_string[(MAX_LINE-1)] = '\0';
-        for (p=star_string; p<star_string+(LINESIZE-1); p++)
-            *p = '_';           /* Used for printfs later */
-        star_string[(LINESIZE-1)] = '\0';
+        underscore_string[MAX_LINE] = '\0';
+	/*
+	 * Create and array of underscores for the STARS macro. - FM
+	 */
+	memset(star_string, '_', (MAX_LINE-1));
+        star_string[(MAX_LINE-1)] = '\0';
+        star_string[MAX_LINE] = '\0';
     }
 
     underline_on = FALSE; /* reset */
@@ -594,7 +601,8 @@ PRIVATE void display_title ARGS1(HText *,text)
     if (cp == NULL)
         outofmem(__FILE__, "display_title");
     if (HTCJK != NOCJK) {
-        if (*title && (tmp = (unsigned char *)calloc(1, strlen(title) + 1))) {
+        if (*title &&
+	    (tmp = (unsigned char *)calloc(1, (strlen(title) + 1)))) {
 	    if (kanji_code == EUC) {
 	        TO_EUC((unsigned char *)title, tmp);
 	    } else if (kanji_code == SJIS) {
@@ -878,7 +886,7 @@ PRIVATE void display_page ARGS3(HText *,text, int,line_number, char *, target)
 	    }
 	} 
 
-	if (Anchor_ptr == text->last_anchor)
+	if (Anchor_ptr == text->last_anchor || nlinks == MAXLINKS)
 	    break;
     }
 
@@ -953,7 +961,7 @@ PRIVATE void split_line ARGS2(HText *,text, int,split)
     HTLine * previous = text->last_line;
     int ctrl_chars_on_previous_line = 0;
     char * cp;
-    HTLine * line = (HTLine *)calloc(sizeof(char), LINE_SIZE(MAX_LINE));
+    HTLine * line = (HTLine *)calloc(1, LINE_SIZE(MAX_LINE));
 
     ctrl_chars_on_this_line = 0; /*reset since we are going to a new line*/
     HTML_Last_Char = ' ';
@@ -1126,7 +1134,7 @@ PRIVATE void split_line ARGS2(HText *,text, int,split)
      *  problem with Ultrix (4.2) : realloc() is not declared properly.
      *  So we'll use a substitute for realloc.
      */
-    temp = (HTLine *)calloc(sizeof(char), LINE_SIZE(previous->size));
+    temp = (HTLine *)calloc(1, LINE_SIZE(previous->size));
     if (temp == NULL)
         outofmem(__FILE__, "split_line");
     memcpy(temp, previous, LINE_SIZE(previous->size));
@@ -1639,7 +1647,7 @@ PUBLIC void HText_beginAnchor ARGS2(HText *,text, HTChildAnchor *,anc)
 {
     char marker[16];
 
-    TextAnchor * a = (TextAnchor *) calloc(sizeof(*a),1);
+    TextAnchor * a = (TextAnchor *) calloc(1, sizeof(*a));
     
     if (a == NULL)
         outofmem(__FILE__, "HText_beginAnchor");
@@ -1938,7 +1946,8 @@ PUBLIC HTChildAnchor * HText_childNumber ARGS1(int,number)
     return (HTChildAnchor *)0;	/* Fail */
 }
 
-/* HTGetLinkInfo returns some link info based on the number
+/*
+ *  HTGetLinkInfo returns some link info based on the number.
  */
 PUBLIC int HTGetLinkInfo ARGS3(int, number, char **, hightext, char **, lname)
 {
@@ -1969,16 +1978,18 @@ PUBLIC int HTGetLinkInfo ARGS3(int, number, char **, hightext, char **, lname)
     return(NO);
 }
 
-/* HText_getNumOfLines returns the number of lines in the
- * current document
+/*
+ *  HText_getNumOfLines returns the number of lines in the
+ *  current document.
  */
 PUBLIC int HText_getNumOfLines NOARGS
 {
      return(HTMainText->lines);
 }
 
-/* HText_getTitle returns the title of the
- * current document
+/*
+ *  HText_getTitle returns the title of the
+ *  current document.
  */
 PUBLIC char * HText_getTitle NOARGS
 {
@@ -1986,12 +1997,47 @@ PUBLIC char * HText_getTitle NOARGS
 }
 
 /*
- * HText_pageDisplay displays a screen of text
- * starting from the line 'line_num'-1
- * this is the primary call for lynx
+ *  HText_getSugFname returns the suggested filename of the current
+ *  document (normally derived from a Content-Disposition header with
+ *  file; filename=name.suffix). - FM
+ */
+PUBLIC char * HText_getSugFname NOARGS
+{
+   return((char *) HTAnchor_SugFname(HTMainText->node_anchor));
+}
+
+/*
+ *  HText_getLastModified returns the Last-Modified header
+ *  if available, for the current document. - FM
  */
-extern char is_www_index;
+PUBLIC char * HText_getLastModified NOARGS
+{
+   return((char *) HTAnchor_last_modified(HTMainText->node_anchor));
+}
 
+/*
+ *  HText_getDate returns the Date header
+ *  if available, for the current document. - FM
+ */
+PUBLIC char * HText_getDate NOARGS
+{
+   return((char *) HTAnchor_date(HTMainText->node_anchor));
+}
+
+/*
+ *  HText_getServer returns the Server header
+ *  if available, for the current document. - FM
+ */
+PUBLIC char * HText_getServer NOARGS
+{
+   return((char *) HTAnchor_server(HTMainText->node_anchor));
+}
+
+/*
+ *  HText_pageDisplay displays a screen of text
+ *  starting from the line 'line_num'-1
+ *  this is the primary call for lynx
+ */
 PUBLIC void HText_pageDisplay ARGS2(int,line_num, char *, target)
 {
     display_page(HTMainText, line_num-1, target);
@@ -2000,8 +2046,8 @@ PUBLIC void HText_pageDisplay ARGS2(int,line_num, char *, target)
 } 
 
 /*
- * HText_LinksInLines returns the number of links in the
- * 'lines' number of lines beginning with 'line_num'-1. - FM
+ *  HText_LinksInLines returns the number of links in the
+ *  'lines' number of lines beginning with 'line_num'-1. - FM
  */
 PUBLIC int HText_LinksInLines ARGS3(HText *,text, int,line_num, int,lines)
 {
@@ -2034,7 +2080,8 @@ PUBLIC void HText_setStale ARGS1(HText *,text)
 
 PUBLIC void HText_refresh ARGS1(HText *,text)
 {
-    if (text->stale) display_page(text, text->top_of_screen, "");
+    if (text->stale)
+        display_page(text, text->top_of_screen, "");
 }
 
 PUBLIC int HText_sourceAnchors ARGS1(HText *,text)
@@ -2679,8 +2726,7 @@ PUBLIC void www_user_search ARGS2(int,start_line, char *,target)
 	        www_search_result=count;
 		return;
 	    } else if (count > start_line) {  /* next line */
-    		_user_message("\"%s\" could not be found in this document",
-			      target);
+    		_user_message(STRING_NOT_FOUND, target);
     		sleep(MessageSecs);
 	        return;			/* end */
 	    } else {
@@ -2721,7 +2767,18 @@ PUBLIC  void  user_message ARGS2(char *,message, char *,argument)
  */
 PUBLIC char * HText_getOwner NOARGS
 {
-   return((char *)HTAnchor_owner(HTMainText->node_anchor));
+    return((char *)HTAnchor_owner(HTMainText->node_anchor));
+}
+
+/* HText_setMainTextOwner sets the owner for the
+ * current document
+ */
+PUBLIC void HText_setMainTextOwner ARGS1(CONST char *, owner)
+{
+    if (!HTMainText)
+        return;
+
+    HTAnchor_setOwner(HTMainText->node_anchor, owner);
 }
 
 /* HText_getRevTitle returns the RevTitle element of the
@@ -2730,7 +2787,7 @@ PUBLIC char * HText_getOwner NOARGS
  */
 PUBLIC char * HText_getRevTitle NOARGS
 {
-   return((char *)HTAnchor_RevTitle(HTMainText->node_anchor));
+    return((char *)HTAnchor_RevTitle(HTMainText->node_anchor));
 }
 
 PUBLIC void HTuncache_current_document NOARGS
@@ -2743,53 +2800,85 @@ PUBLIC void HTuncache_current_document NOARGS
 
 PUBLIC int HTisDocumentSource NOARGS
 {
-   return(HTMainText->source);
+    return(HTMainText->source);
 }
 
 PUBLIC char * HTLoadedDocumentURL NOARGS
 {
-   if (!HTMainText)
+    if (!HTMainText)
 	return ("");
 
-   if (HTMainText->node_anchor && HTMainText->node_anchor->address) 
+    if (HTMainText->node_anchor && HTMainText->node_anchor->address) 
        	return(HTMainText->node_anchor->address);
-   else
+    else
 	return ("");
 }
 
 PUBLIC char * HTLoadedDocumentPost_data NOARGS
 {
-   if (!HTMainText)
+    if (!HTMainText)
 	return ("");
 
-   if (HTMainText->node_anchor && HTMainText->node_anchor->post_data) 
+    if (HTMainText->node_anchor && HTMainText->node_anchor->post_data) 
        	return(HTMainText->node_anchor->post_data);
-   else
+    else
 	return ("");
 }
 
 PUBLIC char * HTLoadedDocumentTitle NOARGS
 {
-   if (!HTMainText)
+    if (!HTMainText)
 	return ("");
 
-   if (HTMainText->node_anchor && HTMainText->node_anchor->title) 
+    if (HTMainText->node_anchor && HTMainText->node_anchor->title) 
        	return(HTMainText->node_anchor->title);
-   else
+    else
 	return ("");
 }
 
 PUBLIC BOOLEAN HTLoadedDocumentIsHEAD NOARGS
 {
-   if (!HTMainText)
+    if (!HTMainText)
 	return (FALSE);
 
-   if (HTMainText->node_anchor && HTMainText->node_anchor->isHEAD) 
+    if (HTMainText->node_anchor && HTMainText->node_anchor->isHEAD) 
        	return(HTMainText->node_anchor->isHEAD);
-   else
+    else
 	return (FALSE);
 }
 
+PUBLIC char * HTLoadedDocumentCharset NOARGS
+{
+    if (!HTMainText)
+	return (NULL);
+
+    if (HTMainText->node_anchor && HTMainText->node_anchor->charset) 
+       	return(HTMainText->node_anchor->charset);
+    else
+	return (NULL);
+}
+
+PUBLIC void HText_setNodeAnchorBookmark ARGS1(
+	CONST char *,	bookmark)
+{
+    if (!HTMainText)
+	return;
+
+    if (HTMainText->node_anchor)
+	HTAnchor_setBookmark(HTMainText->node_anchor, bookmark);
+}
+
+PUBLIC char * HTLoadedDocumentBookmark NOARGS
+{
+    if (!HTMainText)
+	return (NULL);
+
+    if (HTMainText->node_anchor && HTMainText->node_anchor->bookmark) 
+       	return(HTMainText->node_anchor->bookmark);
+    else
+	return (NULL);
+}
+
 PUBLIC int HText_LastLineSize ARGS1(HText *,text)
 {
     if (!text || !text->last_line || !text->last_line->size)
@@ -2921,6 +3010,7 @@ PRIVATE int HTFormMethod;
 PRIVATE char * HTFormAction = NULL;
 PRIVATE char * HTFormEnctype = NULL;
 PRIVATE char * HTFormTitle = NULL;
+PRIVATE BOOLEAN HTFormDisabled = FALSE;
 
 PUBLIC void HText_beginForm ARGS4(
 	char *,		action,
@@ -2931,7 +3021,11 @@ PUBLIC void HText_beginForm ARGS4(
     HTFormMethod = URL_GET_METHOD;
     HTFormNumber++;
     HTFormFields = 0;
+    HTFormDisabled = FALSE;
 
+    /*
+     *  Check the ACTION. - FM
+     */
     if (action != NULL) {
 	if (!strncmp(action, "mailto:", 7)) {
 	    HTFormMethod = URL_MAIL_METHOD;
@@ -2941,15 +3035,28 @@ PUBLIC void HText_beginForm ARGS4(
     else
 	StrAllocCopy(HTFormAction, HTLoadedDocumentURL());
     
-    if (method != NULL)
-	if (!strcasecomp(method,"post") && HTFormMethod != URL_MAIL_METHOD)
-	   HTFormMethod = URL_POST_METHOD;
+    /*
+     *  Check the METHOD. - FM
+     */
+    if (method != NULL && HTFormMethod != URL_MAIL_METHOD)
+	if (!strcasecomp(method,"post") || !strcasecomp(method,"pget"))
+	    HTFormMethod = URL_POST_METHOD;
 
-    if ((enctype != NULL) && *enctype)
+    /*
+     *  Check the ENCTYPE. - FM
+     */
+    if ((enctype != NULL) && *enctype) {
         StrAllocCopy(HTFormEnctype, enctype);
-    else
+	if (HTFormMethod != URL_MAIL_METHOD &&
+	    !strncasecomp(enctype, "multipart/form-data", 19)) 
+	    HTFormMethod = URL_POST_METHOD;
+    } else {
         FREE(HTFormEnctype);
+    }
 
+    /*
+     *  Check the TITLE. - FM
+     */
     if ((title != NULL) && *title)
         StrAllocCopy(HTFormTitle, title);
     else
@@ -2992,6 +3099,8 @@ PUBLIC void HText_endForm ARGS1(HText *,text)
 		    StrAllocCopy(a->input_field->submit_title, HTFormTitle);
 		a->input_field->submit_method = HTFormMethod;
 		a->input_field->type = F_TEXT_SUBMIT_TYPE;
+		if (HTFormDisabled)
+		    a->input_field->disabled = TRUE;
 		break;
 	    }
 	    if (a == text->last_anchor)
@@ -3006,6 +3115,7 @@ PUBLIC void HText_endForm ARGS1(HText *,text)
     FREE(HTFormEnctype);
     FREE(HTFormTitle);
     HTFormFields = 0;
+    HTFormDisabled = FALSE;
 }
 
 PUBLIC void HText_beginSelect ARGS3(char *,name, BOOLEAN,multiple, char *, size)
@@ -3087,7 +3197,15 @@ PUBLIC char * HText_setLastOptionValue ARGS5(HText *, text, char *, value,
 	 *  Put the text on the screen as well.
 	 */
         HText_appendText(text, cp);
- 
+
+    } else if (LYSelectPopups == FALSE) {
+        StrAllocCopy(text->last_anchor->input_field->value,
+		     (submit_value ? submit_value : cp));
+        /*
+	 *  Put the text on the screen as well.
+	 */
+        HText_appendText(text, cp);
+
     } else {
 	/*
 	 *  Create a linked list of option values.
@@ -3106,7 +3224,7 @@ PUBLIC char * HText_setLastOptionValue ARGS5(HText *, text, char *, value,
 	     *  No option items yet.
 	     */
 	    new_ptr = text->last_anchor->input_field->select_list = 
-				(OptionType *) calloc(1,sizeof(OptionType));
+				(OptionType *) calloc(1, sizeof(OptionType));
 	    if (new_ptr == NULL)
 	        outofmem(__FILE__, "HText_setLastOptionValue");
 
@@ -3119,7 +3237,7 @@ PUBLIC char * HText_setLastOptionValue ARGS5(HText *, text, char *, value,
 	    number++;  /* add one more */
 
 	    op_ptr->next = new_ptr =
-	    			(OptionType *) calloc(1,sizeof(OptionType));
+	    			(OptionType *) calloc(1, sizeof(OptionType));
 	    if (new_ptr == NULL)
 	        outofmem(__FILE__, "HText_setLastOptionValue");
 	}
@@ -3248,11 +3366,17 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
 
 
     /*
-     *  If this is a radio button, and it's the first with this name,
-     *  make sure it's checked by default.  Otherwise, if it's checked,
-     *  uncheck the default or any preceding radio button with this name
-     *  that was checked. - FM
+     *  If this is a radio button, or an OPTION we're converting
+     *  to a radio button, and it's the first with this name, make
+     *  sure it's checked by default.  Otherwise, if it's checked,
+     *  uncheck the default or any preceding radio button with this
+     *  name that was checked. - FM
      */
+    if (I->type != NULL && !strcmp(I->type,"OPTION") &&
+ 	HTCurSelectGroupType == F_RADIO_TYPE && LYSelectPopups == FALSE) {
+	I->type = "RADIO";
+	I->name = HTCurSelectGroup;
+    }
     if (I->name && I->type && !strcasecomp(I->type, "radio")) {
         if (!text->last_anchor) {
 	    I->checked = TRUE;
@@ -3299,7 +3423,7 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
 
     f->select_list = 0;
     f->number = HTFormNumber;
-    f->disabled = I->disabled;
+    f->disabled = (HTFormDisabled ? TRUE : I->disabled);
     f->no_cache = NO;
 
     HTFormFields++;
@@ -3312,22 +3436,12 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
         f->no_cache = TRUE;
 
     /*
-     *  Disable if the ENCTYPE is multipart/form-data
-     *  until we add code to handle it. - FM
-     */
-    if (HTFormEnctype) {
-         if (!strcmp(HTFormEnctype, "multipart/form-data")) {
-	     f->disabled = YES;
-	 }
-    }
-
-    /*
      *  Set up VALUE.
      */
     if (I->value)
         StrAllocCopy(IValue, I->value);
     if (IValue && HTCJK != NOCJK) {
-	if ((tmp = (unsigned char *)calloc(1, strlen(IValue)+1))) {
+	if ((tmp = (unsigned char *)calloc(1, (strlen(IValue) + 1)))) {
 	    if (kanji_code == EUC) {
 		TO_EUC((unsigned char *)IValue, tmp);
 	    } else if (kanji_code == SJIS) {
@@ -3346,6 +3460,7 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
 
     /*
      *  Special case of OPTION.
+     *  Is handled above if radio type and LYSelectPopups is FALSE.
      */
     /* set the values and let the parsing below do the work */
     if (I->type != NULL && !strcmp(I->type,"OPTION")) {
@@ -3365,7 +3480,6 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
 	if (HTCurSelectGroupSize != NULL) {
 	    f->size_l = atoi(HTCurSelectGroupSize);
 	    FREE(HTCurSelectGroupSize);
-	    HTCurSelectGroupSize = NULL;
 	}
     }
 
@@ -3518,10 +3632,10 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I)
 	    StrAllocCopy(f->submit_title, HTFormTitle);
 	f->submit_method = HTFormMethod;
 
-    } else if (f->type == F_RADIO_TYPE || f->type == F_CHECKBOX_TYPE ) {
+    } else if (f->type == F_RADIO_TYPE || f->type == F_CHECKBOX_TYPE) {
 	f->size=3;
 	if (IValue == NULL)
-	   StrAllocCopy(f->value, "on");
+	   StrAllocCopy(f->value, (f->type == F_CHECKBOX_TYPE ? "on" : ""));
 
     }
     FREE(IValue); 
@@ -3578,9 +3692,20 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
     char *previous_blanks = NULL;
     BOOLEAN PlainText = FALSE;
     BOOLEAN SemiColon = FALSE;
+    char *Boundary = NULL;
+    char *MultipartContentType = NULL;
 
     if (submit_item->submit_action) {
         /*
+	 *  If we're mailing, make sure it's a mailto ACTION. - FM
+	 */
+        if ((submit_item->submit_method == URL_MAIL_METHOD) &&
+	    strncmp(submit_item->submit_action, "mailto:", 7)) {
+	    HTAlert(BAD_FORM_MAILTO);
+	    return;
+	}
+
+        /*
 	 *  Set length plus breathing room.
 	 */
         len = strlen(submit_item->submit_action) + 2048;
@@ -3589,6 +3714,36 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
     }
 
     /*
+     *  Check the ENCTYPE and set up the appropriate variables. - FM
+     */
+    if (submit_item->submit_enctype &&
+	!strncasecomp(submit_item->submit_enctype, "text/plain", 10)) {
+	/*
+	 *  Do not hex escape, and use physical newlines
+	 *  to separate name=value pairs. - FM
+	 */
+	PlainText = TRUE;
+    } else if (submit_item->submit_enctype &&
+	       !strncasecomp(submit_item->submit_enctype,
+			     "application/sgml-form-urlencoded", 32)) {
+	/*
+	 *  Use semicolons instead of ampersands as the
+	 *  separators for name=value pairs. - FM
+	 */
+	SemiColon = TRUE;
+    } else if (submit_item->submit_enctype &&
+	       !strncasecomp(submit_item->submit_enctype,
+			     "multipart/form-data", 19)) {
+	/*
+	 *  Use the multipart MIME format.  We should generate
+	 *  a boundary string which we are sure doesn't occur
+	 *  in the content, but for now we'll just assume that
+	 *  this string doesn't. - FM
+	 */
+	Boundary = "xnyLAaB03X";
+    }
+
+    /*
      *  Go through list of anchors and get size first.
      */
     while (1) {
@@ -3597,15 +3752,14 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 
 	        form_ptr = anchor_ptr->input_field;
 	
-	        len += strlen(form_ptr->name)+10;
+	        len += (strlen(form_ptr->name) + (Boundary ? 100 : 10));
 		/*
 		 *	Calculate by the option submit value if present.
 		 */
-		if (form_ptr->cp_submit_value != NULL)	{
-			len += strlen(form_ptr->cp_submit_value) + 10;
-		}
-		else	{
-	        	len += strlen(form_ptr->value)+10;
+		if (form_ptr->cp_submit_value != NULL) {
+		    len += (strlen(form_ptr->cp_submit_value) + 10);
+		} else {
+	            len += (strlen(form_ptr->value) + 10);
 		}
 	        len += 32; /* plus and ampersand + safty net */
 
@@ -3623,28 +3777,11 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
     /*
      *  Get query ready.
      */
-    query = (char *)calloc (sizeof(char), len);
+    query = (char *)calloc(1, len);
     if (query == NULL)
         outofmem(__FILE__, "HText_SubmitForm");
 
-    if (submit_item->submit_enctype &&
-	!strncasecomp(submit_item->submit_enctype, "text/plain", 10)) {
-	/*
-	 *  Do not hex escape, and use physical newlines
-	 *  to separate name=value pairs. - FM
-	 */
-	PlainText = TRUE;
-    } else if (submit_item->submit_enctype &&
-	       !strncasecomp(submit_item->submit_enctype,
-			     "application/sgml-form-urlencoded", 32)) {
-	/*
-	 *  Use semicolons instead of ampersands as the
-	 *  separators for name=value pairs. - FM
-	 */
-	SemiColon = TRUE;
-    }
-
-    if (submit_item->submit_method == URL_GET_METHOD) {
+    if (submit_item->submit_method == URL_GET_METHOD && Boundary == NULL) {
        	strcpy (query, submit_item->submit_action);
        	/*
 	 *  Method is GET.  Clip out any anchor in the current URL.
@@ -3660,44 +3797,59 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 	strcat(query,"?");
     } else {
         query[0] = '\0';
-	if (submit_item->submit_method != URL_MAIL_METHOD) {
-	    /*
-	     *  We are submitting POST content to a server,
-	     *  so load the post_content_type element. - FM
-	     */
-	    if (SemiColon == TRUE) {
-	        StrAllocCopy(doc->post_content_type,
-			     "application/sgml-form-urlencoded");
-	    } else if (PlainText == TRUE) {
-	        StrAllocCopy(doc->post_content_type,
-			     "text/plain");
-	    } else {
-	        StrAllocCopy(doc->post_content_type,
-	        	     "application/x-www-form-urlencoded");
-	    }
+	/*
+	 *  We are submitting POST content to a server,
+	 *  so load the post_content_type element. - FM
+	 */
+	if (SemiColon == TRUE) {
+	    StrAllocCopy(doc->post_content_type,
+			 "application/sgml-form-urlencoded");
+	} else if (PlainText == TRUE) {
+	    StrAllocCopy(doc->post_content_type,
+			 "text/plain");
+	} else if (Boundary != NULL) {
+	    StrAllocCopy(doc->post_content_type,
+			 "multipart/form-data; boundary=");
+	    StrAllocCat(doc->post_content_type, Boundary);
+	} else {
+	    StrAllocCopy(doc->post_content_type,
+			 "application/x-www-form-urlencoded");
+	}
 
-	    /*
-	     *  Append the exended charset info if known, and it is
-	     *  not ISO-8859-1 or US-ASCII.  We'll assume the user
-	     *  has the matching character set selected, or a
-	     *  download offer would have been forced and we would
-	     *  not be processing the form here.  We don't yet want
-	     *  to do this unless the server indicated the charset
-	     *  in the original transmission, because otherwise it
-	     *  might be an old server and CGI script which will
-	     *  not parse out the extended charset info, and reject
-	     *  the POST Content-Type as invalid. - FM
-	     */
-	    if (HTMainText->node_anchor->charset != NULL &&
-	        *HTMainText->node_anchor->charset != '\0') {
-		if (strcasecomp(HTMainText->node_anchor->charset,
-				"iso-8859-1") &&
-		    strcasecomp(HTMainText->node_anchor->charset,
-				"us-ascii")) {
-		    StrAllocCat(doc->post_content_type, ";charset=");
-		    StrAllocCat(doc->post_content_type,
-				HTMainText->node_anchor->charset);
-		}
+	/*
+	 *  Append the exended charset info if known, and it is not
+	 *  ISO-8859-1 or US-ASCII.  We'll assume the user has the
+	 *  matching character set selected, or a download offer would
+	 *  have been forced and we would not be processing the form
+	 *  here.  We don't yet want to do this unless the server
+	 *  indicated the charset in the original transmission, because
+	 *  otherwise it might be an old server and CGI script which
+	 *  will not parse out the extended charset info, and reject
+	 *  the POST Content-Type as invalid.  If the ENCTYPE is
+	 *  multipart/form-data and the charset is known, set up a
+	 *  Content-Type string for the text fields and append the
+	 *  charset even if it is ISO-8859-1 or US-ASCII, but don't
+	 *  append it to the post_content_type header.  Note that we do
+	 *  not yet have a way to vary the charset among multipart form
+	 *  fields, so this code assumes it is the same for all of the
+	 *  text fields. - FM
+	 */
+	if (HTMainText->node_anchor->charset != NULL &&
+	    *HTMainText->node_anchor->charset != '\0') {
+	    if (Boundary == NULL &&
+	        strcasecomp(HTMainText->node_anchor->charset, "iso-8859-1") &&
+		strcasecomp(HTMainText->node_anchor->charset, "us-ascii")) {
+		StrAllocCat(doc->post_content_type, "; charset=");
+		StrAllocCat(doc->post_content_type,
+			    HTMainText->node_anchor->charset);
+	    } else if (Boundary != NULL) {
+	        MultipartContentType = (char *)calloc(1,
+			     (40 + strlen(HTMainText->node_anchor->charset)));
+		if (query == NULL)
+		    outofmem(__FILE__, "HText_SubmitForm");
+		sprintf(MultipartContentType,
+			"\r\nContent-Type: text/plain; charset=%s",
+			HTMainText->node_anchor->charset);
 	    }
 	}
     }
@@ -3735,12 +3887,19 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 		        (form_ptr->value && *form_ptr->value != '\0' &&
 		         !strcmp(form_ptr->value, link_value)))) {
 		        if (first_one) {
+			    if (Boundary) {
+			        sprintf(&query[strlen(query)],
+					"--%s\r\n", Boundary);
+			    }
                             first_one=FALSE;
                         } else {
 			    if (PlainText) {
 			        strcat(query, "\n");
 			    } else if (SemiColon) {
 			        strcat(query, ";");
+			    } else if (Boundary) {
+			        sprintf(&query[strlen(query)],
+					"\r\n--%s\r\n", Boundary);
 			    } else {
                                 strcat(query, "&");
 			    }
@@ -3749,6 +3908,14 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			if (PlainText) {
 			    StrAllocCopy(escaped1, (form_ptr->name ?
 			    			    form_ptr->name : ""));
+			} else if (Boundary) {
+			    StrAllocCopy(escaped1,
+			    	    "Content-Disposition: form-data; name=");
+			    StrAllocCat(escaped1, (form_ptr->name ?
+			    			    form_ptr->name : ""));
+			    if (MultipartContentType)
+			        StrAllocCat(escaped1, MultipartContentType);
+			    StrAllocCat(escaped1, "\r\n\r\n");
 			} else {
 		            escaped1 = HTEscape(form_ptr->name,URL_XALPHAS);
 			}
@@ -3772,7 +3939,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 				    form_ptr->cp_submit_value[i] = 173;
 				}
 			    }
-			    if (PlainText) {
+			    if (PlainText || Boundary) {
 			        StrAllocCopy(escaped2,
 					     (form_ptr->cp_submit_value ?
 					      form_ptr->cp_submit_value : ""));
@@ -3796,7 +3963,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 				    form_ptr->value[i] = 173;
 				}
 			    }
-			    if (PlainText) {
+			    if (PlainText || Boundary) {
 			        StrAllocCopy(escaped2, (form_ptr->value ?
 							form_ptr->value : ""));
 			    } else {
@@ -3805,34 +3972,46 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			    }
 		        }
 
-			if (!strcmp(form_ptr->value, "[IMAGE]-Submit"))
+			if (!strcmp(form_ptr->value, "[IMAGE]-Submit")) {
 			    /*
 			     * It's a clickable image submit button.
 			     * Fake a 0,0 coordinate pair, which
 			     * typically returns the image's default. - FM
 			     */
-			    sprintf(&query[strlen(query)],
-				    "%s.x=0%s%s.y=0%s",
-				    escaped1,
-				    (PlainText ?
-				          "\n" : (SemiColon ?
-					  		";" : "&")),
-				    escaped1,
-				    ((PlainText && *escaped1) ?
-				    			 "\n" : ""));
-			else
+			    if (Boundary) {
+			        escaped1[(strlen(escaped1) - 4)] = '\0';
+			        sprintf(&query[strlen(query)],
+				    "%s.x\r\n\r\n0\r\n--%s\r\n%s.y\r\n\r\n0",
+					escaped1,
+					Boundary,
+					escaped1);
+			    } else {
+			        sprintf(&query[strlen(query)],
+					"%s.x=0%s%s.y=0%s",
+					escaped1,
+					(PlainText ?
+					      "\n" : (SemiColon ?
+							    ";" : "&")),
+					escaped1,
+					((PlainText && *escaped1) ?
+				    			     "\n" : ""));
+			    }
+			} else {
 			    /*
 			     * It's a standard submit button.
 			     * Use the name=value pair. = FM
 			     */
 			    sprintf(&query[strlen(query)],
-				    "%s=%s%s%s",
+				    "%s%s%s%s%s",
 				    escaped1,
+				    (Boundary ?
+				    	   "" : "="),
 				    (PlainText ?
 				          "\n" : ""),
 				    escaped2,
 				    ((PlainText && *escaped2) ?
 				    			 "\n" : ""));
+			}
 		        FREE(escaped1);
 		        FREE(escaped2);
 		    }
@@ -3843,12 +4022,19 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 		    /* only add if selected */
 		    if (form_ptr->num_value) {
 	                if (first_one) {
+			    if (Boundary) {
+			        sprintf(&query[strlen(query)],
+					"--%s\r\n", Boundary);
+			    }
 		            first_one=FALSE;
 	                } else {
 			    if (PlainText) {
 			        strcat(query, "\n");
 			    } else if (SemiColon) {
 			        strcat(query, ";");
+			    } else if (Boundary) {
+			        sprintf(&query[strlen(query)],
+					"\r\n--%s\r\n", Boundary);
 			    } else {
 		                strcat(query, "&");
 			    }
@@ -3857,6 +4043,15 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			if (PlainText) {
 			    StrAllocCopy(escaped1, (form_ptr->name ?
 			    			    form_ptr->name : ""));
+			} else if (Boundary) {
+			    StrAllocCopy(escaped1,
+			    	     "Content-Disposition: form-data; name=");
+			    StrAllocCat(escaped1,
+				        (form_ptr->name ?
+			    		 form_ptr->name : ""));
+			    if (MultipartContentType)
+			        StrAllocCat(escaped1, MultipartContentType);
+			    StrAllocCat(escaped1, "\r\n\r\n");
 			} else {
 		            escaped1 = HTEscape(form_ptr->name, URL_XALPHAS);
 			}
@@ -3879,7 +4074,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 				    form_ptr->cp_submit_value[i] = 173;
 				 }
 			    }
-			    if (PlainText) {
+			    if (PlainText || Boundary) {
 			        StrAllocCopy(escaped2,
 					     (form_ptr->cp_submit_value ?
 					      form_ptr->cp_submit_value : ""));
@@ -3904,7 +4099,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 
 				}
 			    }
-			    if (PlainText) {
+			    if (PlainText || Boundary) {
 			        StrAllocCopy(escaped2, (form_ptr->value ?
 							form_ptr->value : ""));
 			    } else {
@@ -3914,8 +4109,10 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			}
 
                         sprintf(&query[strlen(query)],
-				"%s=%s%s%s",
+				"%s%s%s%s%s",
 				escaped1,
+				(Boundary ?
+				       "" : "="),
 				(PlainText ?
 				      "\n" : ""),
 				escaped2,
@@ -3939,7 +4136,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			    form_ptr->value[i] = 173;
 			}
 		    }
-		    if (PlainText) {
+		    if (PlainText || Boundary) {
 		        StrAllocCopy(escaped2, (form_ptr->value ? 
 						form_ptr->value : ""));
 		    } else {
@@ -3955,12 +4152,19 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			 */
 			FREE(previous_blanks);
 		        if (first_one) {
+			    if (Boundary) {
+			        sprintf(&query[strlen(query)],
+					"--%s\r\n", Boundary);
+			    }
                             first_one=FALSE;
                         } else {
 			    if (PlainText) {
 			        strcat(query, "\n");
 			    } else if (SemiColon) {
 			        strcat(query, ";");
+			    } else if (Boundary) {
+			        sprintf(&query[strlen(query)],
+					"\r\n--%s\r\n", Boundary);
 			    } else {
                                 strcat(query, "&");
 			    }
@@ -3968,12 +4172,22 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			if (PlainText) {
 			    StrAllocCopy(escaped1, (form_ptr->name ?
 			    			    form_ptr->name : ""));
+			} else if (Boundary) {
+			    StrAllocCopy(escaped1,
+			    	    "Content-Disposition: form-data; name=");
+			    StrAllocCat(escaped1, (form_ptr->name ?
+			    			    form_ptr->name : ""));
+			    if (MultipartContentType)
+			        StrAllocCat(escaped1, MultipartContentType);
+			    StrAllocCat(escaped1, "\r\n\r\n");
 			} else {
                             escaped1 = HTEscape(form_ptr->name, URL_XALPHAS);
 			}
                         sprintf(&query[strlen(query)],
-				"%s=%s%s%s",
+				"%s%s%s%s%s",
 				escaped1,
+				(Boundary ?
+				       "" : "="),
 				(PlainText ?
 				      "\n" : ""),
 				escaped2,
@@ -3994,6 +4208,9 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			    if (PlainText) {
 			        sprintf(&query[strlen(query)], "%s\n",
 							       escaped2);
+			    } else if (Boundary) {
+			        sprintf(&query[strlen(query)], "%s\r\n",
+							       escaped2);
 			    } else {
 			        sprintf(&query[strlen(query)], "%%0a%s",
 							       escaped2);
@@ -4001,6 +4218,8 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 			} else {
 			    if (PlainText) {
 			        StrAllocCat(previous_blanks, "\n");
+			    } else if (Boundary) {
+			        StrAllocCat(previous_blanks, "\r\n");
 			    } else {
 			        StrAllocCat(previous_blanks, "%0a");
 			    }
@@ -4014,12 +4233,19 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 		case F_OPTION_LIST_TYPE:
 		case F_HIDDEN_TYPE:
 	            if (first_one) {
+			if (Boundary) {
+			    sprintf(&query[strlen(query)],
+				    "--%s\r\n", Boundary);
+			}
 		        first_one=FALSE;
 	            } else {
 		        if (PlainText) {
 			    strcat(query, "\n");
 			} else if (SemiColon) {
 			    strcat(query, ";");
+			} else if (Boundary) {
+			    sprintf(&query[strlen(query)],
+			    	    "\r\n--%s\r\n", Boundary);
 			} else {
 		            strcat(query, "&");
 			}
@@ -4028,6 +4254,14 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 		    if (PlainText) {
 		       StrAllocCopy(escaped1, (form_ptr->name ?
 		       			       form_ptr->name : ""));
+		    } else if (Boundary) {
+			StrAllocCopy(escaped1,
+			    	    "Content-Disposition: form-data; name=");
+			StrAllocCat(escaped1, (form_ptr->name ?
+			    		       form_ptr->name : ""));
+			if (MultipartContentType)
+			    StrAllocCat(escaped1, MultipartContentType);
+			StrAllocCat(escaped1, "\r\n\r\n");
 		    } else {
 		        escaped1 = HTEscape(form_ptr->name, URL_XALPHAS);
 		    }
@@ -4051,7 +4285,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 				form_ptr->cp_submit_value[i] = 173;
 			    }
 			}
-			if (PlainText) {
+			if (PlainText || Boundary) {
 			    StrAllocCopy(escaped2,
 			    		 (form_ptr->cp_submit_value ?
 					  form_ptr->cp_submit_value : ""));
@@ -4075,7 +4309,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 				form_ptr->value[i] = 173;
 			    }
 			}
-			if (PlainText) {
+			if (PlainText || Boundary) {
 			    StrAllocCopy(escaped2, (form_ptr->value ?
 			    			    form_ptr->value : ""));
 			} else {
@@ -4085,8 +4319,10 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 		    }
 
                     sprintf(&query[strlen(query)],
-		    	    "%s=%s%s%s",
+		    	    "%s%s%s%s%s",
 			    escaped1,
+			    (Boundary ?
+			    	   "" : "="),
 			    (PlainText ?
 				  "\n" : ""),
 			    escaped2,
@@ -4106,15 +4342,13 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 
 	anchor_ptr = anchor_ptr->next;
     }
+    if (Boundary) {
+        sprintf(&query[strlen(query)], "\r\n--%s--\r\n", Boundary);
+    }
     FREE(previous_blanks);
 
     if (submit_item->submit_method == URL_MAIL_METHOD) {
-	if (strncmp(submit_item->submit_action, "mailto:", 7)) {
-	    HTAlert(BAD_FORM_MAILTO);
-	    FREE(query);
-	    return;
-	}
-	_user_message("submitting %s", submit_item->submit_action);
+	_user_message("Submitting %s", submit_item->submit_action);
 	if (TRACE) {
 	    fprintf(stderr, "\nGridText - mailto_address: %s\n",
 	    		    (submit_item->submit_action+7));
@@ -4133,14 +4367,16 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
 		   (submit_item->submit_title) :
 		   	     (HText_getTitle() ?
 			      HText_getTitle() : "")),
-		 query);
+		 query,
+		 doc->post_content_type);
 	FREE(query);
+        FREE(doc->post_content_type);
 	return;
     } else {
         _statusline(SUBMITTING_FORM);
     }
    
-    if (submit_item->submit_method == URL_POST_METHOD) {
+    if (submit_item->submit_method == URL_POST_METHOD || Boundary) {
         StrAllocCopy(doc->post_data, query);
         if (TRACE)
 	    fprintf(stderr,"GridText - post_data: %s\n",doc->post_data);
@@ -4156,14 +4392,42 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc,
     }
 }
 
+PUBLIC void HText_DisableCurrentForm NOARGS
+{
+    TextAnchor * anchor_ptr = HTMainText->first_anchor;
+
+    HTFormDisabled = TRUE;
+
+    /*
+     *  Go through list of anchors and set the disabled flag.
+     */
+    while (1) {
+        if (anchor_ptr->link_type == INPUT_ANCHOR &&
+            anchor_ptr->input_field->number == HTFormNumber) {
+
+            anchor_ptr->input_field->disabled = TRUE;
+        }
+
+        if (anchor_ptr == HTMainText->last_anchor)
+            break;
+
+
+        anchor_ptr = anchor_ptr->next;
+    }
+
+    return;
+}
+
 PUBLIC void HText_ResetForm ARGS1(FormInfo *,form)
 {
     TextAnchor * anchor_ptr = HTMainText->first_anchor;
 
     _statusline(RESETTING_FORM);
 
-   /* go through list of anchors and reset values */
-   while (1) {
+    /*
+     *  Go through list of anchors and reset values.
+     */
+    while (1) {
         if (anchor_ptr->link_type == INPUT_ANCHOR) {
             if (anchor_ptr->input_field->number == form->number) {
 
@@ -4198,9 +4462,7 @@ PUBLIC void HText_ResetForm ARGS1(FormInfo *,form)
 
 
         anchor_ptr = anchor_ptr->next;
-   }
-
-
+    }
 }
 
 PUBLIC void HText_activateRadioButton ARGS1(FormInfo *,form)
diff --git a/src/GridText.h b/src/GridText.h
index c20ae2ec..0ed5cad0 100644
--- a/src/GridText.h
+++ b/src/GridText.h
@@ -64,7 +64,12 @@ extern int HText_sourceAnchors PARAMS((HText * text));
 extern void HText_setStale PARAMS((HText * text));
 extern void HText_refresh PARAMS((HText * text));
 extern char * HText_getTitle NOPARAMS;
+extern char * HText_getSugFname NOPARAMS;
+extern char * HText_getLastModified NOPARAMS;
+extern char * HText_getDate NOPARAMS;
+extern char * HText_getServer NOPARAMS;
 extern char * HText_getOwner NOPARAMS;
+extern void HText_setMainTextOwner PARAMS((CONST char * owner));
 extern char * HText_getRevTitle NOPARAMS;
 extern void print_wwwfile_to_fd PARAMS((FILE * fp, int is_reply));
 extern BOOLEAN HTFindPoundSelector PARAMS((char *selector));
@@ -78,6 +83,9 @@ extern char * HTLoadedDocumentURL NOPARAMS;
 extern char * HTLoadedDocumentPost_data NOPARAMS;
 extern char * HTLoadedDocumentTitle NOPARAMS;
 extern BOOLEAN HTLoadedDocumentIsHEAD NOPARAMS;
+extern char * HTLoadedDocumentCharset NOPARAMS;
+extern void HText_setNodeAnchorBookmark PARAMS((CONST char *bookmark));
+extern char * HTLoadedDocumentBookmark NOPARAMS;
 extern int HText_LastLineSize PARAMS((HText *me));
 extern int HText_PreviousLineSize PARAMS((HText *me));
 extern void HText_NegateLineOne PARAMS((HText *text));
@@ -99,6 +107,7 @@ extern char * HText_setLastOptionValue PARAMS((HText *text, char *value,
 extern int HText_beginInput PARAMS((HText *text, InputFieldData *I));
 extern void HText_SubmitForm PARAMS((FormInfo *submit_item, document *doc,
 				     char *link_name, char *link_value));
+extern void HText_DisableCurrentForm NOPARAMS;
 extern void HText_ResetForm PARAMS((FormInfo *form));
 extern void HText_activateRadioButton PARAMS((FormInfo *form));
 
diff --git a/src/HTAlert.c b/src/HTAlert.c
index 79a4a7b0..5a3ddc1c 100644
--- a/src/HTAlert.c
+++ b/src/HTAlert.c
@@ -13,11 +13,12 @@
 #include "HTUtils.h"
 #include "tcp.h"
 #include "HTAlert.h"
+#include "LYGlobalDefs.h"
+#include "LYCurses.h"
 #include "LYStrings.h"
 #include "LYUtils.h"
 #include "LYSignal.h"
 #include "GridText.h"
-#include "LYGlobalDefs.h"
 
 #include "LYLeaks.h"
 
@@ -214,3 +215,109 @@ PUBLIC void HTPromptUsernameAndPassword ARGS3(CONST char *,     Msg,
     }
 }
 
+
+#define	SERVER_ASKED_FOR_REDIRECTION \
+ "Server asked for redirection of POST content to"
+#define	PROCEED_GET_CANCEL "P)roceed, use G)ET or C)ancel "
+#define	ADVANCED_POST_REDIRECT \
+ "Redirection of POST content. P)roceed, see U)RL, use G)ET or C)ancel"
+#define	LOCATION_HEADER "Location: "
+
+/*      Confirm redirection of POST		HTConfirmPostRedirect()
+**
+** On entry,
+**      redirecting_url             is the Location.
+**
+** On exit,
+**      Returns 0 on cancel,
+**	  1 for redirect of POST with content,
+**	303 for redirect as GET without content
+*/
+PUBLIC int HTConfirmPostRedirect ARGS1(
+	CONST char *,	redirecting_url)
+{
+    char *show_POST_url = NULL;
+    char url[256];
+    int on_screen = 0;	/* 0 - show menu
+   			 * 1 - show url
+			 * 2 - menu is already on screen */
+
+    if (dump_output_immediately)
+	/*
+	 *  Treat as 303 (GET without content) if not interactive.
+	 */
+        return 303;
+
+    if (user_mode == NOVICE_MODE) {
+        on_screen = 2;
+        move(LYlines-2, 0);
+        addstr(SERVER_ASKED_FOR_REDIRECTION);
+	clrtoeol();
+        move(LYlines-1, 0);
+	sprintf(url, "URL: %.*s",
+		    (LYcols < 250 ? LYcols-6 : 250), redirecting_url);
+        addstr(url);
+	clrtoeol();
+        _statusline(PROCEED_GET_CANCEL);
+    } else {
+	StrAllocCopy(show_POST_url, LOCATION_HEADER);
+	StrAllocCat(show_POST_url, redirecting_url);
+    }
+    while (1) {
+	int c;  
+
+	switch (on_screen) {
+	    case 0:
+	        _statusline(ADVANCED_POST_REDIRECT);
+		break;
+	    case 1:
+	        _statusline(show_POST_url);
+	}
+	c = LYgetch();
+	switch (TOUPPER(c)) {
+	    case 'P':
+		/*
+		 *  Proceed with 301 or 302 redirect of POST
+		 *  (we check only for 0 and 303 in HTTP.c).
+		 */
+	        FREE(show_POST_url);
+		return 1;	
+
+ 	    case 7:
+ 	    case 'C':
+	        /*
+		 * Cancel request.
+		 */
+	        FREE(show_POST_url);
+		return 0;
+
+	    case 'G':
+	        /*
+		 *  Treat as 303 (GET without content).
+		 */
+	        FREE(show_POST_url);
+		return 303;
+
+	    case 'U':
+	        /*
+		 *  Show URL for intermediate or advanced mode.
+		 */
+	        if (user_mode != NOVICE_MODE)
+		    if (on_screen == 1)
+			on_screen = 0;
+		    else
+			on_screen = 1;
+		break;
+
+	    default:
+	        /*
+		 *  Get another character.
+		 */
+		if (on_screen == 1)
+		    on_screen = 0;
+		else
+		    on_screen = 2;
+	}
+    }
+}
+
diff --git a/src/HTAlert.h b/src/HTAlert.h
index 8ce0be53..dc470cfd 100644
--- a/src/HTAlert.h
+++ b/src/HTAlert.h
@@ -81,6 +81,20 @@ extern void HTPromptUsernameAndPassword PARAMS((
 	char **		username,
 	char **		password));
 
+
+/*      Confirm redirection of POST		HTConfirmPostRedirect()
+**
+** On entry,
+**      redirecting_url             is the Location.
+**
+** On exit,
+**      Returns 0 on cancel,
+**	  1 for redirect of POST with content,
+**	303 for redirect as GET without content
+*/
+extern int HTConfirmPostRedirect PARAMS((
+	CONST char *	redirecting_url));
+
 /*
 
     */
diff --git a/src/HTFWriter.c b/src/HTFWriter.c
index a3b46f0c..e9f7d1ee 100644
--- a/src/HTFWriter.c
+++ b/src/HTFWriter.c
@@ -50,6 +50,11 @@ PUBLIC unsigned long LYVMS_FixedLengthRecords PARAMS((char *filename));
 #endif /* USE_COMMAND_FILE */
 #endif /* VMS */
 
+PUBLIC HTStream* HTSaveToFile PARAMS((
+        HTPresentation *       pres,
+        HTParentAnchor *       anchor,
+        HTStream *             sink));
+
 #define FREE(x) if (x) {free(x); x = NULL;}
 
 
@@ -201,13 +206,23 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 		    StrAllocCat(addr, path);
 #endif /* VMS */
 		    StrAllocCopy(me->anchor->FileCache, path);
+		    FREE(path);
 		    FREE(me->anchor->content_encoding);
 		    status = HTLoadFile(addr,
 			    		me->anchor,
 			    		me->pres->rep_out,
 					me->sink);
+		    if (dump_output_immediately &&
+		        me->pres->rep_out == HTAtom_for("www/present")) {
+			FREE(addr);
+			remove(me->anchor->FileCache);
+			FREE(me->anchor->FileCache);
+			FREE(me->remove_command);
+			FREE(me->end_command);
+			FREE(me);
+		        return;
+		    }
 		}
-		FREE(path);
 		FREE(addr);
 	    }
 
@@ -251,9 +266,10 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 	FREE(me->end_command);
     }
 
-    FREE(me);
-
     if (dump_output_immediately) {
+        if (me->anchor->FileCache)
+            remove(me->anchor->FileCache);
+	FREE(me);
         (void) signal(SIGHUP, SIG_DFL);
         (void) signal(SIGTERM, SIG_DFL);
 #ifndef VMS
@@ -265,6 +281,9 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 #endif /* SIGTSTP */
         exit(0);
     }
+
+    FREE(me);
+    return;
 }
 
 /*	Abort writing
@@ -368,6 +387,10 @@ PUBLIC HTStream* HTSaveAndExecute ARGS3(
 
 #if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS)
     if (pres->quality == 999.0) { /* exec link */
+        if (dump_output_immediately) {
+	    LYCancelledFetch = TRUE;
+	    return(NULL);
+	}
         if (no_exec) {
             _statusline(EXECUTION_DISABLED);
             sleep(AlertSecs);
@@ -390,6 +413,10 @@ PUBLIC HTStream* HTSaveAndExecute ARGS3(
     }
 #endif /* EXEC_LINKS || EXEC_SCRIPTS */
     
+    if (dump_output_immediately) {
+        return(HTSaveToFile(pres, anchor, sink));
+    }
+
     me = (HTStream*)calloc(sizeof(*me),1);
     if (me == NULL)
         outofmem(__FILE__, "HTSaveAndExecute");
@@ -681,6 +708,17 @@ PUBLIC HTStream* HTSaveToFile ARGS3(
     _statusline(RETRIEVING_FILE);
 
     StrAllocCopy(anchor->FileCache, fnam);
+    if (!strncasecomp(pres->rep->name, "text/html", 9)) {
+        /*
+	 *  Add the document's URL as a BASE tag at the top of the file,
+	 *  so that any partial or relative URLs within it will be resolved
+	 *  relative to that if no BASE tag is present and replaces it.
+	 *  Note that the markup will be technically invalid if a DOCTYPE
+	 *  declaration, or HTML or HEAD tags, are present, and thus the
+	 *  file may need editing for perfection. - FM
+	 */
+        fprintf(ret_obj->fp, "<BASE HREF=\"%s\">\n\n", anchor->address);
+    }
     return ret_obj;
 }
 
diff --git a/src/HTInit.c b/src/HTInit.c
index 0038e605..63933236 100644
--- a/src/HTInit.c
+++ b/src/HTInit.c
@@ -141,6 +141,12 @@ PUBLIC void HTFormatInit NOARGS
 /*
  *  Now add our basic conversions.
  */
+ HTSetConversion("text/x-sgml",
+ 			      "www/source",  HTPlainPresent, 1.0, 0.0, 0.0, 0);
+ HTSetConversion("text/x-sgml",
+ 			      "www/present", HTMLPresent,    1.0, 0.0, 0.0, 0);
+ HTSetConversion("text/sgml", "www/source",  HTPlainPresent, 1.0, 0.0, 0.0, 0);
+ HTSetConversion("text/sgml", "www/present", HTMLPresent,    1.0, 0.0, 0.0, 0);
  HTSetConversion("text/plain","www/present", HTPlainPresent, 1.0, 0.0, 0.0, 0);
  HTSetConversion("text/html", "www/source",  HTPlainPresent, 1.0, 0.0, 0.0, 0);
  HTSetConversion("text/html", "text/x-c",    HTMLToC, 	     0.5, 0.0, 0.0, 0);
diff --git a/src/HTML.c b/src/HTML.c
index 885a5596..e96ab89d 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -1,10 +1,10 @@
 /*		Structured stream to Rich hypertext converter
 **		============================================
 **
-**	This generates of a hypertext object.  It converts from the
-**	structured stream interface fro HTMl events into the style-
-**	oriented iunterface of the HText.h interface.  This module is
-**	only used in clients and shouldnot be linked into servers.
+**	This generates a hypertext object.  It converts from the
+**	structured stream interface of HTML events into the style-
+**	oriented interface of the HText.h interface.  This module is
+**	only used in clients and should not be linked into servers.
 **
 **	Override this module if making a new GUI browser.
 **
@@ -13,43 +13,31 @@
 */
 #include "HTUtils.h"
 #include "tcp.h"
-
 #include "HTML.h"
-
-/* #define CAREFUL		 Check nesting here not really necessary */
-
-/*#include <ctype.h> included by HTUtils.h -- FM */
-/*#include <stdio.h> included by HTUtils.h -- FM */
-
 #include "HTCJK.h"
 #include "HTAtom.h"
 #include "HTChunk.h"
 #include "HText.h"
 #include "HTStyle.h"
-
 #include "HTAlert.h"
 #include "HTMLGen.h"
 #include "HTParse.h"
-
 #include "HTNestedList.h"
 #include "HTForms.h"
-
 #include "GridText.h"
-
 #include "HTFont.h"
-
-#ifdef VMS
-#include "LYCurses.h"
-#include "HTVMSUtils.h"
-#endif /* VMS */
-
-
 #include "LYGlobalDefs.h"
 #include "LYSignal.h"
 #include "LYUtils.h"
 #include "LYCharSets.h"
 #include "LYCharUtils.h"
 #include "LYMap.h"
+#include "LYBookmark.h"
+
+#ifdef VMS
+#include "LYCurses.h"
+#include "HTVMSUtils.h"
+#endif /* VMS */
 
 #include "LYexit.h"
 #include "LYLeaks.h"
@@ -305,7 +293,7 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
     /*
      *  Ignore all non-MAP content when just
      *  scanning a document for MAPs. - FM
-     *  
+     */
     if (LYMapsOnly)
         return;
 
@@ -414,8 +402,7 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
 	    B_inPRE = TRUE;
 
 	} else if (!strcmp(me->sp->style->name,"Listing") ||
-		   !strcmp(me->sp->style->name,"Example") ||
-		   !strcmp(me->sp->style->name,"Style")) {
+		   !strcmp(me->sp->style->name,"Example")) {
 	    if (c != '\r') {
 		B_inP = TRUE; 
 		B_inLABEL = FALSE; 
@@ -637,8 +624,6 @@ PRIVATE void HTML_start_element ARGS5(
 	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
 	    B_inUnderline = FALSE;
 	}
-	FREE(base_href);
-        B_inBASE = FALSE;
 	break;
 
     case HTML_HEAD:
@@ -652,8 +637,6 @@ PRIVATE void HTML_start_element ARGS5(
 	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
 	    B_inUnderline = FALSE;
 	}
-	FREE(base_href);
-        B_inBASE = FALSE;
 	break;
 
     case HTML_BASE:
@@ -1023,9 +1006,9 @@ PRIVATE void HTML_start_element ARGS5(
 			}
 			B_CurrentA = HTAnchor_findChildAndLink(
 				me->node_anchor,		/* Parent */
-				(id_string ? id_string : 0),	/* Tag */
+				id_string,			/* Tag */
 				href,				/* Addresss */
-				0);				/* Type */
+				(void *)0);			/* Type */
 			if (id_string)
 			    *cp = '#';
 			FREE(id_string);
@@ -1225,9 +1208,9 @@ PRIVATE void HTML_start_element ARGS5(
 		 */
 	        B_CurrentA = HTAnchor_findChildAndLink(
 				me->node_anchor,	/* Parent */
-		    		0,			/* Tag */
-		    		href ? href : 0,	/* Addresss */
-		    		0);			/* Type */
+		    		NULL,			/* Tag */
+		    		href,			/* Addresss */
+		    		(void *)0);		/* Type */
 		{
 		    if (dest = HTAnchor_parent(
 			    HTAnchor_followMainLink((HTAnchor*)B_CurrentA)
@@ -1240,8 +1223,8 @@ PRIVATE void HTML_start_element ARGS5(
 		        (B_ID_A = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					LYToolbarName,		/* Tag */
-					0,			/* Addresss */
-					0))) {			/* Type */
+					NULL,			/* Addresss */
+					(void *)0))) {		/* Type */
 			HText_beginAnchor(me->text, B_ID_A);
 			HText_endAnchor(me->text);
 			HText_setToolbar(me->text);
@@ -1439,9 +1422,9 @@ PRIVATE void HTML_start_element ARGS5(
 
 	    B_CurrentA = HTAnchor_findChildAndLink(
 				me->node_anchor,	/* Parent */
-				0,			/* Tag */
+				NULL,			/* Tag */
 				href,			/* Addresss */
-				0);			/* Type */
+				(void *)0);		/* Type */
 	    HTML_EnsureSingleSpace(me);
 	    if (B_inUnderline == FALSE)
 	        HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR);
@@ -1478,8 +1461,8 @@ PRIVATE void HTML_start_element ARGS5(
 	    (B_ID_A = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					LYToolbarName,		/* Tag */
-					0,			/* Addresss */
-					0))) {			/* Type */
+					NULL,			/* Addresss */
+					(void *)0))) {		/* Type */
 	    HText_beginAnchor(me->text, B_ID_A);
 	    HText_endAnchor(me->text);
 	    HText_setToolbar(me->text);
@@ -1938,7 +1921,7 @@ PRIVATE void HTML_start_element ARGS5(
 	 *  use chevrons, but for now we'll always use double-
 	 *  or single-quotes. - FM
 	 */
-	if (Quote_Level == ((Quote_Level/2)*2))
+	if (!(Quote_Level & 1))
 	    HText_appendCharacter(me->text, '"');
 	else
 	    HText_appendCharacter(me->text, '`');
@@ -2517,13 +2500,13 @@ PRIVATE void HTML_start_element ARGS5(
 	    }
 
 	    B_CurrentA = HTAnchor_findChildAndLink(
-			me->node_anchor,		/* Parent */
-			(id_string ? id_string : 0),	/* Tag */
-			(href ? href : 0),		/* Address */
+			me->node_anchor,			/* Parent */
+			id_string,				/* Tag */
+			href,					/* Address */
 			(present &&
 			 present[HTML_A_TYPE] &&
 			   value[HTML_A_TYPE]) ? 
-   (HTLinkType*)HTAtom_for(value[HTML_A_TYPE]) : 0);	/* Type */
+   (HTLinkType*)HTAtom_for(value[HTML_A_TYPE]) : (void *)0);	/* Type */
 
 	    /*
 	     *	Get rid of href since no longer needed.
@@ -2821,17 +2804,17 @@ PRIVATE void HTML_start_element ARGS5(
 		        if (B_ID_A = HTAnchor_findChildAndLink(
 				  me->node_anchor,	/* Parent */
 				  id_string,		/* Tag */
-				  0,			/* Addresss */
-				  0)) {			/* Type */
+				  NULL,			/* Addresss */
+				  (void *)0)) {		/* Type */
 		            HText_beginAnchor(me->text, B_ID_A);
 		            HText_endAnchor(me->text);
 		        }
 		    }
 		    B_CurrentA = HTAnchor_findChildAndLink(
 		    		me->node_anchor,	/* Parent */
-				0,			/* Tag */
+				NULL,			/* Tag */
 				map_href,		/* Addresss */
-				0);			/* Type */
+				(void *)0);		/* Type */
 		    if (B_CurrentA && title) {
 			if (dest = HTAnchor_parent(
 				HTAnchor_followMainLink((HTAnchor*)B_CurrentA)
@@ -2862,8 +2845,8 @@ PRIVATE void HTML_start_element ARGS5(
 		    if (B_ID_A = HTAnchor_findChildAndLink(
 				  me->node_anchor,	/* Parent */
 				  id_string,		/* Tag */
-				  0,			/* Addresss */
-				  0)) {			/* Type */
+				  NULL,			/* Addresss */
+				  (void *)0)) {		/* Type */
 		        HText_beginAnchor(me->text, B_ID_A);
 		        HText_endAnchor(me->text);
 		    }
@@ -2875,17 +2858,17 @@ PRIVATE void HTML_start_element ARGS5(
 		    if (B_ID_A = HTAnchor_findChildAndLink(
 				  me->node_anchor,	/* Parent */
 				  id_string,		/* Tag */
-				  0,			/* Addresss */
-				  0)) {			/* Type */
+				  NULL,			/* Addresss */
+				  (void *)0)) {		/* Type */
 		        HText_beginAnchor(me->text, B_ID_A);
 		        HText_endAnchor(me->text);
 		    }
 		}
 		B_CurrentA = HTAnchor_findChildAndLink(
 		    		me->node_anchor,	/* Parent */
-				0,			/* Tag */
+				NULL,			/* Tag */
 				map_href,		/* Addresss */
-				0);			/* Type */
+				(void *)0);		/* Type */
 		if (B_CurrentA && title) {
 		    if (dest = HTAnchor_parent(
 				HTAnchor_followMainLink((HTAnchor*)B_CurrentA)
@@ -2916,8 +2899,8 @@ PRIVATE void HTML_start_element ARGS5(
 		    if (B_ID_A = HTAnchor_findChildAndLink(
 				  me->node_anchor,	/* Parent */
 				  id_string,		/* Tag */
-				  0,			/* Addresss */
-				  0)) {			/* Type */
+				  NULL,			/* Addresss */
+				  (void *)0)) {		/* Type */
 		        HText_beginAnchor(me->text, B_ID_A);
 		        HText_endAnchor(me->text);
 		    }
@@ -2929,9 +2912,9 @@ PRIVATE void HTML_start_element ARGS5(
 	     */
 	    B_CurrentA = HTAnchor_findChildAndLink(
 			me->node_anchor,		/* Parent */
-			0,				/* Tag */
-			href ? href : 0,		/* Addresss */
-			0);				/* Type */
+			NULL,				/* Tag */
+			href,				/* Addresss */
+			(void *)0);			/* Type */
 	    FREE(href);
 	    HText_beginAnchor(me->text, B_CurrentA);
 	    if (B_inBoldH == FALSE)
@@ -2969,9 +2952,9 @@ PRIVATE void HTML_start_element ARGS5(
 	    }
 	    B_CurrentA = HTAnchor_findChildAndLink(
 		    		me->node_anchor,	/* Parent */
-				0,			/* Tag */
+				NULL,			/* Tag */
 				map_href,		/* Addresss */
-				0);			/* Type */
+				(void *)0);		/* Type */
 	    if (B_CurrentA && title) {
 		if (dest = HTAnchor_parent(
 				HTAnchor_followMainLink((HTAnchor*)B_CurrentA)
@@ -3007,8 +2990,8 @@ PRIVATE void HTML_start_element ARGS5(
 		if (B_ID_A = HTAnchor_findChildAndLink(
 				  me->node_anchor,	/* Parent */
 				  id_string,		/* Tag */
-				  0,			/* Addresss */
-				  0)) {			/* Type */
+				  NULL,			/* Addresss */
+				  (void *)0)) {		/* Type */
 		    HText_beginAnchor(me->text, B_ID_A);
 		    HText_endAnchor(me->text);
 		}
@@ -3238,9 +3221,9 @@ PRIVATE void HTML_start_element ARGS5(
 
 		if ((B_CurrentA = HTAnchor_findChildAndLink(
 		       			me->node_anchor,	/* Parent */
-		       			0,			/* Tag */
+		       			NULL,			/* Tag */
 		       			href,			/* Addresss */
-		       			0))) {			/* Type */
+		       			(void *)0))) {		/* Type */
 		    HText_beginAnchor(me->text, B_CurrentA);
 		    if (B_inBoldH == FALSE)
 			HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
@@ -3415,9 +3398,9 @@ PRIVATE void HTML_start_element ARGS5(
 
 		if ((B_CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
-					0,			/* Tag */
+					NULL,			/* Tag */
 					href,			/* Addresss */
-					0))) {			/* Type */
+					(void *)0))) {		/* Type */
 		    if (!me->text) {
 		        UPDATE_STYLE;
 		    } else {
@@ -3566,9 +3549,9 @@ PRIVATE void HTML_start_element ARGS5(
 	    if ((href && *href) &&
 	        (B_CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
-					0,			/* Tag */
+					NULL,			/* Tag */
 					href,			/* Addresss */
-					0))) {			/* Type */
+					(void *)0))) {		/* Type */
 		HText_beginAnchor(me->text, B_CurrentA);
 		if (B_inBoldH == FALSE)
 		    HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
@@ -3632,9 +3615,9 @@ PRIVATE void HTML_start_element ARGS5(
 	        UPDATE_STYLE;
 	    if ((B_CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
-					0,			/* Tag */
+					NULL,			/* Tag */
 					href,			/* Addresss */
-					0))) {			/* Type */
+					(void *)0))) {		/* Type */
 		HTML_put_character(me, ' ');  /* space char may be ignored */
 		me->in_word = NO;
 		HText_beginAnchor(me->text, B_CurrentA);
@@ -3741,9 +3724,9 @@ PRIVATE void HTML_start_element ARGS5(
 
 		if ((B_CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
-					0,			/* Tag */
+					NULL,			/* Tag */
 					href,			/* Addresss */
-					0))) {			/* Type */
+					(void *)0))) {		/* Type */
 		    HText_beginAnchor(me->text, B_CurrentA);
 		    if (B_inBoldH == FALSE)
 			HText_appendCharacter(me->text,LY_BOLD_START_CHAR);
@@ -3885,9 +3868,9 @@ PRIVATE void HTML_start_element ARGS5(
 	    }
 	    if (action) {
 	        source = HTAnchor_findChildAndLink(me->node_anchor, 
-						   0,
+						   NULL,
 						   action,
-						   0);
+						   (void *)0);
 		if (link_dest = HTAnchor_followMainLink((HTAnchor *)source)) {
 		    /*
 		     *  Memory leak fixed.
@@ -4033,6 +4016,7 @@ PRIVATE void HTML_start_element ARGS5(
 		     *  Not yet implemented.
 		     */
 		    HTML_put_string(me,"[RANGE Input] (Not yet implemented.)");
+		    HText_DisableCurrentForm();
 		    if (TRACE)
 		        fprintf(stderr, "HTML: Ignoring TYPE=\"range\"\n");
 		    break;
@@ -4052,6 +4036,7 @@ PRIVATE void HTML_start_element ARGS5(
 		        HText_appendCharacter(me->text,
 					      LY_UNDERLINE_END_CHAR);
 		    }
+		    HText_DisableCurrentForm();
 		    if (TRACE)
 		        fprintf(stderr, "HTML: Ignoring TYPE=\"file\"\n");
 		    break;
@@ -4232,8 +4217,8 @@ PRIVATE void HTML_start_element ARGS5(
 	        (B_ID_A = HTAnchor_findChildAndLink(
 				me->node_anchor,	 /* Parent */
 				id_string,		 /* Tag */
-				0,			 /* Addresss */
-				0))) {			 /* Type */
+				NULL,			 /* Addresss */
+				(void *)0))) {		 /* Type */
 		if (!me->text)
 		    UPDATE_STYLE;
 		HText_beginAnchor(me->text, B_ID_A);
@@ -4309,15 +4294,27 @@ PRIVATE void HTML_start_element ARGS5(
 		select_disabled=YES;
 	    if (present && present[HTML_SELECT_SIZE] &&
 	        value[HTML_SELECT_SIZE] && *value[HTML_SELECT_SIZE]) {
+#ifdef NOTDEFINED
 		StrAllocCopy(size, value[HTML_SELECT_SIZE]);
+#else
+		/*
+		 *  Let the size be determined by the number of OPTIONs. - FM
+		 */
+		if (TRACE)
+		    fprintf(stderr,
+		    	    "HTML: Ignoring SIZE=\"%s\" for SELECT.\n",
+		    	    (char *)value[HTML_SELECT_SIZE]);
+#endif /* NOTDEFINED */
 	    }
 
-	    if (B_inBoldH == TRUE && multiple == NO) {
+	    if (B_inBoldH == TRUE &&
+	        (multiple == NO || LYSelectPopups == FALSE)) {
 	        HText_appendCharacter(me->text,LY_BOLD_END_CHAR);
 		B_inBoldH = FALSE;
 		B_needBoldH = TRUE;
 	    }
-	    if (B_inUnderline == TRUE && multiple == NO) {
+	    if (B_inUnderline == TRUE &&
+	        (multiple == NO || LYSelectPopups == FALSE)) {
 	        HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
 		B_inUnderline = FALSE;
 	    }
@@ -4376,12 +4373,15 @@ PRIVATE void HTML_start_element ARGS5(
 	    }
 
 	    /*
-	     *  If its not a multiple option list then don't
-	     *  use the checkbox method, and don't put
-	     *  anything on the screen yet.
+	     *  If its not a multiple option list and select popups
+	     *  are enabled, then don't use the checkbox/button method,
+	     *  and don't put anything on the screen yet.
 	     */
-	    if (first_option || HTCurSelectGroupType == F_CHECKBOX_TYPE) {
-		if (HTCurSelectGroupType == F_CHECKBOX_TYPE) {
+	    if (first_option ||
+	        HTCurSelectGroupType == F_CHECKBOX_TYPE ||
+		LYSelectPopups == FALSE) {
+		if (HTCurSelectGroupType == F_CHECKBOX_TYPE ||
+		    LYSelectPopups == FALSE) {
 	            /*
 		     *  Start a newline before each option.
 		     */
@@ -4405,7 +4405,9 @@ PRIVATE void HTML_start_element ARGS5(
 
 	        I.type = "OPTION";
     
-	        if (present && present[HTML_OPTION_SELECTED])
+	        if ((present && present[HTML_OPTION_SELECTED]) ||
+		    (first_option && LYSelectPopups == FALSE &&
+		     HTCurSelectGroupType == F_RADIO_TYPE))
 		    I.checked=YES;
 
 		if (present && present[HTML_OPTION_VALUE] &&
@@ -4445,8 +4447,8 @@ PRIVATE void HTML_start_element ARGS5(
 		    if (B_ID_A = HTAnchor_findChildAndLink(
 				    me->node_anchor,	   /* Parent */
 				    value[HTML_OPTION_ID], /* Tag */
-				    0,			   /* Addresss */
-				    0)) {		   /* Type */
+				    NULL,		   /* Addresss */
+				    (void *)0)) {	   /* Type */
 			HText_beginAnchor(me->text, B_ID_A);
 			HText_endAnchor(me->text);
 		        I.id = (char *)value[HTML_OPTION_ID];
@@ -4455,9 +4457,8 @@ PRIVATE void HTML_start_element ARGS5(
 
 	        HText_beginInput(me->text, &I);
     
-	        first_option = FALSE;
-
-		if (HTCurSelectGroupType == F_CHECKBOX_TYPE) {
+		if (HTCurSelectGroupType == F_CHECKBOX_TYPE ||
+		    LYSelectPopups == FALSE) {
 	            /*
 		     *  Put 3 underscores and one space before each option.
 		     */
@@ -4472,10 +4473,14 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  Get ready for the next value.
 	     */
             HTChunkClear(&me->option);
-	    if (present && present[HTML_OPTION_SELECTED])
-		LastOptionChecked=YES;
+	    if ((present && present[HTML_OPTION_SELECTED]) ||
+	        (first_option && LYSelectPopups == FALSE &&
+		 HTCurSelectGroupType == F_RADIO_TYPE))
+		LastOptionChecked = TRUE;
 	    else
-		LastOptionChecked=NO;
+		LastOptionChecked = FALSE;
+	    first_option = FALSE;
+
 
 	    if (present && present[HTML_OPTION_VALUE] &&
 	        value[HTML_OPTION_VALUE])
@@ -4596,6 +4601,9 @@ PRIVATE void HTML_end_element ARGS3(
 	int,			element_number,
 	char **,		include)
 {
+    int i;
+    char *temp = NULL;
+
 #ifdef CAREFUL			/* parser assumed to produce good nesting */
     if (element_number != me->sp[0].tag_number) {
         fprintf(stderr, 
@@ -4604,15 +4612,23 @@ PRIVATE void HTML_end_element ARGS3(
 		HTML_dtd.tags[me->sp->tag_number].name);
 		/* panic */
     }
-#endif
+#endif /* CAREFUL */
+
+    /*
+     *  If we're seeking MAPs, skip everything that's
+     *  not a MAP or AREA tag. - FM
+     */
     if (LYMapsOnly) {
         if (!(element_number == HTML_MAP || element_number == HTML_AREA)) {
 	    return;
 	}
     }
-    
+
+    /*
+     *  Pop state off stack.
+     */
     if (me->sp < me->stack + MAX_NESTING+1) {
-        (me->sp)++;				/* Pop state off stack */
+        (me->sp)++;
         if (TRACE)
 	    fprintf(stderr,
 	    	    "HTML:end_element: Popped style off stack - %s\n",
@@ -4623,7 +4639,9 @@ PRIVATE void HTML_end_element ARGS3(
   "Stack underflow error!  Tried to pop off more styles than exist in stack\n");
     }
     
-    /* Check for unclosed TEXTAREA */
+    /*
+     *  Check for unclosed TEXTAREA. - FM
+     */
     if (B_inTEXTAREA && element_number != HTML_TEXTAREA)
         if (TRACE) {
 	    fprintf(stderr, "HTML: Missing TEXTAREA end tag\n");
@@ -4633,6 +4651,9 @@ PRIVATE void HTML_end_element ARGS3(
 	    sleep(MessageSecs);
 	}
 
+    /*
+     *  Handle the end tag. - FM
+     */
     switch(element_number) {
 
     case HTML_HTML:
@@ -4647,8 +4668,6 @@ PRIVATE void HTML_end_element ARGS3(
 	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
 	    B_inUnderline = FALSE;
 	}
-	FREE(base_href);
-        B_inBASE = FALSE;
 	if (B_inA || B_inFORM || B_inSELECT || B_inTEXTAREA)
 	    if (TRACE)
 	        fprintf(stderr,
@@ -4683,6 +4702,36 @@ PRIVATE void HTML_end_element ARGS3(
         HTChunkTerminate(&me->title);
     	HTAnchor_setTitle(me->node_anchor, me->title.data);
         HTChunkClear(&me->title);
+	/*
+	 *  Check if it's a bookmark file, and if so, insert the
+	 *  current description string and filepath for it. - FM
+	 */
+	if (me->node_anchor->bookmark && *me->node_anchor->bookmark) {
+	    for (i = 0; i <= MBM_V_MAXFILES; i++) {
+	        if (MBM_A_subbookmark[i] &&
+		    !strcmp(MBM_A_subbookmark[i],
+		    	    me->node_anchor->bookmark)) {
+		    StrAllocCat(*include, "<H2><EM>Description:</EM> ");
+		    StrAllocCopy(temp,
+		    		 ((MBM_A_subdescript[i] &&
+				   *MBM_A_subdescript[i]) ?
+				     MBM_A_subdescript[i] : "(none)"));
+		    LYEntify((char **)&temp, TRUE);
+		    StrAllocCat(*include, temp);
+		    StrAllocCat(*include,
+		    		"<BR><EM>&nbsp;&nbsp;&nbsp;Filepath:</EM> ");
+		    StrAllocCopy(temp,
+		    		 ((MBM_A_subbookmark[i] &&
+				   *MBM_A_subbookmark[i]) ?
+				     MBM_A_subbookmark[i] : "(unknown)"));
+		    LYEntify((char **)&temp, TRUE);
+		    StrAllocCat(*include, temp);
+		    FREE(temp);
+		    StrAllocCat(*include, "</H2>");
+		    break;
+		}
+	    }
+	}
 	break;
 	
     case HTML_STYLE:
@@ -4886,7 +4935,7 @@ PRIVATE void HTML_end_element ARGS3(
 	 *  use chevrons, but for now we'll always use double-
 	 *  or single-quotes. - FM
 	 */
-	if (Quote_Level == ((Quote_Level/2)*2))
+	if (!(Quote_Level & 1))
 	    HText_appendCharacter(me->text, '"');
 	else
 	    HText_appendCharacter(me->text, '\'');
@@ -5508,9 +5557,10 @@ End_Object:
 
 	    LastOptionChecked = FALSE;
 
-	    if (HTCurSelectGroupType == F_CHECKBOX_TYPE) {
+	    if (HTCurSelectGroupType == F_CHECKBOX_TYPE ||
+	        LYSelectPopups == FALSE) {
 	            /*
-		     *  Start a newline after the last checkbox option.
+		     *  Start a newline after the last checkbox/button option.
 		     */
 		    HTML_EnsureSingleSpace(me);
 	    } else {
@@ -5648,11 +5698,22 @@ PUBLIC void HTML_free ARGS1(HTStructured *, me)
     UPDATE_STYLE;		/* Creates empty document here! */
     if (me->comment_end)
 		HTML_put_string(me,me->comment_end);
-    HText_endAppend(me->text);
+    if (me->text) {
+	if (B_inUnderline) {
+	    HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR);
+	    B_inUnderline = FALSE;
+	}
+	HText_endAppend(me->text);
+    }
 
     if (me->target) {
         (*me->targetClass._free)(me->target);
     }
+    List_Nesting_Level = -1;
+    HTML_zero_OL_Counter();
+    Division_Level = -1;
+    Underline_Level = 0;
+    Quote_Level = 0;
     if (me->sp && me->sp->style && me->sp->style->name) {
         if (!strcmp(me->sp->style->name, "DivCenter") ||
 	    !strcmp(me->sp->style->name, "HeadingCenter")) {
@@ -5666,6 +5727,7 @@ PUBLIC void HTML_free ARGS1(HTStructured *, me)
 	styles[HTML_PRE]->alignment = HT_LEFT;
     }
     FREE(base_href);
+    B_inBASE = FALSE;
     FREE(LYMapName);
     FREE(me);
 }
@@ -5689,6 +5751,21 @@ PRIVATE void HTML_abort ARGS2(HTStructured *, me, HTError, e)
     if (me->target) {
         (*me->targetClass._abort)(me->target, e);
     }
+    if (me->sp && me->sp->style && me->sp->style->name) {
+        if (!strcmp(me->sp->style->name, "DivCenter") ||
+	    !strcmp(me->sp->style->name, "HeadingCenter")) {
+	    me->sp->style->alignment = HT_CENTER;
+	} else if (!strcmp(me->sp->style->name, "DivRight") ||
+		   !strcmp(me->sp->style->name, "HeadingRight")) {
+	    me->sp->style->alignment = HT_RIGHT;
+	} else  {
+	    me->sp->style->alignment = HT_LEFT;
+	}
+	styles[HTML_PRE]->alignment = HT_LEFT;
+    }
+    FREE(base_href);
+    B_inBASE = FALSE;
+    FREE(LYMapName);
     FREE(me);
 }
 
@@ -5762,7 +5839,6 @@ PRIVATE void get_styles NOARGS
     styles[HTML_PLAINTEXT] =
     styles[HTML_XMP] =		HTStyleNamed(styleSheet, "Example");
     styles[HTML_PRE] =		HTStyleNamed(styleSheet, "Preformatted");
-    styles[HTML_STYLE] =	HTStyleNamed(styleSheet, "Style");
     styles[HTML_LISTING] =	HTStyleNamed(styleSheet, "Listing");
 }
 /*				P U B L I C
@@ -6206,8 +6282,8 @@ PRIVATE void HTML_CheckForID ARGS4(
 	    (B_ID_A = HTAnchor_findChildAndLink(
 				me->node_anchor,	/* Parent */
 				temp,			/* Tag */
-				0,			/* Addresss */
-				0))) {			/* Type */
+				NULL,			/* Addresss */
+				(void *)0))) {		/* Type */
 	    HText_beginAnchor(me->text, B_ID_A);
 	    HText_endAnchor(me->text);
 	}
@@ -6238,8 +6314,8 @@ PRIVATE void HTML_HandleID ARGS2(
     if (B_ID_A = HTAnchor_findChildAndLink(
 				me->node_anchor,	/* Parent */
 				id,			/* Tag */
-				0,			/* Addresss */
-				0)) {			/* Type */
+				NULL,			/* Addresss */
+				(void *)0)) {		/* Type */
 	HText_beginAnchor(me->text, B_ID_A);
 	HText_endAnchor(me->text);
     }
diff --git a/src/LYBookmark.c b/src/LYBookmark.c
index 88dca1ef..4ba29d0b 100644
--- a/src/LYBookmark.c
+++ b/src/LYBookmark.c
@@ -9,10 +9,12 @@
 #include "LYSystem.h"
 #include "LYKeymap.h"
 #include "LYCharUtils.h"
+#include "LYCurses.h"
 
 #ifdef VMS
 #include "HTVMSUtils.h"
 #include <nam.h>
+extern BOOLEAN HadVMSInterrupt;	/* Flag from cleanup_sig() AST */
 #endif /* VMS */
 
 #include "LYLeaks.h"
@@ -26,52 +28,70 @@ PRIVATE char * convert_mosaic_bookmark_file PARAMS((char *filename_buffer));
  *  Tries to open the bookmark file for reading.
  *  if successful the file is closed and the filename
  *  is returned and the URL is given in name.
+ *
+ *  Returns a zero-length pointer to flag a cancel,
+ *  a space to flag an undefined selection, and
+ *  NULL for a failure (processing error). - FM
  */
-PUBLIC char * get_bookmark_filename ARGS1(char **,URL)
+PUBLIC char * get_bookmark_filename ARGS1(
+	char **, URL)
 {
     char URL_buffer[256];
     static char filename_buffer[256];
     char string_buffer[256];
     FILE *fp;
+    int MBM_tmp;
 
-    if (!bookmark_page) {
+    /*
+     *  Multi_Bookmarks support. - FMG & FM
+     *  Let user select a bookmark file.
+     */
+    MBM_tmp = select_multi_bookmarks();
+    if (MBM_tmp == -2)
+        /*
+	 *  Zero-length pointer flags a cancel.
+	*/
+        return("");
+    if (MBM_tmp == -1) {
 	sprintf(string_buffer,
 		BOOKMARK_FILE_NOT_DEFINED,
 		key_for_func(LYK_OPTIONS));
 	_statusline(string_buffer);
 	sleep(AlertSecs);
-	return(NULL);
+	/*
+	 *  Space flags an undefined selection.
+	*/
+	return(" ");
+    } else {
+	StrAllocCopy(BookmarkPage, MBM_A_subbookmark[MBM_tmp]);
     }
 
     /*
-     *  See if it is in the home path.
+     *  Seek it in the home path.
      */
 #ifdef VMS
-    sprintf(filename_buffer,"%s%s", Home_Dir(), bookmark_page);
+    LYVMS_HomePathAndFilename(filename_buffer,
+			      sizeof(filename_buffer),
+			      BookmarkPage);
 #else
-    sprintf(filename_buffer,"%s/%s", Home_Dir(), bookmark_page);
+    sprintf(filename_buffer,"%s/%s", Home_Dir(), BookmarkPage);
 #endif /* VMS */
+    if (TRACE)
+        fprintf(stderr, "\nget_bookmark_filename: SEEKING %s\n   AS %s\n\n",
+		BookmarkPage, filename_buffer);
     if ((fp = fopen(filename_buffer,"r")) != NULL) {
 	goto success;
     }
 
     /*
-     *  See if we can open it raw.
-     */
-    if ((fp = fopen(bookmark_page,"r")) != NULL) {
-	strcpy(filename_buffer, bookmark_page);
-	goto success;
-    } 
-
-    /*
      *  Failure.
      */
     return(NULL);
 
 success:
     /*
-     *  We now have the file open.  Check if it is a mosaic
-     *  hotlist.
+     *  We now have the file open.
+     *  Check if it is a mosaic hotlist.
      */
     if (fgets(string_buffer, 255, fp) &&
 	!strncmp(string_buffer, "ncsa-xmosaic-hotlist-format-1", 29)) {
@@ -79,23 +99,23 @@ success:
 	/*
 	 *  It is a mosaic hotlist file.
 	 */
-	is_mosaic_hotlist=TRUE;
+	is_mosaic_hotlist = TRUE;
 	fclose(fp);
 	newname = convert_mosaic_bookmark_file(filename_buffer);
 #ifdef VMS
-    sprintf(URL_buffer,"file://localhost%s", HTVMS_wwwName((char *)newname));
+	sprintf(URL_buffer,"file://localhost%s",
+		HTVMS_wwwName((char *)newname));
 #else
-    sprintf(URL_buffer,"file://localhost%s", newname);
+	sprintf(URL_buffer,"file://localhost%s", newname);
 #endif /* VMS */
-
     } else {
 	fclose(fp);
-	is_mosaic_hotlist=FALSE;
+	is_mosaic_hotlist = FALSE;
 #ifdef VMS
-    sprintf(URL_buffer,"file://localhost%s",
-    			HTVMS_wwwName((char *)filename_buffer));
+	sprintf(URL_buffer,"file://localhost%s",
+    		HTVMS_wwwName((char *)filename_buffer));
 #else
-    sprintf(URL_buffer,"file://localhost%s", filename_buffer);
+	sprintf(URL_buffer,"file://localhost%s", filename_buffer);
 #endif /* VMS */
     }
 
@@ -104,7 +124,8 @@ success:
 
 } /* big end */
 
-PRIVATE char * convert_mosaic_bookmark_file ARGS1(char *,filename_buffer)
+PRIVATE char * convert_mosaic_bookmark_file ARGS1(
+	char *,	filename_buffer)
 {
     static char newfile[256];
     static BOOLEAN first = TRUE;
@@ -122,14 +143,13 @@ PRIVATE char * convert_mosaic_bookmark_file ARGS1(char *,filename_buffer)
 #endif /* VMS */
     }
 
-
-    if((nfp = fopen(newfile, "w")) == NULL) {
+    if ((nfp = fopen(newfile, "w")) == NULL) {
 	_statusline(NO_TEMP_FOR_HOTLIST);
 	sleep(AlertSecs);
 	return ("");
     }
 
-    if((fp = fopen(filename_buffer, "r")) == NULL)
+    if ((fp = fopen(filename_buffer, "r")) == NULL)
 	return ("");  /* should always open */
 
     fprintf(nfp,"<head>\n<title>%s</title>\n</head>\n",MOSAIC_BOOKMARK_TITLE);
@@ -161,7 +181,9 @@ PRIVATE char * convert_mosaic_bookmark_file ARGS1(char *,filename_buffer)
     return(newfile);
 }
 
-PUBLIC void save_bookmark_link ARGS2(char *,address, char *,title)
+PUBLIC void save_bookmark_link ARGS2(
+	char *,	address,
+	char *,	title)
 {
     FILE *fp;
     BOOLEAN first_time = FALSE;
@@ -177,10 +199,27 @@ PUBLIC void save_bookmark_link ARGS2(char *,address, char *,title)
     }
 
     filename = get_bookmark_filename(&bookmark_URL);
-    FREE(bookmark_URL); /* don't need it */
-    if (!bookmark_page)
+
+    /*
+     *  If filename is a space, invalid bookmark
+     *  file was selected.  If zero-length, user
+     *  cancelled.  Ignore request in both cases!
+     */
+    if (filename)
+      if (*filename == '\0' || !strcmp(filename," "))
+	return;
+    /*
+     *  If BookmarkPage didn't get loaded, something
+     *  went wrong, so ignore the request.
+     */
+    if (!BookmarkPage)
 	return;
 
+     /*
+      *  We don't need the full URL.
+      */
+    FREE(bookmark_URL);
+
     /*
      *  Allow user to change the title. - FM
      */
@@ -205,32 +244,25 @@ PUBLIC void save_bookmark_link ARGS2(char *,address, char *,title)
     /*
      *  Open the bookmark file. - FM
      */
-    if (filename == NULL) {
+    if (filename == NULL)
 	first_time = TRUE;
-	/*
-	 *  Try in the home directory first.
-	 */
+    /*
+     *  Try in the home directory.
+     */
 #ifdef VMS
-    	sprintf(filename_buffer, "sys$login:%s", bookmark_page);
+    LYVMS_HomePathAndFilename(filename_buffer,
+			      sizeof(filename_buffer),
+			      BookmarkPage);
 #else
-    	sprintf(filename_buffer, "%s/%s", Home_Dir(), bookmark_page);
+    sprintf(filename_buffer, "%s/%s", Home_Dir(), BookmarkPage);
 #endif /* VMS */
-    	if ((fp = fopen(filename_buffer,"w")) == NULL) {
-	   /*
-	    *  Try it raw.
-	    */
-    	    if ((fp = fopen(bookmark_page,"r")) == NULL) {
-	        _statusline(BOOKMARK_OPEN_FAILED);
-	        sleep(AlertSecs);
-	        return;
-	    }
-	}
-    } else {
-	if ((fp = fopen(filename,"a+")) == NULL) {
-	    _statusline(BOOKMARK_OPEN_FAILED);
-	    sleep(AlertSecs);
-	    return;
-	}
+    if (TRACE)
+        fprintf(stderr, "\nsave_bookmark_link: SEEKING %s\n   AS %s\n\n",
+		BookmarkPage, filename_buffer);
+    if ((fp = fopen(filename_buffer, (first_time ? "w" : "a+"))) == NULL) {
+	_statusline(BOOKMARK_OPEN_FAILED);
+	sleep(AlertSecs);
+	return;
     }
 
     /*
@@ -245,8 +277,8 @@ PUBLIC void save_bookmark_link ARGS2(char *,address, char *,title)
     if (first_time) {
 	fprintf(fp,"<head>\n<title>%s</title>\n</head>\n",BOOKMARK_TITLE);
 	fprintf(fp,"\
-     You can delete links using the new remove bookmark command.\n\
-     it is usually the 'R' key but may have been remapped by you or\n\
+     You can delete links using the remove bookmark command.  It\n\
+     is usually the 'R' key but may have been remapped by you or\n\
      your system administrator.<br>\n\
      This file may also be edited with a standard text editor.\n\
      Outdated or invalid links may be removed by simply deleting\n\
@@ -277,38 +309,47 @@ PUBLIC void save_bookmark_link ARGS2(char *,address, char *,title)
     sleep(MessageSecs);
 }
 	
-PUBLIC void remove_bookmark_link ARGS1(int,cur)
+PUBLIC void remove_bookmark_link ARGS2(
+	int,		cur,
+	char *,		cur_bookmark_page)
 {
     FILE *fp, *nfp;
     char buf[BUFSIZ];
     int n;
 #ifdef VMS
+    char filename_buffer[NAM$C_MAXRSS+12];
     char newfile[NAM$C_MAXRSS+12];
 #else
-    char newfile[128];
+    char filename_buffer[256];
+    char newfile[256];
     struct stat stat_buf;
     mode_t mode;
 #endif /* VMS */
-    char *filename;
-    char *URL = 0;
 
     if (TRACE)
 	fprintf(stderr, "remove_bookmark_link: deleting link number: %d\n",
 			cur);
 
-    filename = get_bookmark_filename(&URL);
-    FREE(URL); /* don't need it */
-    if (!bookmark_page)
+    if (!cur_bookmark_page)
 	return;
-
-    if ((!filename) || (fp=fopen(filename, "r")) == NULL) {
+#ifdef VMS
+    LYVMS_HomePathAndFilename(filename_buffer,
+			      sizeof(filename_buffer),
+			      cur_bookmark_page);
+#else
+    sprintf(filename_buffer,"%s/%s", Home_Dir(), cur_bookmark_page);
+#endif /* VMS */
+    if (TRACE)
+        fprintf(stderr, "\nremove_bookmark_link: SEEKING %s\n   AS %s\n\n",
+		cur_bookmark_page, filename_buffer);
+    if ((fp = fopen(filename_buffer, "r")) == NULL) {
 	_statusline(BOOKMARK_OPEN_FAILED_FOR_DEL);
 	sleep(AlertSecs);
 	return;
     }
 
 #ifdef VMS
-    sprintf(newfile, "%s-%d", filename, getpid());
+    sprintf(newfile, "%s-%d", filename_buffer, getpid());
 #else
     tempname(newfile, NEW_FILE);
 #endif /* VMS */
@@ -327,7 +368,7 @@ PUBLIC void remove_bookmark_link ARGS1(int,cur)
     /*
      *  Explicitly preserve bookmark file mode on Unix. - DSL
      */
-    if (stat(filename,&stat_buf) == 0) {
+    if (stat(filename_buffer, &stat_buf) == 0) {
 	mode = ((stat_buf.st_mode & 0777) | 0600);
 	(void) fclose(nfp);
 	nfp = NULL;
@@ -385,27 +426,27 @@ PUBLIC void remove_bookmark_link ARGS1(int,cur)
 
     if (TRACE)
 	fprintf(stderr, "remove_bookmark_link: files: %s %s\n",
-			newfile, filename);
+			newfile, filename_buffer);
 
     fclose(fp);
     fp = NULL;
     fclose(nfp);
     nfp = NULL;
  	
-    if (rename(newfile, filename) != -1) {
+    if (rename(newfile, filename_buffer) != -1) {
 #ifdef VMS
 	char VMSfilename[256];
 	/*
 	 *  Purge lower version of file.
 	 */
-	sprintf(VMSfilename, "%s;-1", filename);
+	sprintf(VMSfilename, "%s;-1", filename_buffer);
         while (remove(VMSfilename) == 0)
 	    ;
 	/*
 	 *  Reset version number.
 	 */
-	sprintf(VMSfilename, "%s;1", filename);
-	rename(filename, VMSfilename);
+	sprintf(VMSfilename, "%s;1", filename_buffer);
+	rename(filename_buffer, VMSfilename);
 #endif /* VMS */
         return;
     } else {
@@ -417,7 +458,7 @@ PUBLIC void remove_bookmark_link ARGS1(int,cur)
 	 */
 	if (errno == EXDEV) {
 	    char buffer[2048];
-	    sprintf(buffer, "%s %s %s", MV_PATH, newfile, filename);
+	    sprintf(buffer, "%s %s %s", MV_PATH, newfile, filename_buffer);
 	    system(buffer);
 	    return;
 	}
@@ -442,3 +483,304 @@ failure:
         fclose(fp);
     remove(newfile);
 }
+
+/*
+ *  Allows user to select sub-bookmarks files. - FMG & FM
+ */
+PUBLIC int select_multi_bookmarks NOARGS
+{
+    int c;
+
+    /*
+     *  If not enabled, pick the "default" (0).
+     */
+    if (LYMultiBookmarks == FALSE || LYHaveSubBookmarks() == FALSE) {
+	if (MBM_A_subbookmark[0]) /* If it exists! */
+            return(0);
+	else
+            return(-1);
+    }
+
+    /*
+     *  For ADVANCED users, we can just mess with the status line to save
+     *  the 2 redraws of the screen, if LYMBMAdvnced is TRUE.  '=' will
+     *  still show the screen and let them do it the "long" way.
+     */
+    if (LYMBMAdvanced && user_mode == ADVANCED_MODE) {
+	move(LYlines-1, 0);
+	clrtoeol();
+	start_reverse();
+	addstr("Select subbookmark, '=' for menu, or ^G to cancel: ");
+	stop_reverse();
+	refresh();
+
+get_advanced_choice:
+	c = LYgetch();
+#ifdef VMS
+	if (HadVMSInterrupt) {
+	    HadVMSInterrupt = FALSE;
+	    c = 7;
+        }
+#endif /* VMS */
+	if (LYisNonAlnumKeyname(c, LYK_PREV_DOC) ||
+	    c == 7 || c == 3) {
+	    /*
+	     *  Treat left-arrow, ^G, or ^C as cancel.
+	     */
+	    return(-2);
+	}
+	if (LYisNonAlnumKeyname(c, LYK_REFRESH)) {
+	    /*
+	     *  Refresh the screen.
+	     */
+	    clearok(curscr, TRUE);
+	    refresh();
+	    goto get_advanced_choice;
+	}
+	if (LYisNonAlnumKeyname(c, LYK_ACTIVATE)) {
+	    /*
+	     *  Assume default bookmark file on ENTER or right-arrow.
+	     */
+	    return (MBM_A_subbookmark[0] ? 0 : -1);
+	}
+	switch (c) {
+	    case '=':
+	        /*
+		 *  Get the choice via the menu.
+		 */
+		return(select_menu_multi_bookmarks());
+
+	    default:
+	        /*
+		 *  Convert to an array index, act on it if valid.
+		 *  Otherwise, get another keystroke.
+		 */
+		c = TOUPPER(c) - 'A';
+		if (c < 0 || c > MBM_V_MAXFILES) {
+		    goto get_advanced_choice;
+		}
+	}
+	/*
+	 *  See if we have a bookmark like that.
+	 */
+	return (MBM_A_subbookmark[c] ? c : -1);
+    } else {
+        /*
+	 *  Get the choice via the menu.
+	 */
+	return(select_menu_multi_bookmarks());
+    }
+}
+
+/*
+ *  Allows user to select sub-bookmarks files. - FMG & FM
+ */
+PUBLIC int select_menu_multi_bookmarks NOARGS
+{
+    FILE *fp;
+    int c, MBM_counter, MBM_tmp_count, MBM_allow;
+    int MBM_screens, MBM_from, MBM_to, MBM_current;
+    char string_buffer[256];
+    char *cp, *cp1;
+
+    /*
+     *  If not enabled, pick the "default" (0).
+     */
+    if (LYMultiBookmarks == FALSE)
+	return(0);
+
+    /*
+     *  Filip M. Gieszczykiewicz (filipg@paranoia.com) & FM
+     *  ---------------------------------------------------
+     *  LYMultiBookmarks - TRUE when multi_support enabled.
+     *
+     *  MBM_A_subbookmark[n] - Hold values of the respective
+     *  "multi_bookmarkn" in the lynxrc file.
+     *
+     *  MBM_A_subdescript[n] - Hold description entries in the
+     *  lynxrc file.
+     *
+     *  Note: MBM_A_subbookmark[0] is defined to be same value as
+     *        "bookmark_file" in the lynxrc file and/or the startup
+     *        "bookmark_page".
+     *
+     *  We make the display of bookmarks depend on rows we have
+     *  available.
+     *
+     *  We load BookmarkPage with the valid MBM_A_subbookmark[n]
+     *  via get_bookmark_filename().  Otherwise, that function
+     *  returns a zero-length string to indicate a cancel, a
+     *  single space to indicate an invalid choice, or NULL to
+     *  indicate an inaccessible file.
+     */
+    MBM_allow=(LYlines-7);	/* We need 7 for header and footer */
+    /*
+     *  Screen big enough?
+     */
+    if (MBM_allow <= 0) {
+        /*
+	 *  Too small.
+	 */
+	_statusline(MULTIBOOKMARKS_SMALL);
+	sleep(AlertSecs);
+	return (-2);
+    }
+    /*
+     *  Load the bad choice message.
+     */
+    sprintf(string_buffer,
+    	    BOOKMARK_FILE_NOT_DEFINED,
+	    key_for_func(LYK_OPTIONS));
+
+    MBM_screens = (MBM_V_MAXFILES/MBM_allow)+1; /* int rounds off low. */
+
+    MBM_current = 1; /* Gotta start somewhere :-) */
+
+draw_bookmark_choices:
+    MBM_from = MBM_allow * MBM_current - MBM_allow;
+    if (MBM_from < 0)
+	MBM_from = 0; /* 0 is default bookmark... */
+    if (MBM_current != 1)
+	MBM_from++;
+
+    MBM_to = (MBM_allow * MBM_current);
+    if (MBM_to > MBM_V_MAXFILES)
+	MBM_to = MBM_V_MAXFILES;
+
+    /*
+     * Display menu of bookmarks.
+     */
+    clear();
+    move(1, 5);
+    if (bold_H1 || bold_headers)
+	start_bold();
+    if (MBM_screens > 1)
+	printw(" Select Bookmark (screen %d of %d)", MBM_current, MBM_screens);
+    else
+	printw("       Select Bookmark");
+    if (bold_H1 || bold_headers)
+	stop_bold();
+
+    MBM_tmp_count = 0;
+    for (c = MBM_from; c <= MBM_to; c++) {
+	move(3+MBM_tmp_count, 5);
+	printw("%c : %s",(c+'A'),
+	       (!MBM_A_subdescript[c] ? "" : MBM_A_subdescript[c]));
+
+	move(3+MBM_tmp_count,36);
+	printw("(%s)",
+	       (!MBM_A_subbookmark[c] ? "" : MBM_A_subbookmark[c]));
+
+	MBM_tmp_count++;
+    }
+
+    /*
+     *  Don't need to show it if it all fits on one screen!
+     */
+    if (MBM_screens > 1) {
+	move(LYlines-2, 0);
+	addstr(MULTIBOOKMARKS_MOVE);
+    }
+
+    move(LYlines-1, 0);
+    clrtoeol();
+    start_reverse();
+    addstr(MULTIBOOKMARKS_SAVE);
+    stop_reverse();
+    refresh();
+
+get_bookmark_choice:
+    c = LYgetch();
+#ifdef VMS
+    if (HadVMSInterrupt) {
+	HadVMSInterrupt = FALSE;
+	c = 7;
+    }
+#endif /* VMS */
+
+    if (LYisNonAlnumKeyname(c, LYK_PREV_DOC) ||
+	c == 7 || c == 3) {
+	/*
+	 *  Treat left-arrow, ^G, or ^C as cancel.
+	 */
+	return(-2);
+    }
+
+    if (LYisNonAlnumKeyname(c, LYK_REFRESH)) {
+	/*
+	 *  Refresh the screen.
+	 */
+	clearok(curscr, TRUE);
+	refresh();
+	goto get_bookmark_choice;
+    }
+
+    if (LYisNonAlnumKeyname(c, LYK_ACTIVATE)) {
+	/*
+	 *  Assume default bookmark file on ENTER or right-arrow.
+	 */
+	return(MBM_A_subbookmark[0] ? 0 : -1);
+    }
+
+    /*
+     *  Next range, if available.
+     */
+    if ((c == ']' ||  LYisNonAlnumKeyname(c, LYK_NEXT_PAGE)) &&
+        MBM_screens > 1) {
+	if (++MBM_current > MBM_screens)
+	    MBM_current = 1;
+	goto draw_bookmark_choices;
+    }
+
+    /*
+     *  Previous range, if available.
+     */
+    if ((c == '[' ||  LYisNonAlnumKeyname(c, LYK_PREV_PAGE)) &&
+        MBM_screens > 1) {
+	if (--MBM_current <= 0)
+	    MBM_current = MBM_screens;
+	goto draw_bookmark_choices;
+    }
+
+    c = TOUPPER(c) - 'A';
+    /*
+     *  See if we have a bookmark like that.
+     */
+    if (c < 0 || c > MBM_V_MAXFILES) {
+	goto get_bookmark_choice;
+    } else if (!MBM_A_subbookmark[c]) {
+	move(LYlines-1, 0);
+	clrtoeol();
+	start_reverse();
+ 	addstr(string_buffer);
+	stop_reverse();
+	refresh();
+	sleep(AlertSecs);
+	move(LYlines-1, 0);
+	clrtoeol();
+	start_reverse();
+	addstr(MULTIBOOKMARKS_SAVE);
+	stop_reverse();
+	refresh();
+	goto get_bookmark_choice;
+    } else {
+	return(c);
+    }
+}
+
+/*
+ *  This function returns TRUE if we have sub-bookmarks defined.
+ *  Otherwise (i.e., only the default bookmark file is defined),
+ *  it returns FALSE. - FM
+ */
+PUBLIC BOOLEAN LYHaveSubBookmarks NOARGS
+{
+    int i;
+
+    for (i = 1; i < MBM_V_MAXFILES; i++) {
+        if (MBM_A_subbookmark[i] != NULL && *MBM_A_subbookmark[i] != '\0')
+	    return(TRUE);
+    }
+
+    return(FALSE);
+}
diff --git a/src/LYBookmark.h b/src/LYBookmark.h
index 838c025e..41f54c6b 100644
--- a/src/LYBookmark.h
+++ b/src/LYBookmark.h
@@ -8,10 +8,22 @@
 
 extern char * get_bookmark_filename PARAMS((char **name));
 extern void save_bookmark_link PARAMS((char *address, char *title));
-extern void remove_bookmark_link PARAMS((int cur));
+extern void remove_bookmark_link PARAMS((int cur, char *cur_bookmark_page));
+extern int select_multi_bookmarks NOPARAMS;
+extern int select_menu_multi_bookmarks NOPARAMS;
+extern BOOLEAN LYHaveSubBookmarks NOPARAMS;
+
+extern void edit_bookmarks NOPARAMS; /* in LYOptions.c */
 
 #define BOOKMARK_TITLE "Bookmark file"
 #define MOSAIC_BOOKMARK_TITLE "Converted Mosaic Hotlist"
+#define MBM_V_MAXFILES  25	/* Max number of sub-bookmark files */
+/*
+ *  Arrays that holds the names of sub-bookmark files
+ *  and their descriptions.
+ */
+char  *MBM_A_subbookmark[MBM_V_MAXFILES+1];
+char  *MBM_A_subdescript[MBM_V_MAXFILES+1];
 
 #endif /* LYBOOKMARK_H */
 
diff --git a/src/LYCgi.c b/src/LYCgi.c
index 77eefb77..9a81fadb 100644
--- a/src/LYCgi.c
+++ b/src/LYCgi.c
@@ -176,10 +176,8 @@ PUBLIC int LYLoadCGI ARGS4(
 	sleep(MessageSecs);
 	status = HT_NOT_LOADED;
 
-    } else if (!reloading && no_bookmark_exec && bookmark_page &&
-	       (strstr(HTLoadedDocumentURL(), bookmark_page) ||
-		!strcmp(HTLoadedDocumentTitle(),
-			MOSAIC_BOOKMARK_TITLE))) {
+    } else if (!reloading && no_bookmark_exec &&
+ 	       HTLoadedDocumentBookmark()) {
 	_statusline(BOOKMARK_EXEC_DISABLED);
 	sleep(MessageSecs);
 	status = HT_NOT_LOADED;
diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c
index 75d50f8d..18aa65d0 100644
--- a/src/LYCharUtils.c
+++ b/src/LYCharUtils.c
@@ -1024,7 +1024,7 @@ PUBLIC char *LYFindEndOfComment ARGS1(
 	 */
         return NULL;
 
-    if (strcmp(str, "<!--"))
+    if (strncmp(str, "<!--", 4))
         /*
 	 *  We don't have the start of a comment, so
 	 *  return the beginning of the string. - FM
diff --git a/src/LYCurses.h b/src/LYCurses.h
index 065fdd1d..d18cd6e3 100644
--- a/src/LYCurses.h
+++ b/src/LYCurses.h
@@ -12,8 +12,7 @@
 #if defined(UNIX) && !defined(unix)
 #define unix
 #endif /* UNIX && !unix */
-#include "slang.h"
-#include "slcurses.h"
+#include <slang.h>
 
 #else /* Using curses: */
 
@@ -125,6 +124,21 @@ extern unsigned int Lynx_Color_Flags;
 #define NO_TTYTYPE
 #endif /* !NO_TTYTYPE */
 
+/* Map some curses functions to slang functions. */
+#define stdscr NULL
+#define COLS SLtt_Screen_Cols
+#define LINES SLtt_Screen_Rows
+#define move SLsmg_gotorc
+#define addstr SLsmg_write_string
+#define clear SLsmg_cls
+#define standout SLsmg_reverse_video
+#define standend  SLsmg_normal_video
+#define clrtoeol SLsmg_erase_eol
+#define scrollok(a,b) SLsmg_Newline_Moves = ((b) ? 1 : -1)
+#define addch SLsmg_write_char
+#define echo()
+#define printw SLsmg_printf
+ 
 extern int curscr;
 extern BOOLEAN FullRefresh;
 #ifdef clearok
@@ -139,10 +153,9 @@ extern void LY_SLrefresh NOPARAMS;
 
 #ifdef VMS
 extern void VTHome NOPARAMS;
-#ifdef endwin
-#undef endwin
-#endif /*endwin */
 #define endwin() clear(),refresh(),SLsmg_reset_smg(),VTHome()
+#else
+#define endwin SLsmg_reset_smg(),SLang_reset_tty
 #endif /* VMS */
 
 #else /* Define curses functions: */
diff --git a/src/LYForms.c b/src/LYForms.c
index 14132d58..b7cd64ee 100644
--- a/src/LYForms.c
+++ b/src/LYForms.c
@@ -25,8 +25,8 @@ extern HTCJKlang HTCJK;
 
 PRIVATE int form_getstr PARAMS((struct link * form_link));
 PRIVATE int popup_options PARAMS((int cur_selection, OptionType *list, 
-						   int ly, int lx, int width,
-						   int i_length));
+				  int ly, int lx, int width,
+				  int i_length, int disabled));
 
 PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, 
 				  document *,newdoc, BOOLEAN *,refresh_screen,
@@ -36,10 +36,11 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
     FormInfo *form = form_link->form;
     int c=DO_NOTHING;
 
-	/*	If there is no form to perform action on, don't do anything.
+	/*
+	 *  If there is no form to perform action on, don't do anything.
 	 */
-	if(form == NULL)	{
-		return(c);
+	if (form == NULL) {
+	    return(c);
 	}
 
     /* move to the link position */
@@ -49,7 +50,7 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
 	case F_CHECKBOX_TYPE:
 	    if (form->disabled == YES)
 	        break;
-	    if(form->num_value) {
+	    if (form->num_value) {
 		form_link->hightext = unchecked_box;
 		form->num_value = 0;
 	    } else {
@@ -69,18 +70,18 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
 	        int dummy;
 		dummy = popup_options(form->num_value, form->select_list,
 				form_link->ly, form_link->lx, form->size,
-				form->size_l);
+				form->size_l, form->disabled);
 	        c = 12;  /* CTRL-R for repaint */
 	        break;
 	    }
 	    form->num_value = popup_options(form->num_value, form->select_list,
 				form_link->ly, form_link->lx, form->size,
-				form->size_l);
+				form->size_l, form->disabled);
 
 	    {
     	        OptionType * opt_ptr=form->select_list;
 		int i;
-    	        for(i=0; i<form->num_value; i++, opt_ptr = opt_ptr->next) 
+    	        for (i = 0; i < form->num_value; i++, opt_ptr = opt_ptr->next) 
 		    ; /* null body */
 		form->value = opt_ptr->name;   /* set the name */
 		form->cp_submit_value = opt_ptr->cp_submit_value; /* set the value */
@@ -94,7 +95,7 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
 		/* radio buttons must have one and
 		 * only one down at a time! 
 		 */
-	    if(form->num_value) {
+	    if (form->num_value) {
 		_statusline(NEED_CHECKED_RADIO_BUTTON);
 		sleep(MessageSecs);
 
@@ -104,8 +105,8 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
 		 * unselect any that are selected. :) 
 		 */
 		start_bold();
-		for(i=0; i < nlinks; i++)
-		   if(links[i].type == WWW_FORM_LINK_TYPE &&
+		for (i = 0; i < nlinks; i++)
+		   if (links[i].type == WWW_FORM_LINK_TYPE &&
 		       links[i].form->type == F_RADIO_TYPE &&
 		        links[i].form->number == form->number &&
    		         /* if it has the same name and its on */
@@ -128,7 +129,7 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
 	case F_TEXTAREA_TYPE:
 	case F_PASSWORD_TYPE:
 	    c = form_getstr(form_link);
-	    if(form->type == F_PASSWORD_TYPE) 
+	    if (form->type == F_PASSWORD_TYPE) 
         	form_link->hightext = STARS(strlen(form->value));
 	    else
 	    	form_link->hightext = form->value;
@@ -230,7 +231,7 @@ PRIVATE int form_getstr ARGS1(struct link *, form_link)
     /* get the initial position of the cursor */
     GetYX(startline, startcol);
 
-    if(startcol + form->size > LYcols-1)
+    if (startcol + form->size > LYcols-1)
 	far_col = LYcols-1;
     else
 	far_col = startcol + form->size;
@@ -291,11 +292,11 @@ again:
 	    case LTARROW:
 	        if (MyEdit.pos==0) {
 		    int c='Y';	/* Go back immediately if no changes */
-		    if(strcmp(MyEdit.buffer, form->value)) {
+		    if (strcmp(MyEdit.buffer, form->value)) {
 		        _statusline(PREV_DOC_QUERY);
 			c=LYgetch();
 		    }
-		    if(TOUPPER(c) == 'Y') {
+		    if (TOUPPER(c) == 'Y') {
 #ifdef NOTDEFINED
 			/*
 			 * Why not just keep what we have??
@@ -351,97 +352,124 @@ breakfor:
 }
 
 
-PRIVATE int popup_options ARGS6(int,cur_selection, OptionType *,list, 
-						   int, ly, int, lx, int,width,
-						   int, i_length)
+PRIVATE int popup_options ARGS7(
+	int,		cur_selection,
+	OptionType *,	list,
+	int,		ly,
+	int,		lx,
+	int,		width,
+	int,		i_length,
+	int,		disabled)
 {
     /*
-     * Revamped to handle within-tag VALUE's, if present,
-     * and to position the popup window appropriately,
-     * taking the user_mode setting into account. -- FM
+     *  Revamped to handle within-tag VALUE's, if present,
+     *  and to position the popup window appropriately,
+     *  taking the user_mode setting into account. -- FM
      */
-    int c=0, cmd=0, i=0;
+    int c = 0, cmd = 0, i = 0, j = 0;
     int orig_selection = cur_selection;
 #ifndef USE_SLANG
     WINDOW * form_window;
 #endif /* !USE_SLANG */
-    int num_options=0, top, bottom, length= -1;
-    OptionType * opt_ptr=list;
-    int window_offset=0;
+    int num_options = 0, top, bottom, length = -1;
+    OptionType * opt_ptr = list;
+    int window_offset = 0;
     int display_lines;
 #ifdef VMS
     extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */
-#endif
+#endif /* VMS */
+    static char prev_target[512]; 		/* Search string buffer */
+    static char prev_target_buffer[512];	/* Next search buffer */
+    static BOOL first = TRUE;
+    char *cp;
+    int ch = 0, recall;
+    int QueryTotal;
+    int QueryNum;
+    BOOLEAN FirstRecall = TRUE;
+    OptionType * tmp_ptr;
+    BOOLEAN ReDraw = FALSE;
+
+    /*
+     * Initialize the search string buffer. - FM
+     */
+    if (first) {
+	*prev_target_buffer = '\0';
+	first = FALSE;
+    }
+    *prev_target = '\0';
+    QueryTotal = (search_queries ? HTList_count(search_queries) : 0);
+    recall = ((QueryTotal >= 1) ? RECALL : NORECALL);
+    QueryNum = QueryTotal;
 
     /*
-     * Set display_lines based on the user_mode global.
+     *  Set display_lines based on the user_mode global.
      */
-    if(user_mode==NOVICE_MODE)
+    if (user_mode==NOVICE_MODE)
         display_lines = LYlines-4;
     else
         display_lines = LYlines-2;
 
     /*
-     * Counting the number of options to be displayed.
+     *  Counting the number of options to be displayed.
      *   num_options ranges 0...n
      */
-    for(; opt_ptr->next; num_options++, opt_ptr = opt_ptr->next)
+    for (; opt_ptr->next; num_options++, opt_ptr = opt_ptr->next)
          ; /* null body */
 
     /*
-     * Let's assume for the sake of sanity that ly is the number
+     *  Let's assume for the sake of sanity that ly is the number
      *   corresponding to the line the selection box is on.
-     * Let's also assume that cur_selection is the number of the
+     *  Let's also assume that cur_selection is the number of the
      *   item that should be initially selected, as 0 beign the
      *   first item.
-     * So what we have, is the top equal to the current screen line
+     *  So what we have, is the top equal to the current screen line
      *   subtracting the cur_selection + 1 (the one must be for the
      *   top line we will draw in a box).  If the top goes under 0,
      *   consider it 0.
      */
     top = ly - (cur_selection + 1);
-    if(top < 0)
+    if (top < 0)
 	top = 0;
 
     /*
-     * Check and see if we need to put the i_length parameter up to
-     *   the number of real options.
+     *  Check and see if we need to put the i_length parameter up to
+     *  the number of real options.
      */
-    if(!i_length) {
+    if (!i_length) {
         i_length = num_options;
     }
     else {
         /*
-	 * Otherwise, it is really one number too high.
+	 *  Otherwise, it is really one number too high.
 	 */
 	i_length--;
     }
 
     /*
-     * The bottom is the value of the top plus the number of options
-     *   to view plus 3 (one for the top line, one for the bottom line,
-     *   and one to offset the 0 counted in the num_options).
+     *  The bottom is the value of the top plus the number of options
+     *  to view plus 3 (one for the top line, one for the bottom line,
+     *  and one to offset the 0 counted in the num_options).
      */
     bottom = top + i_length + 3;
 
     /*
-     * Hmm...  If the bottom goes beyond the number of lines available
+     *  Hmm...  If the bottom goes beyond the number of lines available,
      */
-    if(bottom > display_lines) {
+    if (bottom > display_lines) {
         /*
-	 * Position the window at the top if we have more options
-	 *   than will fit in the window.
+	 *  Position the window at the top if we have more
+	 *  options than will fit in the window.
 	 */
-	if(i_length+3 > display_lines) {
+	if (i_length+3 > display_lines) {
 	    top = 0;
             bottom = top + i_length+3;
-	    if(bottom > display_lines)
+	    if (bottom > display_lines)
 	        bottom = display_lines + 1;
 	} else {
 	    /*
-	     * Try to position the window so that the selected option will
-	     *    appear where the selecton box currently is positioned.
-	     * It could end up too high, at this point, but we'll move it
+	     *  Try to position the window so that the selected option will
+	     *    appear where the selection box currently is positioned.
+	     *  It could end up too high, at this point, but we'll move it
 	     *    down latter, if that has happened.
 	     */
 	    top = (display_lines + 1) - (i_length + 3);
@@ -450,12 +478,12 @@ PRIVATE int popup_options ARGS6(int,cur_selection, OptionType *,list,
     }
 
     /*
-     * This is really fun, when the length is 4, it means 0-4, or 5.
+     *  This is really fun, when the length is 4, it means 0-4, or 5.
      */
     length = (bottom - top) - 2;
 
     /*
-     * Move the window down if it's too high.
+     *  Move the window down if it's too high.
      */
     if (bottom < ly + 2) {
         bottom = ly + 2;
@@ -465,8 +493,8 @@ PRIVATE int popup_options ARGS6(int,cur_selection, OptionType *,list,
     }
 
     /*
-     * Set up the overall window, including the boxing characters ('*'), if
-     * it all fits.  Otherwise, set up the widest window possible. - FM
+     *  Set up the overall window, including the boxing characters ('*'),
+     *  if it all fits.  Otherwise, set up the widest window possible. - FM
      */
 #ifndef USE_SLANG
     if (!(form_window = newwin(bottom - top, width+4, top, lx - 1)) &&
@@ -480,11 +508,11 @@ PRIVATE int popup_options ARGS6(int,cur_selection, OptionType *,list,
 #endif /* !USE_SLANG */
 
     /*
-     * Set up the window_offset for options.
+     *  Set up the window_offset for options.
      *   cur_selection ranges from 0...n
      *   length ranges from 0...m
      */
-    if(cur_selection >= length)	{
+    if (cur_selection >= length) {
         window_offset = cur_selection - length + 1;
     }
 
@@ -495,12 +523,13 @@ PRIVATE int popup_options ARGS6(int,cur_selection, OptionType *,list,
  *        09-05-94 FM
  */
 redraw:
+    opt_ptr = list;
 
-    opt_ptr=list;
-
-    /* display the boxed options */
-    for(i = 0; i <= num_options; i++, opt_ptr = opt_ptr->next) {
-        if(i >= window_offset && i - window_offset < length) {
+    /*
+     *  Display the boxed options.
+     */
+    for (i = 0; i <= num_options; i++, opt_ptr = opt_ptr->next) {
+        if (i >= window_offset && i - window_offset < length) {
 #ifndef USE_SLANG
 	    wmove(form_window,(i+1)-window_offset,2);
 	    wclrtoeol(form_window);
@@ -521,12 +550,16 @@ redraw:
 #else
     SLsmg_draw_box (top, lx - 1, bottom - top, width + 4);
 #endif /* !USE_SLANG */
-    opt_ptr=NULL;
+    opt_ptr = NULL;
 
-    /* loop on user input */
-    while(cmd != LYK_ACTIVATE) {
+    /*
+     *  Loop on user input.
+     */
+    while (cmd != LYK_ACTIVATE) {
 
-        /* unreverse cur selection */
+        /*
+	 *  Unreverse cur selection.
+	 */
 	if (opt_ptr != NULL) {
 #ifndef USE_SLANG
 	    wmove(form_window,(i+1)-window_offset,2);
@@ -537,9 +570,9 @@ redraw:
 #endif /* !USE_SLANG */
 	}
 
-        opt_ptr=list;
+        opt_ptr = list;
 
-        for(i=0; i<cur_selection; i++, opt_ptr = opt_ptr->next) 
+        for (i = 0; i < cur_selection; i++, opt_ptr = opt_ptr->next) 
 	    ; /* null body */
 
 #ifndef USE_SLANG
@@ -568,85 +601,67 @@ redraw:
         switch(cmd) {
             case LYK_PREV_LINK:
 	    case LYK_UP_LINK:
-	
-	    if( cur_selection)
-                cur_selection--;
 
-		/* scroll the window up if neccessary */
-		if (cur_selection-window_offset < 0) {
+		if (cur_selection > 0)
+		    cur_selection--;
+
+		/*
+		 *  Scroll the window up if neccessary.
+		 */
+		if ((cur_selection - window_offset) < 0) {
 		    window_offset--;
-#ifdef USE_SLANG
 		    goto redraw;
-#else
-		    wmove(form_window,1,2);
-		    winsertln(form_window);
-#ifdef VMS
-		    VMSbox(form_window, (bottom - top), (width + 4));
-#else
-    		    box(form_window, BOXVERT, BOXHORI);
-#endif /* VMS */
-#endif /* USE_SLANG */
 		}
                 break;
 
             case LYK_NEXT_LINK:
 	    case LYK_DOWN_LINK:
-		if(cur_selection < num_options)
+		if (cur_selection < num_options)
                     cur_selection++;
 
-		/* scroll the window down if neccessary */
-		if(cur_selection-window_offset >= length) {
-		    /* remove the bottom border befor scrolling */
+		/*
+		 *  Scroll the window down if neccessary
+		 */
+		if ((cur_selection - window_offset) >= length) {
 		    window_offset++;
-#ifdef USE_SLANG
 		    goto redraw;
-#else
-		    wmove(form_window,length+1,1);
-		    wclrtoeol(form_window);
-		    scroll(form_window);
-#ifdef VMS
-		    VMSbox(form_window, (bottom - top), (width + 4));
-#else
-    		    box(form_window, BOXVERT, BOXHORI);
-#endif /* VMS */
-#endif /* USE_SLANG */
 		}
                 break;
 
 	    case LYK_NEXT_PAGE:
 		/*
-		 * Okay, are we on the last page of the list?
-		 *   if not then,
+		 *  Okay, are we on the last page of the list?
+		 *  If not then,
 		 */
-		if(window_offset != num_options - length + 1) {
+		if (window_offset != (num_options - length + 1)) {
 		    /*
-		     * Modify the current selection to not be a
-		     *   coordinate in the list, but a coordinate
-		     *   on the item selected in the window.
+		     *  Modify the current selection to not be a
+		     *  coordinate in the list, but a coordinate
+		     *  on the item selected in the window.
 		     */
 		    cur_selection -= window_offset;
 
 		    /*
-		     * Page down the proper length for the list.
-		     * If simply to far, back up.
+		     *  Page down the proper length for the list.
+		     *  If simply to far, back up.
 		     */
 		    window_offset += length;
-		    if(window_offset > num_options - length) {
-		        window_offset = num_options - length + 1;
+		    if (window_offset > (num_options - length)) {
+		        window_offset = (num_options - length + 1);
 		    }
 
 		    /*
-		     * Readjust the current selection to be a list
-		     *   coordinate rather than window.
-		     * Redraw this thing.
+		     *  Readjust the current selection to be a
+		     *  list coordinate rather than window.
+		     *  Redraw this thing.
 		     */
 		    cur_selection += window_offset;
 		    goto redraw;
 		}
-		else if(cur_selection < num_options) {
+		else if (cur_selection < num_options) {
 		    /*
-		     * Already on last page of the list so just
-		     *   redraw it with the last item selected.
+		     *  Already on last page of the list so just
+		     *  redraw it with the last item selected.
 		     */
 		    cur_selection = num_options;
 		}
@@ -654,47 +669,372 @@ redraw:
 
 	    case LYK_PREV_PAGE:
 		/*
-		 * Are we on the first page of the list?
-		 *   if not then,
+		 *  Are we on the first page of the list?
+		 *  If not then,
 		 */
-		if(window_offset != 0) {
+		if (window_offset != 0) {
 		    /*
-		     * Modify the current selection to not be a list
-		     *   coordinate, but a window coordinate.
+		     *  Modify the current selection to not be a
+		     *  list coordinate, but a window coordinate.
 		     */
 		    cur_selection -= window_offset;
 
 		    /*
-		     * Page up the proper length.
-		     * If too far, back up.
+		     *  Page up the proper length.
+		     *  If too far, back up.
 		     */
 		    window_offset -= length;
-		    if(window_offset < 0) {
+		    if (window_offset < 0) {
 		        window_offset = 0;
 		    }
 
 		    /*
-		     * Readjust the current selection.
+		     *  Readjust the current selection.
 		     */
 		    cur_selection += window_offset;
 		    goto redraw;
-		}
-		else if(cur_selection > 0) {
+		} else if (cur_selection > 0) {
 		    /*
-		     * Already on the first page so just
-		     *   back up to the first item.
+		     *  Already on the first page so just
+		     *  back up to the first item.
 		     */
 		    cur_selection = 0;
 		}
 		break;
 
+	    case LYK_HOME:
+	        cur_selection = 0;
+		if (window_offset > 0) {
+		    window_offset = 0;
+		    goto redraw;
+		}
+		break;
+
+	    case LYK_END:
+	        cur_selection = num_options;
+		if (window_offset != (num_options - length + 1)) {
+		    window_offset = (num_options - length + 1);
+		    goto redraw;
+		}
+		break;
+
+            case LYK_DOWN_TWO:
+	        cur_selection += 2;
+		if (cur_selection > num_options)
+                    cur_selection = num_options;
+
+		/*
+		 *  Scroll the window down if neccessary.
+		 */
+		if ((cur_selection - window_offset) >= length) {
+		    window_offset += 2;
+		    if (window_offset > (num_options - length + 1))
+		        window_offset = (num_options - length + 1);
+		    goto redraw;
+		}
+                break;
+
+	    case LYK_UP_TWO:
+	        cur_selection -= 2;
+		if (cur_selection < 0)
+		    cur_selection = 0;
+
+		/*
+		 *  Scroll the window up if neccessary.
+		 */
+		if ((cur_selection - window_offset) < 0) {
+		    window_offset -= 2;
+		    if (window_offset < 0)
+		        window_offset = 0;
+		    goto redraw;
+		}
+                break;
+
+            case LYK_DOWN_HALF:
+	        cur_selection += (length/2);
+		if (cur_selection > num_options)
+                    cur_selection = num_options;
+
+		/*
+		 *  Scroll the window down if neccessary.
+		 */
+		if ((cur_selection - window_offset) >= length) {
+		    window_offset += (length/2);
+		    if (window_offset > (num_options - length + 1))
+		        window_offset = (num_options - length + 1);
+		    goto redraw;
+		}
+                break;
+
+	    case LYK_UP_HALF:
+	        cur_selection -= (length/2);
+		if (cur_selection < 0)
+		    cur_selection = 0;
+
+		/*
+		 *  Scroll the window up if neccessary.
+		 */
+		if ((cur_selection - window_offset) < 0) {
+		    window_offset -= (length/2);
+		    if (window_offset < 0)
+		        window_offset = 0;
+		    goto redraw;
+		}
+                break;
+
+	    case LYK_REFRESH:
+	        clearok(curscr, TRUE);
+	        refresh();
+		break;
+
+	    case LYK_NEXT:
+	        strcpy(prev_target, prev_target_buffer);
+	    case LYK_WHEREIS:
+	        if (*prev_target == '\0' ) {
+		    _statusline(ENTER_WHEREIS_QUERY);
+		    if ((ch = LYgetstr(prev_target, VISIBLE,
+	    		 	       sizeof(prev_target_buffer),
+				       recall)) < 0) {
+			/*
+			 *  User cancelled the search via ^G. - FM
+			 */
+			_statusline(CANCELLED);
+			sleep(InfoSecs);
+			goto restore_popup_statusline;
+		    }
+		}
+
+check_recall:
+		if (*prev_target == '\0' &&
+		    !(recall && (ch == UPARROW || ch == DNARROW))) {
+		    /*
+		     *  No entry.  Simply break.   - FM
+		     */
+	            _statusline(CANCELLED);
+		    sleep(InfoSecs);
+		    goto restore_popup_statusline;
+		}
+
+		if (recall && ch == UPARROW) {
+		    if (FirstRecall) {
+		        /*
+			 *  Use the current string or
+			 *  last query in the list. - FM
+			 */
+			FirstRecall = FALSE;
+			if (*prev_target_buffer) {
+			    for (QueryNum = (QueryTotal - 1);
+			         QueryNum > 0; QueryNum--) {
+				if ((cp=(char *)HTList_objectAt(search_queries,
+	    						QueryNum)) != NULL &&
+				    !strcmp(prev_target_buffer, cp)) {
+				    break;
+				}
+			    }
+			} else {
+			    QueryNum = 0;
+			}
+		    } else {
+			/*
+			 *  Go back to the previous query in the list. - FM
+			 */
+			QueryNum++;
+		    }
+		    if (QueryNum >= QueryTotal)
+			/*
+			 *  Roll around to the last query in the list. - FM
+			 */
+			QueryNum = 0;
+		    if ((cp=(char *)HTList_objectAt(search_queries,
+	    					    QueryNum)) != NULL) {
+			strcpy(prev_target, cp);
+			if (*prev_target_buffer &&
+			    !strcmp(prev_target_buffer, prev_target)) {
+			    _statusline(EDIT_CURRENT_QUERY);
+			} else if ((*prev_target_buffer && QueryTotal == 2) ||
+				   (!(*prev_target_buffer) &&
+				      QueryTotal == 1)) {
+			    _statusline(EDIT_THE_PREV_QUERY);
+			} else {
+			    _statusline(EDIT_A_PREV_QUERY);
+			}
+			if ((ch=LYgetstr(prev_target, VISIBLE,
+				sizeof(prev_target_buffer), recall)) < 0) {
+			    /*
+			     *  User cancelled the search via ^G. - FM
+			     */
+			    _statusline(CANCELLED);
+			    sleep(InfoSecs);
+			    goto restore_popup_statusline;
+			}
+			goto check_recall;
+		    }
+		} else if (recall && ch == DNARROW) {
+		    if (FirstRecall) {
+		    /*
+		     *  Use the current string or
+		     *  first query in the list. - FM
+		     */
+		    FirstRecall = FALSE;
+		    if (*prev_target_buffer) {
+			for (QueryNum = 0;
+			     QueryNum < (QueryTotal - 1); QueryNum++) {
+			    if ((cp=(char *)HTList_objectAt(search_queries,
+	    					    QueryNum)) != NULL &&
+				!strcmp(prev_target_buffer, cp)) {
+				    break;
+			    }
+			}
+		    } else {
+			QueryNum = QueryTotal - 1;
+		    }
+		} else {
+		    /*
+		     *  Advance to the next query in the list. - FM
+		     */
+		    QueryNum--;
+		}
+		if (QueryNum < 0)
+		    /*
+		     *  Roll around to the first query in the list. - FM
+		     */
+		    QueryNum = QueryTotal - 1;
+		    if ((cp=(char *)HTList_objectAt(search_queries,
+	    				QueryNum)) != NULL) {
+			strcpy(prev_target, cp);
+			if (*prev_target_buffer &&
+			    !strcmp(prev_target_buffer, prev_target)) {
+			    _statusline(EDIT_CURRENT_QUERY);
+			} else if ((*prev_target_buffer &&
+				    QueryTotal == 2) ||
+				   (!(*prev_target_buffer) &&
+				    QueryTotal == 1)) {
+			    _statusline(EDIT_THE_PREV_QUERY);
+			} else {
+			    _statusline(EDIT_A_PREV_QUERY);
+			}
+			if ((ch = LYgetstr(prev_target, VISIBLE,
+					   sizeof(prev_target_buffer),
+					   recall)) < 0) {
+			    /*
+			     * User cancelled the search via ^G. - FM
+			     */
+			    _statusline(CANCELLED);
+			    sleep(InfoSecs);
+			    goto restore_popup_statusline;
+	    		}
+			goto check_recall;
+		    }
+ 		}
+		/*
+		 *  Replace the search string buffer with the new target. - FM
+		 */
+		strcpy(prev_target_buffer, prev_target);
+		HTAddSearchQuery(prev_target_buffer);
+
+		/*
+		 *  Start search at the next option. - FM
+		 */
+		for (j = 1, tmp_ptr = opt_ptr->next;
+		     tmp_ptr != NULL; tmp_ptr = tmp_ptr->next, j++) {
+		    if (case_sensitive) {
+			if (strstr(tmp_ptr->name, prev_target_buffer) != NULL)
+			    break;
+		    } else {
+			if (LYstrstr(tmp_ptr->name, prev_target_buffer) != NULL)
+			    break;
+		    }
+		}
+		if (tmp_ptr != NULL) {
+		    /*
+		     *  We have a hit, so make that option the current. - FM
+		     */
+		    cur_selection += j;
+		    /*
+		     *  Scroll the window down if neccessary.
+		     */
+		    if ((cur_selection - window_offset) >= length) {
+		        window_offset += j;
+			if (window_offset > (num_options - length + 1))
+			    window_offset = (num_options - length + 1);
+			ReDraw = TRUE;
+		    }
+		    goto restore_popup_statusline;
+		}
+
+		/*
+		 *  If we started at the beginning, it can't be present. - FM
+		 */
+		if (cur_selection == 0) {
+		    _user_message(STRING_NOT_FOUND, prev_target_buffer);
+		    sleep(MessageSecs);
+		    goto restore_popup_statusline;
+		}
+
+		/*
+		 *  Search from the beginning to the current option. - FM
+		 */
+		for (j = 0, tmp_ptr = list;
+		     j < cur_selection; tmp_ptr = tmp_ptr->next, j++) {
+		    if (case_sensitive) {
+			if (strstr(tmp_ptr->name, prev_target_buffer) != NULL)
+			    break;
+		    } else {
+			if (LYstrstr(tmp_ptr->name, prev_target_buffer) != NULL)
+			    break;
+		    }
+		}
+		if (j < cur_selection) {
+		    /*
+		     *  We have a hit, so make that option the current. - FM
+		     */
+		    j = (cur_selection - j);
+		    cur_selection -= j;
+		    /*
+		     *  Scroll the window up if neccessary.
+		     */
+		    if ((cur_selection - window_offset) < 0) {
+		        window_offset -= j;
+			if (window_offset < 0)
+			    window_offset = 0;
+			ReDraw = TRUE;
+		    }
+		    goto restore_popup_statusline;
+		}
+
+		/*
+		 *  Didn't find it in the preceding options either. - FM
+		 */
+		_user_message(STRING_NOT_FOUND, prev_target_buffer);
+		sleep(MessageSecs);
+
+restore_popup_statusline:
+		/*
+		 *  Restore the popup statusline and
+		 *  reset the search variables. - FM
+		 */
+		if (disabled)
+		    _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
+   		else
+		    _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
+		*prev_target = '\0';
+		QueryTotal = (search_queries ? HTList_count(search_queries)
+					     : 0);
+		recall = ((QueryTotal >= 1) ? RECALL : NORECALL);
+		QueryNum = QueryTotal;
+		if (ReDraw == TRUE) {
+		    ReDraw = FALSE;
+		    goto redraw;
+		}
+		break;
+
 	    case LYK_QUIT:
 	    case LYK_ABORT:
 	    case LYK_PREV_DOC:
 	    case 7:	/* Control-G */
 	    case 3:	/* Control-C */
 		cur_selection = orig_selection;
-		cmd=LYK_ACTIVATE; /* to exit */
+		cmd = LYK_ACTIVATE; /* to exit */
 		break;
         }
 
@@ -706,4 +1046,3 @@ redraw:
 
     return(cur_selection);
 }
-
diff --git a/src/LYGetFile.c b/src/LYGetFile.c
index 81d0d945..cd8ef577 100644
--- a/src/LYGetFile.c
+++ b/src/LYGetFile.c
@@ -53,28 +53,28 @@ extern BOOLEAN LYDidRename;
 PRIVATE char * LYSanctify ARGS1(char *, href) 
 {
     int i;
-    char *p,*cp,*tp;
+    char *p, *cp, *tp;
     char address_buffer[1024];
 
-    i = strlen(href) - 1;
+    i = (strlen(href) - 1);
     while (i && href[i] == '/') href[i--] = '\0';
 
-    if ((cp = (char *) strchr(href,'~')) != NULL) {
-       if (!strncmp(href,"file://localhost/",17))
-	 tp = href + 17;
+    if ((cp = (char *)strchr(href,'~')) != NULL) {
+       if (!strncmp(href, "file://localhost/", 17))
+	 tp = (href + 17);
        else 
-	 tp = href + 5;
-       if ((cp-tp) && *(cp-1) != '/')
+	 tp = (href + 5);
+       if ((cp - tp) && *(cp-1) != '/')
 	 return href;
-       LYstrncpy(address_buffer,href,cp-href);
-       if (address_buffer[strlen(address_buffer)-1] == '/')
-	 address_buffer[strlen(address_buffer)-1] = '\0';
+       LYstrncpy(address_buffer, href, (cp - href));
+       if (address_buffer[(strlen(address_buffer) - 1)] == '/')
+	 address_buffer[(strlen(address_buffer) - 1)] = '\0';
        p = (char *)Home_Dir();
-       strcat(address_buffer,p);
+       strcat(address_buffer, p);
        if (strlen(++cp))
-	 strcat(address_buffer,cp);
-       if (strcmp(href,address_buffer))
-	 StrAllocCopy(href,address_buffer);
+	 strcat(address_buffer, cp);
+       if (strcmp(href, address_buffer))
+	 StrAllocCopy(href, address_buffer);
     }
     return href;
 }
@@ -92,6 +92,7 @@ Try_Redirected_URL:
 	WWWDoc.address = doc->address;
         WWWDoc.post_data = doc->post_data;
         WWWDoc.post_content_type = doc->post_content_type;
+        WWWDoc.bookmark = doc->bookmark;
 	WWWDoc.isHEAD = doc->isHEAD;
 
 	/* reset WWW_Download_File just in case */
@@ -133,7 +134,8 @@ Try_Redirected_URL:
 		}
 		if (traversal) {
 		    /* only traverse http URLs */
-		    if (url_type != HTTP_URL_TYPE)
+		    if (url_type != HTTP_URL_TYPE &&
+		        url_type != LYNXIMGMAP_URL_TYPE)
 		        return(NULLFILE);
 		} else if (check_realm && !LYPermitURL && !LYJumpFileURL) {
 		    if (!(0==strncmp(startrealm, WWWDoc.address,
@@ -237,6 +239,7 @@ Try_Redirected_URL:
 		       WWWDoc.address = doc->address;
         	       WWWDoc.post_data = doc->post_data;
         	       WWWDoc.post_content_type = doc->post_content_type;
+		       WWWDoc.bookmark = doc->bookmark;
 		       WWWDoc.isHEAD = doc->isHEAD;
 
 		       if (!HTLoadAbsolute(&WWWDoc))
@@ -266,6 +269,7 @@ Try_Redirected_URL:
 		    WWWDoc.address = doc->address;
         	    WWWDoc.post_data = doc->post_data;
         	    WWWDoc.post_content_type = doc->post_content_type;
+		    WWWDoc.bookmark = doc->bookmark;
 		    WWWDoc.isHEAD = doc->isHEAD;
 
 		    if (!HTLoadAbsolute(&WWWDoc)) {
@@ -283,10 +287,8 @@ Try_Redirected_URL:
 				 doc->address+9, ALWAYS_EXEC_PATH)) {
             	        statusline(EXECUTION_DISABLED);
             		sleep(MessageSecs);
-		    } else if (no_bookmark_exec && bookmark_page &&
-		    	       (strstr(HTLoadedDocumentURL(), bookmark_page) ||
-			        !strcmp(HTLoadedDocumentTitle(),
-					MOSAIC_BOOKMARK_TITLE))) {
+		    } else if (no_bookmark_exec &&
+		    	       HTLoadedDocumentBookmark()) {
 			statusline(BOOKMARK_EXEC_DISABLED);
 			sleep(MessageSecs);
 		    } else if (local_exec || (local_exec_on_local_files &&
@@ -476,6 +478,7 @@ Try_Redirected_URL:
 			WWWDoc.address = doc->address;
 			WWWDoc.post_data = doc->post_data;
 			WWWDoc.post_content_type = doc->post_content_type;
+			WWWDoc.bookmark = doc->bookmark;
 			WWWDoc.isHEAD = doc->isHEAD;
 		        status = HTLoadAbsolute(&WWWDoc);
 		    }
@@ -639,51 +642,80 @@ Try_Redirected_URL:
 		     */
                     {
                         char *pound;
-                        /* check for #selector */
+                        /*
+			 *  Check for #selector.
+			 */
                         pound = (char *)strchr(doc->address, '#');
 
-			/* check to see if there is a temp
-			 * file waiting for us to download
+			/*
+			 *  Check to see if there is a temp
+			 *  file waiting for us to download.
 			 */
 			if (WWW_Download_File) {
-				HTMLSetCharacterHandling(current_char_set);
-				if (LYdownload_options(&doc->address,
-						       WWW_Download_File) < 0)
-				    return(NOT_FOUND);
-		    		WWWDoc.address = doc->address;
-		    		FREE(WWWDoc.post_data);
-		    		FREE(WWWDoc.post_content_type);
-				WWWDoc.isHEAD = FALSE;
-				HTOutputFormat = WWW_PRESENT;
-				if (!HTLoadAbsolute(&WWWDoc)) 
-                        	    return(NOT_FOUND);
-				else 
-				    return(NORMAL);
+			    HTParentAnchor *tmpanchor;
+			    char *fname = NULL;
+
+			    HTMLSetCharacterHandling(current_char_set);
+			    /*
+			     *  Check for a suggested filename from
+			     *  the Content-Dispostion header. - FM
+			     */
+			    if (((tmpanchor = HTAnchor_parent(
+						HTAnchor_findAddress(&WWWDoc)
+							     )) != NULL) &&
+				HTAnchor_SugFname(tmpanchor) != NULL) {
+				StrAllocCopy(fname,
+					     HTAnchor_SugFname(tmpanchor));
+			    } else {
+			        StrAllocCopy(fname, doc->address);
+			    }
+			    if (LYdownload_options(&fname,
+						   WWW_Download_File) < 0) {
+				FREE(fname);
+				return(NOT_FOUND);
+			    }
+			    StrAllocCopy(doc->address, fname);
+			    FREE(fname);
+		    	    WWWDoc.address = doc->address;
+		    	    FREE(WWWDoc.post_data);
+		    	    FREE(WWWDoc.post_content_type);
+			    WWWDoc.bookmark = doc->bookmark;
+			    WWWDoc.isHEAD = FALSE;
+			    HTOutputFormat = WWW_PRESENT;
+			    if (!HTLoadAbsolute(&WWWDoc)) 
+                        	return(NOT_FOUND);
+			    else 
+				return(NORMAL);
 
 			} else if (pound == NULL &&
-				  /*
-				   * HTAnchor hash-table searches are now
-				   * case-sensitive (hopefully, without
-				   * anchor deletion problems), so this
-				   * is too. - FM
-				   */
-                                  (strcmp(doc->address,
-						HTLoadedDocumentURL()) ||
-				  /*
-				   * Also check the post_data elements. - FM
-				   */
-				  strcmp(doc->post_data ? doc->post_data : "",
-				    	 HTLoadedDocumentPost_data()) ||
-				  /*
-				   * Also check the isHEAD element. - FM
-				   */
-				  doc->isHEAD != HTLoadedDocumentIsHEAD())) {
+				   /*
+				    * HTAnchor hash-table searches are now
+				    * case-sensitive (hopefully, without
+				    * anchor deletion problems), so this
+				    * is too. - FM
+				    */
+				   (strcmp(doc->address,
+				  	   HTLoadedDocumentURL()) ||
+				   /*
+				    * Also check the post_data elements. - FM
+				    */
+				   strcmp((doc->post_data ?
+				   	   doc->post_data : ""),
+				    	  HTLoadedDocumentPost_data()) ||
+				   /*
+				    * Also check the isHEAD element. - FM
+				    */
+				   doc->isHEAD != HTLoadedDocumentIsHEAD())) {
 			    HTMLSetCharacterHandling(current_char_set);
-			    /* nothing needed to be shown */
+			    /*
+			     *  Nothing needed to be shown.
+			     */
 			    return(NULLFILE);
 
                         } else {
-                        /* may set www_search_result */
+                        /*
+			 *  May set www_search_result.
+			 */
                             if (pound != NULL)
                                 HTFindPoundSelector(pound+1);
 			    HTMLSetCharacterHandling(current_char_set);
diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h
index 88c84b82..5f2577c5 100644
--- a/src/LYGlobalDefs.h
+++ b/src/LYGlobalDefs.h
@@ -48,7 +48,7 @@ extern char *list_format;
 extern BOOLEAN lynx_edit_mode;
 extern BOOLEAN no_dired_support;
 extern BOOLEAN dir_list_style;
-extern taglink *tagged;
+extern HTList *tagged;
 #define FILES_FIRST 1
 #define MIXED_STYLE 2
 #ifdef OK_OVERRIDE
@@ -81,7 +81,8 @@ extern BOOLEAN LYUseNoviceLineTwo;  /* True if TOGGLE_HELP is not mapped */
 
 #define MAX_LINE 1024	/* Hope that no window is larger than this */
 extern char star_string[MAX_LINE + 1]; /* from GridText.c */
-#define STARS(n) (&star_string[(MAX_LINE-1) - (n)])
+#define STARS(n) \
+ ((n) >= MAX_LINE ? star_string : &star_string[(MAX_LINE-1)] - (n))
 #define DIRNAMESIZE 256
 
 extern BOOLEAN LYShowCursor;   /* show the cursor or hide it */
@@ -153,6 +154,8 @@ extern BOOLEAN no_suspend;
 extern BOOLEAN no_editor;
 extern BOOLEAN no_shell;
 extern BOOLEAN no_bookmark;
+extern BOOLEAN no_multibook;
+extern BOOLEAN no_bookmark_exec;
 extern BOOLEAN no_option_save;
 extern BOOLEAN no_print;
 extern BOOLEAN no_download;
@@ -160,7 +163,6 @@ extern BOOLEAN no_disk_save;
 extern BOOLEAN no_exec;
 extern BOOLEAN no_lynxcgi;
 extern BOOLEAN exec_frozen;
-extern BOOLEAN no_bookmark_exec;
 extern BOOLEAN no_goto;
 extern BOOLEAN no_goto_cso;
 extern BOOLEAN no_goto_file;
@@ -197,6 +199,7 @@ extern char *editor;          /* if non empty it enables edit mode with
 			       * the editor that is named */
 extern char *jumpfile;
 extern char *bookmark_page;
+extern char *BookmarkPage;
 extern char *personal_type_map;
 extern char *global_type_map;
 extern char *global_extension_map;
@@ -248,5 +251,10 @@ extern BOOLEAN LYisConfiguredForX;
 extern char *URLDomainPrefixes;
 extern char *URLDomainSuffixes;
 extern BOOLEAN startfile_ok;
+extern BOOLEAN LYSelectPopups;		/* Cast popups to radio buttons? */
+extern BOOLEAN LYUseDefSelPop;		/* Command line -popup toggle    */
+extern int LYMultiBookmarks;    	/* Multi bookmark support on?	 */
+extern BOOLEAN LYMBMBlocked;		/* Force MBM support off?	 */
+extern BOOLEAN LYMBMAdvanced;		/* MBM statusline for ADVANCED?	 */
 
 #endif /* LYGLOBALDEFS_H */
diff --git a/src/LYHistory.c b/src/LYHistory.c
index d947820d..8ad69cb3 100644
--- a/src/LYHistory.c
+++ b/src/LYHistory.c
@@ -66,14 +66,16 @@ PUBLIC void LYpush ARGS1(document *,doc)
     if (nhist<MAXHIST)  {
 	history[nhist].link = doc->link;
 	history[nhist].page = doc->line;
-	history[nhist].title = 0;
+	history[nhist].title = NULL;
 	StrAllocCopy(history[nhist].title, doc->title);
-	history[nhist].address = 0;
+	history[nhist].address = NULL;
 	StrAllocCopy(history[nhist].address, doc->address);
-	history[nhist].post_data = 0;
+	history[nhist].post_data = NULL;
 	StrAllocCopy(history[nhist].post_data, doc->post_data);
-	history[nhist].post_content_type = 0;
+	history[nhist].post_content_type = NULL;
 	StrAllocCopy(history[nhist].post_content_type, doc->post_content_type);
+	history[nhist].bookmark = NULL;
+	StrAllocCopy(history[nhist].bookmark, doc->bookmark);
 	history[nhist].isHEAD = doc->isHEAD;
 	nhist++;
 
@@ -101,6 +103,8 @@ PUBLIC void LYpop ARGS1(document *,doc)
 	doc->post_data = history[nhist].post_data;
 	FREE(doc->post_content_type);
 	doc->post_content_type = history[nhist].post_content_type;
+	FREE(doc->bookmark);
+	doc->bookmark = history[nhist].bookmark;
 	doc->isHEAD = history[nhist].isHEAD;
 
         if(TRACE)
@@ -124,6 +128,7 @@ PUBLIC void LYpop_num ARGS2(int,number, document *,doc)
 	StrAllocCopy(doc->address, history[number].address);
 	StrAllocCopy(doc->post_data, history[number].post_data);
 	StrAllocCopy(doc->post_content_type, history[number].post_content_type);
+	StrAllocCopy(doc->bookmark, history[number].bookmark);
 	doc->isHEAD = history[number].isHEAD;
     }
 }
@@ -236,6 +241,7 @@ PUBLIC void historytarget ARGS1(document *,newdoc)
 	    WWWDoc.address = newdoc->address;
             WWWDoc.post_data = newdoc->post_data;
             WWWDoc.post_content_type = newdoc->post_content_type;
+            WWWDoc.bookmark = newdoc->bookmark;
 	    WWWDoc.isHEAD = newdoc->isHEAD;
 	    if ((HText *)HTAnchor_document(
 				HTAnchor_parent(HTAnchor_findAddress(&WWWDoc))
diff --git a/src/LYKeymap.c b/src/LYKeymap.c
index a12a471b..5ba5f6a1 100644
--- a/src/LYKeymap.c
+++ b/src/LYKeymap.c
@@ -750,3 +750,19 @@ PUBLIC char *key_for_func ARGS1 (int,func)
 	}
 	return buf;
 }
+
+/*
+ *  This function returns TRUE if the ch is non-alphanumeric
+ *  and maps to keyname (LYK_foo in the keymap[] array). - FM
+ */ 
+PUBLIC BOOL LYisNonAlnumKeyname ARGS2(
+	int,	ch,
+	int,	keyname)
+{
+    if ((ch >= '0' && ch <= '9') ||
+        (ch >= 'A' && ch <= 'z') ||
+	ch < 0 || ch > 269)
+	return (FALSE);
+
+    return(keymap[ch+1] == keyname);
+}
diff --git a/src/LYKeymap.h b/src/LYKeymap.h
index af29e432..99c38fd2 100644
--- a/src/LYKeymap.h
+++ b/src/LYKeymap.h
@@ -12,6 +12,7 @@ extern void set_numbers_as_arrows NOPARAMS;
 extern void reset_numbers_as_arrows NOPARAMS;
 extern void print_keymap PARAMS((char **newfile));
 extern char *key_for_func PARAMS((int func));
+extern BOOLEAN LYisNonAlnumKeyname PARAMS((int ch, int keyname));
 
 extern char keymap[]; /* main keymap matrix */
 
diff --git a/src/LYLocal.c b/src/LYLocal.c
index 591b7ff4..95a49abc 100644
--- a/src/LYLocal.c
+++ b/src/LYLocal.c
@@ -5,8 +5,16 @@
 	Added OK_PERMIT compilation option.
 	Support replacement of compiled-in f)ull menu configuration via
 	  DIRED_MENU definitions in lynx.cfg, so that more than one menu
-	  can be driven by the same executable.
-*/
+	  can be driven by the same executable. */
+/* Modified Oct-96 Klaus Weide (kweide@tezcat.com):
+	Changed to use the library's HTList_* functions and macros for
+	  managing the list of tagged file URLs.
+	Keep track of proper level of URL escaping, so that unusual filenames
+	  which contain #% etc. are handled properly (some HTUnEscapeSome()'s
+	  left in to be conservative, and to document where superfluous
+	  unescaping took place before).
+	Dynamic memory instead of fixed length buffers in a few cases.
+	Other minor changes to make things work as intended. */
 
 #ifdef DIRED_SUPPORT
 
@@ -19,6 +27,8 @@
 #include "LYStrings.h"
 #include "LYStructs.h"
 #include "LYGetFile.h"
+#include "LYHistory.h"
+#include "LYUpload.h"
 #include "LYLocal.h"
 #include "LYSystem.h"
 
@@ -30,7 +40,6 @@
 
 #define FREE(x) if (x) {free(x); x = NULL;}
 
-PRIVATE void clear_tags NOPARAMS;
 PRIVATE int my_spawn PARAMS((char *path, char **argv, char *msg));
 PRIVATE char *filename PARAMS((char *prompt, char *buf, int bufsize));
 
@@ -39,7 +48,8 @@ PRIVATE BOOLEAN permit_location PARAMS((char * destpath, char * srcpath,
 					char ** newpath));
 #endif /* OK_PERMIT */
 
-PRIVATE char *render_item PARAMS((char *s, char *path, char *dir, char *buf));
+PRIVATE char *render_item PARAMS((char *s, char *path, char *dir, char *buf,
+				  int bufsize, BOOLEAN url_syntax));
 
 PRIVATE struct dired_menu *menu_head = NULL;
 struct dired_menu {
@@ -129,7 +139,7 @@ struct dired_menu {
 
 #ifdef OK_ZIP
 { DE_DIR,	      "", "Package and compress",
-           "(using zip)", "LYNXDIRED://ZIP%f",			NULL },
+           "(using zip)", "LYNXDIRED://ZIP%p",			NULL },
 #endif /* OK_ZIP */
 
 { DE_FILE,	      "", "Compress",
@@ -142,11 +152,11 @@ struct dired_menu {
 
 #ifdef OK_ZIP
 { DE_FILE,	      "", "Compress",
-           "(using zip)", "LYNXDIRED://ZIP%f",			NULL },
+           "(using zip)", "LYNXDIRED://ZIP%p",			NULL },
 #endif /* OK_ZIP */
 
 { DE_TAG,	      "", "Move all tagged items to another location.",
-		      "", "LYNXDIRED://MOVE_TAGGED",		NULL },
+		      "", "LYNXDIRED://MOVE_TAGGED%d",		NULL },
 
 { DE_TAG,	      "", "Remove all tagged files and directories.",
 		      "", "LYNXDIRED://REMOVE_TAGGED",		NULL },
@@ -162,13 +172,14 @@ PRIVATE BOOLEAN remove_tagged NOARGS
    int c, ans;
    char *cp,*tp;
    char tmpbuf[1024];
-   char testpath[512];
+   char *testpath = NULL;
    struct stat dir_info;
    int count,i;
-   taglink *tag;
+   HTList *tag;
    char *args[5];
 
-   if (tagged == NULL) return 0; /* should never happen */
+   if (HTList_isEmpty(tagged))  /* should never happen */
+       return 0;
 
    _statusline("Remove all tagged files and directories (y or n): ");
    c = LYgetch();
@@ -176,15 +187,14 @@ PRIVATE BOOLEAN remove_tagged NOARGS
 
    count = 0;
    tag = tagged;
-   while(ans == 'Y' && tag != NULL) {
-      cp = tag->name;
+   while(ans == 'Y' && (cp = (char *)HTList_nextObject(tag)) != NULL) {
       if(is_url(cp) == FILE_URL_TYPE) { /* unecessary check */
 	 tp = cp;
 	 if(!strncmp(tp,"file://localhost",16))
 	   tp += 16;
 	 else if(!strncmp(tp,"file:",5))
 	   tp += 5;
-	 strcpy(testpath,tp);
+	 StrAllocCopy(testpath,tp);
 	 HTUnEscape(testpath);
 	 if((i = strlen(testpath)) && testpath[i-1] == '/')
 	   testpath[i-1] = '\0';
@@ -202,19 +212,25 @@ PRIVATE BOOLEAN remove_tagged NOARGS
 	    args[2] = testpath;
 	    args[3] = (char *) 0;
 	    sprintf(tmpbuf, "remove %s", testpath);
-	    if (my_spawn(RM_PATH, args, tmpbuf) <= 0)
+	    if (my_spawn(RM_PATH, args, tmpbuf) <= 0) {
+		FREE(testpath);
 		return count;
+	    }
 	    ++count;
 	 }
       }
-      tag = tag->next;
    }
+   FREE(testpath);
    clear_tags();
    return count;
 }
 
 /* Move all tagged files and directories to a new location. */
 /* Input is current directory. */
+/* The tests in this function can, at best, prevent some user mistakes -
+   anybody who relies on them for security is seriously misguided.
+   If a user has enough permissions to move a file somewhere, the same 
+   uid with Lynx & dired can do the same thing. */
 
 PRIVATE BOOLEAN modify_tagged ARGS1(
 	char *,		testpath)
@@ -224,13 +240,15 @@ PRIVATE BOOLEAN modify_tagged ARGS1(
    ino_t inode;
    uid_t owner;
    char tmpbuf[1024];
-   char savepath[512];
+   char *savepath = NULL;
+   char *srcpath = NULL;
    struct stat dir_info;
    char *args[5];
-   int count;
-   taglink *tag;
+   int count = 0;
+   HTList *tag;
 
-   if (tagged == NULL) return 0; /* should never happen */
+   if (HTList_isEmpty(tagged))  /* should never happen */
+       return 0;
 
    _statusline("Enter new location for tagged items: ");
 
@@ -240,17 +258,46 @@ PRIVATE BOOLEAN modify_tagged ARGS1(
 
 /* determine the ownership of the current location */
 
-      cp = testpath;
+   
+      /*
+       *  This test used to always fail from the dired menu...
+       *  changed to something that hopefully makes more sense - KW
+       */ 
+      if (testpath && *testpath && 0!=strcmp(testpath,"/")) {
+	  /*
+	   *  testpath passed in and is not empty and not
+	   *  a single "/" (which would probably be bogus) - use it
+	   */
+	  cp = testpath;
+      } else {
+	  /*
+	   *  Prepare to get directory path from one of the tagged files.
+	   */
+	  cp = HTList_lastObject(tagged);
+	  testpath = NULL;	/* won't be needed any more in this function,
+				 set to NULL as a flag */
+	  if (!cp)   /* last resort, should never happen */
+	      cp = "/";
+      }
       if (!strncmp(cp,"file://localhost",16))
 	cp += 16;
       else if (!strncmp(cp,"file:",5))
 	cp += 5;
-      strcpy(savepath,cp);
+      if (testpath==NULL) {
+          /*
+	   *  Get the directory containing the file or subdir.
+	   */
+	  cp = strip_trailing_slash(cp);
+	  savepath = HTParse(".", cp, PARSE_PATH+PARSE_PUNCTUATION);
+      } else {
+	  StrAllocCopy(savepath, cp);
+      }
       HTUnEscape(savepath);
       if (stat(savepath,&dir_info) == -1) {
 	 sprintf(tmpbuf,"Unable to get status of %s ",savepath);
 	 _statusline(tmpbuf);
 	 sleep(AlertSecs);
+	 FREE(savepath);
 	 return 0;
       } 
 
@@ -264,20 +311,29 @@ PRIVATE BOOLEAN modify_tagged ARGS1(
 /* replace ~/ references to the home directory */
 
       if (!strncmp(tmpbuf,"~/",2)) {
-	 cp = (char *)Home_Dir();
-	 strcpy(testpath,cp);
-	 strcat(testpath,tmpbuf+1);
-	 strcpy(tmpbuf,testpath);
+	  char *cp1 = NULL;
+	  StrAllocCopy(cp1, (char *)Home_Dir());
+	  StrAllocCat(cp1, (tmpbuf+1));
+	  if (strlen(cp1) > (sizeof(tmpbuf)-1)) {
+	      sprintf(tmpbuf, "%s ", "Path too long");
+	      _statusline(tmpbuf);
+	      sleep(AlertSecs);
+	      FREE(savepath);
+	      FREE(cp1);
+	      return 0;
+	  }
+	  strcpy(tmpbuf, cp1);
+	  FREE(cp1);
       }
 
 /* if path is relative prefix it with current location */
 
       if (tmpbuf[0] != '/') {
 	 if (savepath[strlen(savepath)-1] != '/')
-	   strcat(savepath,"/");
-	 strcat(savepath,tmpbuf);
+	     StrAllocCat(savepath,"/");
+	 StrAllocCat(savepath,tmpbuf);
       } else {
-	 strcpy(savepath,tmpbuf);
+	 StrAllocCopy(savepath,tmpbuf);
       }
 
 /* stat the target location to determine type and ownership */
@@ -286,6 +342,7 @@ PRIVATE BOOLEAN modify_tagged ARGS1(
 	 sprintf(tmpbuf,"Unable to get status of %s ",savepath);
 	 _statusline(tmpbuf);
 	 sleep(AlertSecs);
+	 FREE(savepath);
 	 return 0;
       }
 
@@ -295,6 +352,7 @@ PRIVATE BOOLEAN modify_tagged ARGS1(
 	 _statusline(
 	   "Source and destination are the same location - request ignored!");
 	 sleep(AlertSecs);
+	 FREE(savepath);
 	 return 0;
       }
 
@@ -308,35 +366,38 @@ PRIVATE BOOLEAN modify_tagged ARGS1(
 
 /* move all tagged items to the target location */
 
-	    while (tag != NULL) {
-	       cp = tag->name;
+	    while((cp = (char *)HTList_nextObject(tag)) != NULL) {
 	       if(!strncmp(cp,"file://localhost",16))
 		 cp += 16;
 	       else if(!strncmp(cp,"file:",5))
 		 cp += 5;
-	       strcpy(testpath,cp);
-	       HTUnEscape(testpath);
+	       StrAllocCopy(srcpath, cp);
+	       HTUnEscape(srcpath);
 
-	       sprintf(tmpbuf,"move %s to %s",testpath,savepath);
+	       sprintf(tmpbuf, "move %s to %s", srcpath, savepath);
 	       args[0] = "mv";
-	       args[1] = testpath;
+	       args[1] = srcpath;
 	       args[2] = savepath;
 	       args[3] = (char *) 0;
 	       if (my_spawn(MV_PATH, args, tmpbuf) <= 0)
 		  break;
-	       tag = tag->next;
 	       ++count;
 	    }
+	    FREE(srcpath);
+	    FREE(savepath);
 	    clear_tags();
 	    return count;
 	 } else {
 	    _statusline("Destination has different owner! Request denied. ");
 	    sleep(AlertSecs);
+	    FREE(srcpath);
+	    FREE(savepath);
 	    return 0;
 	 }
       } else {
 	 _statusline("Destination is not a valid directory! Request denied. ");
 	 sleep(AlertSecs);
+	 FREE(savepath);
 	 return 0;
       }
    }
@@ -548,14 +609,14 @@ PUBLIC BOOLEAN local_modify ARGS2(
    char testpath[512]; /* a bit ridiculous */
    int count;
 
-   if (tagged != NULL) {
+   if (!HTList_isEmpty(tagged)) {
       cp = doc->address;
       if (!strncmp(cp,"file://localhost",16))
 	cp += 16;
       else if (!strncmp(cp,"file:",5))
 	cp += 5;
       strcpy(testpath,cp);
-      HTUnEscape(testpath);
+      HTUnEscapeSome(testpath,"/");
       count = modify_tagged(testpath);
 
       if (doc->link > (nlinks-count-1)) doc->link = nlinks-count-1;
@@ -842,7 +903,7 @@ PUBLIC BOOLEAN local_remove ARGS1(
    char testpath[512];
    int count,i;
 
-   if (tagged != NULL) {
+   if (!HTList_isEmpty(tagged)) {
 
       count = remove_tagged();
 
@@ -972,8 +1033,12 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	fprintf(fp0, "<Html><Head>\n<Title>%s</Title>\n</Head>\n<Body>\n",
 		PERMIT_OPTIONS_TITLE);
 	fprintf(fp0,"<H1>Permissions for %s</H1>\n", user_filename);
-	fprintf(fp0, "<Form Action=\"LYNXDIRED://PERMIT_LOCATION%s\">\n",
-		srcpath);
+	{  /* prevent filenames which include '#' or '?' from messing it up */
+	    char * srcpath_url = HTEscape(srcpath, URL_PATH);
+	    fprintf(fp0, "<Form Action=\"LYNXDIRED://PERMIT_LOCATION%s\">\n",
+		    srcpath_url);
+	    FREE(srcpath_url);
+	}
 	
 	fprintf(fp0, "<Ol><Li>Specify permissions below:<Br><Br>\n");
 	fprintf(fp0, "Owner:<Br>\n");
@@ -1038,7 +1103,6 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	char *args[5];
 	char amode[10];
 	
-	HTUnEscape(destpath);
 	cp = destpath;
 	while (*cp != '\0' && *cp != '?') { /* Find filename */
 	    cp++;
@@ -1048,6 +1112,8 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	}
 	*cp++ = '\0';	/* Null terminate file name
 			   and start working on the masks */
+
+	HTUnEscape(destpath);	/* will now operate only on filename part */
 	
 	/* A couple of sanity tests */
 	destpath = strip_trailing_slash(destpath);
@@ -1121,6 +1187,7 @@ PRIVATE BOOLEAN permit_location ARGS3(
 }
 #endif /* OK_PERMIT */
 
+#ifdef NOTDEFINED
 PUBLIC BOOLEAN is_a_file ARGS1(
 	char *,		testname)
 { 
@@ -1143,6 +1210,7 @@ PUBLIC BOOLEAN is_a_file ARGS1(
      else
        return 0;
 }
+#endif /* NOTDEFINED */
 
 /* display or remove a tag from a given link */
 
@@ -1174,19 +1242,19 @@ PUBLIC void tagflag ARGS2(
 }
 
 PUBLIC void showtags ARGS1(
-	taglink *,	t)
+	HTList *,	t)
 {
     int i;
-    taglink *s;
-    
+    HTList *s;
+    char * name;
+
     for(i=0;i<nlinks;i++) {
       s = t;
-      while(s != NULL) {
-	 if(!strcmp(links[i].lname,s->name)) {
+      while((name = HTList_nextObject(s)) != NULL) {
+	 if(!strcmp(links[i].lname,name)) {
 	    tagflag(ON,i);
 	    break;
-	 } else
-	    s = s->next;
+	 }
       }
    }
 }
@@ -1201,18 +1269,31 @@ PUBLIC char * strip_trailing_slash ARGS1(
    return dirname;
 }
 
-/* Perform file management operations for LYNXDIRED URL's */
-
+/*
+**  Perform file management operations for LYNXDIRED URL's.
+**  Attempt to be consistent.  These are (pseudo) URLs - i.e. they should
+**  be in URL syntax: some bytes will be URL-escaped with '%'.  This is 
+**  necessary because these (pseudo) URLs will go through some of the same 
+**  kinds of interpretations and mutilations as real ones: HTParse, stripping
+**  off #fragments etc.  (Some access schemes currently have special rules 
+**  about not escaping parsing '#' "the URL way" built into HTParse, but that
+**  doesn't look like a clean way.)  
+*/
 PUBLIC int local_dired ARGS1(
 	document *,	doc)
 {
-   char *line;
-   char *cp,*tp;
+   char *line_url;    /* will point to doc's address, which is a URL */
+   char *line = NULL; /* same as line_url, but HTUnEscaped, will be alloced */
+   char *cp, *tp, *bp;
    char tmpbuf[256];
    char buffer[512];
 
-   line = doc->address;
-   HTUnEscape(line);
+   line_url = doc->address;
+   HTUnEscapeSome(line_url,"/");	/* don't mess too much with *doc */
+
+   StrAllocCopy(line, line_url);
+   HTUnEscape(line);	/* _file_ (not URL) syntax, for those functions
+			   that need it.  DOn't forget to FREE it. */
 
    /* This causes a SIGSEGV later when StrAllocCopy tries to free tp
     * let's make it point to NULL
@@ -1226,6 +1307,7 @@ PUBLIC int local_dired ARGS1(
    } else if (!strncmp(line,"LYNXDIRED://INSTALL_SRC",23)) {
       local_install(NULL, &line[23], &tp);
       StrAllocCopy(doc->address, tp);
+      FREE(line);
       return 0;
    } else if (!strncmp(line,"LYNXDIRED://INSTALL_DEST",24)) {
       local_install(&line[24], NULL, &tp);
@@ -1235,26 +1317,36 @@ PUBLIC int local_dired ARGS1(
    } else if (!strncmp(line,"LYNXDIRED://MODIFY_LOCATION",27)) {
       if (modify_location(&line[27])) ++LYforce_no_cache;
    } else if (!strncmp(line,"LYNXDIRED://MOVE_TAGGED",23)) {
-      if (modify_tagged(&line[23])) ++LYforce_no_cache;
+      if (modify_tagged(&line_url[23])) ++LYforce_no_cache;
 #ifdef OK_PERMIT
    } else if (!strncmp(line,"LYNXDIRED://PERMIT_SRC",22)) {
       permit_location(NULL, &line[22], &tp);
-      StrAllocCopy(doc->address, tp);
+      if (tp)			/* one of the checks may have failed */
+	  StrAllocCopy(doc->address, tp);
+      FREE(line);
       return 0;
    } else if (!strncmp(line,"LYNXDIRED://PERMIT_LOCATION",27)) {
-       permit_location(&line[27], NULL, &tp);
+       permit_location(&line_url[27], NULL, &tp);
 #endif /* OK_PERMIT */
    } else if (!strncmp(line,"LYNXDIRED://REMOVE_SINGLE",25)) {
       if (remove_single(&line[25])) ++LYforce_no_cache;
    } else if (!strncmp(line,"LYNXDIRED://REMOVE_TAGGED",25)) {
       if (remove_tagged()) ++LYforce_no_cache;
    } else if (!strncmp(line,"LYNXDIRED://UPLOAD",18)) {
-     if (LYUpload(line)) ++LYforce_no_cache;
+      /*
+       *  They're written by LYUpload_options() HTUnEscaped,
+       *  don't want to change that for now... so pass through
+       *  without more unescaping.  Directory names containing
+       *  '#' will probably fail..
+       */
+      if (LYUpload(line_url)) ++LYforce_no_cache;
    } else {
       if (line[strlen(line)-1] == '/')
 	line[strlen(line)-1] = '\0';
-      if ((cp = strrchr(line,'/')) == NULL)
+      if ((cp = strrchr(line,'/')) == NULL) {
+	FREE(line);
 	return 0;
+      }
 
 /* Construct the appropriate system command taking care to escape all
    path references to avoid spoofing the shell. */
@@ -1347,12 +1439,20 @@ PUBLIC int local_dired ARGS1(
 #ifdef OK_ZIP
       } else if (!strncmp(line,"LYNXDIRED://ZIP",15)) {
 	tp = quote_pathname(line+15);
-	sprintf(buffer,"%s -rq %s.zip %s", ZIP_PATH, tp, tp);
+	*cp++ = '\0';
+	bp = quote_pathname(cp);
+	cp = quote_pathname(line+15);
+	sprintf(buffer,"cd %s; %s -rq %s.zip %s", cp, ZIP_PATH, tp, bp);
+	FREE(cp);
+	FREE(bp);
 	FREE(tp);
 # ifndef ARCHIVE_ONLY
       } else if (!strncmp(line,"LYNXDIRED://UNZIP",17)) {
 	tp = quote_pathname(line+17);
-	sprintf(buffer,"%s -q %s", UNZIP_PATH, tp);
+	*cp = '\0';
+	cp = quote_pathname(line+17);
+	sprintf(buffer,"cd %s; %s -q %s", cp, UNZIP_PATH, tp);
+	FREE(cp);
 	FREE(tp);
 # endif /* !ARCHIVE_ONLY */
 #endif /* OK_ZIP */
@@ -1383,6 +1483,7 @@ PUBLIC int local_dired ARGS1(
       }
    }
 
+   FREE(line);
    LYpop(doc);
    return 0;
 }
@@ -1402,7 +1503,10 @@ PUBLIC int dired_options ARGS2(
     struct stat dir_info;
     FILE *fp0;
     char *cp,*tp = NULL;
-    char *escaped;
+    /* char *escaped; */
+    char * dir_url = NULL;
+    char * path_url = NULL;
+    BOOLEAN nothing_tagged;
     int count;
     struct dired_menu *mp;
     char buf[2048];
@@ -1430,6 +1534,9 @@ PUBLIC int dired_options ARGS2(
     else if(!strncmp(cp,"file:",5))
       cp += 5;
     strcpy(dir,cp);
+    StrAllocCopy(dir_url, cp);
+    if (dir_url[strlen(dir_url)-1] == '/')
+      dir_url[strlen(dir_url)-1] = '\0';
     HTUnEscape(dir);
     if (dir[strlen(dir)-1] == '/')
       dir[strlen(dir)-1] = '\0';
@@ -1441,6 +1548,9 @@ PUBLIC int dired_options ARGS2(
        else if(!strncmp(cp,"file:",5))
 	 cp += 5;
        strcpy(path,cp);
+       StrAllocCopy(path_url,cp);
+       if (path_url[strlen(path_url)-1] == '/')
+	   path_url[strlen(path_url)-1] = '\0';
        HTUnEscape(path);
        if (path[strlen(path)-1] == '/')
 	  path[strlen(path)-1] = '\0';
@@ -1449,17 +1559,22 @@ PUBLIC int dired_options ARGS2(
 	  sprintf(tmpbuf,"Unable to get status of %s ",path);
 	  _statusline(tmpbuf);
 	  sleep(AlertSecs);
+	  FREE(dir_url);
+	  FREE(path_url);
 	  return 0;
        } 
 
+#ifdef NOTDEFINED
        if ((cp = strrchr(path,'.')) != NULL && strlen(path) > strlen(cp)) {
 	  *cp = '\0';
 	  tp = strrchr(path,'.');
 	  *cp = '.';
        }
+#endif /* NOTDEFINED */
     } else path[0] = '\0';
 
-    escaped = (char *) HTEscape(path,(unsigned char) 4);
+  /*escaped = (char *) HTEscape(path,(unsigned char) 4); path_url instead- kw*/
+    nothing_tagged = (HTList_isEmpty(tagged));
 
     fprintf(fp0,"<head>\n<title>%s</title></head>\n<body>\n",DIRED_MENU_TITLE);
 
@@ -1468,7 +1583,7 @@ PUBLIC int dired_options ARGS2(
 
     fprintf(fp0,"Current directory is %s <br>\n",dir);
 
-    if (tagged == NULL)
+    if (nothing_tagged)
        if (strlen(path))
           fprintf(fp0,"Current selection is %s <p>\n",path);
        else
@@ -1487,9 +1602,9 @@ PUBLIC int dired_options ARGS2(
     }
 
     for (mp = menu_head; mp != NULL; mp = mp->next) {
-	if (mp->cond != DE_TAG && tagged != NULL)
+	if (mp->cond != DE_TAG && !nothing_tagged)
 	    continue;
-	if (mp->cond == DE_TAG && tagged == NULL)
+	if (mp->cond == DE_TAG && nothing_tagged)
 	    continue;
 	if (mp->cond == DE_DIR && (dir_info.st_mode & S_IFMT) != S_IFDIR)
 	    continue;
@@ -1497,9 +1612,12 @@ PUBLIC int dired_options ARGS2(
 	    continue;
 	if (strcmp(mp->sfx, &path[strlen(path)-strlen(mp->sfx)]) != 0)
 	    continue;
-	fprintf(fp0, "<a href=\"%s", render_item(mp->href, path, dir, buf));
-	fprintf(fp0, "\">%s</a> ", render_item(mp->link, path, dir, buf));
-	fprintf(fp0, "%s<br>\n", render_item(mp->rest, path, dir, buf));
+	fprintf(fp0, "<a href=\"%s",
+		render_item(mp->href, path_url, dir_url, buf,2048, YES));
+	fprintf(fp0, "\">%s</a> ",
+		render_item(mp->link, path, dir, buf,2048, NO));
+	fprintf(fp0, "%s<br>\n",
+		render_item(mp->rest, path, dir, buf,2048, NO));
     }
 
     if (uploaders != NULL) {
@@ -1513,7 +1631,9 @@ PUBLIC int dired_options ARGS2(
     fprintf(fp0,"</body>\n");
     fclose(fp0);
 
-    FREE(escaped);
+    /* FREE(escaped);  not used any more - kw*/
+    FREE(dir_url);
+    FREE(path_url);
 
     LYforce_no_cache = 1;
 
@@ -1534,18 +1654,18 @@ PRIVATE int my_spawn ARGS3(
     int wstatus;
 #endif /* NeXT || AIX4 || sony_news */
 
-    rc = 1;                 /* It will work */
+    rc = 1;		/* It will work */
+    tmpbuf[0] = '\0';	/* empty buffer for alert messages */
     stop_curses();
-    pid = fork(); /* fork and execute rm */
+    pid = fork();	/* fork and execute rm */
     switch (pid) {
       case -1:
 	sprintf(tmpbuf, "Unable to %s due to system error!", msg);
-	_statusline(tmpbuf);
-	sleep(AlertSecs);
 	rc = 0;
+	break;		/* don't fall thru! - KW */
       case 0:  /* child */
 	execv(path, argv);
-	exit(-1);    /* execv failed, give wait() something to look at */
+	exit(-1);	/* execv failed, give wait() something to look at */
       default:  /* parent */
 #if defined(NeXT) || defined(AIX4) || defined(sony_news)
 	while (wait(&wstatus) != pid)
@@ -1557,8 +1677,6 @@ PRIVATE int my_spawn ARGS3(
 	    WTERMSIG(wstatus) != 0)  { /* error return */
 	    sprintf(tmpbuf, "Probable failure to %s due to system error!",
 		    msg);
-	    _statusline(tmpbuf);
-	    sleep(AlertSecs);
 	    rc = 0;
 	}
     }
@@ -1568,7 +1686,19 @@ PRIVATE int my_spawn ARGS3(
 	HadVMSInterrupt = FALSE;
     }
 #endif /* VMS */
+
+    if (rc == 0) {
+        /*
+	 *  Screen may have message from the failed execv'd command.
+	 *  Give user time to look at it before screen refresh.
+	 */
+	sleep(AlertSecs);
+    }
     start_curses();
+    if (tmpbuf[0]) {
+	_statusline(tmpbuf);
+	sleep(AlertSecs);
+    }
 
     return(rc);
 }
@@ -1616,7 +1746,7 @@ PUBLIC BOOLEAN local_install ARGS3(
    static char savepath[512]; /* this will be the link that is to be installed */
    struct stat dir_info;
    char *args[5];
-   taglink *tag;
+   HTList *tag;
    int count = 0;
 
 /* Determine the status of the selected item. */
@@ -1671,40 +1801,39 @@ PUBLIC BOOLEAN local_install ARGS3(
    args[3] = (char *) 0;
    sprintf(tmpbuf, "install %s", destpath);
    tag = tagged;
-   for (;;) {
-      if (tagged) {
-	 args[1] = tag->name;
-	 if (strncmp("file://localhost", args[1], 16) == 0)
-	    args[1] = tag->name + 16;
-      } else
-         args[1] = savepath;
 
-      if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0)
-         return count;
-      count++;
-      if (!tagged)
-	 break;
-      tag = tag->next;
-      if (!tag)
-	break;
+   if (HTList_isEmpty(tagged)) {
+         args[1] = savepath;
+	 if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0)
+	     return count;
+	 count++;
+   } else {
+       char * name;
+       while ((name = (char *)HTList_nextObject(tag))) {
+	   args[1] = name;
+	   if (strncmp("file://localhost", args[1], 16) == 0)
+	       args[1] = name + 16;
+
+	   if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0)
+	       return count;
+	   count++;
+       }	
+       clear_tags();
    }
-   if (tagged)
-      clear_tags();
    statusline("Installation complete");
    sleep(InfoSecs);
    return count;
 }
 
-PRIVATE void clear_tags NOARGS
+PUBLIC void clear_tags NOARGS
 {
-    taglink *t1;
+    char *cp = NULL;
 
-    while((t1=tagged) != NULL) { 
-	tagged = tagged->next;
-	FREE(t1->name);
-	FREE(t1);
+    while ((cp = HTList_removeLastObject(tagged)) != NULL) { 
+	FREE(cp);
     }
-    tagged = NULL;
+    if (HTList_isEmpty(tagged))
+	FREE(tagged);
 }
 
 PUBLIC void add_menu_item ARGS1(
@@ -1758,34 +1887,50 @@ PUBLIC void add_menu_item ARGS1(
 	menu_head = new;
 }
 
-PRIVATE char * render_item ARGS4(
+PRIVATE char * render_item ARGS6(
 	char *,		s,
 	char *,		path,
 	char *,		dir,
-	char *,		buf)
+	char *,		buf,
+	int,		bufsize,
+	BOOLEAN,	url_syntax)
 {
 	char *cp;
 	char *bp;
-	taglink *t1;
-	char *taglist;
+	char overrun = '\0';
+	char *taglist = NULL;
+#define BP_INC (bp>buf+bufsize-2 ?  &overrun : bp++)
+				/* Buffer overrun could happen for very long
+				 tag list, if %l or %t are used */
 
 	bp = buf;
-	while (*s) {
+	while (*s && !overrun) {
 	    if (*s == '%') {
 		s++;
 		switch (*s) {
 		case '%':
-		    *bp++ = '%';
+		    *BP_INC = '%';
+#ifdef NOTDEFINED
+		    /*
+		     *  These chars come from lynx.cfg or the default, let's
+		     *  just assume there won't be any improper %'s there that
+		     *  would need escaping.
+		     */
+		    if(url_syntax) {
+			*BP_INC = '2';
+			*BP_INC = '5';
+		    }
+#endif /* NOTDEFINED */
 		    break;
 		case 'p':
 		    cp = path;
 		    while (*cp)
-			*bp++ = *cp++;
+			*BP_INC = *cp++;
 		    break;
 		case 'd':
 		    cp = dir;
 		    while (*cp)
-			*bp++ = *cp++;
+			*BP_INC = *cp++;
 		    break;
 		case 'f':
 		    cp = strrchr(path, '/');
@@ -1794,32 +1939,59 @@ PRIVATE char * render_item ARGS4(
 		    else
 			cp = path;
 		    while (*cp)
-			*bp++ = *cp++;
+			*BP_INC = *cp++;
 		    break;
 		case 'l':
 		case 't':
-		    FREE(taglist);
-		    for (t1=tagged; t1 != NULL; t1 = t1->next) { 
-			if (*s == 'l' && (cp = strrchr(t1->name, '/')))
-			    cp++;
-			else
-			    cp = t1->name;
-			StrAllocCat(taglist, cp);
-			StrAllocCat(taglist, " ");
+		    if (!HTList_isEmpty(tagged)) {
+			HTList *cur = tagged; 
+			char *name;
+
+			while(!overrun &&
+			      (name = (char *)HTList_nextObject(cur))!=NULL) {
+			    if (*s == 'l' && (cp = strrchr(name, '/')))
+				cp++;
+			    else
+				cp = name;
+			    StrAllocCat(taglist, cp);
+			    StrAllocCat(taglist, " "); /* should this be %20?*/
+			}
+		    }
+		    if (taglist) {
+			/* could HTUnescape here... */
+			cp = taglist;
+			while (*cp)
+			    *BP_INC = *cp++;
+			FREE(taglist);
 		    }
-		    cp = taglist;
-		    while (*cp)
-			*bp++ = *cp++;
 		    break;
 		default:
-		    *bp++ = '%';
-		    *bp++ =*s;
+		    *BP_INC = '%';
+#ifdef NOTDEFINED
+		    if (url_syntax) {
+			*BP_INC = '2';
+			*BP_INC = '5';
+		    }
+#endif /* NOTDEFINED */
+		    *BP_INC =*s;
 		    break;
 		}
-	    } else
-		*bp++ =*s;
+	    } else {
+	        /*
+		 *  Other chars come from the lynx.cfg or
+		 *  the default. Let's assume there isn't
+		 *  anything weird there that needs escaping.
+		 */
+		*BP_INC =*s;
+	    }
 	    s++;
 	}
+	if (overrun & url_syntax) {
+	    sprintf(buf,"Temporary URL or list would be too long.");
+	    _statusline(buf);
+	    sleep(AlertSecs);
+	    bp = buf;	/* set to start, will return empty string as URL */
+	}
 	*bp = '\0';
 	return buf;
 }
diff --git a/src/LYLocal.h b/src/LYLocal.h
index 6771898b..66dbff4d 100644
--- a/src/LYLocal.h
+++ b/src/LYLocal.h
@@ -40,6 +40,9 @@ extern BOOLEAN local_modify PARAMS((document *doc, char **newpath));
 extern BOOLEAN local_remove PARAMS((document *doc));
 extern BOOLEAN local_install PARAMS((char *destpath, char *srcpath, char **newpath));
 
+/* MainLoop needs to know about this one for atexit cleanup */
+extern void clear_tags NOPARAMS;
+
 /* Define the PRIVATE routines in case they ever go PUBLIC
 
 extern BOOLEAN modify_name PARAMS((char *testpath));
@@ -49,10 +52,10 @@ extern BOOLEAN create_directory PARAMS((char *testpath));
 extern BOOLEAN modify_tagged PARAMS((char *testpath));
 extern BOOLEAN remove_tagged NOPARAMS;
 extern BOOLEAN remove_single PARAMS ((char *testpath));
-*/
 extern BOOLEAN is_a_file PARAMS((char *testname));
+*/
 extern void tagflag PARAMS((int flag, int cur)); 
-extern void showtags PARAMS((taglink *tag));
+extern void showtags PARAMS((HTList *tag));
 extern char * strip_trailing_slash PARAMS((char * dirname));
 extern int local_dired PARAMS((document *doc));
 extern int dired_options PARAMS ((document *doc, char ** newfile));
diff --git a/src/LYMail.c b/src/LYMail.c
index fdb2efea..094e6da8 100644
--- a/src/LYMail.c
+++ b/src/LYMail.c
@@ -22,8 +22,11 @@ PRIVATE void remove_tildes PARAMS((char *string));
 /*
 **  mailform() sends form content to the mailto address(es). - FM
 */
-PUBLIC void mailform ARGS3(char *,mailto_address, char *,mailto_subject,
-			   char *,mailto_content)
+PUBLIC void mailform ARGS4(
+	char *,		mailto_address,
+	char *,		mailto_subject,
+	char *,		mailto_content,
+	char *,		mailto_type)
 {
     FILE *fd;
     char *address = NULL;
@@ -46,42 +49,31 @@ PUBLIC void mailform ARGS3(char *,mailto_address, char *,mailto_subject,
     StrAllocCopy(address, mailto_address);
 
     /*
-     *  Check for a ?subject=foo. - FM
+     *  Check for a ?searchpart with subject=foo. - FM
      */
     subject[0] = '\0';
-    if ((cp = strchr(address, '?')) != NULL &&
-	strcasecomp(cp+1, "subject=")) {
-	*cp = '\0';
-	cp += 9;
-	strncpy(subject, cp, 70);
-	subject[70] = '\0';
-	HTUnEscape(subject);
-    }
-
-    /*
-     *  Unescape any hex escaped pounds. - FM
-     */
-    while ((cp1 = strstr(address, "%23")) != NULL) {
-	*cp1 = '#';
-	cp0 = (cp1 + 1);
-	cp1 = (cp0 + 2);
-	for (i = 0; cp1[i]; i++) {
-	    cp0[i] = cp1[i];
+    if ((cp = strchr(address, '?')) != NULL) {
+	*cp++ = '\0';
+	while (*cp != '\0' && strncasecomp(cp, "subject=", 8))
+	    cp++;
+	cp0 = (cp - 1);
+	if ((*cp != '\0') &&
+	    (*cp0 == '\0' || *cp0 == '&' || *cp0 == ';')) {
+	    if ((cp1 = strchr(cp, '&')) != NULL) {
+	        *cp1 = '\0';
+	    } else if ((cp1 = strchr(cp, ';')) != NULL) {
+	        *cp1 = '\0';
+	    }
+	    strncpy(subject, cp, 70);
+	    subject[70] = '\0';
+	    HTUnEscape(subject);
 	}
-	cp0[i] = '\0';
     }
 
     /*
-     *  Unescape any hex escaped percents. - FM
+     *  Unescape the address field. - FM
      */
-    while ((cp1 = strstr(address, "%25")) != NULL) {
-	cp0 = (cp1 + 1);
-	cp1 = (cp0 + 2);
-	for (i = 0; cp1[i]; i++) {
-	    cp0[i] = cp1[i];
-	}
-	cp0[i] = '\0';
-    }
+    HTUnEscape(address);
 
     /*
      * Convert any Explorer semi-colon Internet address
@@ -134,6 +126,10 @@ PUBLIC void mailform ARGS3(char *,mailto_address, char *,mailto_subject,
 	return;
     }
 
+    if (mailto_type && *mailto_type) {
+	fprintf(fd, "Mime-Version: 1.0\n");
+	fprintf(fd, "Content-Type: %s\n", mailto_type);
+    }
     fprintf(fd,"To: %s\n", address);
     if (personal_mail_address && *personal_mail_address)
 	fprintf(fd,"From: %s\n", personal_mail_address);
@@ -141,13 +137,21 @@ PUBLIC void mailform ARGS3(char *,mailto_address, char *,mailto_subject,
     _statusline(SENDING_FORM_CONTENT);
 #endif /* UNIX */
 #ifdef VMS
-    sprintf(tmpfile,"%s%s",lynx_temp_space, "temp_mail.");
+    sprintf(tmpfile,"%s%s",lynx_temp_space, "temp_mail.txt");
     if ((fd = fopen(tmpfile,"w")) == NULL) {
 	HTAlert(FORM_MAILTO_FAILED);
 	FREE(address);
 	return;
     }
-
+    if (mailto_type &&
+        !strncasecomp(mailto_type, "multipart/form-data", 19)) {
+	/*
+	 *  Ugh!  There's no good way to include headers while
+	 *  we're still using "generic" VMS MAIL, so we'll put
+	 *  this in the body of the message. - FM
+	 */
+	fprintf(fd, "X-Content-Type: %s\n\n", mailto_type);
+    }
 #endif /* VMS */
 
     /*
@@ -242,35 +246,15 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
     StrAllocCopy(address, owner_address);
 
     /*
-     *  Check for a ?subject=foo and trim it. - FM
+     *  Check for a ?searchpart and trim it. - FM
      */
-    if ((cp = strchr(address, '?')) != NULL && strcasecomp(cp+1, "subject="))
+    if ((cp = strchr(address, '?')) != NULL && strchr(cp+1, '=') != NULL)
 	*cp = '\0';
 
     /*
-     *  Unescape any hex escaped pounds. - FM
-     */
-    while((cp1 = strstr(address, "%23")) != NULL) {
-	*cp1 = '#';
-	cp0 = (cp1 + 1);
-	cp1 = (cp0 + 2);
-	for (i = 0; cp1[i]; i++) {
-	    cp0[i] = cp1[i];
-	}
-	cp0[i] = '\0';
-    }
-
-    /*
-     *  Unescape any hex escaped percents. - FM
+     *  Unescape the address field. - FM
      */
-    while ((cp1 = strstr(address, "%25")) != NULL) {
-	cp0 = (cp1 + 1);
-	cp1 = (cp0 + 2);
-	for (i = 0; cp1[i]; i++) {
-	    cp0[i] = cp1[i];
-	}
-	cp0[i] = '\0';
-    }
+    HTUnEscape(address);
 	
     /*
      *  Convert any Explorer semi-colon Internet address
@@ -304,7 +288,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
     fprintf(fd,"X-Mailer: Lynx, Version %s\n\n",LYNX_VERSION);
 #endif /* UNIX */
 #ifdef VMS
-    sprintf(tmpfile,"%s%s",lynx_temp_space, "temp_mail.");
+    sprintf(tmpfile,"%s%s",lynx_temp_space, "temp_mail.txt");
     if ((fd = fopen(tmpfile,"w")) == NULL) {
 	FREE(address);
 	return;
@@ -417,22 +401,39 @@ PUBLIC void reply_by_mail ARGS3(
     }
 
     tempname(tmpfile,NEW_FILE);
+    if (((cp = strrchr(tmpfile, '.')) != NULL) &&
+#ifdef VMS
+	NULL == strchr(cp, ']') &&
+#endif /* VMS */
+	NULL == strchr(cp, '/')) {
+	*cp = '\0';
+	strcat(tmpfile, ".txt");
+    }
     if ((fd = fopen(tmpfile,"w")) == NULL) {
 	HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
 	return;
     }
 
     /*
-     *  Check for a ?subject=foo. - FM
+     *  Check for a ?searchpart with subject=foo. - FM
      */
     subject[0] = '\0';
-    if ((cp = strchr(address, '?')) != NULL &&
-	strcasecomp(cp+1, "subject=")) {
-	*cp = '\0';
-	cp += 9;
-	strncpy(subject, cp, 70);
-	subject[70] = '\0';
-	HTUnEscape(subject);
+    if ((cp = strchr(address, '?')) != NULL) {
+	*cp++ = '\0';
+	while (*cp != '\0' && strncasecomp(cp, "subject=", 8))
+	    cp++;
+	cp0 = (cp - 1);
+	if ((*cp != '\0') &&
+	    (*cp0 == '\0' || *cp0 == '&' || *cp0 == ';')) {
+	    if ((cp1 = strchr(cp, '&')) != NULL) {
+	        *cp1 = '\0';
+	    } else if ((cp1 = strchr(cp, ';')) != NULL) {
+	        *cp1 = '\0';
+	    }
+	    strncpy(subject, cp, 70);
+	    subject[70] = '\0';
+	    HTUnEscape(subject);
+	}
     }
     if (subject[0] == '\0' && title && *title) {
 	strncpy(subject, title, 70);
@@ -440,31 +441,11 @@ PUBLIC void reply_by_mail ARGS3(
     }
 
     /*
-     *  Unescape any hex escaped pounds. - FM
+     *  Unescape the address field. - FM
      */
-    while ((cp1 = strstr(address, "%23")) != NULL) {
-	*cp1 = '#';
-	cp0 = (cp1 + 1);
-	cp1 = (cp0 + 2);
-	for (i = 0; cp1[i]; i++) {
-	    cp0[i] = cp1[i];
-	}
-	cp0[i] = '\0';
-    }
+    HTUnEscape(address);
 
     /*
-     *  Unescape any hex escaped percents. - FM
-     */
-    while ((cp1 = strstr(address, "%25")) != NULL) {
-	cp0 = (cp1 + 1);
-	cp1 = (cp0 + 2);
-	for (i = 0; cp1[i]; i++) {
-	    cp0[i] = cp1[i];
-	}
-	cp0[i] = '\0';
-    }
-	
-    /*
      *  Convert any Explorer semi-colon Internet address
      *  separators to commas. - FM
      */
diff --git a/src/LYMail.h b/src/LYMail.h
index 9dd72931..b14ab5f4 100644
--- a/src/LYMail.h
+++ b/src/LYMail.h
@@ -1,5 +1,4 @@
 
-
 #ifndef LYMAIL_H
 #define LYMAIL_H
 
@@ -7,13 +6,19 @@
 #include "LYStructs.h"
 #endif /* LYSTRUCTS_H */
 
-extern void mailform PARAMS((char *mailto_address,  char *mailto_subject,
-					char *mailto_content));
-extern void mailmsg PARAMS((int cur, char *owner_address, 
-                			char *filename, char *linkname));
-extern void reply_by_mail PARAMS((char *mail_address,
-					char *filename, char *title));
-
+extern void mailform PARAMS((
+	char *	mailto_address,
+	char *	mailto_subject,
+	char *	mailto_content,
+	char *	mailto_type));
+extern void mailmsg PARAMS((
+	int 	cur,
+	char *	owner_address,
+	char *	filename,
+	char *	linkname));
+extern void reply_by_mail PARAMS((
+	char *	mail_address,
+	char *	filename,
+	char *	title));
 
 #endif /* LYMAIL_H */
-
diff --git a/src/LYMain.c b/src/LYMain.c
index fe4703ca..963a528a 100644
--- a/src/LYMain.c
+++ b/src/LYMain.c
@@ -1,10 +1,15 @@
 #include "HTUtils.h"
 #include "tcp.h"
-#include "HTInit.h"
+#include "HTParse.h"
+#include "HTAccess.h"
+#include "HTList.h"
 #include "HTFile.h"
+#ifdef VMS
+#include "HTVMSUtils.h"
+#endif /* VMS */
+#include "HTInit.h"
 #include "LYCurses.h"
 #include "HTML.h"
-#include "HTAccess.h"
 #include "LYUtils.h"
 #include "LYGlobalDefs.h"
 #include "LYSignal.h"
@@ -16,12 +21,9 @@
 #include "LYReadCFG.h"
 #include "LYrcFile.h"
 #include "LYKeymap.h"
-#include "HTParse.h"
-#ifdef VMS
-#include "HTVMSUtils.h"
-#endif /* VMS */
 #include "LYList.h"
 #include "LYJump.h"
+#include "LYBookmark.h"
 
 #ifndef VMS
 #ifdef SYSLOG_REQUESTED_URLS
@@ -83,7 +85,7 @@ PUBLIC char *syslog_txt = NULL;		/* syslog arb text for session */
 PUBLIC BOOLEAN lynx_edit_mode = FALSE;
 PUBLIC BOOLEAN no_dired_support = FALSE;
 PUBLIC BOOLEAN dir_list_style = MIXED_STYLE;
-PUBLIC taglink *tagged = NULL;
+PUBLIC HTList *tagged = NULL;
 #ifdef OK_OVERRIDE
 PUBLIC BOOLEAN prev_lynx_edit_mode = FALSE;
 #endif /* OK_OVERRIDE */
@@ -177,6 +179,8 @@ PUBLIC BOOLEAN no_suspend = FALSE;
 PUBLIC BOOLEAN no_editor = FALSE;
 PUBLIC BOOLEAN no_shell = FALSE;
 PUBLIC BOOLEAN no_bookmark = FALSE;
+PUBLIC BOOLEAN no_multibook = FALSE;
+PUBLIC BOOLEAN no_bookmark_exec = FALSE;
 PUBLIC BOOLEAN no_option_save = FALSE;
 PUBLIC BOOLEAN no_print = FALSE;
 PUBLIC BOOLEAN no_download = FALSE;
@@ -184,7 +188,6 @@ PUBLIC BOOLEAN no_disk_save = FALSE;
 PUBLIC BOOLEAN no_exec = FALSE;
 PUBLIC BOOLEAN no_lynxcgi = FALSE;
 PUBLIC BOOLEAN exec_frozen = FALSE;
-PUBLIC BOOLEAN no_bookmark_exec = FALSE;
 PUBLIC BOOLEAN no_goto = FALSE;
 PUBLIC BOOLEAN no_goto_cso = FALSE;
 PUBLIC BOOLEAN no_goto_file = FALSE;
@@ -220,7 +223,8 @@ PUBLIC char *homepage = NULL;	/* home page or main screen */
 PUBLIC char *editor = NULL;	/* the name of the current editor */
 PUBLIC char *jumpfile = NULL;	/* the name of the default jumps file */
 PUBLIC char *jumpprompt = NULL;	/* the default jumps prompt */
-PUBLIC char *bookmark_page = NULL; /* the name of the current bookmark page */
+PUBLIC char *bookmark_page = NULL; /* the name of the default bookmark page */
+PUBLIC char *BookmarkPage = NULL;  /* the name of the current bookmark page */
 PUBLIC char *startfile = NULL;	/* the first file */
 PUBLIC char *helpfile = NULL; 	/* the main help file */
 PUBLIC char *helpfilepath = NULL;   /* the path to the help file set */
@@ -276,9 +280,9 @@ PUBLIC int more = FALSE;	/* is there more text to display? */
 PUBLIC int InfoSecs;	/* Seconds to sleep() for Information messages */
 PUBLIC int MessageSecs;	/* Seconds to sleep() for important Messages   */
 PUBLIC int AlertSecs;	/* Seconds to sleep() for HTAlert() messages   */
-PUBLIC BOOLEAN bookmark_start=FALSE;
-PUBLIC char *LYUserAgent=NULL;		/* Lynx User-Agent header          */
-PUBLIC char *LYUserAgentDefault=NULL;	/* Lynx default User-Agent header  */
+PUBLIC BOOLEAN bookmark_start = FALSE;
+PUBLIC char *LYUserAgent = NULL;	/* Lynx User-Agent header          */
+PUBLIC char *LYUserAgentDefault = NULL;	/* Lynx default User-Agent header  */
 PUBLIC BOOLEAN LYNoRefererHeader=FALSE;	/* Never send Referer header?      */
 PUBLIC BOOLEAN LYNoRefererForThis=FALSE;/* No Referer header for this URL? */
 PUBLIC BOOLEAN LYNoFromHeader=FALSE;	/* Never send From header?         */
@@ -288,6 +292,11 @@ PUBLIC BOOLEAN LYisConfiguredForX = FALSE;
 PUBLIC char *URLDomainPrefixes = NULL;
 PUBLIC char *URLDomainSuffixes = NULL;
 PUBLIC BOOLEAN startfile_ok = FALSE;
+PUBLIC BOOLEAN LYSelectPopups = USE_SELECT_POPUPS;
+PUBLIC BOOLEAN LYUseDefSelPop = TRUE;	/* Command line -popup toggle */
+PUBLIC int LYMultiBookmarks = MULTI_BOOKMARK_SUPPORT;
+PUBLIC BOOLEAN LYMBMBlocked = BLOCK_MULTI_BOOKMARKS;
+PUBLIC BOOLEAN LYMBMAdvanced = ADVANCED_MULTI_BOOKMARKS;
 
 /* These are declared in cutil.h for current freeWAIS libraries. - FM */
 #ifdef DECLARE_WAIS_LOGFILES
@@ -367,6 +376,11 @@ PRIVATE void free_lynx_globals NOARGS
     FREE(helpfilepath);
     FREE(aboutfilepath);
     FREE(bookmark_page);
+    FREE(BookmarkPage);
+    for (i = 0; i <= MBM_V_MAXFILES; i++) {
+        FREE(MBM_A_subbookmark[i]);
+        FREE(MBM_A_subdescript[i]);
+    }
     FREE(editor);
     FREE(authentication_info[0]);
     FREE(authentication_info[1]);
@@ -431,14 +445,23 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
      *  Initialize our startup and global variables.
      */
 #ifdef ULTRIX
-    /* Need this for ultrix. */
+    /*
+     *  Need this for ultrix.
+     */
     terminal = getenv("TERM");
     if ((terminal == NULL) || !strncasecomp(terminal, "xterm", 5))
         terminal = "vt100";
 #endif /* ULTRIX */
-    /* Zero the links and history struct array. */
+    /*
+     *  Zero the links and history struct arrays.
+     */
     memset((void *)links, 0, sizeof(linkstruct)*MAXLINKS);
     memset((void *)history, 0, sizeof(histstruct)*MAXHIST);
+    /*
+     *  Zero the MultiBookmark arrays.
+     */
+    memset((void *)MBM_A_subbookmark, 0, sizeof(char)*(MBM_V_MAXFILES+1));
+    memset((void *)MBM_A_subdescript, 0, sizeof(char)*(MBM_V_MAXFILES+1));
 #ifndef VMS
 #ifdef SYSLOG_REQUESTED_URLS
     openlog("lynx", LOG_PID, LOG_LOCAL5);
@@ -840,10 +863,36 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
     if (keypad_mode == NUMBERS_AS_ARROWS)
         set_numbers_as_arrows();
 
-    /* disable news posting if no posting command */
+    /*
+     *  Check the -popup command line toggle. - FM
+     */
+    if (LYUseDefSelPop == FALSE) {
+        if (LYSelectPopups == TRUE)
+	    LYSelectPopups = FALSE;
+	else
+	    LYSelectPopups = TRUE;
+    }
+
+    /*
+     *  Disable news posting if no posting command.
+     */
     if (*inews_path == '\0' || !strcasecomp(inews_path,"none"))
         no_newspost = TRUE;
 
+    /*
+     *  Disable multiple bookmark support if not interactive,
+     *  so it doesn't crash on curses functions, or if the
+     *  support was blocked via userdefs.h and/or lynx.cfg,
+     *  or via command line restrictions. - FM
+     */
+    if (no_multibook)
+        LYMBMBlocked = TRUE;
+    if (dump_output_immediately || LYMBMBlocked || no_multibook) {
+        LYMultiBookmarks = FALSE;
+	LYMBMBlocked = TRUE;
+	no_multibook == TRUE;
+    }
+
 #ifdef VMS
     set_vms_keys();
 #endif /* VMS */
@@ -1015,6 +1064,9 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
     if (!homepage)
 	StrAllocCopy(homepage, startfile);
 
+    /*
+     *  Set up the inside/outside domain restriction flags. - FM
+     */
     if (inlocaldomain()) {
 #if defined(NO_UTMP) || defined(VMS) /* not selective */
         telnet_ok = !no_inside_telnet && !no_outside_telnet && telnet_ok;
@@ -1039,12 +1091,15 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
     }
 
 #ifdef SIGTSTP
+    /*
+     *  Block Control-Z suspending if requested. - FM
+     */
     if (no_suspend)
 	(void) signal(SIGTSTP,SIG_IGN);
 #endif /* SIGTSTP */
 
     /*
-     *  Here's where we do all the work.
+     *  Check for a valid HEAD request. - FM
      */
     if (HEAD_request && strncmp(startfile, "http", 4)) {
         fprintf(stderr,
@@ -1061,6 +1116,10 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
 #endif /* SIGTSTP */
 	exit(-1);
     }
+
+    /*
+     *  Check for a valid MIME headers request. - FM
+     */
     if (keep_mime_headers && strncmp(startfile, "http", 4)) {
         fprintf(stderr,
  "The '-mime_header' switch is for http URLs and cannot be used for\n'%s'.\n",
@@ -1076,6 +1135,10 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
 #endif /* SIGTSTP */
 	exit(-1);
     }
+
+    /*
+     *  Check for a valid traversal request. - FM
+     */
     if (traversal && strncmp(startfile, "http", 4)) {
         fprintf(stderr,
  "The '-traversal' switch is for http URLs and cannot be used for\n'%s'.\n",
@@ -1091,6 +1154,10 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
 #endif /* SIGTSTP */
 	exit(-1);
     }
+
+    /*
+     *  Set up our help and about file base paths. - FM
+     */
     StrAllocCopy(helpfilepath, helpfile);
     if ((cp=strrchr(helpfilepath, '/')) != NULL)
         *cp = '\0';
@@ -1100,9 +1167,32 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
 	StrAllocCat(aboutfilepath, "/about_lynx/");
     }
     StrAllocCat(helpfilepath, "/");
-    if (!bookmark_page || *bookmark_page == '\0')
+
+
+    /*
+     *  Make sure our bookmark default strings
+     *  are all allocated and synchronized. - FM
+     */
+    if (!bookmark_page || *bookmark_page == '\0') {
         StrAllocCopy(bookmark_page, "lynx_bookmarks.html");
+        StrAllocCopy(BookmarkPage, bookmark_page);
+        StrAllocCopy(MBM_A_subbookmark[0], bookmark_page);
+        StrAllocCopy(MBM_A_subdescript[0], "Default");
+    }
+    if (!BookmarkPage || *BookmarkPage == '\0') {
+        StrAllocCopy(BookmarkPage, bookmark_page);
+        StrAllocCopy(MBM_A_subbookmark[0], bookmark_page);
+        StrAllocCopy(MBM_A_subdescript[0], MULTIBOOKMARKS_DEFAULT);
+    }
+
+    /*
+     *  Here's where we do all the work.
+     */
     if (dump_output_immediately) {
+        /*
+	 *  Finish setting up and start a
+	 *  NON-INTERACTIVE session. - FM
+	 */
         if (crawl && !number_links) {
 	    keypad_mode = NUMBERS_AS_ARROWS;
 	} else if (!nolist) {
@@ -1124,6 +1214,10 @@ PUBLIC int main ARGS2(int,argc, char **,argv)
 	  (void) signal(SIGTSTP,SIG_DFL);
 #endif /* SIGTSTP */
     } else {
+        /*
+	 *  Finish setting up and start an
+	 *  INTERACTIVE session. - FM
+	 */
  	if (setup(terminal)) {
 	    if (display != NULL && *display != '\0') {
 	        LYisConfiguredForX = TRUE;
@@ -1253,6 +1347,7 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc)
 	        printf("\
    jump            disable the 'j' (jump) command\n\
    mail            disallow mail\n\
+   multibook       disallow multiple bookmark files\n\
    news_post       disallow USENET News posting setting in the O)ptions menu\n\
    option_save     disallow saving options in .lynxrc\n");
 #if defined(NO_UTMP) || defined(VMS) /* not selective */
@@ -1345,8 +1440,8 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc)
 	emacs_keys = TRUE;
 	
     } else if (strncmp(argv[0], "-version", 8) == 0) {
-	printf("\n%s Version %s\n(c)GNU General Public License\n\
-<URL:http://www.nyu.edu/pages/wsn/subir/lynx.html>\n\n",
+	printf("\n%s Version %s\n(c)1996 GNU General Public License\n\
+<URL:http://lynx.browser.org/>\n\n",
 		LYNX_NAME, LYNX_VERSION);
 	exit(0);
 	
@@ -1369,6 +1464,9 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc)
     } else if (strncmp(argv[0], "-noreferer", 10) == 0) {
 	LYNoRefererHeader = TRUE;
 	
+    } else if (strncmp(argv[0], "-popup", 6) == 0) {
+	LYUseDefSelPop = FALSE;
+
     } else if (strncmp(argv[0], "-crawl", 6) == 0) {
 	crawl = TRUE;
 	LYcols=80;
@@ -1583,6 +1681,7 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc)
         /* Include mime headers and force source dump */
 	keep_mime_headers = TRUE;
 	dump_output_immediately = TRUE;
+	HTOutputFormat = HTAtom_for("www/dump");
 	LYcols=999;
 
     } else if (strncmp(argv[0], "-error_file", 11) == 0) { /* Output return
@@ -1726,6 +1825,8 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc)
 #endif /* SOCKS */
 	printf("    -nostatus        disable the miscellaneous information messages\n");
 	printf("    -number_links    force numbering of links\n");
+	printf("    -popup           toggles handling of single-choice SELECT options via\n");
+        printf("                     popup windows or as lists of radio buttons\n");
  	printf("    -post_data       user data for post forms, read from stdin,\n");
         printf("                     terminated by '---' on a line\n");
 	printf("    -print           enable print functions (DEFAULT)\n");
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index bbef7371..83567743 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -2,8 +2,12 @@
 #include "tcp.h"
 #include "HTAccess.h"
 #include "HTParse.h"
+#include "HTList.h"
+#include "HTFTP.h"
+#include "HTTP.h"
 #include "LYCurses.h"
 #include "LYGlobalDefs.h"
+#include "HTAlert.h"
 #include "LYUtils.h"
 #include "GridText.h"
 #include "LYStrings.h"
@@ -28,9 +32,6 @@
 #include "LYTraversal.h"
 #include "LYCharSets.h"
 #include "LYCharUtils.h"
-#include "HTFTP.h"
-#include "HTTP.h"
-#include "HTAlert.h"
 
 #ifdef VMS
 #include "HTVMSUtils.h"
@@ -80,13 +81,18 @@ PRIVATE void free_mainloop_variables NOARGS
     FREE(newdoc.address);
     FREE(newdoc.post_data);
     FREE(newdoc.post_content_type);
+    FREE(newdoc.bookmark);
     FREE(curdoc.title);
     FREE(curdoc.address);
     FREE(curdoc.post_data);
     FREE(curdoc.post_content_type);
+    FREE(curdoc.bookmark);
     FREE(traversal_host);
     FREE(traversal_link_to_add);
     FREE(CurrentUserAgent);
+#ifdef DIRED_SUPPORT
+    clear_tags();
+#endif /* DIRED_SUPPORT */
 
     return;
 }
@@ -107,7 +113,8 @@ int mainloop NOARGS
     int newline=0;
     char prev_target[512];
     char user_input_buffer[1024];
-    char *owner_address=NULL;  /* holds the responsible owner's address */
+    char *owner_address=NULL;  /* holds the responsible owner's address     */
+    char *ownerS_address=NULL; /* holds owner's address during source fetch */
     BOOLEAN first_file=TRUE;
     BOOLEAN refresh_screen=FALSE;
     BOOLEAN force_load = FALSE;
@@ -121,6 +128,7 @@ int mainloop NOARGS
     int CurrentCharSet_flag = current_char_set;
     BOOLEAN show_dotfiles_flag = show_dotfiles;
     BOOLEAN LYRawMode_flag = LYRawMode;
+    BOOLEAN LYSelectPopups_flag = LYSelectPopups;
     char cfile[128];
     FILE *cfp;
     char *cp, *toolbar;
@@ -137,7 +145,6 @@ int mainloop NOARGS
     char *tp;
     char tmpbuf[1024];
     struct stat dir_info;
-    taglink *t1, *t2=NULL;
 #endif /* DIRED_SUPPORT */
 
 /*
@@ -153,12 +160,14 @@ int mainloop NOARGS
     newdoc.title = NULL;
     newdoc.post_data = NULL;
     newdoc.post_content_type = NULL;
+    newdoc.bookmark = NULL;
     curdoc.address = NULL;
     curdoc.title = NULL;
     curdoc.post_data = NULL;
     curdoc.post_content_type = NULL;
+    curdoc.bookmark = NULL;
     atexit(free_mainloop_variables);
-    if (strcmp(startfile, homepage))
+    if (startfile && homepage && strcmp(startfile, homepage))
         HTAddGotoURL(homepage);
     HTAddGotoURL(startfile);
 initialize:
@@ -206,12 +215,14 @@ initialize:
 	    goto initialize;
 	} else {
 	    /* 
-	     * See if a bookmark page exists.  If it does,
-	     * replace newdoc.address with it's name 
+	     *  See if a bookmark page exists.  If it does,
+	     *  replace newdoc.address with it's name 
 	     */
-	    if (get_bookmark_filename(&newdoc.address) != NULL) {
+	    if ((cp = get_bookmark_filename(&newdoc.address)) != NULL &&
+	         *cp != '\0' && strcmp(cp, " ")) {
 		LYforce_HTML_mode = TRUE;  /* force HTML */
-		StrAllocCopy(newdoc.title, "Bookmark File");
+		StrAllocCopy(newdoc.title, BOOKMARK_TITLE);
+		StrAllocCopy(newdoc.bookmark, BookmarkPage);
 		StrAllocCopy(startrealm, newdoc.address);
 		FREE(newdoc.post_data);
 		FREE(newdoc.post_content_type);
@@ -276,14 +287,18 @@ try_again:
 		    /*
 		     *  Make SURE this is an appropriate request. - FM
 		     */
-		    if (!strncmp(newdoc.address, "http", 4))
+		    if (newdoc.address &&
+		        !strncmp(newdoc.address, "http", 4))
 		        newdoc.isHEAD = TRUE;
 		    HEAD_request = FALSE;
 		}
 
 		LYRequestTitle = newdoc.title;
+		if (newdoc.bookmark)
+		    LYforce_HTML_mode = TRUE;
 		if (LYValidate &&
 		    startfile_ok &&
+		    newdoc.address && startfile && homepage &&
 		    (!strcmp(newdoc.address, startfile) ||
 		     !strcmp(newdoc.address, homepage))) {
 		    LYPermitURL = TRUE;
@@ -366,6 +381,7 @@ try_again:
 		     */
 		    LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
 		    FREE(newdoc.address); /* to pop last doc */
+		    FREE(newdoc.bookmark);
 		    LYJumpFileURL = FALSE;
 		    reloading = FALSE;
 		    LYPermitURL = FALSE;
@@ -394,10 +410,11 @@ try_again:
 			*/
 		       if (first_file && homepage &&
 #ifdef VMS
-			   strcasecomp(homepage, startfile) != 0) {
+			   strcasecomp(homepage, startfile) != 0)
 #else
-			   strcmp(homepage, startfile) != 0) {
+			   strcmp(homepage, startfile) != 0)
 #endif /* VMS */
+			{
 			   /* 
 			    * Couldn't return to the first file but there is a
 			    * homepage we can use instead. Useful for when the
@@ -411,6 +428,7 @@ try_again:
 			   StrAllocCopy(newdoc.address, homepage);
 			   FREE(newdoc.post_data);
 			   FREE(newdoc.post_content_type);
+			   FREE(newdoc.bookmark);
 			   StrAllocCopy(startfile, homepage);
 			   newdoc.isHEAD = FALSE;
 		       } else {
@@ -447,9 +465,9 @@ try_again:
 
 		    if (traversal) {
 		        /*
-			 * During traversal build up lists of all links
-			 * traversed.  Traversal mode is a special 
-			 * feature for traversing http links in the web.
+			 *  During traversal build up lists of all links
+			 *  traversed.  Traversal mode is a special 
+			 *  feature for traversing http links in the web.
 			 */
 			if (traversal_link_to_add) {
 			    /* Add the address we sought to TRAVERSE_FILE */
@@ -457,7 +475,8 @@ try_again:
 			        add_to_table(traversal_link_to_add);
 			    FREE(traversal_link_to_add);
 			}
-			if (curdoc.address && curdoc.title)
+			if (curdoc.address && curdoc.title &&
+			    strncasecomp(curdoc.address, "LYNXIMGMAP:", 11))
 			    /* Add the address we got to TRAVERSE_FOUND_FILE */
 			    add_to_traverse_list(curdoc.address, curdoc.title);
 		    }
@@ -472,6 +491,7 @@ try_again:
 		        !strcmp(curdoc.title, DOWNLOAD_OPTIONS_TITLE)) {
 			StrAllocCopy(newdoc.address, curdoc.address);
 			StrAllocCopy(newdoc.title, curdoc.title);
+			StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
 			newdoc.line = curdoc.line;
 			newdoc.link = curdoc.link;
 		    }
@@ -506,12 +526,18 @@ try_again:
 	   StrAllocCopy(curdoc.address, newdoc.address);
 	   StrAllocCopy(curdoc.post_data, newdoc.post_data);
 	   StrAllocCopy(curdoc.post_content_type, newdoc.post_content_type);
+	   StrAllocCopy(curdoc.bookmark, newdoc.bookmark);
 	   curdoc.isHEAD = newdoc.isHEAD;
 
 	   /*
 	    *  Reset WWW present mode so that if we were getting
 	    *  the source, we get rendered HTML from now on.
 	    */
+	   if (ownerS_address != NULL) {
+	       if (HTOutputFormat == WWW_SOURCE && !HText_getOwner())
+	           HText_setMainTextOwner(ownerS_address);
+	       FREE(ownerS_address);
+	   }
 	   HTOutputFormat = WWW_PRESENT;
 	   /*
 	    *  Reset all of the other relevant flags. - FM
@@ -595,7 +621,8 @@ try_again:
 		 * Set up the crawl output stuff.
 		 */
 		if (curdoc.address && !lookup(curdoc.address)) {
-		    crawl_ok = TRUE;
+		    if (strncasecomp(curdoc.address, "LYNXIMGMAP:", 11))
+		        crawl_ok = TRUE;
 		    add_to_table(curdoc.address);
 		}
 		/*
@@ -644,7 +671,7 @@ try_again:
 	    HText_pageDisplay(newline, prev_target);
 
 #ifdef DIRED_SUPPORT
-	    if (lynx_edit_mode && nlinks > 0 && tagged != NULL)
+	    if (lynx_edit_mode && nlinks > 0 && !HTList_isEmpty(tagged))
 	      showtags(tagged);
 #endif /* DIRED_SUPPORT */
 	    /* if more equals true then there is more
@@ -685,7 +712,7 @@ try_again:
 	    HText_pageDisplay(newline, prev_target);
 
 #ifdef DIRED_SUPPORT
-	    if (lynx_edit_mode && nlinks > 0 && tagged != NULL)
+	    if (lynx_edit_mode && nlinks > 0 && !HTList_isEmpty(tagged))
 	        showtags(tagged);
 #endif /* DIRED_SUPPORT */
 	    if (user_mode == NOVICE_MODE)
@@ -968,10 +995,15 @@ new_keyboard_input:
 	     */
 	    rlink_exists = (nlinks > 0 && links[curdoc.link].lname != NULL);
 	    if (rlink_exists) {
-	        rlink_allowed = (!lookup_reject(links[curdoc.link].lname) &&
-				 !strncmp(traversal_host,
-				 	  links[curdoc.link].lname,
-					  strlen(traversal_host)));
+	        rlink_allowed =
+		    (!lookup_reject(links[curdoc.link].lname) &&
+		     traversal_host && links[curdoc.link].lname &&
+		     !strncmp(traversal_host,
+			      (strncasecomp(links[curdoc.link].lname,
+					    "LYNXIMGMAP:", 11)
+					 ?
+		links[curdoc.link].lname : (links[curdoc.link].lname + 11)),
+			      strlen(traversal_host)));
 	    } else {	
 	        rlink_allowed = FALSE;
 	    }
@@ -1003,7 +1035,9 @@ new_keyboard_input:
 		} else {
 		    StrAllocCopy(traversal_link_to_add,
 		    		 links[curdoc.link].lname);
-		    crawl_ok = TRUE;
+		    if (strncasecomp(traversal_link_to_add,
+		    		     "LYNXIMGMAP:", 11))
+		        crawl_ok = TRUE;
 		    c = RTARROW;
 		}
 	    } else { /* no good right link, so only down and left arrow ok*/
@@ -1091,6 +1125,7 @@ new_cmd:  /* a goto point for new input without going
 		if (are_different(&curdoc, &newdoc)) {
 		    FREE(newdoc.post_data);
 		    FREE(newdoc.post_content_type);
+		    FREE(newdoc.bookmark);
 		    newdoc.isHEAD = FALSE;
 		}
 		force_load = TRUE;  /* force MainLoop to reload */
@@ -1107,10 +1142,13 @@ new_cmd:  /* a goto point for new input without going
 	    break;
 
 	case LYK_SOURCE:  /* toggle view source mode */
-	    if (HTisDocumentSource()) 
+	    if (HTisDocumentSource()) {
 	        HTOutputFormat = WWW_PRESENT;
-	    else
+	    } else {
+	        if (HText_getOwner())
+		    StrAllocCopy(ownerS_address, HText_getOwner());
 	        HTOutputFormat = WWW_SOURCE;
+	    }
 	    HTuncache_current_document();
 	    FREE(curdoc.address); /* so it doesn't get pushed */
 	    break;
@@ -1381,7 +1419,7 @@ new_cmd:  /* a goto point for new input without going
 
 	    } else if (old_c != real_c) {
 		old_c = real_c;
-		_statusline(ALREADY_AT_FIRST);
+		_statusline(ALREADY_AT_BEGIN);
 		sleep(MessageSecs);
 	    }
 	    break;
@@ -1537,7 +1575,7 @@ new_cmd:  /* a goto point for new input without going
 	    break;
 
 	case LYK_HISTORY: 	/* show the history page */
-	    if (strcmp(curdoc.title, HISTORY_PAGE_TITLE)) {
+	    if (curdoc.title && strcmp(curdoc.title, HISTORY_PAGE_TITLE)) {
 		/*
 		 *  Don't do this if already viewing history page.
 		 *
@@ -1562,6 +1600,7 @@ new_cmd:  /* a goto point for new input without going
  		FREE(curdoc.address);  /* so it doesn't get pushed */
 		FREE(newdoc.post_data);
 		FREE(newdoc.post_content_type);
+		FREE(newdoc.bookmark);
 		newdoc.isHEAD = FALSE;
 
                 LYpop(&curdoc);
@@ -1626,8 +1665,11 @@ new_cmd:  /* a goto point for new input without going
 			   /*
 			    * Do nothing if it's disabled. - FM
 			    */
-			   if (links[curdoc.link].form->disabled == YES)
+			   if (links[curdoc.link].form->disabled == YES) {
+			       HTOutputFormat = WWW_PRESENT;
+			       LYforce_no_cache = FALSE;
 			       break;
+			   }
 			   /*
 			    * Make sure we have an action. - FM
 			    */
@@ -1636,6 +1678,8 @@ new_cmd:  /* a goto point for new input without going
 			       					== '\0') {
 			       _statusline(NO_FORM_ACTION);
 			       sleep(MessageSecs);
+			       HTOutputFormat = WWW_PRESENT;
+			       LYforce_no_cache = FALSE;
 			       break;
 			    }
 		            /*
@@ -1645,6 +1689,8 @@ new_cmd:  /* a goto point for new input without going
 			    if (links[curdoc.link].form->submit_method
 			             == URL_MAIL_METHOD && no_mail) {
 			        HTAlert(FORM_MAILTO_DISALLOWED);
+				HTOutputFormat = WWW_PRESENT;
+				LYforce_no_cache = FALSE;
 			        break;
 			    }
 			    /*
@@ -1656,6 +1702,8 @@ new_cmd:  /* a goto point for new input without going
 				    links[curdoc.link].form->submit_action,
 				    "file:", 5)) {
 				HTAlert(FILE_ACTIONS_DISALLOWED);
+				HTOutputFormat = WWW_PRESENT;
+				LYforce_no_cache = FALSE;
 				break;
 			    }
 #ifdef NOTDEFINED /* We're disabling form inputs instead of using this. - FM */
@@ -1669,6 +1717,8 @@ new_cmd:  /* a goto point for new input without going
 				      "multipart/form-data")) {
 				    HTAlert(
 	"Enctype multipart/form-data not yet supported!  Cannot submit.");
+				    HTOutputFormat = WWW_PRESENT;
+				    LYforce_no_cache = FALSE;
 				    break;
 				}
 			    }
@@ -1697,10 +1747,7 @@ new_cmd:  /* a goto point for new input without going
 			if (strncasecomp(curdoc.address, "file:", 5)) {
 			    HTAlert(FILE_SERVED_LINKS_DISALLOWED);
 			    break;
-			} else if (bookmark_page &&
-				   (strstr(curdoc.address, bookmark_page) ||
-				    !strcmp(curdoc.title,
-					    MOSAIC_BOOKMARK_TITLE))) {
+			} else if (curdoc.bookmark != NULL) {
 			    HTAlert(FILE_BOOKMARKS_DISALLOWED);
 			    break;
 			}
@@ -1717,16 +1764,15 @@ new_cmd:  /* a goto point for new input without going
 		    if (are_different(&curdoc, &newdoc)) {
 		        FREE(newdoc.post_data);
 		        FREE(newdoc.post_content_type);
+			FREE(newdoc.bookmark);
 		    }
-		    if (!no_jump && lynxjumpfile &&
+		    if (!no_jump && lynxjumpfile && curdoc.address &&
 		        !strcmp(lynxjumpfile, curdoc.address)) {
 			LYJumpFileURL = TRUE;
 			LYUserSpecifiedURL = TRUE;
-		    } else if (!strcmp(curdoc.title, HISTORY_PAGE_TITLE) ||
-		    	       (bookmark_page &&
-			        (strstr(curdoc.address, bookmark_page) ||
-				 !strcmp(curdoc.title,
-				 	 MOSAIC_BOOKMARK_TITLE))) ||
+		    } else if (curdoc.title &&
+		    	       !strcmp(curdoc.title, HISTORY_PAGE_TITLE) ||
+			       curdoc.bookmark != NULL ||
 			       (lynxjumpfile &&
 			        !strcmp(lynxjumpfile, curdoc.address))) {
 		        LYUserSpecifiedURL = TRUE;
@@ -1739,7 +1785,11 @@ new_cmd:  /* a goto point for new input without going
 #ifdef DIRED_SUPPORT
 		    if (lynx_edit_mode) {
 			  HTuncache_current_document();
-			  HTUnEscape(newdoc.address);
+			  /*  Unescaping any slash chars in the URL,
+			   *  but avoid double unescaping and too-early
+			   *  unescaping of other chars. - KW
+			   */
+			  HTUnEscapeSome(newdoc.address,"/");
 			  strip_trailing_slash(newdoc.address);
 		    }
 #endif /* DIRED_SUPPORT */
@@ -1777,8 +1827,8 @@ new_cmd:  /* a goto point for new input without going
 	     * Ask the user.
 	     */
 	    _statusline(URL_TO_OPEN);
-	    if ((ch=LYgetstr(user_input_buffer, VISIBLE,
-	    		     sizeof(user_input_buffer), recall)) < 0 ) {
+	    if ((ch = LYgetstr(user_input_buffer, VISIBLE,
+	    		       sizeof(user_input_buffer), recall)) < 0 ) {
 		/*
 		 * User cancelled the Goto via ^G.
 		 * Restore user_input_buffer and break. - FM
@@ -1821,8 +1871,8 @@ check_recall:
 		     * Roll around to the last URL in the list. - FM
 		     */
 		    URLNum = 0;
-		if ((cp=(char *)HTList_objectAt(Goto_URLs,
-	    					    URLNum)) != NULL) {
+		if ((cp = (char *)HTList_objectAt(Goto_URLs,
+	    					  URLNum)) != NULL) {
 		    strcpy(user_input_buffer, cp);
 		    if (goto_buffer && *temp &&
 		        !strcmp(temp, user_input_buffer)) { 
@@ -1833,8 +1883,9 @@ check_recall:
 		    } else {
 			_statusline(EDIT_A_PREV_GOTO);
 		    }
-		    if ((ch=LYgetstr(user_input_buffer, VISIBLE,
-				     sizeof(user_input_buffer), recall)) < 0) {
+		    if ((ch = LYgetstr(user_input_buffer, VISIBLE,
+				      sizeof(user_input_buffer),
+				      recall)) < 0) {
 			/*
 			 * User cancelled the Goto via ^G.
 			 * Restore user_input_buffer and break. - FM
@@ -1877,8 +1928,9 @@ check_recall:
 		    } else {
 			_statusline(EDIT_A_PREV_GOTO);
 		    }
-		    if ((ch=LYgetstr(user_input_buffer, VISIBLE,
-				     sizeof(user_input_buffer), recall)) < 0) {
+		    if ((ch = LYgetstr(user_input_buffer, VISIBLE,
+				       sizeof(user_input_buffer),
+				       recall)) < 0) {
 			/*
 			 * User cancelled the Goto via ^G.
 			 * Restore user_input_buffer and break. - FM
@@ -2063,8 +2115,8 @@ check_recall:
 
 #ifdef VMS
 		/*
-		 * On VMS, a file://localhost/ URL means
-		 * a listing for the login directory. - FM
+		 *  On VMS, a file://localhost/ URL means
+		 *  a listing for the login directory. - FM
 		 */
 		if (!strcmp(user_input_buffer, "file://localhost/"))
 		    strcat(user_input_buffer,
@@ -2074,12 +2126,13 @@ check_recall:
 	        StrAllocCopy(newdoc.address, user_input_buffer);
 		newdoc.isHEAD = FALSE;
 		/*
-		 * Might be an anchor in the same doc from a POST
-		 * form.  If so, dont't free the content. -- FM
+		 *  Might be an anchor in the same doc from a POST
+		 *  form.  If so, dont't free the content. -- FM
 		 */
 		if (are_different(&curdoc, &newdoc)) {
 		    FREE(newdoc.post_data);
 		    FREE(newdoc.post_content_type);
+		    FREE(newdoc.bookmark);
 		}
 		force_load = TRUE;
 		LYUserSpecifiedURL = TRUE;
@@ -2098,6 +2151,7 @@ check_recall:
 	        StrAllocCopy(newdoc.title, "Help Screen");
 		FREE(newdoc.post_data);
 		FREE(newdoc.post_content_type);
+		FREE(newdoc.bookmark);
 		newdoc.isHEAD = FALSE;
 	    }
 	    break;
@@ -2118,6 +2172,7 @@ check_recall:
 	            StrAllocCopy(newdoc.title, "System Index"); /* name it */
 		    FREE(newdoc.post_data);
 		    FREE(newdoc.post_content_type);
+		    FREE(newdoc.bookmark);
 		    newdoc.isHEAD = FALSE;
 	        } /* end else */
 	    }  /* end if */
@@ -2177,6 +2232,7 @@ check_recall:
                     StrAllocCopy(newdoc.title, "Entry into main screen");
 		    FREE(newdoc.post_data);
 		    FREE(newdoc.post_content_type);
+		    FREE(newdoc.bookmark);
 		    newdoc.isHEAD = FALSE;
 	            highlight(OFF,curdoc.link); 
 #ifdef DIRED_SUPPORT
@@ -2212,6 +2268,7 @@ check_recall:
 		CurrentCharSet_flag != current_char_set ||
 		show_dotfiles_flag != show_dotfiles ||
 		LYRawMode_flag != LYRawMode ||
+		LYSelectPopups_flag != LYSelectPopups ||
 		strcmp(CurrentUserAgent, (LYUserAgent ?
 					  LYUserAgent : ""))) {
 		HTuncache_current_document();
@@ -2222,6 +2279,7 @@ check_recall:
 		CurrentCharSet_flag = current_char_set;
 		show_dotfiles_flag = show_dotfiles;
 		LYRawMode_flag = LYRawMode;
+		LYSelectPopups_flag = LYSelectPopups;
 		StrAllocCopy(CurrentUserAgent, (LYUserAgent ?
 						LYUserAgent : ""));
 	    }
@@ -2264,6 +2322,7 @@ check_recall:
 	           StrAllocCopy(newdoc.address, use_this_url_instead);
 		   FREE(newdoc.post_data);
 		   FREE(newdoc.post_content_type);
+		   FREE(newdoc.bookmark);
 		   newdoc.isHEAD = FALSE;
 	           FREE(use_this_url_instead);
 		   force_load = TRUE;
@@ -2318,90 +2377,124 @@ check_recall:
 	    break;
 
 	case LYK_COMMENT:  /* reply by mail */
-	   if (!owner_address) {
+	    if (!owner_address &&
+	        strncasecomp(curdoc.address, "http", 4)) {
 		if (old_c != real_c)	{
-			old_c = real_c;
-			_statusline(NO_OWNER);
-			sleep(MessageSecs);
+		    old_c = real_c;
+		    _statusline(NO_OWNER);
+		    sleep(MessageSecs);
 		}
-	   } else if (no_mail) {
-	       if (old_c != real_c) {
-	           old_c = real_c;
-		   _statusline(MAIL_DISALLOWED);
-		   sleep(MessageSecs);
-	       }
-	   } else {
+	    } else if (no_mail) {
+	        if (old_c != real_c) {
+	            old_c = real_c;
+		    _statusline(MAIL_DISALLOWED);
+		    sleep(MessageSecs);
+	        }
+	    } else {
 		_statusline(CONFIRM_COMMENT);
 		c = LYgetch();
 	        if (TOUPPER(c) == 'Y') {
-
-	           if (is_url(owner_address) != MAILTO_URL_TYPE) { 
-			/* the address is a url */
-			/* just follow the link */
-			
-		       StrAllocCopy(newdoc.address, owner_address);
-
-	           } else {
-		       /* the owner_address is a mailto: url type */
-		       cp = HText_getRevTitle();
-		       if (strchr(owner_address,':')!=NULL)
-			 /* send a reply. The address is after the colon */
-	      	         reply_by_mail(strchr(owner_address,':')+1,
-			 	       curdoc.address,
-				       (cp ? cp : "")); 
-		       else
-	      	         reply_by_mail(owner_address, curdoc.address,
-				       (cp ? cp : "")); 
-
-	               refresh_screen=TRUE;  /* to force a showpage */
-	          }
+		    if (!owner_address) {
+		        /*
+			 *  No owner defined, so make a guess and
+			 *  and offer it to the user. - FM
+			 */
+		        char *address = NULL;
+			char *path = HTParse(curdoc.address, "", PARSE_PATH);
+			if (path != NULL) {
+			    HTUnEscape(path);
+			    if (*path == '~' && strlen(path) > 1) {
+			        /*
+				 *  It's a ~user URL so guess user@host. - FM
+				 */
+			        if ((cp = strchr((path+1), '/')) != NULL)
+				    *cp = '\0';
+				StrAllocCopy(address, "mailto:");
+				StrAllocCat(address, (path+1));
+				StrAllocCat(address, "@");
+			    }
+			    FREE(path);
+			}
+			if (address == NULL)
+			    /*
+			     *  Wasn't a ~user URL so guess WebMaster@host. - FM
+			     */
+		            StrAllocCopy(address, "mailto:WebMaster@");
+		        StrAllocCat(address,
+		       		    HTParse(curdoc.address, "", PARSE_HOST));
+			_user_message(NO_OWNER_USE, address);
+			c = LYgetch();
+			if (TOUPPER(c) == 'Y') {
+			    StrAllocCopy(owner_address, address);
+			    FREE(address);
+			} else {
+			    FREE(address);
+			    break;
+			}
+		    }
+	            if (is_url(owner_address) != MAILTO_URL_TYPE) { 
+			/*
+			 *  The address is a URL.  Just follow the link.
+			 */
+		        StrAllocCopy(newdoc.address, owner_address);
+	            } else {
+		        /*
+			 *  The owner_address is a mailto: URL.
+			 */
+		        cp = HText_getRevTitle();
+		        if (strchr(owner_address,':')!=NULL)
+			     /*
+			      *  Send a reply.  The address is after the colon.
+			      */
+	      	             reply_by_mail(strchr(owner_address,':')+1,
+					   curdoc.address,
+					   (cp ? cp : "")); 
+		        else
+	      	            reply_by_mail(owner_address, curdoc.address,
+				          (cp ? cp : "")); 
+
+	                refresh_screen=TRUE;  /* to force a showpage */
+	           }
 	       }
 	   }
 	   break;
 
 #ifdef DIRED_SUPPORT
-	case LYK_TAG_LINK:  /* tag or untag the current link */
-	   if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
-	      if (dir_list_style == MIXED_STYLE) {
-		 if (!strcmp(links[curdoc.link].hightext,"../")) 
-		   break;
-	      } else if (!strncmp(links[curdoc.link].hightext,"Up to ",6)) 
-		 break;
-	      t1 = tagged;
-	      while (t1 != NULL) {
-		 if (!strcmp(links[curdoc.link].lname,t1->name)) {
-		    if (t1 == tagged) 
-		      tagged = t1->next;
-		    else 
-		      t2->next = t1->next;
-		    FREE(t1->name);
-		    FREE(t1);
-		    tagflag(OFF,curdoc.link);
+	case LYK_TAG_LINK:	/* tag or untag the current link */
+	    if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
+	        if (!strcmp(links[curdoc.link].hightext, "..")) 
+		    break;	/* Never tag the parent directory */
+	        if (dir_list_style == MIXED_STYLE) {
+		    if (!strcmp(links[curdoc.link].hightext, "../")) 
+		        break;
+	        } else if (!strncmp(links[curdoc.link].hightext,"Up to ",6)) 
 		    break;
-		 }
-		 t2 = t1;
-		 t1 = t1->next;
-	      }
-	      if (t1 == NULL) {
-		 t1 = (taglink *) malloc(sizeof(taglink));
-		 if (tagged == NULL) 
-		   tagged = t1;
-		 else 
-		   t2->next = t1;
-		 t1->next = NULL;
-		 t1->name = NULL;
-		 StrAllocCopy(t1->name,links[curdoc.link].lname);
-		 tagflag(ON,curdoc.link);
-	      }
-	      if (curdoc.link < nlinks-1) {
-		highlight(OFF, curdoc.link);
-		curdoc.link++;
-	      } else if (!more && newline==1 && curdoc.link==nlinks-1) {
-		highlight(OFF,curdoc.link); 
-		curdoc.link = 0;
-	      } else if (more) {  /* next page */
-                newline += (display_lines);
-	      }
+	        {
+		    /*
+		     *  HTList-based management of tag list, see LYLocal.c - KW
+		     */
+		    HTList * t1 = tagged;
+		    char * tagname = NULL;
+		    BOOLEAN found = FALSE;
+
+		    while ((tagname = (char *)HTList_nextObject(t1)) != NULL) {
+		        if (!strcmp(links[curdoc.link].lname,tagname)) {
+			    found = TRUE;
+			    HTList_removeObject(tagged, tagname);
+			    FREE(tagname);
+			    tagflag(OFF,curdoc.link);
+			    break;
+		        }
+		    }
+		    if (!found) {
+		        if (tagged == NULL)
+			    tagged = HTList_new();
+		        tagname = NULL;
+		        StrAllocCopy(tagname,links[curdoc.link].lname);
+		        HTList_addObject(tagged,tagname);
+		        tagflag(ON,curdoc.link);
+		    }
+	        }
 	   }
 	   break;
 
@@ -2469,7 +2562,7 @@ check_recall:
 		    } else {
 		       if (((dir_info.st_mode) & S_IFMT) == S_IFREG) {
 			  strcpy(tmpbuf,cp);
-			  HTUnEscape(tmpbuf);
+			  HTUnEscapeSome(tmpbuf,"/");
 			  if (edit_current_file(tmpbuf,curdoc.link,newline))
 			  {
 			    	HTuncache_current_document();
@@ -2524,31 +2617,38 @@ check_recall:
 	case LYK_DEL_BOOKMARK:  /* delete home page link */
 #ifdef DIRED_SUPPORT
 	case LYK_REMOVE:  /* remove files and directories */
-	   if (lynx_edit_mode && nlinks > 0 && !no_dired_support)
+	   c = 'N';
+	   if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
 		local_remove(&curdoc);
-	    else
+		c = 'Y';
+	   } else
 #endif /* DIRED_SUPPORT */
 
-	    if (bookmark_page && (strstr(curdoc.address, bookmark_page) ||
-			!strcmp(curdoc.title, MOSAIC_BOOKMARK_TITLE))) {
+	    if (curdoc.bookmark != NULL) {
 		_statusline(CONFIRM_BOOKMARK_DELETE);
              	c = LYgetch();
                 if (TOUPPER(c) != 'Y')
                     break;
-                remove_bookmark_link(links[curdoc.link].anchor_number-1);
+                remove_bookmark_link(links[curdoc.link].anchor_number-1,
+				     curdoc.bookmark);
 	    } else {	/* behave like REFRESH for backward compatability */
-	        refresh_screen=TRUE;
+	        refresh_screen = TRUE;
 	        break;
 	    }
-	    HTuncache_current_document();
-	    StrAllocCopy(newdoc.address, curdoc.address);
-	    FREE(curdoc.address);	
-	    newdoc.line = curdoc.line;
-	    if (curdoc.link == nlinks-1)
-	       /* if we deleted the last link on the page */
-               newdoc.link=curdoc.link-1; 
-	    else
-                newdoc.link=curdoc.link;
+	    if (TOUPPER(c) == 'Y') {
+		HTuncache_current_document();
+		StrAllocCopy(newdoc.address, curdoc.address);
+		FREE(curdoc.address);	
+		newdoc.line = curdoc.line;
+		if (curdoc.link == nlinks-1) {
+		    /*
+		     *  We deleted the last link on the page. - FM
+		     */
+		    newdoc.link = curdoc.link-1;
+		} else {
+		    newdoc.link = curdoc.link;
+		}
+	    }
 	    break;
 
 #ifdef DIRED_SUPPORT
@@ -2560,7 +2660,7 @@ check_recall:
 
 	case LYK_INFO:  /* show document info */
 	   /* don't do if already viewing info page */	
-	   if (strcmp(curdoc.title, SHOWINFO_TITLE)) {
+	   if (strcmp((curdoc.title ? curdoc.title : ""), SHOWINFO_TITLE)) {
 	        showinfo(&curdoc, lines_in_file, &newdoc, owner_address);
 		LYforce_no_cache = TRUE;
 		if (LYValidate || check_realm)
@@ -2583,7 +2683,8 @@ check_recall:
 	    }
 
 	    /* don't do if already viewing print options page */	
-	    if (strcmp(curdoc.title, PRINT_OPTIONS_TITLE)) {	
+	    if (strcmp((curdoc.title ? curdoc.title : ""),
+	    	       PRINT_OPTIONS_TITLE)) {	
 
                 if (print_options(&newdoc.address, lines_in_file) < 0)
 		    break;
@@ -2595,7 +2696,8 @@ check_recall:
 
 	case LYK_LIST:  /* list links in the current document */
 	    /* don't do if already viewing list page */	
-	    if (strcmp(curdoc.title, LIST_PAGE_TITLE)) {
+	    if (strcmp((curdoc.title ? curdoc.title : ""),
+	    	       LIST_PAGE_TITLE)) {
 		if (showlist(&newdoc.address, TRUE) < 0)
 		    break;
 		refresh_screen=TRUE;  /* redisplay */
@@ -2632,7 +2734,8 @@ check_recall:
        case LYK_DIRED_MENU:  /* provide full file management menu */
 	    /* don't do if not allowed or already viewing the menu */	
 	    if (lynx_edit_mode && !no_dired_support &&
-	        strcmp(curdoc.title, DIRED_MENU_TITLE)) {
+	        strcmp((curdoc.title ? curdoc.title : ""),
+		       DIRED_MENU_TITLE)) {
 	        dired_options(&curdoc,&newdoc.address);
 	        refresh_screen=TRUE;  /* redisplay */
 	    }
@@ -2649,35 +2752,58 @@ check_recall:
 		break;
 	    }
 
-	    if (strcmp(curdoc.title, HISTORY_PAGE_TITLE) &&
-	        strcmp(curdoc.title, SHOWINFO_TITLE) && 
-	        strcmp(curdoc.title, PRINT_OPTIONS_TITLE) &&
+	    if (strcmp((curdoc.title ? curdoc.title : ""),
+	    	       HISTORY_PAGE_TITLE) &&
+	        strcmp((curdoc.title ? curdoc.title : ""),
+		       SHOWINFO_TITLE) && 
+	        strcmp((curdoc.title ? curdoc.title : ""),
+		       PRINT_OPTIONS_TITLE) &&
 #ifdef DIRED_SUPPORT
-	        strcmp(curdoc.title, DIRED_MENU_TITLE) &&
-	        strcmp(curdoc.title, PERMIT_OPTIONS_TITLE) &&
-	        strcmp(curdoc.title, UPLOAD_OPTIONS_TITLE) &&
+	        strcmp((curdoc.title ? curdoc.title : ""),
+		       DIRED_MENU_TITLE) &&
+	        strcmp((curdoc.title ? curdoc.title : ""),
+		       PERMIT_OPTIONS_TITLE) &&
+	        strcmp((curdoc.title ? curdoc.title : ""),
+		       UPLOAD_OPTIONS_TITLE) &&
 #endif /* DIRED_SUPPORT */
-	        strcmp(curdoc.title, DOWNLOAD_OPTIONS_TITLE) &&
-	        strcmp(curdoc.title, LIST_PAGE_TITLE)) {
-
+	        strcmp((curdoc.title ? curdoc.title : ""),
+		       DOWNLOAD_OPTIONS_TITLE) &&
+	        strcmp((curdoc.title ? curdoc.title : ""),
+		       LIST_PAGE_TITLE)) {
 		if (nlinks > 0) {
-		    if (curdoc.post_data == NULL) {
+		    if (curdoc.post_data == NULL &&
+		        curdoc.bookmark == NULL) {
 		        /*
-			 *  Document doesn't have POST content, so
-			 *  we can save either that of the link. - FM
+			 *  Document doesn't have POST content,
+			 *  and is not a bookmark file, so we can
+			 *  save either that or the link. - FM
 			 */
 		        _statusline(BOOK_D_L_OR_CANCEL);
 			c = LYgetch();
 			if (TOUPPER(c) == 'D') {
 			    save_bookmark_link(curdoc.address, curdoc.title);
-			    break;
+                            refresh_screen = TRUE; /* MultiBookmark support */
+			    goto check_add_bookmark_to_self;
 			}
 		    } else {
-		        /*
-			 *  Only offer the link in a document
-			 *  with POST content. - FM
-			 */
-		        _statusline(BOOK_L_OR_CANCEL);
+			if (LYMultiBookmarks == FALSE &&
+			    curdoc.bookmark != NULL) {
+			    /*
+			     *  If multiple bookmarks are disabled, offer
+			     *  the L)ink or C)ancel, but with wording
+			     *  which indicates that the link already
+			     *  exists in this bookmark file. - FM
+			     */
+			    _statusline(MULTIBOOKMARKS_SELF);
+			} else {
+		            /*
+			     *  Only offer the link in a document with
+			     *  POST content, or if the current document
+			     *  is a bookmark file and multiple bookmarks
+			     *  are enabled. - FM
+			     */
+		            _statusline(BOOK_L_OR_CANCEL);
+			}
 			c = LYgetch();
 		    }
 		    if (TOUPPER(c) == 'L') {
@@ -2704,6 +2830,17 @@ check_recall:
 		    if (TOUPPER(c) == 'D')
 		        save_bookmark_link(curdoc.address, curdoc.title);
 		}
+check_add_bookmark_to_self:
+		if (curdoc.bookmark && BookmarkPage &&
+		    !strcmp(curdoc.bookmark, BookmarkPage)) {
+		    HTuncache_current_document();
+		    StrAllocCopy(newdoc.address, curdoc.address);
+		    StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
+		    FREE(curdoc.address);	
+		    newdoc.line = curdoc.line;
+		    newdoc.link = curdoc.link;
+		}
+		FREE(temp);
 	    } else {
 		if (old_c != real_c)	{
 			old_c = real_c;
@@ -2711,6 +2848,7 @@ check_recall:
 			sleep(MessageSecs);
 		}
 	    }
+            refresh_screen = TRUE; /* MultiBookmark support */
 	    break;
 
 	case LYK_VIEW_BOOKMARK:   /* v to view home page */
@@ -2723,13 +2861,20 @@ check_recall:
 		break;
 	    }
 
-	    /* see if a bookmark exists
-	     * if it does replace newdoc.address with it's name 
+	    /*
+	     *  See if a bookmark exists.
+	     *  If it does replace newdoc.address with it's name.
 	     */
-	    if (get_bookmark_filename(&newdoc.address) != NULL) {
+	    if ((cp = get_bookmark_filename(&newdoc.address)) != NULL) {
+	        if (*cp == '\0' || !strcmp(cp, " ") ||
+		    !strcmp(curdoc.address, newdoc.address)) {
+		    refresh_screen = TRUE; /* MultiBookmark support */
+		    break;
+		}
 		LYforce_HTML_mode = TRUE;  /* force HTML */
 		LYforce_no_cache = TRUE;  /*force the document to be reloaded*/
-		StrAllocCopy(newdoc.title, "Bookmark File");
+		StrAllocCopy(newdoc.title, BOOKMARK_TITLE);
+		StrAllocCopy(newdoc.bookmark, BookmarkPage);
 		FREE(newdoc.post_data);
 		FREE(newdoc.post_content_type);
 		newdoc.isHEAD = FALSE;
@@ -2743,6 +2888,7 @@ check_recall:
        			sleep(MessageSecs);
 		}
 	    }
+            refresh_screen = TRUE; /* MultiBookmark support */
 	    break;
 
 	case LYK_SHELL:  /* shell escape */
@@ -2779,18 +2925,35 @@ check_recall:
 	    }
 
 	    /* don't do if already viewing download options page */	
-	    if (0==strcmp(curdoc.title, DOWNLOAD_OPTIONS_TITLE))
+	    if (0==strcmp((curdoc.title ? curdoc.title : ""),
+	    		  DOWNLOAD_OPTIONS_TITLE))
 	        break;
 
 	    if (nlinks > 0) {
                 if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
-		    if (old_c != real_c)	{
+		    if (links[curdoc.link].form->type == F_SUBMIT_TYPE) {
+		        if (links[curdoc.link].form->submit_method ==
+				 URL_MAIL_METHOD) {
+			    if (old_c != real_c) {
+				old_c = real_c;
+				_statusline(NO_DOWNLOAD_MAILTO_ACTION);
+				sleep(MessageSecs);
+			    }
+			    break;
+			}
+			HTOutputFormat = HTAtom_for("www/download");
+			LYforce_no_cache = TRUE;
+			cmd = LYK_ACTIVATE;
+			goto new_cmd;
+		    }
+		    if (old_c != real_c) {
 			old_c = real_c;
 			_statusline(NO_DOWNLOAD_INPUT);
 			sleep(MessageSecs);
 		    }
 
-		} else if (0==strcmp(curdoc.title, PRINT_OPTIONS_TITLE)) {
+		} else if (0==strcmp((curdoc.title ? curdoc.title : ""),
+				     PRINT_OPTIONS_TITLE)) {
 		    if (old_c != real_c)	{
 			old_c = real_c;
 			_statusline(NO_DOWNLOAD_PRINT_OP);
@@ -2798,14 +2961,16 @@ check_recall:
 		    }
 
 #ifdef DIRED_SUPPORT
-		} else if (0==strcmp(curdoc.title, UPLOAD_OPTIONS_TITLE)) {
+		} else if (0==strcmp((curdoc.title ? curdoc.title : ""),
+				     UPLOAD_OPTIONS_TITLE)) {
 		    if (old_c != real_c)	{
 			old_c = real_c;
 			_statusline(NO_DOWNLOAD_UPLOAD_OP);
 			sleep(MessageSecs);
 		    }
 
-		} else if (0==strcmp(curdoc.title, PERMIT_OPTIONS_TITLE)) {
+		} else if (0==strcmp((curdoc.title ? curdoc.title : ""),
+				     PERMIT_OPTIONS_TITLE)) {
 		    if (old_c != real_c)	{
 			old_c = real_c;
 			_statusline(NO_DOWNLOAD_PERMIT_OP);
@@ -2822,10 +2987,12 @@ check_recall:
 		    FREE(temp);
 #endif /* DIRED_SUPPORT */
 
-		} else if (0==strcmp(curdoc.title, HISTORY_PAGE_TITLE)) {
+		} else if (0==strcmp((curdoc.title ? curdoc.title : ""),
+				     HISTORY_PAGE_TITLE)) {
 		    int number = atoi(links[curdoc.link].lname+9);
 		    StrAllocCopy(newdoc.address, history[number].address);
                     StrAllocCopy(newdoc.title, links[curdoc.link].hightext);
+		    StrAllocCopy(newdoc.address, history[number].bookmark);
 		    FREE(newdoc.post_data);
 		    FREE(newdoc.post_content_type);
 		    if (history[number].post_data)
@@ -2839,7 +3006,7 @@ check_recall:
 	            HTOutputFormat = HTAtom_for("www/download");
 		    LYUserSpecifiedURL = TRUE;
 		    /*force the document to be reloaded*/
-		    LYforce_no_cache = TRUE;  
+		    LYforce_no_cache = TRUE;
 		    force_load = TRUE;  /* force MainLoop to reload */
 		    
 		} else if (!strncasecomp(links[curdoc.link].lname,
@@ -2864,12 +3031,13 @@ check_recall:
 		    if (are_different(&curdoc, &newdoc)) {
 			FREE(newdoc.post_data);
 			FREE(newdoc.post_content_type);
+			FREE(newdoc.bookmark);
 			newdoc.isHEAD = FALSE;
 		    }
                     newdoc.link = 0;
 	            HTOutputFormat = HTAtom_for("www/download");
 		    /*force the document to be reloaded*/
-		    LYforce_no_cache = TRUE;  
+		    LYforce_no_cache = TRUE;
 		    force_load = TRUE;  /* force MainLoop to reload */
                 }
             } else if (old_c != real_c)	{
@@ -2882,7 +3050,8 @@ check_recall:
 #ifdef DIRED_SUPPORT
 	  case LYK_UPLOAD:
 	    /* don't do if already viewing upload options page */	
-	    if (0==strcmp(curdoc.title, UPLOAD_OPTIONS_TITLE))
+	    if (0==strcmp((curdoc.title ? curdoc.title : ""),
+	    		  UPLOAD_OPTIONS_TITLE))
 	        break;
 
 	    if (lynx_edit_mode && !no_dired_support) {
@@ -3023,6 +3192,7 @@ check_recall:
 		StrAllocCopy(newdoc.address, "LYNXKEYMAP:");
 	        FREE(newdoc.post_data);
 	        FREE(newdoc.post_content_type);
+		FREE(newdoc.bookmark);
 		newdoc.isHEAD = FALSE;
 		/*
 		 * If vi_keys changed, the keymap did too,
@@ -3092,6 +3262,7 @@ check_recall:
 		      StrAllocCopy(lynxjumpfile, ret);
 		      FREE(newdoc.post_data);
 	    	      FREE(newdoc.post_content_type);
+		      FREE(newdoc.bookmark);
 		      newdoc.isHEAD = FALSE;
 		      FREE(ret);
 		      LYUserSpecifiedURL = TRUE;
diff --git a/src/LYMap.c b/src/LYMap.c
index a147a79b..9720586b 100644
--- a/src/LYMap.c
+++ b/src/LYMap.c
@@ -212,6 +212,7 @@ PRIVATE int LYLoadIMGmap ARGS4 (
 	WWWDoc.address = address;
         WWWDoc.post_data = NULL;
         WWWDoc.post_content_type = NULL;
+        WWWDoc.bookmark = NULL;
 	WWWDoc.isHEAD = FALSE;
         LYforce_no_cache = TRUE;
 	reloading = TRUE;
@@ -246,6 +247,7 @@ PRIVATE int LYLoadIMGmap ARGS4 (
 	WWWDoc.address = address;
         WWWDoc.post_data = NULL;
         WWWDoc.post_content_type = NULL;
+        WWWDoc.bookmark = NULL;
 	WWWDoc.isHEAD = FALSE;
         LYforce_no_cache = TRUE;
 	reloading = TRUE;
diff --git a/src/LYNews.c b/src/LYNews.c
index 1ace9b6b..2bdab054 100644
--- a/src/LYNews.c
+++ b/src/LYNews.c
@@ -49,6 +49,7 @@ PUBLIC int LYNewsPost ARGS2(document *,newdoc, BOOLEAN,followup)
 	WWWDoc.address = newdoc->address;
 	WWWDoc.post_data = newdoc->post_data;
 	WWWDoc.post_content_type = newdoc->post_content_type;
+	WWWDoc.bookmark = newdoc->bookmark;
 	WWWDoc.isHEAD = newdoc->isHEAD;
         if(!HTLoadAbsolute(&WWWDoc)) {
 	    FREE(newsgroups);
diff --git a/src/LYOptions.c b/src/LYOptions.c
index deb94e8b..345c7d0e 100644
--- a/src/LYOptions.c
+++ b/src/LYOptions.c
@@ -14,6 +14,7 @@
 #include "LYKeymap.h"
 #include "LYrcFile.h"
 #include "HTAlert.h"
+#include "LYBookmark.h"
 
 #include "LYLeaks.h"
 
@@ -29,7 +30,8 @@
 
 BOOLEAN term_options;
 PRIVATE void terminate_options  PARAMS((int sig));
-PUBLIC int boolean_choice PARAMS((int status, int line, char **choices));
+PRIVATE int boolean_choice PARAMS((int status, int line,
+				   int column, char **choices));
 
 #define MAXCHOICES 10
 
@@ -60,13 +62,12 @@ PRIVATE void option_statusline ARGS1(char *,text)
     refresh();
 }
 
-
 PUBLIC void options NOARGS
 {
 #ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS
     int itmp;
 #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */
-    int response=0, ch;
+    int response, ch;
     /* if the user changes the display I need memory to put it in */
     char display_option[256]; 
 #ifndef VMS
@@ -106,98 +107,113 @@ PUBLIC void options NOARGS
     term_options = FALSE;
     signal(SIGINT, terminate_options);
 
+draw_options:
+    response = 0;
     clear(); 
-    move(0,5);
+    move(0, 5);
     if (bold_H1 || bold_headers)
         start_bold();
     printw("         Options Menu (%s Version %s)",
     	   			   LYNX_NAME, LYNX_VERSION);
     if (bold_H1 || bold_headers)
         stop_bold();
-    move(L_EDITOR,5);  
+    move(L_EDITOR, 5);  
     printw("E)ditor                      : %s",
     		((editor && *editor) ? editor : "NONE"));
 
-    move(L_DISPLAY,5);  
+    move(L_DISPLAY, 5);  
     printw("D)ISPLAY variable            : %s",
     		((display && *display) ? display : "NONE"));
 
-    move(L_MAIL_ADDRESS,5);  
+    move(L_MAIL_ADDRESS, 5);  
     printw("P)ersonal mail address       : %s",
     		((personal_mail_address && *personal_mail_address) ?
 					     personal_mail_address : "NONE"));
 
-    move(L_HOME,5);  
-    printw("B)ookmark file               : %s",
+    move(L_HOME, 5);
+    printw("mu(L)ti-bookmarks: %s",
+		(LYMultiBookmarks ? (LYMBMAdvanced ?
+                                     "ADVANCED" : "STANDARD") : "OFF"));
+    move(L_HOME, B_BOOK);
+    if (LYMultiBookmarks) {
+        printw("review/edit B)ookmarks files");
+    } else {
+        printw("B)ookmark file: %s",
     		((bookmark_page && *bookmark_page) ? bookmark_page : "NONE"));
+    }
 
-    move(L_FTPSTYPE,5);
+    move(L_FTPSTYPE, 5);
     printw("F)TP sort criteria           : %s",(HTfileSortMethod==FILE_BY_NAME ?
 					"By Filename" :
 					  (HTfileSortMethod==FILE_BY_SIZE ?
 					    "By Size" : 
 					      (HTfileSortMethod==FILE_BY_TYPE ?
 						"By Type" : "By Date"))));
-    move(L_SSEARCH,5); 
+    move(L_SSEARCH, 5); 
     printw("S)earching type              : %s",(case_sensitive ?
 				        "CASE SENSITIVE" : "CASE INSENSITIVE"));
 
-    move(L_CHARSET,5);
+    move(L_CHARSET, 5);
     printw("display (C)haracter set      : %s", 
     					LYchar_set_names[current_char_set]);
     
-    move(L_RAWMODE,5);
+    move(L_RAWMODE, 5);
     printw("Raw 8-bit or CJK m(O)de      : %s", (LYRawMode ? "ON" : "OFF"));
 
-    move(L_LANGUAGE,5);
+    move(L_LANGUAGE, 5);
     printw("preferred document lan(G)uage: %s",
     		((language && *language) ? language : "NONE"));
 
-    move(L_PREF_CHARSET,5);
+    move(L_PREF_CHARSET, 5);
     printw("preferred document c(H)arset : %s",
     		((pref_charset && *pref_charset) ? pref_charset : "NONE"));
 
-    move(L_VIKEYS,5); 
-    printw("V)I keys                     : %s", (vi_keys ? "ON" : "OFF"));
+    move(L_BOOL_A, B_VIKEYS);
+    printw("V)I keys: %s", (vi_keys ? "ON" : "OFF"));
     
-    move(L_EMACSKEYS,5); 
-    printw("e(M)acs keys                 : %s", (emacs_keys ? "ON" : "OFF"));
+    move(L_BOOL_A, B_EMACSKEYS);
+    printw("e(M)acs keys: %s", (emacs_keys ? "ON" : "OFF"));
     
-    move(L_KEYPAD,5); 
+    move(L_BOOL_A, B_SHOW_DOTFILES);
+    printw("sho(W) dot files: %s",
+    			((!no_dotfiles && show_dotfiles) ? "ON" : "OFF"));
+
+    move(L_SELECT_POPUPS, 5);
+    printw("popups for selec(T) fields   : %s",
+    			(LYSelectPopups ? "ON" : "OFF"));
+
+    move(L_KEYPAD, 5); 
     printw("K)eypad mode                 : %s", 
 			   		  (keypad_mode == NUMBERS_AS_ARROWS ? 
 					   "Numbers act as arrows" : 
 				           "Links are numbered"));
 
-    move(L_LINEED,5);
+    move(L_LINEED, 5);
     printw("li(N)e edit style            : %s",
     					   LYLineeditNames[current_lineedit]);
 
 #ifdef DIRED_SUPPORT
-    move(L_DIRED,5);
+    move(L_DIRED, 5);
     printw("l(I)st directory style       : %s",
                      (dir_list_style == FILES_FIRST ? "Files first          " :
 		     (dir_list_style == MIXED_STYLE ? "Mixed style          " : 
                                                       "Directories first    ")));
 #endif /* DIRED_SUPPORT */
 
-    move(L_SHOW_DOTFILES,5);
-    printw("sho(W) dot files             : %s",
-    			((!no_dotfiles && show_dotfiles) ? "ON" : "OFF"));
-
-    move(L_USER_MODE,5);
+    move(L_USER_MODE, 5);
     printw("U)ser mode                   : %s",
 			(user_mode == NOVICE_MODE ? "Novice" : 
 			(user_mode == INTERMEDIATE_MODE ? "Intermediate" :
 							     "Advanced")));
 
-    move(L_USER_AGENT,5);
+    move(L_USER_AGENT, 5);
     printw("user (A)gent                 : %s",
     		((LYUserAgent && *LYUserAgent) ? LYUserAgent : "NONE"));
 
+
 #ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS
-    move(L_EXEC,5);
-    printw("L)ocal execution links       : ");
+    move(L_EXEC, 5);
+    printw("local e(X)ecution links      : ");
 #ifndef NEVER_ALLOW_REMOTE_EXEC
     addstr((local_exec ? "ALWAYS ON" :
                     (local_exec_on_local_files ? "FOR LOCAL FILES ONLY" :
@@ -230,9 +246,10 @@ PUBLIC void options NOARGS
     addstr("'");
     addstr(TO_RETURN_SEGMENT);
 
-    while(TOUPPER(response) != 'R' && response != LTARROW &&
-          response != '>' && !term_options && response != 7 &&
-	  				      response != 3) {
+    while (TOUPPER(response) != 'R' &&
+    	   !LYisNonAlnumKeyname(response, LYK_PREV_DOC) &&
+           response != '>' && !term_options &&
+	   response != 7 &&  response != 3) {
 
            move(LYlines-2, 0);
 	   start_reverse();
@@ -243,7 +260,11 @@ PUBLIC void options NOARGS
            response = LYgetch();
 	   if (term_options || response == 7 || response == 3)
 	       response = 'R';
-	   switch(response) {
+	   if (LYisNonAlnumKeyname(response, LYK_REFRESH)) {
+	       clearok(curscr, TRUE);
+	       goto draw_options;
+	   }
+	   switch (response) {
 	 	case 'e':  /* change the editor */
 		case 'E':
 	                if (no_editor) {
@@ -275,8 +296,10 @@ PUBLIC void options NOARGS
 			        StrAllocCopy(editor, display_option);
 				addstr(display_option);
 			    }
+			    clrtoeol();
 			    option_statusline(VALUE_ACCEPTED);
 			}
+			response = ' ';
 			break;
 
 		case 'd':  /* change the display */
@@ -298,16 +321,19 @@ PUBLIC void options NOARGS
 			if ((term_options || ch == -1) ||
 			    (display != NULL &&
 #ifdef VMS
-			     0 == strcasecomp(display, display_option))) {
+			     0 == strcasecomp(display, display_option)))
 #else
-			     0 == strcmp(display, display_option))) {
+			     0 == strcmp(display, display_option)))
 #endif /* VMS */
+			{
 			    /*
 			     *  Cancelled, or a non-NULL display string
 			     *  wasn't changed. - FM
 			     */
 			    addstr((display && *display) ? display : "NONE");
+			    clrtoeol();
 			    option_statusline(VALUE_ACCEPTED);
+			    response = ' ';
 			    break;
 			} else if (*display_option == '\0') {
 			    if ((display == NULL) ||
@@ -317,7 +343,9 @@ PUBLIC void options NOARGS
 				 *  wasn't changed. - FM
 				 */
 			        addstr("NONE");
+				clrtoeol();
 				option_statusline(VALUE_ACCEPTED);
+				response = ' ';
 				break;
 			    }
 			}
@@ -340,6 +368,7 @@ PUBLIC void options NOARGS
 			    display = NULL;
 			}
 			addstr(display ? display : "NONE");
+			clrtoeol();
 			if ((display == NULL && *display_option == '\0') ||
 			    (display != NULL &&
 			     0 == strcmp(display, display_option))) {
@@ -359,6 +388,46 @@ PUBLIC void options NOARGS
 			        option_statusline(FAILED_CLEAR_SET_DISPLAY);
 			    }
 			}
+			response = ' ';
+			break;
+
+		case 'l':
+		case 'L':
+			if (LYMBMBlocked) {
+			    option_statusline(MULTIBOOKMARKS_DISALLOWED);
+			    response = ' ';
+			    break;
+			}
+			choices[0] = NULL;
+			StrAllocCopy(choices[0],"OFF     ");
+			choices[1] = NULL;
+			StrAllocCopy(choices[1],"STANDARD");
+			choices[2] = NULL;
+			StrAllocCopy(choices[2],"ADVANCED");
+			choices[3] = NULL;
+			LYMultiBookmarks = boolean_choice(LYMultiBookmarks *
+                                                          (1 + LYMBMAdvanced),
+                                                          L_HOME, C_MULTI,
+                                                          choices);
+			FREE(choices[0]);
+			FREE(choices[1]);
+			FREE(choices[2]);
+                        if (LYMultiBookmarks == 2) {
+                            LYMultiBookmarks = TRUE;
+                            LYMBMAdvanced = TRUE;
+                        } else {
+                            LYMBMAdvanced = FALSE;
+                        }
+			
+			move(L_HOME, B_BOOK);
+			clrtoeol();
+    			if (LYMultiBookmarks) {
+    			    printw("review/edit B)ookmarks files");
+    			} else {
+			    printw("B)ookmark file: %s",
+    		((bookmark_page && *bookmark_page) ? bookmark_page : "NONE"));
+    			}
+			response = ' ';
 			break;
 
 		case 'b':  /* change the bookmark page location */
@@ -367,34 +436,41 @@ PUBLIC void options NOARGS
 			 * change the bookmark page
 			 */
 			if (!no_bookmark) {
+			    if (LYMultiBookmarks) {
+				edit_bookmarks();
+				signal(SIGINT, terminate_options);
+				goto draw_options;
+			    }
 			    if (bookmark_page && *bookmark_page)
 			        strcpy(display_option, bookmark_page);
 			    else {  /* clear the NONE */
-				move(L_HOME, COL_OPTION_VALUES);
-				addstr("    ");
+				move(L_HOME, C_DEFAULT);
+				clrtoeol();
 			        *display_option = '\0';
 			    }
 			    option_statusline(ACCEPT_DATA);
-			    move(L_HOME, COL_OPTION_VALUES);  
+			    move(L_HOME, C_DEFAULT);  
 			    standout();
 			    ch = LYgetstr(display_option, VISIBLE,
 			    		  sizeof(display_option), NORECALL);
 			    standend();
-			    move(L_HOME, COL_OPTION_VALUES);
-			    if (term_options || ch == -1) {
+			    move(L_HOME, C_DEFAULT);
+			    if (term_options ||
+			        ch == -1 || *display_option == '\0') {
 			        addstr((bookmark_page && *bookmark_page) ?
 						    bookmark_page : "NONE");
-			    } else if (*display_option == '\0') {
-				FREE(bookmark_page);
-				addstr("NONE");
 			    } else {
 			        StrAllocCopy(bookmark_page, display_option);
+				StrAllocCopy(MBM_A_subbookmark[0],
+					     bookmark_page);
 				addstr(display_option);
 			    }
+			    clrtoeol();
 			    option_statusline(VALUE_ACCEPTED);
 			} else { /* anonymous */
 			    option_statusline(BOOKMARK_CHANGE_DISALLOWED);
 			}
+			response = ' ';
 			break;
 
 		case 'f':
@@ -410,10 +486,11 @@ PUBLIC void options NOARGS
                         StrAllocCopy(choices[3],"By Date    ");
                         choices[4] = NULL;
                         HTfileSortMethod = boolean_choice(HTfileSortMethod,
-                                               L_FTPSTYPE, choices);
+                                               L_FTPSTYPE, -1, choices);
                         FREE(choices[0]);
                         FREE(choices[1]);
                         FREE(choices[2]);
+			response = ' ';
                         break;
 
 		case 'p':  /* change personal mail address for From headers */
@@ -443,27 +520,30 @@ PUBLIC void options NOARGS
 			    StrAllocCopy(personal_mail_address, display_option);
 			    addstr(display_option);
 			}
+			clrtoeol();
 			option_statusline(VALUE_ACCEPTED);
+			response = ' ';
 			break;
 
 		case 's':
 		case 'S':
-			 /* copy strings into choice array */
-			 choices[0] = NULL;
-			 StrAllocCopy(choices[0],"CASE INSENSITIVE");
-			 choices[1] = NULL;
-			 StrAllocCopy(choices[1],"CASE SENSITIVE  ");
-			 choices[2] = NULL;
-			 case_sensitive = boolean_choice(case_sensitive,
-						L_SSEARCH, choices);
-			 FREE(choices[0]);
-			 FREE(choices[1]);
+			/* copy strings into choice array */
+			choices[0] = NULL;
+			StrAllocCopy(choices[0],"CASE INSENSITIVE");
+			choices[1] = NULL;
+			StrAllocCopy(choices[1],"CASE SENSITIVE  ");
+			choices[2] = NULL;
+			case_sensitive = boolean_choice(case_sensitive,
+						L_SSEARCH, -1, choices);
+			FREE(choices[0]);
+			FREE(choices[1]);
+			response = ' ';
 			break;
 
 		case 'c':
 		case 'C':
 			current_char_set = boolean_choice(current_char_set,
-			    		L_CHARSET, LYchar_set_names);
+			    		L_CHARSET, -1, LYchar_set_names);
 			/*
 			 *  Set the raw 8-bit or CJK mode defaults and
 			 *  character set if changed. - FM
@@ -478,6 +558,7 @@ PUBLIC void options NOARGS
 			    clrtoeol();
 			    addstr(LYRawMode ? "ON " : "OFF");
 			}
+			response = ' ';
 			break;
 
 		case 'o':
@@ -489,7 +570,7 @@ PUBLIC void options NOARGS
 			StrAllocCopy(choices[1], "ON ");
 			choices[2] = NULL;
 			LYRawMode = boolean_choice(LYRawMode,
-						   L_RAWMODE, choices);
+						   L_RAWMODE, -1, choices);
 			/*
 			 *  Set the LYUseDefaultRawMode value and character
 			 *  handling if LYRawMode was changed. - FM
@@ -502,6 +583,7 @@ PUBLIC void options NOARGS
 			}
 			FREE(choices[0]);
 			FREE(choices[1]);
+			response = ' ';
 			break;
 
 		case 'g':  /* change language preference */
@@ -530,7 +612,9 @@ PUBLIC void options NOARGS
 			    StrAllocCopy(language, display_option);
 			    addstr(display_option);
 			}
+			clrtoeol();
 			option_statusline(VALUE_ACCEPTED);
+			response = ' ';
 			break;
 
 		case 'h':  /* change character set preference */
@@ -559,7 +643,9 @@ PUBLIC void options NOARGS
 			    StrAllocCopy(pref_charset, display_option);
 			    addstr(display_option);
 			}
+			clrtoeol();
 			option_statusline(VALUE_ACCEPTED);
+			response = ' ';
 			break;
 
 		case 'v':
@@ -570,13 +656,16 @@ PUBLIC void options NOARGS
 			choices[1] = NULL;
 			StrAllocCopy(choices[1],"ON ");
 			choices[2] = NULL;
-			vi_keys = boolean_choice(vi_keys, L_VIKEYS, choices);
+			vi_keys = boolean_choice(vi_keys,
+						 L_BOOL_A, C_VIKEYS,
+						 choices);
 			if (vi_keys)
                             set_vi_keys();
                         else
                             reset_vi_keys();
 			FREE(choices[0]);
 			FREE(choices[1]);
+			response = ' ';
 			break;
 
 		case 'M':
@@ -587,14 +676,53 @@ PUBLIC void options NOARGS
 			choices[1] = NULL;
 			StrAllocCopy(choices[1],"ON ");
 			choices[2] = NULL;
-			emacs_keys = boolean_choice(emacs_keys, L_EMACSKEYS, 
-								      choices);
+			emacs_keys = boolean_choice(emacs_keys,
+						    L_BOOL_A, C_EMACSKEYS,
+						    choices);
                         if (emacs_keys)
                             set_emacs_keys();
                         else
                             reset_emacs_keys();
 			FREE(choices[0]);
 			FREE(choices[1]);
+			response = ' ';
+			break;
+
+		case 'W':
+		case 'w':
+			   if (no_dotfiles) {
+			       option_statusline(DOTFILE_ACCESS_DISABLED);
+			   } else {
+			       /* copy strings into choice array */
+			       choices[0] = NULL;
+			       StrAllocCopy(choices[0],"OFF");
+			       choices[1] = NULL;
+			       StrAllocCopy(choices[1],"ON ");
+			       choices[2] = NULL;
+			       show_dotfiles = boolean_choice(show_dotfiles,
+							      L_BOOL_A,
+							      C_SHOW_DOTFILES, 
+							      choices);
+			       FREE(choices[0]);
+			       FREE(choices[1]);
+			   }
+			   response = ' ';
+			   break;
+
+		case 't':
+		case 'T':
+			/* copy strings into choice array */
+			choices[0] = NULL;
+			StrAllocCopy(choices[0], "OFF");
+			choices[1] = NULL;
+			StrAllocCopy(choices[1], "ON ");
+			choices[2] = NULL;
+			LYSelectPopups = boolean_choice(LYSelectPopups,
+							L_SELECT_POPUPS, -1,
+							choices);
+			FREE(choices[0]);
+			FREE(choices[1]);
+			response = ' ';
 			break;
 
 		case 'k':
@@ -606,19 +734,21 @@ PUBLIC void options NOARGS
 			StrAllocCopy(choices[1],"Links are numbered   ");
 			choices[2] = NULL;
 			keypad_mode = boolean_choice(keypad_mode,
-			       			     L_KEYPAD, choices);
+			       			     L_KEYPAD, -1, choices);
                         if (keypad_mode == NUMBERS_AS_ARROWS)
                             set_numbers_as_arrows();
                         else
                             reset_numbers_as_arrows();
 			FREE(choices[0]);
 			FREE(choices[1]);
+			response = ' ';
 			break;
 
 		case 'n':
 		case 'N':
 			current_lineedit = boolean_choice(current_lineedit,
-			    		L_LINEED, LYLineeditNames);
+			    		L_LINEED, -1, LYLineeditNames);
+			response = ' ';
 			break;
 
 #ifdef DIRED_SUPPORT
@@ -633,32 +763,14 @@ PUBLIC void options NOARGS
 			StrAllocCopy(choices[2],"Mixed style      ");
 			choices[3] = NULL;
 			dir_list_style = boolean_choice(dir_list_style,
-							L_DIRED, choices);
+							L_DIRED, -1, choices);
 			FREE(choices[0]);
 			FREE(choices[1]);
 			FREE(choices[2]);
+			response = ' ';
 			break;
 #endif /* DIRED_SUPPORT */
 
-		case 'W':
-		case 'w':
-			   if (no_dotfiles) {
-			       option_statusline(DOTFILE_ACCESS_DISABLED);
-			   } else {
-			       /* copy strings into choice array */
-			       choices[0] = NULL;
-			       StrAllocCopy(choices[0],"OFF");
-			       choices[1] = NULL;
-			       StrAllocCopy(choices[1],"ON ");
-			       choices[2] = NULL;
-			       show_dotfiles = boolean_choice(show_dotfiles,
-							      L_SHOW_DOTFILES,
-							      choices);
-			       FREE(choices[0]);
-			       FREE(choices[1]);
-			   }
-			   break;
-
 		case 'u':
 		case 'U':
 			/* copy strings into choice array */
@@ -670,7 +782,7 @@ PUBLIC void options NOARGS
 			StrAllocCopy(choices[2],"Advanced    ");
 			choices[3] = NULL;
 			user_mode = boolean_choice(user_mode,
-							L_USER_MODE, choices);
+						   L_USER_MODE, -1, choices);
 			FREE(choices[0]);
 			FREE(choices[1]);
 			FREE(choices[2]);
@@ -678,6 +790,7 @@ PUBLIC void options NOARGS
 			   display_lines = LYlines-4;
 			else
 			   display_lines = LYlines-2;
+			response = ' ';
 			break;
 
 		case 'a':
@@ -710,6 +823,7 @@ PUBLIC void options NOARGS
 			        StrAllocCopy(LYUserAgent, display_option);
 				addstr(display_option);
 			    }
+			    clrtoeol();
 			    if (LYUserAgent && *LYUserAgent &&
 			    	!strstr(LYUserAgent, "Lynx") &&
 				!strstr(LYUserAgent, "lynx")) {
@@ -720,23 +834,24 @@ PUBLIC void options NOARGS
 			} else { /* disallowed */
 			    option_statusline(UA_COPYRIGHT_WARNING);
 			}
+			response = ' ';
 			break;
 
 #ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS
-		case 'l':  /* local exec */
-		case 'L':
-			if(!exec_frozen) {
+		case 'x':  /* local exec */
+		case 'X':
+			if (!exec_frozen) {
 #ifndef NEVER_ALLOW_REMOTE_EXEC
-			   if(local_exec) {
-				itmp=2;
-			   } else {
+			    if (local_exec) {
+				itmp = 2;
+			    } else {
 #else
 			  {
 #endif /* NEVER_ALLOW_REMOTE_EXEC */
-			  	if(local_exec_on_local_files)
-				    	itmp=1;
+			  	if (local_exec_on_local_files)
+				    itmp= 1;
 				else
-					itmp=0;
+				    itmp = 0;
 			   }
 			   /* copy strings into choice array */
 			   choices[0] = NULL;
@@ -748,7 +863,7 @@ PUBLIC void options NOARGS
 			   StrAllocCopy(choices[2],"ALWAYS ON           ");
 			   choices[3] = NULL;
 #endif /* NEVER_ALLOW_REMOTE_EXEC */
-			   itmp = boolean_choice(itmp, L_EXEC, choices);
+			   itmp = boolean_choice(itmp, L_EXEC, -1, choices);
   
 			   FREE(choices[0]);
 			   FREE(choices[1]);
@@ -757,23 +872,27 @@ PUBLIC void options NOARGS
 #endif /* NEVER_ALLOW_REMOTE_EXEC */
 			   switch(itmp) {
 			      case 0:
-				  local_exec=FALSE;
-				  local_exec_on_local_files=FALSE;
+				  local_exec = FALSE;
+				  local_exec_on_local_files = FALSE;
+				  response = ' ';
 				  break;
 			      case 1:
-				  local_exec=FALSE;
-				  local_exec_on_local_files=TRUE;
+				  local_exec = FALSE;
+				  local_exec_on_local_files = TRUE;
+				  response = ' ';
 				  break;
 #ifndef NEVER_ALLOW_REMOTE_EXEC
 			      case 2:
-				  local_exec=TRUE;
-				  local_exec_on_local_files=FALSE;
+				  local_exec = TRUE;
+				  local_exec_on_local_files = FALSE;
+				  response = ' ';
 				  break;
 #endif /* NEVER_ALLOW_REMOTE_EXEC */
 			  } /* end switch */
 			} else {
 			   option_statusline(CHANGE_OF_SETTING_DISALLOWED);
 			}
+			response = ' ';
 			break;
 #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */
 
@@ -805,72 +924,329 @@ PUBLIC void options NOARGS
 			    option_statusline(R_TO_RETURN_TO_LYNX);
 			}
 	    }  /* end switch */
-     }  /* end while */
+    }  /* end while */
 
-     term_options = FALSE;
-     signal(SIGINT, cleanup_sig);
+    term_options = FALSE;
+    signal(SIGINT, cleanup_sig);
 }
 
-
 /* take a boolean status and prompt the user for a new status
  * and return it
  */
 
-PUBLIC int boolean_choice ARGS3(int,status, int,line, char **,choices)
+PRIVATE int boolean_choice ARGS4(
+	int,		status,
+	int,		line,
+	int,		column,
+	char **,	choices)
 {
-	int response=0;
-	int number=0;
+    int response = 0;
+    int number = 0;
+    int col = (column >= 0 ? column : COL_OPTION_VALUES);
 	
-	for (; choices[number] != NULL; number++)
-	    ;  /* empty loop body */
+    for (; choices[number] != NULL; number++)
+	;  /* empty loop body */
 
-	number--;
-
-	option_statusline(ACCEPT_DATA);
-	/* highlight the current selection */
-	move(line, COL_OPTION_VALUES);
-	standout();
-	addstr(choices[status]);
+    number--;
 
-	standend();
-	option_statusline(ANY_KEY_CHANGE_RET_ACCEPT);
-	standout();
+    option_statusline(ACCEPT_DATA);
+    /*
+     *  Highlight the current selection.
+     */
+    move(line, col);
+    standout();
+    addstr(choices[status]);
 
-	while(1) {
-	   move(line, COL_OPTION_VALUES);
-	   response = LYgetch();
-	   if (term_options || response == 7 || response == 3)
-		response = '\n';
-	   if(response != '\n' && response != '\r') {
-		if(status == number)
-		    status = 0;  /* go over the top and around */
-		else
-		    status++;
-		addstr(choices[status]);
-	        refresh();
-	    } else {
-		/* unhighlight selection */
-	        move(line, COL_OPTION_VALUES);
-	        standend();
-	        addstr(choices[status]);
+    standend();
+    option_statusline(ANY_KEY_CHANGE_RET_ACCEPT);
+    standout();
 
-		option_statusline(VALUE_ACCEPTED);
-	 	return(status);
-	    }
+    while (1) {
+	move(line, col);
+	response = LYgetch();
+	if (term_options || response == 7 || response == 3)
+	    response = '\n';
+	if (response != '\n' && response != '\r') {
+	    if (status == number)
+		status = 0;  /* go over the top and around */
+	    else
+		status++;
+	    addstr(choices[status]);
+	    refresh();
+	} else {
+	    /*
+	     *  Unhighlight selection.
+	     */
+	    move(line, col);
+	    standend();
+	    addstr(choices[status]);
+
+	    option_statusline(VALUE_ACCEPTED);
+	     return(status);
 	}
+    }
 }
 
-
 PRIVATE void terminate_options ARGS1(int,sig)
 {
-	term_options=TRUE;
-	/* Reassert the AST */
-	signal(SIGINT, terminate_options);
+    term_options=TRUE;
+    /* Reassert the AST */
+    signal(SIGINT, terminate_options);
 #ifdef VMS
-        /* refresh the screen to get rid of the "interrupt" message */
-	if (!dump_output_immediately) {
+    /* refresh the screen to get rid of the "interrupt" message */
+    if (!dump_output_immediately) {
+	clearok(curscr, TRUE);
+	refresh();
+    }
+#endif /* VMS */
+}
+
+/*
+ *  Multi-Bookmark On-Line editing support. - FMG & FM
+ */
+PUBLIC void edit_bookmarks NOARGS
+{
+    int response = 0, def_response = 0, ch;
+    int MBM_current = 1;
+#define	MULTI_OFFSET 8
+    int a; /* misc counter */
+    char MBM_tmp_line[256]; /* buffer for LYgetstr */
+    
+    /*
+     *  We need (MBM_V_MAXFILES + MULTI_OFFSET) lines to display
+     *  the whole list at once.  Otherwise break it up into two
+     *  segments.  We know it won't be less than that because
+     *  'o'ptions needs 23-24 at LEAST.
+     */
+    term_options = FALSE;
+    signal(SIGINT, terminate_options);
+
+draw_bookmark_list:
+    clear(); 
+    move(0, 5);
+    if (bold_H1 || bold_headers)
+        start_bold();
+    if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET))
+	printw("Editing Bookmark DESCRIPTION and FILEPATH (%d of 2)",
+		MBM_current);
+    else
+        printw("         Editing Bookmark DESCRIPTION and FILEPATH");
+    if (bold_H1 || bold_headers)
+        stop_bold();
+
+    if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) {
+	for (a = ((MBM_V_MAXFILES/2 + 1) * (MBM_current - 1));
+                      a <= ((float)MBM_V_MAXFILES/2 * MBM_current); a++) {
+	    move((3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)), 5);
+	    printw("%c : %s", (a + 'A'),
+		   (!MBM_A_subdescript[a] ? "" : MBM_A_subdescript[a]));
+	    move((3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)), 35);
+	    printw("| %s",
+		   (!MBM_A_subbookmark[a] ? "" : MBM_A_subbookmark[a]));
+        }
+    } else {
+	for (a = 0; a <= MBM_V_MAXFILES; a++) {
+	    move(3 + a, 5);
+	    printw("%c : %s", (a + 'A'),
+		   (!MBM_A_subdescript[a] ? "" : MBM_A_subdescript[a]));
+	    move(3 + a, 35);
+	    printw("| %s",
+		   (!MBM_A_subbookmark[a] ? "" : MBM_A_subbookmark[a]));
+	}
+    }
+
+    /*
+     *  Only needed when we have 2 screens.
+     */
+    if (LYlines < MBM_V_MAXFILES + MULTI_OFFSET) {
+       move((LYlines - 4), 0);
+       start_reverse();
+       addstr(MULTIBOOKMARKS_MOVE);
+       stop_reverse();
+    }
+
+    move((LYlines - 3), 0);
+    if (!no_option_save) {
+        addstr("'");
+	standout();
+	addstr(">");
+	standend();
+	addstr("'");
+	addstr(TO_SAVE_SEGMENT);
+    }
+    addstr(OR_SEGMENT);
+    addstr("'");
+    standout();
+    addstr("^G");
+    standend();
+    addstr("'");
+    addstr(TO_RETURN_SEGMENT);
+
+    while (!term_options &&
+           !LYisNonAlnumKeyname(response, LYK_PREV_DOC) &&
+	   response != 7 && response != 3 &&
+	   response != '>') {
+
+	move((LYlines - 2), 0);
+	start_reverse();
+	addstr("Letter: ");
+	stop_reverse();
+
+	refresh();
+        response = (def_response ? def_response : LYgetch());
+	def_response = 0;
+
+	/*
+	 *  Check for a cancel.
+	 */
+	if (term_options ||
+	    response == 7 || response == 3 ||
+	    LYisNonAlnumKeyname(response, LYK_PREV_DOC))
+	    continue;
+
+	/*
+	 *  Check for a save.
+	 */
+	if (response == '>') {
+	    if (!no_option_save) {
+		option_statusline(SAVING_OPTIONS);
+		if (save_rc())
+		    option_statusline(OPTIONS_SAVED);
+		else 
+		    HTAlert(OPTIONS_NOT_SAVED);
+	    } else {
+		option_statusline(R_TO_RETURN_TO_LYNX);
+		/*
+		 *  Change response so that we don't exit
+		 *  the options menu.
+		 */
+		response = ' ';
+	    }
+	    continue;
+	}
+
+	/*
+	 *  Check for a refresh.
+	 */
+	if (LYisNonAlnumKeyname(response, LYK_REFRESH)) {
 	    clearok(curscr, TRUE);
-	    refresh();
+	    continue;
 	}
-#endif /* VMS */
+
+	/*
+	 *  Move between the screens - if we can't show it all at once.
+	 */
+	if ((response == ']' ||
+	     LYisNonAlnumKeyname(response, LYK_NEXT_PAGE)) &&
+	    LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) {
+	    MBM_current++;
+	    if (MBM_current >= 3)
+		MBM_current = 1;
+	    goto draw_bookmark_list;
+	}
+	if ((response == '[' ||
+	     LYisNonAlnumKeyname(response, LYK_PREV_PAGE)) &&
+	    LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) {
+	    MBM_current--;
+	    if (MBM_current <= 0)
+		MBM_current = 2;
+	    goto draw_bookmark_list;
+	}
+
+	/*
+	 *  Instead of using 26 case statements, we set up
+         *  a scan through the letters and edit the lines
+         *  that way.
+         */
+	for (a = 0; a <= MBM_V_MAXFILES; a++) {
+	    if ((TOUPPER(response) - 'A') == a) {
+		if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) {
+		    if (MBM_current == 1 && a > (MBM_V_MAXFILES/2)) {
+		        MBM_current = 2;
+		        def_response = response;
+			goto draw_bookmark_list;
+		    }
+		    if (MBM_current == 2 && a < (MBM_V_MAXFILES/2)) {
+		        MBM_current = 1;
+		        def_response = response;
+			goto draw_bookmark_list;
+		    }
+		}
+		option_statusline(ACCEPT_DATA);
+
+		if (a > 0) {
+		    standout();
+		    if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET))
+    		        move(
+			 (3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)),
+			     9);
+		    else
+    		        move((3 + a), 9);
+		    strcpy(MBM_tmp_line,
+    		           (!MBM_A_subdescript[a] ?
+			   		       "" : MBM_A_subdescript[a]));
+		    ch = LYgetstr(MBM_tmp_line, VISIBLE,
+	    		          sizeof(MBM_tmp_line), NORECALL);
+		    standend();
+
+		    if (strlen(MBM_tmp_line) < 1) {
+		        FREE(MBM_A_subdescript[a]);
+		    } else {
+		        StrAllocCopy(MBM_A_subdescript[a], MBM_tmp_line);
+		    }
+		    if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET))
+    			move(
+			 (3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)),
+			     5);
+		    else
+    			move((3 + a), 5);
+    		    printw("%c : %s", (a + 'A'),
+    			   (!MBM_A_subdescript[a] ?
+			       		"" : MBM_A_subdescript[a]));
+		    clrtoeol();
+	   	    refresh();
+		}
+
+		if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET))
+    		    move((3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)),
+		    	 35);
+		else
+    		    move((3 + a), 35);
+    		printw("| ");
+
+		standout();
+		strcpy(MBM_tmp_line,
+    		       (!MBM_A_subbookmark[a] ? "" : MBM_A_subbookmark[a]));
+		ch = LYgetstr(MBM_tmp_line, VISIBLE,
+	    		      sizeof(MBM_tmp_line), NORECALL);
+		standend();
+
+		if (*MBM_tmp_line == '\0') {
+		    if (a == 0)
+		        StrAllocCopy(MBM_A_subbookmark[a], bookmark_page);
+		    else
+		        FREE(MBM_A_subbookmark[a]);
+		} else {
+		    StrAllocCopy(MBM_A_subbookmark[a], MBM_tmp_line);
+		    if (a == 0) {
+		        StrAllocCopy(bookmark_page, MBM_A_subbookmark[a]);
+		    }
+		}
+		if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET))
+    		    move((3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current-1)),
+		    	 35);
+		else
+    		    move((3 + a), 35);
+    		printw("| %s", (!MBM_A_subbookmark[a] ?
+						   "" : MBM_A_subbookmark[a]));
+	   	clrtoeol();
+		move(LYlines-1, 0);
+		clrtoeol();
+		break;
+	    }
+	}  /* end for */
+    } /* end while */
+
+    term_options = FALSE;
+    signal(SIGINT, cleanup_sig);
 }
diff --git a/src/LYOptions.h b/src/LYOptions.h
index f154ebec..f89159aa 100644
--- a/src/LYOptions.h
+++ b/src/LYOptions.h
@@ -7,7 +7,12 @@ extern void options NOPARAMS;
 /* values for options */
 #define L_EDITOR	 2
 #define L_DISPLAY	 3
+
 #define L_HOME		 4
+#define C_MULTI		24
+#define B_BOOK		34
+#define C_DEFAULT	50
+
 #define L_FTPSTYPE	 5
 #define L_MAIL_ADDRESS	 6
 #define L_SSEARCH	 7
@@ -15,22 +20,28 @@ extern void options NOPARAMS;
 #define L_RAWMODE	 9
 #define L_LANGUAGE	10
 #define L_PREF_CHARSET	11
-#define L_VIKEYS	12
-#define L_EMACSKEYS	13
+
+#define L_BOOL_A	12
+#define B_VIKEYS	5
+#define C_VIKEYS	15
+#define B_EMACSKEYS	22
+#define C_EMACSKEYS	36
+#define B_SHOW_DOTFILES	44
+#define C_SHOW_DOTFILES	62
+
+#define L_SELECT_POPUPS 13
 #define L_KEYPAD	14 
 #define L_LINEED	15
 
 #ifdef DIRED_SUPPORT
 #define L_DIRED		16
-#define L_SHOW_DOTFILES	17
-#define L_USER_MODE	18
-#define L_USER_AGENT	19
-#define L_EXEC		20
-#else
-#define L_SHOW_DOTFILES	16
 #define L_USER_MODE	17
 #define L_USER_AGENT	18
 #define L_EXEC		19
+#else
+#define L_USER_MODE	16
+#define L_USER_AGENT	17
+#define L_EXEC		18
 #endif /* DIRED_SUPPORT */
 
 #endif /* LYOPTIONS_H */
diff --git a/src/LYPrint.c b/src/LYPrint.c
index 34c17363..8e14c938 100644
--- a/src/LYPrint.c
+++ b/src/LYPrint.c
@@ -83,19 +83,30 @@ PUBLIC int printfile ARGS1(document *,newdoc)
     WWWDoc.address = newdoc->address;
     WWWDoc.post_data = newdoc->post_data;
     WWWDoc.post_content_type = newdoc->post_content_type;
+    WWWDoc.bookmark = newdoc->bookmark;
     WWWDoc.isHEAD = newdoc->isHEAD;
     if(!HTLoadAbsolute(&WWWDoc))
         return(NOT_FOUND);
   
-    StrAllocCopy(sug_filename, newdoc->address); /* must be freed */
+    /*
+     *  Load the suggested filename string. - FM
+     */
+    if (HText_getSugFname() != NULL)
+        StrAllocCopy(sug_filename, HText_getSugFname()); /* must be freed */
+    else
+        StrAllocCopy(sug_filename, newdoc->address); /* must be freed */
 
     /*
      *  Get the number of lines in the file.
      */
     if ((cp = (char *)strstr(link_info, "lines=")) != NULL) {
-	/* terminate prev string here */
+	/*
+	 *  Terminate prev string here.
+	 */
 	*cp = '\0';
-        /* number of characters in "lines=" */
+        /*
+	 *  Number of characters in "lines=".
+	 */
 	cp += 6;
 
         lines_in_file = atoi(cp);
@@ -145,7 +156,7 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 	retry:	strcpy(filename, sug_filename);  /* add suggestion info */
 		/* make the sug_filename conform to system specs */
 		change_sug_filename(filename);
-		if ((len = strlen(filename)) > 4) {
+		if (!(HTisDocumentSource()) && (len = strlen(filename)) > 4) {
 		    len -= 5;
 		    if (!strcasecomp((filename + len), ".html")) {
 		        filename[len] = '\0';
@@ -330,6 +341,18 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		    goto retry;
                 }
 
+		if (HTisDocumentSource()) {
+		    /*
+		     *  Added the document's URL as a BASE tag
+		     *  to the top of the file.  May create
+		     *  technically invalid HTML, but will help
+		     *  get any partial or relative URLs resolved
+		     *  properly if no BASE tag is present to
+		     *  replace it. - FM
+		     */
+		    fprintf(outfile_fp, "<BASE HREF=\"%s\">\n",
+		    			newdoc->address);
+		}
 		print_wwwfile_to_fd(outfile_fp,0);
 		if (keypad_mode)
 		    printlist(outfile_fp,FALSE);
@@ -376,13 +399,41 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		} else {
 		    remove(tempfile);   /* remove duplicates */
 		}
+		if (HTisDocumentSource()) {
+		    if ((len = strlen(tempfile)) > 3) {
+		        len -= 4;
+			if (!strcasecomp((filename + len), ".txt")) {
+			    filename[len] = '\0';
+			    strcat(filename, ".html");
+			}
+		    }
+		} else if ((len = strlen(tempfile)) > 4) {
+		    len -= 5;
+		    if (!strcasecomp((filename + len), ".html")) {
+		        filename[len] = '\0';
+			strcat(filename, ".txt");
+		    }
+		}
 		if((outfile_fp = fopen(tempfile, "w")) == NULL) {
 		    HTAlert(UNABLE_TO_OPEN_TEMPFILE);
 		    break;
 		}
 
 		/* write the contents to a temp file */
-		fprintf(outfile_fp, "X-URL: %s\n", newdoc->address);
+		if (HTisDocumentSource()) {
+		    /*
+		     *  Added the document's URL as a BASE tag to
+		     *  the top of the message body.  May create
+		     *  technically invalid HTML, but will help
+		     *  get any partial or relative URLs resolved
+		     *  properly if no BASE tag is present to
+		     *  replace it. - FM
+		     */
+		    fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n",
+		    			newdoc->address);
+		} else {
+		    fprintf(outfile_fp, "X-URL: %s\n\n", newdoc->address);
+		}
 		print_wwwfile_to_fd(outfile_fp, 0);
 		if (keypad_mode)
 		    printlist(outfile_fp, FALSE);
@@ -410,9 +461,45 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 			break;
 		}
 		
-		fprintf(outfile_fp, "X-URL: %s\n", newdoc->address);
+		if (HTisDocumentSource()) {
+		    /*
+		     *  Add Content-Type, Content-Location, and
+		     *  Content-Base headers for HTML source. - FM
+		     *  Also add Mime-Version header. - HM
+		     */
+		    fprintf(outfile_fp, "Mime-Version: 1.0\n");
+		    fprintf(outfile_fp, "Content-Type: text/html");
+		    if (HTLoadedDocumentCharset() != NULL) {
+		        fprintf(outfile_fp, "; charset=%s\n",
+					    HTLoadedDocumentCharset());
+		    } else {
+		        fprintf(outfile_fp, "\n");
+		    }
+		    fprintf(outfile_fp, "Content-Location: %s\n",
+		    			newdoc->address);
+		    fprintf(outfile_fp, "Content-Base: %s\n",
+		    			newdoc->address);
+		} else {
+		    /*
+		     *  Add an X-URL header for rendered HTML or
+		     *  plain text. - FM
+		     */
+		    fprintf(outfile_fp, "X-URL: %s\n", newdoc->address);
+		}
 		fprintf(outfile_fp, "To: %s\nSubject:%s\n\n",
 				     user_response, sug_filename);
+		if (HTisDocumentSource()) {
+		    /*
+		     *  Added the document's URL as a BASE tag to
+		     *  the top of the message body.  May create
+		     *  technically invalid HTML, but will help
+		     *  get any partial or relative URLs resolved
+		     *  properly if no BASE tag is present to
+		     *  replace it. - FM
+		     */
+		    fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n",
+		    			newdoc->address);
+		}
 		print_wwwfile_to_fd(outfile_fp, 0);
 		if (keypad_mode)
 		    printlist(outfile_fp, FALSE);
@@ -464,6 +551,18 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		signal(SIGINT, SIG_IGN);
 #endif /* !VMS */
 
+		if (HTisDocumentSource()) {
+		    /*
+		     *  Added the document's URL as a BASE tag
+		     *  to the top of the file.  May create
+		     *  technically invalid HTML, but will help
+		     *  get any partial or relative URLs resolved
+		     *  properly if no BASE tag is present to
+		     *  replace it. - FM
+		     */
+		    fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n",
+		    			newdoc->address);
+		}
 		print_wwwfile_to_fd(outfile_fp, 0);
 		if (keypad_mode)
 		    printlist(outfile_fp, FALSE);
@@ -538,6 +637,18 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		    break;
                 }
 
+		if (HTisDocumentSource()) {
+		    /*
+		     *  Added the document's URL as a BASE tag
+		     *  to the top of the file.  May create
+		     *  technically invalid HTML, but will help
+		     *  get any partial or relative URLs resolved
+		     *  properly if no BASE tag is present to
+		     *  replace it. - FM
+		     */
+		    fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n",
+		    			newdoc->address);
+		}
 		print_wwwfile_to_fd(outfile_fp, 0);
 		if (keypad_mode)
 		    printlist(outfile_fp, FALSE);
diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c
index bc9f6c0e..686eb13e 100644
--- a/src/LYReadCFG.c
+++ b/src/LYReadCFG.c
@@ -12,6 +12,7 @@
 #include "LYCgi.h"
 #include "LYCurses.h"
 #include "LYSignal.h"
+#include "LYBookmark.h"
 
 #ifdef DIRED_SUPPORT
 #include "LYLocal.h"
@@ -590,7 +591,19 @@ PUBLIC void read_cfg ARGS1(
 		   user_mode = ADVANCED_MODE;
 
 	} else if(!strncasecomp(buffer,"DEFAULT_BOOKMARK_FILE:",22)) {
-		StrAllocCopy(bookmark_page,buffer+22);
+		StrAllocCopy(bookmark_page, buffer+22);
+		StrAllocCopy(BookmarkPage, bookmark_page);
+		StrAllocCopy(MBM_A_subbookmark[0], bookmark_page);
+		StrAllocCopy(MBM_A_subdescript[0], MULTIBOOKMARKS_DEFAULT);
+
+	} else if(!strncasecomp(buffer,"MULTI_BOOKMARK_SUPPORT:",23)) {
+		LYMultiBookmarks = is_true(buffer+23);
+
+	} else if(!strncasecomp(buffer,"BLOCK_MULTI_BOOKMARKS:",22)) {
+		LYMBMBlocked = is_true(buffer+22);
+
+	} else if(!strncasecomp(buffer,"ADVANCED_MULTI_BOOKMARKS:",25)) {
+		LYMBMAdvanced = is_true(buffer+25);
 
 	} else if(!system_editor && 
 		  !strncasecomp(buffer,"DEFAULT_EDITOR:",15)) {
@@ -957,6 +970,9 @@ PUBLIC void read_cfg ARGS1(
 		    HTNewsChunkSize = HTNewsMaxChunk;
 		}
 
+	} else if(!strncasecomp(buffer,"USE_SELECT_POPUPS:",17)) {
+		LYSelectPopups = is_true(buffer+17);
+
 #if defined(VMS) && defined(VAXC) && !defined(__DECC)
 	} else if (!strncasecomp(buffer, "DEFAULT_VIRTUAL_MEMORY_SIZE:", 28)) {
 		HTVirtualMemorySize = atoi(buffer+28);
diff --git a/src/LYShowInfo.c b/src/LYShowInfo.c
index fb6e5c5e..9566967e 100644
--- a/src/LYShowInfo.c
+++ b/src/LYShowInfo.c
@@ -11,6 +11,7 @@
 #include "LYShowInfo.h"
 #include "LYSignal.h"
 #include "LYCharUtils.h"
+#include "GridText.h"
 
 #include "LYLeaks.h"
 
@@ -97,9 +98,9 @@ PUBLIC int showinfo ARGS4(
     fprintf(fp0,"<h2>%s Version %s</h2>\n", LYNX_NAME, LYNX_VERSION);
 
 #ifdef DIRED_SUPPORT
-    if (lynx_edit_mode) {
+    if (lynx_edit_mode && nlinks > 0) {
 	fprintf(fp0,
-	   	"<h2>Directory that you are currently viewing</h2>\n<pre>");
+	 "<h2>Directory that you are currently viewing</h2>\n<pre>");
 
 	cp = doc->address;
 	if (!strncmp(cp, "file://localhost", 16)) 
@@ -109,8 +110,8 @@ PUBLIC int showinfo ARGS4(
 	strcpy(temp, cp);
 	HTUnEscape(temp);
 
-	fprintf(fp0,"   Name:  %s\n", temp);
-	fprintf(fp0,"    URL:  %s\n", doc->address);
+	fprintf(fp0,"   <em>Name:</em>  %s\n", temp);
+	fprintf(fp0,"   <em> URL:</em>  %s\n", doc->address);
 
 	cp = links[doc->link].lname;
 	if (!strncmp(cp, "file://localhost", 16)) 
@@ -126,16 +127,18 @@ PUBLIC int showinfo ARGS4(
 	    char modes[80];
 	    if (((dir_info.st_mode) & S_IFMT) == S_IFDIR) {
 		fprintf(fp0,
-		 	"\nDirectory that you have currently selected\n\n");
+		 "\nDirectory that you have currently selected\n\n");
 	    } else if (((dir_info.st_mode) & S_IFMT) == S_IFREG) {
-		fprintf(fp0, "\nFile that you have currently selected\n\n");
+		fprintf(fp0, 
+		      "\nFile that you have currently selected\n\n");
 	    } else if (((dir_info.st_mode) & S_IFMT) == S_IFLNK) {
 		fprintf(fp0,
-		      "\nSymbolic link that you have currently selected\n\n");
+	     "\nSymbolic link that you have currently selected\n\n");
 	    } else {
-		fprintf(fp0, "\nItem that you have currently selected\n\n");
+		fprintf(fp0,
+		      "\nItem that you have currently selected\n\n");
 	    }
-	    fprintf(fp0,"       Full name:  %s\n", temp);
+	    fprintf(fp0,"       <em>Full name:</em>  %s\n", temp);
 	    if (((dir_info.st_mode) & S_IFMT) == S_IFLNK) {
 		char buf[1025];
 		int buf_size;
@@ -145,16 +148,16 @@ PUBLIC int showinfo ARGS4(
 		} else {
 		    strcpy(buf, "Unable to follow link");
 		}
-		fprintf(fp0, "  Points to file:  %s\n", buf);
+		fprintf(fp0, "  <em>Points to file:</em>  %s\n", buf);
 	    }
 	    pw = getpwuid(dir_info.st_uid);
 	    if (pw)
-	        fprintf(fp0, "   Name of owner:  %s\n", pw->pw_name);
+	        fprintf(fp0, "   <em>Name of owner:</em>  %s\n", pw->pw_name);
 	    grp = getgrgid(dir_info.st_gid);
 	    if (grp && grp->gr_name)
-	        fprintf(fp0, "      Group name:  %s\n", grp->gr_name);
+	        fprintf(fp0, "      <em>Group name:</em>  %s\n", grp->gr_name);
 	    if (((dir_info.st_mode) & S_IFMT) == S_IFREG) {
-		sprintf(temp, "       File size:  %ld (bytes)\n",
+		sprintf(temp, "       <em>File size:</em>  %ld (bytes)\n",
 		 	      (long)dir_info.st_size);
 		fprintf(fp0, "%s", temp);
 	    }
@@ -162,16 +165,16 @@ PUBLIC int showinfo ARGS4(
 	     *  Include date and time information.
 	     */
 	    cp = ctime(&dir_info.st_ctime);
-	    fprintf(fp0, "   Creation date:  %s", cp);
+	    fprintf(fp0, "   <em>Creation date:</em>  %s", cp);
 
 	    cp = ctime(&dir_info.st_mtime);	      
-	    fprintf(fp0, "   Last modified:  %s", cp);
+	    fprintf(fp0, "   <em>Last modified:</em>  %s", cp);
 
 	    cp = ctime(&dir_info.st_atime);
-	    fprintf(fp0, "   Last accessed:  %s\n", cp);
+	    fprintf(fp0, "   <em>Last accessed:</em>  %s\n", cp);
 
-	    fprintf(fp0, "   Access Permissions\n");
-	    fprintf(fp0, "      Owner:  ");
+	    fprintf(fp0, "   <em>Access Permissions</em>\n");
+	    fprintf(fp0, "      <em>Owner:</em>  ");
 	    modes[0] = '\0';
 	    modes[1] = '\0';   /* In case there are no permissions */
 	    modes[2] = '\0';
@@ -190,7 +193,7 @@ PUBLIC int showinfo ARGS4(
 	    }
 	    fprintf(fp0, "%s\n", (char *)&modes[2]); /* Skip leading ', ' */
 
-	    fprintf(fp0, "      Group:  ");
+	    fprintf(fp0, "      <em>Group:</em>  ");
 	    modes[0] = '\0';
 	    modes[1] = '\0';   /* In case there are no permissions */
 	    modes[2] = '\0';
@@ -209,7 +212,7 @@ PUBLIC int showinfo ARGS4(
 	    }
 	    fprintf(fp0, "%s\n", (char *)&modes[2]);  /* Skip leading ', ' */
 
-	    fprintf(fp0, "      World:  ");
+	    fprintf(fp0, "      <em>World:</em>  ");
 	    modes[0] = '\0';
 	    modes[1] = '\0';   /* In case there are no permissions */
 	    modes[2] = '\0';
@@ -232,21 +235,33 @@ PUBLIC int showinfo ARGS4(
     } else {
 #endif /* DIRED_SUPPORT */
 
-    fprintf(fp0, "<h2>File that you are currently viewing</h2>\n<dl compact>");
+    fprintf(fp0,
+       "<h2>File that you are currently viewing</h2>\n<dl compact>");
 
     StrAllocCopy(Title, doc->title);
     LYEntify(&Title, TRUE);
-    fprintf(fp0,"<dt>Linkname: %s\n", Title);
+    fprintf(fp0,"<dt><em>Linkname:</em> %s\n", Title);
 
     StrAllocCopy(Address, doc->address);
     LYEntify(&Address, FALSE);
-    fprintf(fp0, "<dt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;URL: %s\n", Address);
+    fprintf(fp0,
+    	    "<dt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>URL:</em> %s\n", Address);
+
+    if ((cp = HText_getServer()) != NULL && *cp != '\0')
+        fprintf(fp0, "<dt><em>&nbsp;&nbsp;Server:</em> %s\n", cp);
+
+    if ((cp = HText_getDate()) != NULL && *cp != '\0')
+        fprintf(fp0, "<dt><em>&nbsp;&nbsp;&nbsp;&nbsp;Date:</em> %s\n", cp);
+
+    if ((cp = HText_getLastModified()) != NULL && *cp != '\0')
+        fprintf(fp0, "<dt><em>Last Mod:</em> %s\n", cp);
 
     if (doc->post_data) {
         StrAllocCopy(Address, doc->post_data);
 	LYEntify(&Address, FALSE);
-	fprintf(fp0, "<dt>Post Data: %s\n", Address);
-	fprintf(fp0, "<dt>Post Content Type: %s\n", doc->post_content_type);
+	fprintf(fp0, "<dt><em>Post Data:</em> <xmp>%s</xmp>\n", Address);
+	fprintf(fp0,
+	     "<dt><em>Post Content Type:</em> %s\n", doc->post_content_type);
     }
 
     if (owner_address) {
@@ -255,34 +270,41 @@ PUBLIC int showinfo ARGS4(
     } else {
         StrAllocCopy(Address, "None");
     }
-    fprintf(fp0, "<dt>Owner(s): %s\n", Address);
+    fprintf(fp0, "<dt><em>Owner(s):</em> %s\n", Address);
 
-    fprintf(fp0, "<dt>&nbsp;&nbsp;&nbsp;&nbsp;size: %d lines\n", size_of_file);
+    fprintf(fp0,
+	"<dt>&nbsp;&nbsp;&nbsp;&nbsp;<em>size:</em> %d lines\n", size_of_file);
 
-    fprintf(fp0, "<dt>&nbsp;&nbsp;&nbsp;&nbsp;mode: %s\n",
+    fprintf(fp0, "<dt>&nbsp;&nbsp;&nbsp;&nbsp;<em>mode:</em> %s\n",
 		 (lynx_mode == FORMS_LYNX_MODE ? "forms mode" : "normal"));
 
     fprintf(fp0, "</dl>\n");  /* end of list */
 
     if (nlinks > 0) {
 	fprintf(fp0,
-	        "<h2>Link that you currently have selected</h2>\n<dl compact>");
+      "<h2>Link that you currently have selected</h2>\n<dl compact>");
 	StrAllocCopy(Title, links[doc->link].hightext);
 	LYEntify(&Title, TRUE);
-	fprintf(fp0, "<dt>Linkname: %s\n", Title);
+	fprintf(fp0, "<dt><em>Linkname:</em> %s\n", Title);
 	if (lynx_mode == FORMS_LYNX_MODE &&
 	    links[doc->link].type == WWW_FORM_LINK_TYPE) {
 	    if (links[doc->link].form->submit_method) {
 	        int method = links[doc->link].form->submit_method;
-		fprintf(fp0, "<dt>&nbsp;&nbsp;Method: %s\n",
+	        char *enctype = links[doc->link].form->submit_enctype;
+
+		fprintf(fp0, "<dt>&nbsp;&nbsp;<em>Method:</em> %s\n",
 			     (method == URL_POST_METHOD) ? "POST" :
 			     (method == URL_MAIL_METHOD) ? "(email)" :
 							   "GET");
+		fprintf(fp0, "<dt>&nbsp;<em>Enctype:</em> %s\n",
+			     (enctype &&
+			      *enctype ?
+			       enctype : "application/x-www-form-urlencoded"));
 	    }
 	    if (links[doc->link].form->submit_action) {
 	        StrAllocCopy(Address, links[doc->link].form->submit_action);
 		LYEntify(&Address, FALSE);
-	        fprintf(fp0, "<dt>&nbsp;&nbsp;Action: %s\n", Address);
+	        fprintf(fp0, "<dt>&nbsp;&nbsp;<em>Action:</em> %s\n", Address);
 	    }
 	    if (!(links[doc->link].form->submit_method &&
 		links[doc->link].form->submit_action)) {
@@ -295,7 +317,7 @@ PUBLIC int showinfo ARGS4(
 	    } else {
 	        StrAllocCopy(Title, "");
 	    }
-	    fprintf(fp0, "<dt>Filename: %s\n", Title);
+	    fprintf(fp0, "<dt><em>Filename:</em> %s\n", Title);
 	}
 	fprintf(fp0, "</dl>\n");  /* end of list */
 
diff --git a/src/LYStructs.h b/src/LYStructs.h
index 1be79aed..6ef5d8a7 100644
--- a/src/LYStructs.h
+++ b/src/LYStructs.h
@@ -33,15 +33,9 @@ typedef struct _document {
    int    link;
    int    line;
    BOOL   isHEAD;
+   char * bookmark;
 } document;
 
-#ifdef DIRED_SUPPORT
-typedef struct _taglink {
-   char *name;
-   struct _taglink *next;
-} taglink;
-#endif
-
 #ifndef HTFORMS_H
 #include "HTForms.h" 
 #endif /* HTFORMS_H */
@@ -54,6 +48,7 @@ typedef struct _histstruct {
     int    link;
     int    page;
     BOOL   isHEAD;
+    char * bookmark;
 } histstruct;
 
 extern histstruct history[MAXHIST];
diff --git a/src/LYUtils.c b/src/LYUtils.c
index d775f493..d1cf11f7 100644
--- a/src/LYUtils.c
+++ b/src/LYUtils.c
@@ -3,6 +3,7 @@
 #include "HTParse.h"
 #include "HTAccess.h"
 #include "HTCJK.h"
+#include "HTAlert.h"
 #include "LYCurses.h"
 #include "LYUtils.h"
 #include "LYStrings.h"
@@ -1431,14 +1432,24 @@ PUBLIC void change_sug_filename ARGS1(char *,fname)
 
      /** Replace all but the last period with _'s, or second **/
      /** to last if last is followed by a terminal Z or z,   **/
+     /** or GZ or gz,					     **/
      /** e.g., convert foo.tar.Z to                          **/
      /**               foo.tar_Z                             **/
+     /**   or, convert foo.tar.gz to                         **/
+     /**               foo.tar-gz                            **/
      j = strlen(fname) - 1;
      if ((dot = strrchr(fname, '.')) != NULL) {
-	  if (((fname[j] == 'Z' || fname[j] == 'z') && fname[j-1] == '.') &&
-	      (((cp = strchr(fname, '.')) != NULL) && cp < dot)) {
-	       *dot = '_';
-	       dot = strrchr(fname, '.');
+	  if (TOUPPER(fname[j]) == 'Z') {
+	      if ((fname[j-1] == '.') &&
+	          (((cp = strchr(fname, '.')) != NULL) && cp < dot)) {
+		  *dot = '_';
+		  dot = strrchr(fname, '.');
+	      } else if (((TOUPPER(fname[j-1]) == 'G') &&
+	      		  fname[j-2] == '.') &&
+			 (((cp = strchr(fname, '.')) != NULL) && cp < dot)) {
+		  *dot = '-';
+		  dot = strrchr(fname, '.');
+	      }
 	  }
 	  cp = fname;
 	  while ((cp = strchr(cp, '.')) != NULL && cp < dot)
@@ -1592,6 +1603,8 @@ PRIVATE char *restrict_name[] = {
        "editor"        ,
        "shell"         ,
        "bookmark"      ,
+       "multibook"     ,
+       "bookmark_exec" ,
        "option_save"   ,
        "print"         ,
        "download"      ,
@@ -1599,7 +1612,6 @@ PRIVATE char *restrict_name[] = {
        "exec"          ,
        "lynxcgi"       ,
        "exec_frozen"   ,
-       "bookmark_exec" ,
        "goto"          ,
        "jump"          ,
        "file_url"      ,
@@ -1633,6 +1645,8 @@ PRIVATE BOOLEAN *restrict_flag[] = {
        &no_editor   ,
        &no_shell    ,
        &no_bookmark ,
+       &no_multibook ,
+       &no_bookmark_exec,
        &no_option_save,
        &no_print    ,
        &no_download ,
@@ -1640,7 +1654,6 @@ PRIVATE BOOLEAN *restrict_flag[] = {
        &no_exec     ,
        &no_lynxcgi  ,
        &exec_frozen ,
-       &no_bookmark_exec,
        &no_goto     ,
        &no_jump     ,
        &no_file_url ,
@@ -2132,7 +2145,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 {
     char DomainPrefix[80], *StartP, *EndP;
     char DomainSuffix[80], *StartS, *EndS;
-    char *Str = NULL, *StrColon = NULL;
+    char *Str = NULL, *StrColon = NULL, *MsgStr = NULL;
     char *Host = NULL, *HostColon = NULL;
     char *Path = NULL;
     struct hostent  *phost;
@@ -2176,9 +2189,16 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
      *  Do a DNS test on the potential host field
      *  as presently trimmed. - FM
      */
+    if (LYCursesON) {
+        StrAllocCopy(MsgStr, "Looking up ");
+	StrAllocCat(MsgStr, Str);
+	StrAllocCat(MsgStr, " first.");
+	HTProgress(MsgStr);
+    }
     if ((phost = gethostbyname(Str)) != NULL) {
         GotHost = TRUE;
         FREE(Str);
+        FREE(MsgStr);
 	return GotHost;
     }
 
@@ -2232,15 +2252,36 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 	        isdigit(HostColon[1])) {
 		*HostColon = '\0';
 	    }
+	    if (LYCursesON) {
+ 	        StrAllocCopy(MsgStr, "Looking up ");
+ 		StrAllocCat(MsgStr, Host);
+ 		StrAllocCat(MsgStr, ", guessing...");
+ 		HTProgress(MsgStr);
+	    }
 	    GotHost = ((phost = gethostbyname(Host)) != NULL);
 	    if (HostColon != NULL) {
 	        *HostColon = ':';
 	    }
 	    if (GotHost == FALSE) {
+		/*
+		 *  Give the user chance to interrupt lookup cycles. - KW
+		 */
+		if (LYCursesON && HTCheckForInterrupt()) {
+		    if (TRACE) {
+			fprintf(stderr,
+	 "*** LYExpandHostForURL interrupted while %s failed to resolve\n",
+				Host);
+			    }
+		    FREE(Str);
+		    FREE(MsgStr);
+		    FREE(Host);
+		    return FALSE; /* We didn't find a valid name. */
+		}
+
 	        /*
 		**  Advance to the next suffix, or end of suffix list. - FM
 		*/
-		StartS = ((EndS == '\0') ? EndS : (EndS + 1));
+		StartS = ((*EndS == '\0') ? EndS : (EndS + 1));
 		while ((*StartS) && (WHITE(*StartS) || *StartS == ',')) {
 		    StartS++;	/* Skip whitespace and separators */
 		}
@@ -2256,7 +2297,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
 	   /*
 	   **  Advance to the next prefix, or end of prefix list. - FM
 	   */
-	   StartP = ((EndP == '\0') ? EndP : (EndP + 1));
+	   StartP = ((*EndP == '\0') ? EndP : (EndP + 1));
 	   while ((*StartP) && (WHITE(*StartP) || *StartP == ',')) {
 	       StartP++;	/* Skip whitespace and separators */
 	   }
@@ -2290,6 +2331,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3(
      *  Clean up and return the last test result. - FM
      */
     FREE(Str);
+    FREE(MsgStr);
     FREE(Host);
     return GotHost;
 }
@@ -2591,3 +2633,76 @@ putenv (string)
   return 0;
 }
 #endif /* NO_PUTENV */
+
+#ifdef VMS
+/*
+ *  This function appends fname to the home path and returns
+ *  the full path and filename in VMS syntax.  The fname
+ *  string can be just a filename, or include a subirectory
+ *  off the home directory, in which chase fname should
+ *  with "./" (e.g., ./BM/lynx_bookmarks.html). - FM
+ */
+PUBLIC void LYVMS_HomePathAndFilename ARGS3(
+	char *,		fbuffer,
+	int,		fbuffer_size,
+	char *,		fname)
+{
+    char *home = NULL;
+    char *temp = NULL;
+    int len;
+
+    /*
+     *  Make sure we have a buffer and string. - FM
+     */
+    if (!fbuffer)
+        return;
+    if (!(fname && *fname) || fbuffer_size < 1) {
+        fbuffer[0] = '\0';
+	return;
+    }
+
+    /*
+     *  Set up home string and length. - FM
+     */
+    StrAllocCopy(home, Home_Dir());
+    if (!(home && *home))
+        StrAllocCopy(home, "Error:");
+    len = fbuffer_size - strlen(home) - 1;
+    if (len < 0) {
+        len = 0;
+	home[fbuffer_size] = '\0';
+    }
+
+    /*
+     *  Check whether we have a subdirectory path or just a filename. - FM
+     */
+    if (!strncmp(fname, "./", 2)) {
+        /*
+	 *  We have a subdirectory path. - FM
+	 */
+	if (home[strlen(home)-1] == ']') {
+	    /*
+	     *  We got the home directory, so convert it to
+	     *  SHELL syntax and append subdirectory path,
+	     *  then convert that to VMS syntax. - FM
+	     */
+	    temp = (char *)calloc(1, (strlen(home) + strlen(fname) + 10));
+	    sprintf(temp, "%s%s", HTVMS_wwwName(home), (fname + 1));
+	    sprintf(fbuffer, "%.*s",
+	    	    (fbuffer_size - 1), HTVMS_name("", temp));
+	    FREE(temp);
+	} else {
+	    /*
+	     *  This will fail, but we need something in the buffer. - FM
+	     */
+	    sprintf(fbuffer,"%s%.*s", home, len, fname);
+	}
+    } else {
+        /*
+	 *  We have a file in the home directory. - FM
+	 */
+	sprintf(fbuffer,"%s%.*s", home, len, fname);
+    }
+    FREE(home);
+}
+#endif /* VMS */
diff --git a/src/LYUtils.h b/src/LYUtils.h
index d9fb84b6..7e91f071 100644
--- a/src/LYUtils.h
+++ b/src/LYUtils.h
@@ -47,7 +47,10 @@ extern BOOLEAN LYExpandHostForURL PARAMS((
 extern BOOLEAN LYAddSchemeForURL PARAMS((
 	char **AllocatedString, char *default_scheme));
 #ifdef VMS
-extern void Define_VMSLogical PARAMS((char *LogicalName, char *LogicalValue));
+extern void Define_VMSLogical PARAMS((
+	char *LogicalName, char *LogicalValue));
+extern void LYVMS_HomePathAndFilename PARAMS((
+	char *fbuffer, int fbuffer_size, char * fname));
 #endif /* VMS */
 
 /*	Whether or not the status line must be shown.
diff --git a/src/LYrcFile.c b/src/LYrcFile.c
index 504a0a57..9b8aaa39 100644
--- a/src/LYrcFile.c
+++ b/src/LYrcFile.c
@@ -6,6 +6,7 @@
 #include "LYStrings.h"
 #include "LYGlobalDefs.h"
 #include "LYCharSets.h"
+#include "LYBookmark.h"
 
 #include "LYLeaks.h"
 
@@ -16,6 +17,10 @@ PUBLIC void read_rc()
     FILE *fp;
     char *cp, *cp2;
     int number_sign;
+    char MBM_line[256];
+    int  MBM_counter, MBM_counter2;
+    char *MBM_cp, *MBM_cp2, *MBM_cp1;
+    int  MBM_i1, MBM_i2;
 
     /* make a name */
 #ifdef UNIX
@@ -113,18 +118,92 @@ PUBLIC void read_rc()
  	       StrAllocCopy(editor, cp);
 
 	/* bookmark file */
-	} else if ((cp=LYstrstr(line_buffer,"bookmark_file"))!=NULL &&
-		cp-line_buffer < number_sign) {
+	} else if ((cp = LYstrstr(line_buffer, "bookmark_file")) != NULL &&
+		    cp-line_buffer < number_sign) {
 
-	   if ((cp2 = (char *)strchr(cp,'=')) != NULL)
+	    if ((cp2 = (char *)strchr(cp,'=')) != NULL)
 		cp = cp2+1;
 
-	   while (isspace(*cp)) cp++;  /* get rid of spaces */
-
-	   StrAllocCopy(bookmark_page, cp);
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+
+            /*
+	     *  Since this is the "default" saveto, we save it.
+	     */
+	    StrAllocCopy(bookmark_page, cp);
+	    StrAllocCopy(BookmarkPage, cp);
+            StrAllocCopy(MBM_A_subbookmark[0], cp);
+            StrAllocCopy(MBM_A_subdescript[0], MULTIBOOKMARKS_DEFAULT);
+
+	} else if ((cp = LYstrstr(line_buffer, "multi_bookmark")) != NULL &&
+                   cp-line_buffer < number_sign) {
+            /*
+	     *  Found the root, now cycle through all the
+             *  possible spaces and match specific ones.
+             */
+            for (MBM_counter = 1;
+	         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 ((MBM_cp1 = (char *)strchr(cp, '=')) == NULL) {
+                        break;
+                    } else {
+                        if ((MBM_cp2 = (char *)strchr(cp, ',')) == NULL) {
+                            break;
+                        } else {
+                            MBM_i2 = 0;
+			    /*
+			     *  skip over the '='.
+			     */
+                            MBM_cp1++;
+                            while (MBM_cp1 && MBM_cp1 != MBM_cp2) {
+                                /*
+				 *  Skip spaces.
+				 */
+                                if (isspace(*MBM_cp1)) {
+                                    MBM_cp1++;
+                                    continue;
+                                } else {
+                                    MBM_line[MBM_i2++] = *MBM_cp1++;
+				}
+			    }
+                            MBM_line[MBM_i2++] = '\0';
+
+                            StrAllocCopy(MBM_A_subbookmark[MBM_counter],
+			    		 MBM_line);
+
+                            /*
+			     *  Now get the description ',' and ->.
+			     */
+                            MBM_cp1 = (char *)strchr(cp, ',');
+
+                            MBM_i2 = 0;
+			    /*
+			     *  Skip over the ','.
+			     */
+                            MBM_cp1++;
+                            /*
+			     *  Eat spaces in front of description.
+			     */
+                            while (isspace(*MBM_cp1))
+                                MBM_cp1++;
+                            while (*MBM_cp1)
+                                MBM_line[MBM_i2++] = *MBM_cp1++;
+                            MBM_line[MBM_i2++] = '\0';
+
+                            StrAllocCopy(MBM_A_subdescript[MBM_counter],
+			    		 MBM_line);
+
+                            break;
+			}
+                    }
+		}
+	    }
 
 	/* personal_mail_address */
-	} else if ((cp=LYstrstr(line_buffer,"personal_mail_address"))!=NULL &&
+        } else if((cp=LYstrstr(line_buffer,"personal_mail_address"))!=NULL &&
 		cp-line_buffer < number_sign) {
 
 	   if ((cp2 = (char *)strchr(cp,'=')) != NULL)
@@ -223,9 +302,31 @@ PUBLIC void read_rc()
            else
               emacs_keys=FALSE;
 
+	/* multi bookmarks */
+        } else if ((cp = LYstrstr(line_buffer, "sub_bookmarks")) != NULL &&
+                   cp-line_buffer < number_sign) {
+
+           if ((cp2 = (char *)strchr(cp, '=')) != NULL)
+                cp = (cp2 + 1);
+
+           while (isspace(*cp))
+	       cp++;  /* get rid of spaces */
+
+           if (!strncmp(cp, "on", 2) || !strncmp(cp, "ON", 2))
+              LYMultiBookmarks = TRUE;
+           else if (!strncmp(cp, "standard", 8) ||
+                        !strncmp(cp, "STANDARD", 8)) {
+              LYMultiBookmarks = TRUE;
+              LYMBMAdvanced = FALSE;
+           } else if (!strncmp(cp, "advanced", 8) ||
+                          !strncmp(cp, "ADVANCED", 8)) {
+              LYMultiBookmarks = TRUE;
+              LYMBMAdvanced = TRUE;
+           } else
+              LYMultiBookmarks = FALSE;
 
 	} else if ((cp=LYstrstr(line_buffer,"keypad_mode"))!=NULL &&
-		cp-line_buffer < number_sign) {
+		   cp-line_buffer < number_sign) {
 
 	   if ((cp2 = (char *)strchr(cp,'=')) != NULL)
 		cp = cp2+1;
@@ -292,6 +393,20 @@ PUBLIC void read_rc()
 
 #endif /* DIRED_SUPPORT */
 
+	/* select popups */
+	} else if ((cp=LYstrstr(line_buffer,"select_popups")) != NULL &&
+		cp-line_buffer < number_sign) {
+
+	   if ((cp2 = (char * )strchr(cp,'=')) != NULL)
+		cp = cp2+1;
+
+	   while (isspace(*cp)) cp++;  /* get rid of spaces */
+	
+	   if (!strncasecomp(cp, "off", 3))
+	       LYSelectPopups = FALSE;
+	   else
+	       LYSelectPopups = TRUE;
+
 	} /* end of if */
 
     } /* end of while */
@@ -304,6 +419,7 @@ PUBLIC int save_rc ()
     char rcfile[256];
     FILE *fp;
     int i;
+    int MBM_c;
 
     /* make a name */
 #ifdef UNIX
@@ -392,7 +508,8 @@ PUBLIC int save_rc ()
 
 #if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS) 
     /* local_exec */
-    fprintf(fp,"# if run all execution links is on then all local exection links will\n\
+    fprintf(fp,"\
+# if run all execution links is on then all local exection links will\n\
 # be executed when they are selected.\n\
 #\n\
 # WARNING - this is potentially VERY dangerous.  Since you may view\n\
@@ -402,10 +519,11 @@ PUBLIC int save_rc ()
 #           or compromise security.  This should only be set to on if you\n\
 #           are viewing trusted source information\n");
 
-    fprintf(fp,"run_all_execution_links=%s\n\n",(local_exec ? "on" : "off"));
+    fprintf(fp, "run_all_execution_links=%s\n\n",(local_exec ? "on" : "off"));
 
     /* local_exec_on_local_files */
-    fprintf(fp,"# if run all execution links is on then all local exection links that\n\
+    fprintf(fp,"\
+# if run all execution links is on then all local exection links that\n\
 # are found in LOCAL files will be executed when they are selected.\n\
 # This is different from \"run all execution links\" in that only files\n\
 # that reside on the local system will have execution link permissions\n\
@@ -438,7 +556,34 @@ PUBLIC int save_rc ()
 # ^N - down    ^p - up\n\
 # ^B - left    ^F - right\n\
 # will be enabled.\n");
-    fprintf(fp,"emacs_keys=%s\n\n",(emacs_keys ? "on" : "off"));
+    fprintf(fp, "emacs_keys=%s\n\n", (emacs_keys ? "on" : "off"));
+
+    /* multiple bookmarks - on or off */
+    fprintf(fp,"\
+# If sub_bookmarks are turned on then all bookmark operations\n\
+# will first prompt the user to select an active sub-bookmark file.\n\
+# If the default lynx bookmarks file is defined, it will be used as\n\
+# the default selection. When this option is set to 'advanced', and\n\
+# the user mode is advanced, the 'v'iew bookmark command will invoke\n\
+# a statusline prompt instead of the menu seen in novice and intermediate\n\
+# user modes. When this option is set to 'standard', the menu will be\n\
+# presented regardless of user mode. If this option is set to 'off',\n\
+# sub-bookmark files are disabled.\n");
+    fprintf(fp,"sub_bookmarks=%s\n\n", (LYMultiBookmarks ?
+          (LYMBMAdvanced ? "advanced" : "standard") : "off"));
+
+    /* multiple bookmarks support - list out sub-bookmarks */
+    fprintf(fp,"\
+# The following allow you to define sub-bookmark files and definitions.\n\
+# Format is <keyword><letter>=<filename>,<description>\n\
+# Up to MBM_V_MAXFILES (26 MAX) are allowed.\n\
+# We start with 'multi_bookmarkB' since 'A' is reserved!\n");
+    for (MBM_c = 1; MBM_c <= MBM_V_MAXFILES; MBM_c++)
+       fprintf(fp,"multi_bookmark%c=%s%s%s\n", (MBM_c + 'A'),
+             (MBM_A_subbookmark[MBM_c] ? MBM_A_subbookmark[MBM_c] : ""),
+             (MBM_A_subbookmark[MBM_c] ? "," : ""),
+             (MBM_A_subdescript[MBM_c] ? MBM_A_subdescript[MBM_c] : ""));
+    fprintf(fp,"\n");
 
     /* keypad mode */
     fprintf(fp,"\
@@ -513,6 +658,17 @@ PUBLIC int save_rc ()
 							"DIRECTORIES_FIRST")));
 #endif /* DIRED_SUPPORT */
 
+    /* select popups */
+    fprintf(fp, "\
+# select_popups specifies whether the OPTIONs in a SELECT block which\n\
+# lacks a MULTIPLE attribute are presented as a vertical list of radio\n\
+# buttons or via a popup menu.  Note that if the MULTIPLE attribute is\n\
+# present in the SELECT start tag, Lynx always will create a vertical list\n\
+# of checkboxes for the OPTIONs.  A value of \"on\" will set popup menus\n\
+# as the default while a value of \"off\" will set use of radio boxes.\n\
+# The default can be overridden via the -popup command line toggle.\n");
+    fprintf(fp, "select_popups=%s\n\n",(LYSelectPopups ? "on" : "off"));
+
     fclose(fp);
 
     /* get rid of any copies of the .lynxrc file that VMS creates */
diff --git a/userdefs.h b/userdefs.h
index 0e2e7d24..5b97f116 100644
--- a/userdefs.h
+++ b/userdefs.h
@@ -2,7 +2,7 @@
  * Lynx - Hypertext navigation system
  *
  *   (c) Copyright 1992, 1993, 1994 University of Kansas
- *	 1996: GNU General Public License
+ *	 1995, 1996: GNU General Public License
  */
 
 /*******************************************************************
@@ -345,13 +345,13 @@
  */
 
 /*****************************
- * STARTFILE is the default file if none is specified on the command line
- * or via a WWW_HOME environment variable.
+ * STARTFILE is the default file if none is specified in lynx.cfg,
+ *  on the command line, or via a WWW_HOME environment variable.
  * 
  * note: STARTFILE must be a URL.  See the Lynx online help for more
  *       information on URLs
  */
-#define STARTFILE "http://www.nyu.edu/pages/wsn/subir/lynx.html"
+#define STARTFILE "http://lynx.browser.org/"
 
 /*****************************
  * HELPFILE must be defined as a URL and must have a 
@@ -361,10 +361,10 @@
  *   for this distribution (use SHELL syntax including the device
  *   on VMS systems).
  * The default HELPFILE is:
- * http://www.nyu.edu/pages/wsn/subir/lynx.html
+ * http://www.crl.com/~subir/lynx/lynx_help/lynx_help_main.html
  *   This should be changed here or in lynx.cfg to the local path.
  */
-#define HELPFILE "http://www.nyu.edu/pages/wsn/subir/lynx.html"
+#define HELPFILE "http://www.crl.com/~subir/lynx/lynx_help/lynx_help_main.html"
 /* #define HELPFILE "file://localhost/PATH_TO/lynx_help/lynx_help_main.html" */
 
 /*****************************
@@ -556,6 +556,46 @@
  */
 #define PREFERRED_CHARSET ""
 
+/*****************************
+* If MULTI_BOOKMARK_SUPPORT is set TRUE, and BLOCK_MULTI_BOOKMARKS (see
+* below) is FALSE, and sub-bookmarks exist, all bookmark-operations will
+* first prompt the user to select an active sub-bookmark file or the
+* default bookmark file.  FALSE is the default so that one (the default)
+* bookmark file will be available initially.  The default set here can
+* be overridden in lynx.cfg.  The user can turn on multiple bookmark
+* support via the 'o'ptions menu, and can save that choice as the startup
+* default via the .lynxrc file.   The startup default, however set, can
+* be overridden on the command line via the -restrictions=multibook or
+* the -anonymous or -validate switches.
+*/
+#ifndef MULTI_BOOKMARK_SUPPORT
+#define MULTI_BOOKMARK_SUPPORT FALSE
+#endif /* MULTI_BOOKMARK_SUPPORT */
+
+/*****************************
+* If BLOCK_MULTI_BOOKMARKS is set TRUE, multiple bookmark support will
+* be forced off, and cannot to toggled on via the 'o'ptions menu.  This
+* compilation setting can be overridden via lynx.cfg.
+*/
+#ifndef BLOCK_MULTI_BOOKMARKS
+#define BLOCK_MULTI_BOOKMARKS FALSE
+#endif /* BLOCK_MULTI_BOOKMARKS */
+
+/*****************************
+* If ADVANCED_MULTI_BOOKMARKS is set FALSE, the associated prompting
+* feature will be disabled.  When it is TRUE, multiple bookmark support
+* is on, and the user mode is ADVANCED, the VIEW_BOOKMARK command will
+* invoke a statusline prompt at which the user can enter the letter token
+* of the desired bookmark, or '=' to get a menu of available bookmark
+* files.  The menu always is presented in NOVICE or INTERMEDIATE mode.
+* No prompting or menu display occurs if only one (the startup default)
+* bookmark file has been defined (define additional ones via the 'o'ptions
+* menu).  This compilation setting can be overridden via lynx.cfg.
+*/
+#ifndef ADVANCED_MULTI_BOOKMARKS
+#define ADVANCED_MULTI_BOOKMARKS TRUE
+#endif /* ADVANCED_MULTI_BOOKMARKS */
+
 /********************************
  * URL_DOMAIN_PREFIXES and URL_DOMAIN_SUFFIXES are strings which will be
  * prepended (together with a scheme://) and appended to the first element
@@ -599,6 +639,18 @@
  */
 #define LIST_NEWS_DATES FALSE
 
+/********************************
+ * If USE_SELECT_POPUPS is set FALSE, Lynx will present a vertical list
+ * of radio buttons for the OPTIONs in SELECT blocks which lack the
+ * MULTIPLE attribute, instead of using a popup menu.  Note that if
+ * the MULTIPLE attribute is present in the SELECT start tag, Lynx
+ * always will create a vertical list of checkboxes for the OPTIONs.
+ *
+ * The default defined here can be changed in lynx.cfg, and can be
+ * toggled via the -popup command line switch.
+ */
+#define USE_SELECT_POPUPS TRUE
+
 
 /****************************************************************
  *   Section 2.   Things that you probably want to change or review
diff --git a/utils/inews/Makefile b/utils/inews/Makefile
index 0f594f66..0380e783 100644
--- a/utils/inews/Makefile
+++ b/utils/inews/Makefile
@@ -1,15 +1,12 @@
 # Makefile for NN version of mini inews.
 #
-# $RCSfile: Makefile,v $	$Revision: 1.3 $
+# @RCSfile: Makefile,v @	@Revision: 1.3 @
 #
-# $Author: news $	$Date: 1989/12/21 17:59:52 $
+# @Author: news @	@Date: 89/12/21 17:59:52 @
 #
-# $State: Exp $	$Locker:  $
-#
-# $Log: Makefile,v $
-# Revision 1.3  1989/12/21 17:59:52  news
-# v2_6
+# @State: Exp @	@Locker:  @
 #
+# @Log:	Makefile,v @
 # Revision 1.3  89/12/21  17:59:52  news
 # Added kit processing, cleanups.
 #
@@ -23,14 +20,14 @@ CC	= cc
 # General definitions here which apply to all -- form -DDEF
 DEFS	= -DFOR_NN
 # Link libraries -- form -lLIB
-LIBS	=    # ../hostname.o
+LIBS	= -lsocket -lnsl -lucb
 # Lint definitions -- same as DEFS, but form -D DEF
 LDEFS	= -D lint -D FOR_NN
 # Lint libraries -- same as LIBS, but form -l LIB
 LLIBS	=
 # Set to -g for debugging, -O for optimise, or both if compiler handles it
 DEBUG	= -O
-CFLAGS	= $(DEBUG) $(DEFS) -I.. -I../conf
+CFLAGS	= $(DEBUG) $(DEFS) -I.. -I../conf -L/usr/ucblib
 
 SRCS	= inews.c clientlib.c version.c
 OBJS	= inews.o clientlib.o version.o
diff --git a/utils/inews/clientlib.c b/utils/inews/clientlib.c
index 38f9d68b..530cb1d1 100644
--- a/utils/inews/clientlib.c
+++ b/utils/inews/clientlib.c
@@ -22,7 +22,6 @@ static char	*sccsid = "@(#)clientlib.c	1.11	(Berkeley) 10/27/89";
 #ifndef FOR_NN
 #include <sys/types.h>
 #endif
-#include <sys/socket.h>
 #ifdef FOR_NN
 #if !defined(NETWORK_DATABASE) || defined(NETWORK_BYTE_ORDER)
 #include <netinet/in.h>
@@ -30,6 +29,7 @@ static char	*sccsid = "@(#)clientlib.c	1.11	(Berkeley) 10/27/89";
 #else
 #include <netinet/in.h>
 #endif
+#include <sys/socket.h>
 #ifndef EXCELAN
 # include <netdb.h>
 #endif not EXCELAN