about summary refs log tree commit diff stats
path: root/src/LYMainLoop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/LYMainLoop.c')
-rw-r--r--src/LYMainLoop.c3240
1 files changed, 3240 insertions, 0 deletions
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
new file mode 100644
index 00000000..bbef7371
--- /dev/null
+++ b/src/LYMainLoop.c
@@ -0,0 +1,3240 @@
+#include "HTUtils.h"
+#include "tcp.h"
+#include "HTAccess.h"
+#include "HTParse.h"
+#include "LYCurses.h"
+#include "LYGlobalDefs.h"
+#include "LYUtils.h"
+#include "GridText.h"
+#include "LYStrings.h"
+#include "LYOptions.h"
+#include "LYSignal.h"
+#include "LYGetFile.h"
+#include "HTForms.h"
+#include "LYSearch.h"
+#include "LYClean.h"
+#include "LYHistory.h"
+#include "LYPrint.h"
+#include "LYMail.h"
+#include "LYEdit.h"
+#include "LYShowInfo.h"
+#include "LYBookmark.h"
+#include "LYSystem.h"
+#include "LYKeymap.h"
+#include "LYJump.h"
+#include "LYDownload.h"
+#include "LYList.h"
+#include "LYMap.h"
+#include "LYTraversal.h"
+#include "LYCharSets.h"
+#include "LYCharUtils.h"
+#include "HTFTP.h"
+#include "HTTP.h"
+#include "HTAlert.h"
+
+#ifdef VMS
+#include "HTVMSUtils.h"
+#endif /* VMS */
+
+#ifdef DIRED_SUPPORT
+#include "LYLocal.h"
+#include "LYUpload.h"
+#endif /* DIRED_SUPPORT */
+
+#include "LYexit.h"
+#include "LYLeaks.h"
+
+extern BOOL reloading;		/* For Flushing Cache on Proxy Server */
+
+PRIVATE int are_different PARAMS((document *doc1, document *doc2));
+PUBLIC void HTGotoURLs_free NOPARAMS;
+PUBLIC void HTAddGotoURL PARAMS((char *url));
+
+#define FASTTAB
+#ifdef FASTTAB
+PRIVATE int sametext ARGS2(char *,een, char *,twee) {
+    if (een && twee)
+        return (strcmp(een, twee) == 0);
+    return TRUE;
+}
+#endif /* FASTTAB */
+
+#define FREE(x) if (x) {free(x); x = NULL;}
+
+PUBLIC  HTList * Goto_URLs = NULL;  /* List of Goto URLs */
+
+PUBLIC char * LYRequestTitle = NULL; /* newdoc.title in calls to getfile() */
+
+PRIVATE document newdoc;
+PRIVATE document curdoc;
+PRIVATE char *traversal_host = NULL;
+PRIVATE char *traversal_link_to_add = NULL;
+PRIVATE char *CurrentUserAgent = NULL;
+
+/*
+ *  Function for freeing allocated mainloop() variables. - FM
+ */
+PRIVATE void free_mainloop_variables NOARGS
+{
+    FREE(newdoc.title);
+    FREE(newdoc.address);
+    FREE(newdoc.post_data);
+    FREE(newdoc.post_content_type);
+    FREE(curdoc.title);
+    FREE(curdoc.address);
+    FREE(curdoc.post_data);
+    FREE(curdoc.post_content_type);
+    FREE(traversal_host);
+    FREE(traversal_link_to_add);
+    FREE(CurrentUserAgent);
+
+    return;
+}
+
+/*
+ * Here's where we do all the work.
+ * mainloop is basically just a big switch dependent on the users input.
+ * I have tried to offload most of the work done here to procedures to
+ * make it more modular, but this procedure still does a lot of variable
+ * manipulation.  This needs some work to make it neater. - Lou Moutilli
+ *					(memoir from the original Lynx - FM)
+ */
+
+int mainloop NOARGS
+{
+    int  c=0, real_c=0, old_c=0, cmd, arrowup=FALSE, show_help=FALSE;
+    int lines_in_file= -1;
+    int newline=0;
+    char prev_target[512];
+    char user_input_buffer[1024];
+    char *owner_address=NULL;  /* holds the responsible owner's address */
+    BOOLEAN first_file=TRUE;
+    BOOLEAN refresh_screen=FALSE;
+    BOOLEAN force_load = FALSE;
+    BOOLEAN crawl_ok = FALSE;
+    BOOLEAN rlink_exists;
+    BOOLEAN rlink_allowed;
+    BOOLEAN vi_keys_flag = vi_keys;
+    BOOLEAN emacs_keys_flag = emacs_keys;
+    BOOLEAN keypad_mode_flag = keypad_mode;
+    BOOLEAN HTfileSortMethod_flag = HTfileSortMethod;
+    int CurrentCharSet_flag = current_char_set;
+    BOOLEAN show_dotfiles_flag = show_dotfiles;
+    BOOLEAN LYRawMode_flag = LYRawMode;
+    char cfile[128];
+    FILE *cfp;
+    char *cp, *toolbar;
+#ifdef VMS
+    extern BOOLEAN HadVMSInterrupt;   /* Flag from cleanup_sig */
+#endif /* VMS */
+    int ch, recall;
+    int URLTotal;
+    int URLNum;
+    BOOLEAN FirstURLRecall = TRUE;
+    char *temp = NULL;
+
+#ifdef DIRED_SUPPORT
+    char *tp;
+    char tmpbuf[1024];
+    struct stat dir_info;
+    taglink *t1, *t2=NULL;
+#endif /* DIRED_SUPPORT */
+
+/*
+ *  curdoc.address contains the name of the file that is currently open
+ *  newdoc.address contains the name of the file that will soon be 
+ *		   opened if it exits
+ *  prev_target contains the last search string the user searched for
+ *  newdoc.title contains the link name that the user last chose to get into
+ *		   the current link (file)
+ */
+    /* initalize some variables*/
+    newdoc.address = NULL;
+    newdoc.title = NULL;
+    newdoc.post_data = NULL;
+    newdoc.post_content_type = NULL;
+    curdoc.address = NULL;
+    curdoc.title = NULL;
+    curdoc.post_data = NULL;
+    curdoc.post_content_type = NULL;
+    atexit(free_mainloop_variables);
+    if (strcmp(startfile, homepage))
+        HTAddGotoURL(homepage);
+    HTAddGotoURL(startfile);
+initialize:
+    nhist = 0;
+    StrAllocCopy(newdoc.address, startfile);
+    StrAllocCopy(startrealm, startfile);
+    StrAllocCopy(newdoc.title, "Entry into main screen");
+    newdoc.isHEAD=FALSE;
+    newdoc.line=1;
+    newdoc.link=0;
+    *prev_target='\0';
+    *user_input_buffer='\0';
+    StrAllocCopy(CurrentUserAgent, (LYUserAgent ?
+    				    LYUserAgent : ""));
+
+#ifdef USE_SLANG
+    if (TRACE && LYCursesON) {
+        addstr("\n");
+	refresh();
+    }
+#endif /* USE_SLANG */
+    if (TRACE)
+	fprintf(stderr,"Entering mainloop, startfile=%s\n",startfile);
+
+    if (form_post_data) {
+ 	StrAllocCopy(newdoc.post_data, form_post_data);
+ 	StrAllocCopy(newdoc.post_content_type,
+		     "application/x-www-form-urlencoded");
+    } else if (form_get_data) {
+ 	StrAllocCat(newdoc.address, form_get_data);
+    }
+
+    if (bookmark_start) {
+        if (LYValidate) {
+	    _statusline(BOOKMARKS_DISABLED);
+	    sleep(AlertSecs);
+	    bookmark_start = FALSE;
+	    goto initialize;
+        } else if (traversal) {
+	    _statusline(BOOKMARKS_NOT_TRAVERSED);
+	    sleep(AlertSecs);
+	    traversal = FALSE;
+	    crawl = FALSE;
+	    bookmark_start = FALSE;
+	    goto initialize;
+	} else {
+	    /* 
+	     * See if a bookmark page exists.  If it does,
+	     * replace newdoc.address with it's name 
+	     */
+	    if (get_bookmark_filename(&newdoc.address) != NULL) {
+		LYforce_HTML_mode = TRUE;  /* force HTML */
+		StrAllocCopy(newdoc.title, "Bookmark File");
+		StrAllocCopy(startrealm, newdoc.address);
+		FREE(newdoc.post_data);
+		FREE(newdoc.post_content_type);
+		newdoc.isHEAD = FALSE;
+		if (TRACE)
+		    fprintf(stderr, "Using bookmarks=%s\n", newdoc.address);
+	    } else {
+		_statusline(BOOKMARKS_NOT_OPEN);
+       		sleep(MessageSecs);
+		bookmark_start = FALSE;
+		goto initialize;
+	    }
+	}
+    }
+
+    if (form_post_data) {
+	FREE(form_post_data);
+    } else if (form_get_data) {
+	FREE(form_get_data);
+    }
+
+    if (user_mode==NOVICE_MODE)
+        display_lines = LYlines-4;
+    else
+        display_lines = LYlines-2;
+
+    while (TRUE) {
+	/* if newdoc.address is different then curdoc.address then we need 
+	 * to go out and find and load newdoc.address
+	 */
+	if (LYforce_no_cache || force_load ||
+	    are_different(&curdoc, &newdoc)) {
+
+		force_load = FALSE;  /* done */
+		if (TRACE && LYCursesON) {
+		    move(LYlines-1, LYcols-1);  /* make sure cursor is down */
+#ifdef USE_SLANG
+		    addstr("\n");
+#endif /* USE_SLANG */
+		    refresh();
+		}
+try_again:
+		/*
+		 * Push the old file onto the history stack.
+	 	 */
+		if (curdoc.address && newdoc.address) {
+		    LYpush(&curdoc);
+
+		} else if (!newdoc.address) {
+		    /*
+		     * If newdoc.address is empty then pop a file and load it.
+		     */
+                    LYpop(&newdoc);
+		    if (newdoc.post_data != NULL && LYresubmit_posts) {
+		        LYoverride_no_cache = FALSE;
+		    } else {
+		        LYoverride_no_cache = TRUE;
+		    }
+		}
+
+		if (HEAD_request) {
+		    /*
+		     *  Make SURE this is an appropriate request. - FM
+		     */
+		    if (!strncmp(newdoc.address, "http", 4))
+		        newdoc.isHEAD = TRUE;
+		    HEAD_request = FALSE;
+		}
+
+		LYRequestTitle = newdoc.title;
+		if (LYValidate &&
+		    startfile_ok &&
+		    (!strcmp(newdoc.address, startfile) ||
+		     !strcmp(newdoc.address, homepage))) {
+		    LYPermitURL = TRUE;
+		}
+		switch(getfile(&newdoc)) {
+
+		case NOT_FOUND:
+		    /*
+		     *  OK! can't find the file, so it must not be around now.
+		     *  Do any error logging, if appropriate.
+		     */
+		    LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
+		    if (error_logging && !first_file && owner_address &&
+		        !LYCancelledFetch) {
+		        /*
+			 *  Send an error message.
+			 */
+		        if (!strncasecomp(owner_address, "mailto:", 7)) {
+			    mailmsg(curdoc.link,
+			    	    (owner_address+7), 
+				    history[nhist-1].address,
+				    history[nhist-1].title);
+		        }
+		    } else if (traversal && !first_file && !LYCancelledFetch) {
+		        FILE *ofp;
+
+		        if ((ofp = fopen(TRAVERSE_ERRORS,"a+")) == NULL) {
+ 			    if ((ofp = fopen(TRAVERSE_ERRORS,"w")) == NULL) {
+			        perror(NOOPEN_TRAV_ERR_FILE);
+				(void) signal(SIGHUP, SIG_DFL);
+				(void) signal(SIGTERM, SIG_DFL);
+#ifndef VMS
+				(void) signal(SIGINT, SIG_DFL);
+#endif /* !VMS */
+#ifdef SIGTSTP
+				if (no_suspend)
+				    (void) signal(SIGTSTP,SIG_DFL);
+#endif /* SIGTSTP */
+			        exit(-1);
+			    }
+		        }
+		        fprintf(ofp, "%s %s	in %s\n",
+		       		     links[curdoc.link].lname, 
+				     links[curdoc.link].target,
+				     history[nhist-1].address);
+		        fclose(ofp);
+		    }
+
+		    /*
+		     *  Fall through to do the NULL stuff and reload the
+		     *  old file, unless the first file wasn't found or
+		     *  has gone missing
+		     */
+		    if (!nhist) { 
+			/* 
+			 * If nhist = 0 then it must be the first file.
+			 */
+			if (!dump_output_immediately)
+			    cleanup();
+		        printf("\nlynx: Can't access start file %s\n",
+			       startfile);
+			if (!dump_output_immediately) {
+			    (void) signal(SIGHUP, SIG_DFL);
+			    (void) signal(SIGTERM, SIG_DFL);
+#ifndef VMS
+			    (void) signal(SIGINT, SIG_DFL);
+#endif /* !VMS */
+#ifdef SIGTSTP
+			    if (no_suspend)
+				(void) signal(SIGTSTP,SIG_DFL);
+#endif /* SIGTSTP */
+			    exit(-1);
+			}
+			return(-1);
+		    }
+
+		case NULLFILE:
+		    /*
+		     * Not supposed to return any file.
+		     */
+		    LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
+		    FREE(newdoc.address); /* to pop last doc */
+		    LYJumpFileURL = FALSE;
+		    reloading = FALSE;
+		    LYPermitURL = FALSE;
+		    LYCancelledFetch = FALSE;
+		    if (traversal) {
+		        crawl_ok = FALSE;
+			if (traversal_link_to_add) {
+			    /*
+			     * It's a binary file, or the fetch attempt
+			     * failed.  Add it to TRAVERSE_REJECT_FILE
+			     * so we don't try again in this run.
+			     */
+			    if (!lookup_reject(traversal_link_to_add)) {
+			        add_to_reject_list(traversal_link_to_add);
+			    }
+		            FREE(traversal_link_to_add);
+			}
+		    }
+		   /*
+		    * Make sure the first file was found and
+		    * has not gone missing.
+		    */
+		   if (!nhist) { 
+		       /*
+		        * If nhist = 0 then it must be the first file.
+			*/
+		       if (first_file && homepage &&
+#ifdef VMS
+			   strcasecomp(homepage, startfile) != 0) {
+#else
+			   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
+			    * first URL causes a program to be invoked. - GL
+			    * 
+			    * But first make sure homepage is different from
+			    * startfile (above), then make it the same (below)
+			    * so we don't enter an infinite getfile() loop on
+			    * on failures to find the files. - FM
+			    */
+			   StrAllocCopy(newdoc.address, homepage);
+			   FREE(newdoc.post_data);
+			   FREE(newdoc.post_content_type);
+			   StrAllocCopy(startfile, homepage);
+			   newdoc.isHEAD = FALSE;
+		       } else {
+		           if (!dump_output_immediately)
+			       cleanup();
+			   printf(
+ "\nlynx: Start file could not be found or is not text/html or text/plain\n");
+			   printf("      Exiting...\n");
+		           if (!dump_output_immediately) {
+				(void) signal(SIGHUP, SIG_DFL);
+				(void) signal(SIGTERM, SIG_DFL);
+#ifndef VMS
+				(void) signal(SIGINT, SIG_DFL);
+#endif /* !VMS */
+#ifdef SIGTSTP
+				if (no_suspend)
+				    (void) signal(SIGTSTP,SIG_DFL);
+#endif /* SIGTSTP */
+			       exit(-1);
+			   }
+			   return(-1);
+		       }
+		    }
+
+		    goto try_again;
+                    break;
+
+		case NORMAL:
+		    /*
+		     * Marvelously, we got the document!
+		     */
+		    LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
+		    *prev_target = '\0';    /* Reset for this document. - FM */
+
+		    if (traversal) {
+		        /*
+			 * 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 */
+			    if (!lookup(traversal_link_to_add))
+			        add_to_table(traversal_link_to_add);
+			    FREE(traversal_link_to_add);
+			}
+			if (curdoc.address && curdoc.title)
+			    /* Add the address we got to TRAVERSE_FOUND_FILE */
+			    add_to_traverse_list(curdoc.address, curdoc.title);
+		    }
+
+		    /*
+		     *  If this was a NORMAL download, we still have curdoc,
+		     *  not a newdoc, so reset the address, title and
+		     *  positioning elements. - FM
+		     */
+		    if (newdoc.address && curdoc.title &&
+		        !strncmp(newdoc.address, "LYNXDOWNLOAD:", 13) &&
+		        !strcmp(curdoc.title, DOWNLOAD_OPTIONS_TITLE)) {
+			StrAllocCopy(newdoc.address, curdoc.address);
+			StrAllocCopy(newdoc.title, curdoc.title);
+			newdoc.line = curdoc.line;
+			newdoc.link = curdoc.link;
+		    }
+
+		    /*
+            	     * Set newline to the saved line.  It contains the
+		     * line the user was on if s/he has been in the file
+		     * before, or it is 1 if this is a new file.
+		     */
+                    newline = newdoc.line;
+
+		    /* 
+		     * If we are going to a target line,
+		     * override any www_search line result.
+		     */
+		    if (newline > 1)	
+			 www_search_result = -1;
+
+		    /*
+		     * Make sure curdoc.line will not be equal
+		     * to newline, so we get a redraw.
+		     */
+		    curdoc.line = -1;
+
+	  	    break;	
+		}  /* end switch */
+
+	   if (TRACE)
+	      sleep(AlertSecs); /* allow me to look at the results */
+
+	   /* set the files the same */
+	   StrAllocCopy(curdoc.address, newdoc.address);
+	   StrAllocCopy(curdoc.post_data, newdoc.post_data);
+	   StrAllocCopy(curdoc.post_content_type, newdoc.post_content_type);
+	   curdoc.isHEAD = newdoc.isHEAD;
+
+	   /*
+	    *  Reset WWW present mode so that if we were getting
+	    *  the source, we get rendered HTML from now on.
+	    */
+	   HTOutputFormat = WWW_PRESENT;
+	   /*
+	    *  Reset all of the other relevant flags. - FM
+	    */
+	   LYUserSpecifiedURL = FALSE;	/* only set for goto's and jumps's */
+	   LYJumpFileURL = FALSE;	/* only set for jump's */
+	   LYNoRefererForThis = FALSE;	/* always reset on return here */
+	   reloading = FALSE;		/* only set for RELOAD and RESUBMIT */
+	   HEAD_request = FALSE;	/* only set for HEAD requests */
+	   LYPermitURL = FALSE;		/* only set for LYValidate */
+
+  	} /* end if (STREQ(newdoc.address,curdoc.address) */
+
+        if (dump_output_immediately) {
+	    if (crawl) {
+                if (HText_getTitle())
+	            StrAllocCopy(curdoc.title, HText_getTitle());
+                print_crawl_to_fd(stdout,curdoc.address,curdoc.title);
+	    } else {
+                print_wwwfile_to_fd(stdout,0);
+	    }
+	    return(0);
+	}
+
+	/* if the resent_sizechange variable is set to true
+	   then the window size changed recently. 
+	*/
+	if (recent_sizechange) {
+		stop_curses();
+		start_curses(); 
+		clear();
+		refresh_screen = TRUE; /*to force a redraw */
+		recent_sizechange=FALSE;
+		if (user_mode==NOVICE_MODE) {
+		    display_lines = LYlines-4;
+		} else {
+		    display_lines = LYlines-2;
+		}
+	}
+
+        if (www_search_result != -1) {
+             /* This was a WWW search, set the line
+              * to the result of the search
+              */
+             newline = www_search_result;
+             www_search_result = -1;  /* reset */
+	     more = HText_canScrollDown();
+        }
+
+	if (first_file == TRUE) {
+	    /*
+	     * We can never again have the first file.
+	     */
+	    first_file = FALSE; 
+
+	    temp = HTParse(curdoc.address, "",
+			   PARSE_ACCESS+PARSE_HOST+PARSE_PUNCTUATION);
+	    if (!temp || *temp == '\0') {
+		StrAllocCopy(startrealm, "None");
+	    } else {
+		StrAllocCopy(startrealm, temp);
+		FREE(temp);
+		if (!(temp = HTParse(curdoc.address, "",
+		    		     PARSE_PATH+PARSE_PUNCTUATION))) {
+		    if (startrealm[strlen(startrealm)-1] != '/') {
+			StrAllocCat(startrealm, "/");
+		    }
+		} else {
+		    if ((cp = strrchr(temp, '/')) != NULL) {
+			*(cp+1) = '\0';
+			StrAllocCat(startrealm, temp);
+		    }
+		}
+	    }
+	    FREE(temp);
+	    if (TRACE) {
+		fprintf(stderr, "Starting realm is '%s'\n\n", startrealm);
+	    }
+	    if (traversal) {
+	        /*
+		 * Set up the crawl output stuff.
+		 */
+		if (curdoc.address && !lookup(curdoc.address)) {
+		    crawl_ok = TRUE;
+		    add_to_table(curdoc.address);
+		}
+		/*
+		 * Set up the traversal_host comparison string.
+		 */
+		if (strncmp((curdoc.address ? curdoc.address : "NULL"),
+			    "http", 4)) {
+		    StrAllocCopy(traversal_host, "None");
+		} else if (check_realm) {
+		    StrAllocCopy(traversal_host, startrealm);
+		} else {
+		    char *temp = HTParse(curdoc.address, "",
+		    		 PARSE_ACCESS+PARSE_HOST+PARSE_PUNCTUATION);
+		    if (!temp || *temp == '\0') {
+		        StrAllocCopy(traversal_host, "None");
+		    } else {
+		        StrAllocCopy(traversal_host, temp);
+			if (traversal_host[strlen(traversal_host)-1] != '/') {
+			    StrAllocCat(traversal_host, "/");
+			}
+		    }
+		    FREE(temp);
+		}
+		if (TRACE) {
+		    fprintf(stderr,
+		    	    "Traversal host is '%s'\n\n", traversal_host);
+		}
+	    }
+	    if (TRACE) {
+		refresh_screen = TRUE;
+		sleep(AlertSecs);
+	    }
+	}
+
+	/* if the curdoc.line is different than newline then there must
+	 * have been a change since last update. Run showpage.
+	 * showpage will put a fresh screen of text out.
+	 * If this is a WWW document then use the 
+	 * WWW routine HText_pageDisplay to put the page on
+	 * the screen
+         */
+	if (curdoc.line != newline) {
+	
+   	    refresh_screen = FALSE;
+
+	    HText_pageDisplay(newline, prev_target);
+
+#ifdef DIRED_SUPPORT
+	    if (lynx_edit_mode && nlinks > 0 && tagged != NULL)
+	      showtags(tagged);
+#endif /* DIRED_SUPPORT */
+	    /* if more equals true then there is more
+	     * info below this page 
+	     */
+	    more = HText_canScrollDown();
+	    curdoc.line = newline = HText_getTopOfScreen()+1;
+            lines_in_file = HText_getNumOfLines();
+
+            if (HText_getTitle()) {
+	        StrAllocCopy(curdoc.title, HText_getTitle());
+	    } else {
+	        StrAllocCopy(curdoc.title, newdoc.title);
+	    }
+	   owner_address = HText_getOwner();
+
+	   if (arrowup) { 
+		/* arrow up is set if we just came up from
+		 * a page below 
+		 */
+	        curdoc.link = nlinks - 1;
+	        arrowup = FALSE;
+	   } else {
+	        curdoc.link = newdoc.link;
+		if (curdoc.link >= nlinks)
+	            curdoc.link = nlinks - 1;
+	   }
+
+	   show_help = FALSE; /* reset */
+	   newdoc.line = 1;
+	   newdoc.link = 0;
+	   curdoc.line = newline; /* set */
+	}
+
+	/* refesh the screen if neccessary */
+	if (refresh_screen) {
+	    clear();
+	    HText_pageDisplay(newline, prev_target);
+
+#ifdef DIRED_SUPPORT
+	    if (lynx_edit_mode && nlinks > 0 && tagged != NULL)
+	        showtags(tagged);
+#endif /* DIRED_SUPPORT */
+	    if (user_mode == NOVICE_MODE)
+		noviceline(more);  /* print help message */
+	    refresh_screen=FALSE;
+
+	}
+
+	/* report unread or new mail, if appropriate */
+	if (check_mail && !no_mail && LYCheckMail())
+	    sleep(MessageSecs);
+
+	/* if help is not on the screen 
+	 * then put a message on the screen
+	 * to tell the user other misc info
+	 */
+	if (!show_help) {
+	    /* make sure form novice lines are replaced */
+	    if (user_mode == NOVICE_MODE) {
+		noviceline(more);
+	    }
+
+	    /* if we are in forms mode then explicitly
+	     * tell the user what each kind of link is
+	     */
+	    if (HTisDocumentSource()) {
+		/* currently displaying HTML source */
+		_statusline(SOURCE_HELP);
+
+#ifdef INDICATE_FORMS_MODE_FOR_ALL_LINKS_ON_PAGE
+	    } else if (lynx_mode == FORMS_LYNX_MODE && nlinks > 0) {
+#else
+#ifdef NORMAL_NON_FORM_LINK_STATUSLINES_FOR_ALL_USER_MODES
+	    } else if (lynx_mode == FORMS_LYNX_MODE && nlinks > 0 &&
+	    	       links[curdoc.link].type != WWW_LINK_TYPE) {
+#else
+	    } else if (lynx_mode == FORMS_LYNX_MODE && nlinks > 0 &&
+	    	       !(user_mode == ADVANCED_MODE &&
+	    	         links[curdoc.link].type == WWW_LINK_TYPE)) {
+#endif /* NORMAL_NON_FORM_LINK_STATUSLINES_FOR_ALL_USER_MODES */
+#endif /* INDICATE_FORMS_MODE_FOR_ALL_LINKS_ON_PAGE */
+                if (links[curdoc.link].type == WWW_FORM_LINK_TYPE)
+		    switch(links[curdoc.link].form->type) {
+                    case F_PASSWORD_TYPE:
+		  	if (links[curdoc.link].form->disabled == YES)
+			    statusline(FORM_LINK_PASSWORD_UNM_MSG);
+   			else
+                            statusline(FORM_LINK_PASSWORD_MESSAGE);
+		        break;
+		    case F_OPTION_LIST_TYPE:
+		  	if (links[curdoc.link].form->disabled == YES)
+			    statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
+   			else
+                            statusline(FORM_LINK_OPTION_LIST_MESSAGE);
+			break;
+                    case F_CHECKBOX_TYPE:
+		  	if (links[curdoc.link].form->disabled == YES)
+			    statusline(FORM_LINK_CHECKBOX_UNM_MSG);
+   			else
+                            statusline(FORM_LINK_CHECKBOX_MESSAGE);
+		        break;
+                    case F_RADIO_TYPE:
+		  	if (links[curdoc.link].form->disabled == YES)
+			    statusline(FORM_LINK_RADIO_UNM_MSG);
+   			else
+                            statusline(FORM_LINK_RADIO_MESSAGE);
+		        break;
+                    case F_TEXT_SUBMIT_TYPE:
+		  	if (links[curdoc.link].form->disabled == YES) {
+			    statusline(FORM_LINK_TEXT_SUBMIT_UNM_MSG);
+			} else if (links[curdoc.link].form->submit_method ==
+				 URL_MAIL_METHOD) {
+			    if (no_mail)
+			        statusline(
+				       FORM_LINK_TEXT_SUBMIT_MAILTO_DIS_MSG);
+			    else
+ 			        statusline(FORM_LINK_TEXT_SUBMIT_MAILTO_MSG);
+   			} else if (links[curdoc.link].form->no_cache) {
+                            statusline(FORM_LINK_TEXT_RESUBMIT_MESSAGE);
+   			} else {
+                            statusline(FORM_LINK_TEXT_SUBMIT_MESSAGE);
+			}
+		        break;
+                    case F_SUBMIT_TYPE:
+		  	if (links[curdoc.link].form->disabled == YES) {
+			    statusline(FORM_LINK_SUBMIT_DIS_MSG);
+			} else if (links[curdoc.link].form->submit_method ==
+				 URL_MAIL_METHOD) {
+			    if (no_mail) {
+			        statusline(FORM_LINK_SUBMIT_MAILTO_DIS_MSG);
+			    } else {
+ 			        statusline(FORM_LINK_SUBMIT_MAILTO_MSG);
+			    }
+   			} else if (links[curdoc.link].form->no_cache) {
+                            statusline(FORM_LINK_RESUBMIT_MESSAGE);
+ 			} else { 
+                            statusline(FORM_LINK_SUBMIT_MESSAGE);
+			}
+		        break;
+                    case F_RESET_TYPE:
+		  	if (links[curdoc.link].form->disabled == YES)
+			    statusline(FORM_LINK_RESET_DIS_MSG);
+   			else
+                            statusline(FORM_LINK_RESET_MESSAGE);
+		        break;
+                    case F_TEXT_TYPE:
+		    case F_TEXTAREA_TYPE:
+		  	if (links[curdoc.link].form->disabled == YES)
+			    statusline(FORM_LINK_TEXT_UNM_MSG);
+   			else
+                            statusline(FORM_LINK_TEXT_MESSAGE);
+		        break;
+                    }
+		else
+	            statusline(NORMAL_LINK_MESSAGE);
+
+		/* let them know if it's an index -- very rare*/
+		if (is_www_index) {
+		    move(LYlines-1,LYcols-8);
+		    start_reverse();
+		    addstr("-index-");
+		    stop_reverse();
+		}
+			
+	    } else if (user_mode == ADVANCED_MODE && nlinks > 0) {
+		/* show the URL */
+		if (more)
+		    if (is_www_index)
+		        _user_message("-more- -index- %s",
+						 links[curdoc.link].lname);
+		    else
+		        _user_message("-more- %s",links[curdoc.link].lname);
+		else
+		    if (is_www_index)
+		        _user_message("-index- %s",links[curdoc.link].lname);
+		    else
+		        statusline(links[curdoc.link].lname);
+	    } else if (is_www_index && more) {
+		char buf[128];
+
+		sprintf(buf, WWW_INDEX_MORE_MESSAGE, key_for_func(LYK_INDEX_SEARCH));
+		_statusline(buf);
+	    } else if (is_www_index) {
+		char buf[128];
+
+		sprintf(buf, WWW_INDEX_MESSAGE, key_for_func(LYK_INDEX_SEARCH));
+		_statusline(buf);
+	    } else if (more) {
+		if (user_mode == NOVICE_MODE)
+			_statusline(MORE);
+		else
+			_statusline(MOREHELP);
+	    } else {
+	       _statusline(HELP);
+   	    }	     
+	} else {
+	   show_help = FALSE;
+	}
+
+	if (!(nlinks > 0 &&
+	      links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
+              (links[curdoc.link].form->type == F_TEXT_TYPE ||
+	       links[curdoc.link].form->type == F_TEXTAREA_TYPE)))
+	    highlight(ON, curdoc.link); /* highlight current link */
+
+	if (traversal) {
+	    /*
+	     * Don't go interactively into forms,
+	     * or accept keystrokes from the user
+	     */
+            if (crawl && crawl_ok) {
+	        crawl_ok = FALSE;
+	        sprintf(cfile,"lnk%08d.dat",ccount);
+	        ccount = ccount + 1;
+	        if ((cfp = fopen(cfile,"w"))  != NULL) {
+	            print_crawl_to_fd(cfp,curdoc.address,curdoc.title);
+	            fclose(cfp);
+	        } else {
+		    if (!dump_output_immediately)
+		        cleanup();
+	            printf(
+		        "Fatal error - could not open output file %s\n",cfile);
+		    if (!dump_output_immediately) {
+			(void) signal(SIGHUP, SIG_DFL);
+			(void) signal(SIGTERM, SIG_DFL);
+#ifndef VMS
+			(void) signal(SIGINT, SIG_DFL);
+#endif /* !VMS */
+#ifdef SIGTSTP
+			if (no_suspend)
+			    (void) signal(SIGTSTP,SIG_DFL);
+#endif /* SIGTSTP */
+	                exit(-1);
+		    }
+		    return(-1);
+	        }
+	    }
+	} else {
+	    /*
+	     * Normal, non-traversal handling
+	     */
+	    if (nlinks > 0 &&
+	    	links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
+		(links[curdoc.link].form->type == F_TEXT_TYPE ||
+		 links[curdoc.link].form->type == F_TEXT_SUBMIT_TYPE ||
+		 links[curdoc.link].form->type == F_PASSWORD_TYPE ||
+		 links[curdoc.link].form->type == F_TEXTAREA_TYPE)) {
+	        /*
+		 * Replace novice lines if in NOVICE_MODE
+		 */
+    	        if (user_mode==NOVICE_MODE) {
+		    move(LYlines-2,0); clrtoeol();
+		    addstr(FORM_NOVICELINE_ONE);
+		    move(LYlines-1,0); clrtoeol();
+		    addstr(FORM_NOVICELINE_TWO);
+	        }
+	        c=change_form_link(&links[curdoc.link],
+			       FORM_UP, &newdoc, &refresh_screen,
+			       links[curdoc.link].form->name,
+			       links[curdoc.link].form->value);
+
+	        if (c == '\n' || c == '\r')
+#ifdef FASTTAB
+		    /*
+		     * Make return act like downarrow
+		     */
+		    c = DNARROW;
+#else
+		    /*
+		     * Make return act like tab
+		     */
+		    c = '\t';
+#endif /* FASTTAB */
+	    } else {
+	        /* Get a keystroke from the user
+	         * Save the last keystroke to avoid redundant
+		 * error reporting.
+	         */
+	        real_c = c = LYgetch();	/* get user input */
+#ifndef VMS
+		if (c == 3) {		/* ^C */
+		    /* This shouldn't happen.  We'll try to
+		     * deal with whatever bug caused it. - FM
+		     */
+		    signal(SIGINT, cleanup_sig);
+		    old_c = 0;
+		    cmd = LYK_QUIT;
+		    goto new_cmd;
+		}
+#endif /* !VMS */
+	        if (old_c != real_c) {
+		    old_c = 0;
+	        }
+	    }
+      	}
+
+#ifdef VMS
+        if (HadVMSInterrupt) {
+            HadVMSInterrupt = FALSE;
+            c = DO_NOTHING;
+        }
+#else
+	if (recent_sizechange) {
+	    if (c <= 0)
+	        c = DO_NOTHING;
+	}
+#endif /* VMS */
+
+new_keyboard_input:
+	/* a goto point for new input without going
+         * back through the getch() loop
+         */
+	if (traversal) {
+	    /*
+	     * This is a special feature to traverse every http link
+	     * derived from startfile and check for errors or create
+	     * crawl ouput files.  Only URL's that begin with
+	     * "traversal_host" are searched - this keeps the search
+	     * from crossing to other servers (a feature, not a bug!)
+	     */
+	    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)));
+	    } else {	
+	        rlink_allowed = FALSE;
+	    }
+	    if (rlink_exists && rlink_allowed) {
+	        if (lookup(links[curdoc.link].lname)) {
+		    if (more_links ||
+			(curdoc.link > -1 && curdoc.link < nlinks -1))
+		        c=DNARROW;
+		    else {
+		        if (STREQ(curdoc.title,"Entry into main screen") ||
+			    (nhist <= 0 )) {
+			    if (!dump_output_immediately) {
+			        cleanup();
+				(void) signal(SIGHUP, SIG_DFL);
+				(void) signal(SIGTERM, SIG_DFL);
+#ifndef VMS
+				(void) signal(SIGINT, SIG_DFL);
+#endif /* !VMS */
+#ifdef SIGTSTP
+				if (no_suspend)
+				    (void) signal(SIGTSTP,SIG_DFL);
+#endif /* SIGTSTP */
+			        exit(-1);
+			    }
+			    return(-1);
+			}
+			c=LTARROW;
+		    }
+		} else {
+		    StrAllocCopy(traversal_link_to_add,
+		    		 links[curdoc.link].lname);
+		    crawl_ok = TRUE;
+		    c = RTARROW;
+		}
+	    } else { /* no good right link, so only down and left arrow ok*/
+	        if (rlink_exists)
+		    add_to_reject_list(links[curdoc.link].lname);
+		if (more_links ||
+		    (curdoc.link > -1 && curdoc.link < nlinks-1))
+ 		    c=DNARROW;
+		else {
+		    /*
+		     * curdoc.title doesn't always work, so
+		     * bail out if the history list is empty.
+		     */
+		    if (STREQ(curdoc.title,"Entry into main screen") ||
+	                (nhist <= 0 )) {
+			if (!dump_output_immediately) {
+			    cleanup();
+			    (void) signal(SIGHUP, SIG_DFL);
+			    (void) signal(SIGTERM, SIG_DFL);
+#ifndef VMS
+			    (void) signal(SIGINT, SIG_DFL);
+#endif /* !VMS */
+#ifdef SIGTSTP
+			    if (no_suspend)
+				(void) signal(SIGTSTP,SIG_DFL);
+#endif /* SIGTSTP */
+		            exit(-1);
+			}
+			return(-1);
+		    }
+	            c=LTARROW;
+		}
+	    } /* right link not NULL or link to another site*/
+	} /* traversal */
+
+	cmd=keymap[c+1];  /* add 1 to map EOF to 0 */
+
+#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
+	if (lynx_edit_mode && override[c+1] && !no_dired_support)
+	  cmd = override[c+1];
+#endif /* DIRED_SUPPORT && OK_OVERRIDE */
+
+new_cmd:  /* a goto point for new input without going
+           * back through the getch() loop
+           */
+
+	switch(cmd) {
+	case 0: /* unmapped character */
+	default:
+	    if (more)
+                _statusline(MOREHELP);
+            else
+                _statusline(HELP);
+            show_help = TRUE;
+
+            if (TRACE)
+                printw("%d", c);  /* show the user input */
+            break;
+
+	case LYK_INTERRUPT:
+	    /* No network transmission to interrupt - 'til we multithread */
+	    break;
+
+	case LYK_1:
+	case LYK_2:
+	case LYK_3:
+	case LYK_4:
+	case LYK_5:
+	case LYK_6:
+	case LYK_7:
+	case LYK_8:
+	case LYK_9:
+	    /* get a number from the user and follow that link number */
+	    switch(follow_link_number(c, ((nlinks > 0) ? curdoc.link : 0))) {
+	    case DO_LINK_STUFF:
+                /* follow a normal link */
+		if (nlinks > 0)
+                    StrAllocCopy(newdoc.address, links[curdoc.link].lname);
+		else
+		    StrAllocCopy(newdoc.address, links[0].lname);
+		/*
+		 * Might be an anchor in the same doc from a POST
+		 * form.  If so, don't free the content. -- FM
+		 */
+		if (are_different(&curdoc, &newdoc)) {
+		    FREE(newdoc.post_data);
+		    FREE(newdoc.post_content_type);
+		    newdoc.isHEAD = FALSE;
+		}
+		force_load = TRUE;  /* force MainLoop to reload */
+		break;
+
+	    case PRINT_ERROR:
+		if (old_c == real_c)
+		    break;
+		old_c = real_c;
+		_statusline(BAD_LINK_NUM_ENTERED);
+		sleep(MessageSecs);
+		break;
+	    }
+	    break;
+
+	case LYK_SOURCE:  /* toggle view source mode */
+	    if (HTisDocumentSource()) 
+	        HTOutputFormat = WWW_PRESENT;
+	    else
+	        HTOutputFormat = WWW_SOURCE;
+	    HTuncache_current_document();
+	    FREE(curdoc.address); /* so it doesn't get pushed */
+	    break;
+
+	case LYK_RELOAD:  /* control-R to reload and refresh */
+	    /*
+	     * Check to see if should reload source, or load html
+	     */
+	    if (HTisDocumentSource()) {
+		HTOutputFormat = WWW_SOURCE;
+	    }
+	    HEAD_request = HTLoadedDocumentIsHEAD();
+	    HTuncache_current_document();
+#ifdef NO_ASSUME_SAME_DOC
+	    /*
+	     * Don't assume the reloaded document will be the same. - FM
+	     */
+	    newdoc.line=1;
+	    newdoc.link=0;
+#else
+	    /*
+	     * Do assume the reloaded document will be the same. - FM
+	     * (I don't remember all the reasons why we couldn't assume
+	     *  this.  As the problems show up, we'll try to fix them,
+	     *  or add warnings.  - FM)
+	     */
+	    if (lynx_mode == FORMS_LYNX_MODE) {
+	        /*
+		 * Note that if there are no form links on the current
+		 * page, lynx_mode won't have this setting and we won't
+		 * know that this warning should be issued. - FM
+		 */
+		_statusline(RELOADING_FORM);
+		sleep(AlertSecs);
+	    }
+	    newdoc.line = ((curdoc.line > 0) ? curdoc.line : 1);
+	    newdoc.link = ((curdoc.link > -1) ? curdoc.link : 0);
+#endif /* NO_ASSUME_SAME_DOC */
+	    FREE(curdoc.address); /* so it doesn't get pushed */
+#ifdef VMS
+	    clearok(curscr, TRUE);
+#endif /* VMS */
+	    /*
+	     * Reload should force a cache refresh on a proxy
+	     *        -- Ari L. <luotonen@dxcern.cern.ch>
+	     */
+            reloading = TRUE;
+	    break;
+
+	case LYK_HISTORICAL:  
+	    HTuncache_current_document();
+	    StrAllocCopy(newdoc.address, curdoc.address);
+	    FREE(curdoc.address);
+	    if (historical_comments)
+	        historical_comments = FALSE;
+	    else
+	        historical_comments = TRUE;
+	    if (minimal_comments) {
+	        _statusline(historical_comments ?
+		      HISTORICAL_ON_MINIMAL_OFF : HISTORICAL_OFF_MINIMAL_ON);
+	    } else {
+	        _statusline(historical_comments ?
+			HISTORICAL_ON_VALID_OFF : HISTORICAL_OFF_VALID_ON);
+	    }
+	    sleep(AlertSecs);
+	    break;
+
+	case LYK_MINIMAL:  
+	    if (!historical_comments) {
+	        HTuncache_current_document();
+	        StrAllocCopy(newdoc.address, curdoc.address);
+	        FREE(curdoc.address);
+	    }
+	    if (minimal_comments)
+	        minimal_comments = FALSE;
+	    else
+	        minimal_comments = TRUE;
+	    if (!historical_comments) {
+	        _statusline(minimal_comments ?
+			MINIMAL_ON_IN_EFFECT : MINIMAL_OFF_VALID_ON);
+	    } else {
+	        _statusline(minimal_comments ?
+		   MINIMAL_ON_BUT_HISTORICAL : MINIMAL_OFF_HISTORICAL_ON);
+	    }
+	    sleep(AlertSecs);
+	    break;
+
+	case LYK_SOFT_DQUOTES:  
+	    HTuncache_current_document();
+	    StrAllocCopy(newdoc.address, curdoc.address);
+	    FREE(curdoc.address);
+	    if (soft_dquotes)
+	        soft_dquotes = FALSE;
+	    else
+	        soft_dquotes = TRUE;
+	    _statusline(soft_dquotes ?
+		SOFT_DOUBLE_QUOTE_ON : SOFT_DOUBLE_QUOTE_OFF);
+	    sleep(MessageSecs);
+	    break;
+
+#ifdef NOT_DONE_YET
+	case LYK_PIPE:  
+	    /* ignore for now */
+	    break;
+#endif /* NOT_DONE_YET */
+
+	case LYK_QUIT:	/* quit */
+	    _statusline(REALLY_QUIT);
+	    c = LYgetch();
+#ifdef QUIT_DEFAULT_YES
+	    if (TOUPPER(c) != 'N')
+#else
+	    if (TOUPPER(c) == 'Y')
+#endif /* QUIT_DEFAULT_YES */
+	        return(0);
+	    else {
+	        statusline(NO_CANCEL);
+		sleep(InfoSecs);
+	    }
+	    break;
+	
+	case LYK_ABORT:
+	    return(0);  /* dont ask the user about quitting */
+	    break;
+
+	case LYK_NEXT_PAGE:	/* next page */
+	    if (more) {
+	        newline += display_lines;
+	    } else if (curdoc.link < nlinks-1) {
+		highlight(OFF,curdoc.link);
+		curdoc.link = nlinks-1;  /* put on last link */
+	    } else if (old_c != real_c) {
+		   old_c = real_c;
+		   _statusline(ALREADY_AT_END);
+		   sleep(MessageSecs);
+	    }
+	    break;
+
+	case LYK_PREV_PAGE:  /* page up */
+	    if (newline > 1) {
+		newline -= display_lines;
+	    } else if (curdoc.link > 0) {
+		highlight(OFF,curdoc.link);
+		curdoc.link = 0;  /* put on last link */
+	    } else if (old_c != real_c) {
+		old_c = real_c;
+		_statusline(ALREADY_AT_BEGIN);
+		sleep(MessageSecs);
+	    }
+	    break;
+
+	case  LYK_UP_TWO:
+	    if (newline > 1) {
+	        newline -= 2;
+		if (nlinks > 0 && curdoc.link > -1) {
+		    if (links[curdoc.link].ly <= (display_lines - 2)) {
+		        newdoc.link = curdoc.link +
+				      HText_LinksInLines(HTMainText,
+				      			 newline, 2);
+		    } else {
+		        arrowup = TRUE;
+		    }
+		}
+	    } else if (old_c != real_c) {
+		old_c = real_c;
+		_statusline(ALREADY_AT_BEGIN);
+		sleep(MessageSecs);
+	    }
+	    break;
+
+	case  LYK_DOWN_TWO:
+	    if (more) {
+	        newline += 2;
+		if (nlinks > 0 && curdoc.link > -1 &&
+		    links[curdoc.link].ly > 2) {
+		    int i;
+		    newdoc.link = curdoc.link;
+		    for (i = 0; links[i].ly <= 2; i++)
+		        --newdoc.link;
+		}
+	    } else if (old_c != real_c) {
+		old_c = real_c;
+		_statusline(ALREADY_AT_END);
+		sleep(MessageSecs);
+	    }
+	    break;
+
+	case  LYK_UP_HALF:
+	    if (newline > 1) {
+	        newline -= display_lines/2;
+		if (nlinks > 0 && curdoc.link > -1) {
+		    if (links[curdoc.link].ly <= (display_lines/2)) {
+		        newdoc.link = curdoc.link +
+				      HText_LinksInLines(HTMainText,
+				      			 newline,
+							 (display_lines/2));
+		    } else {
+		        arrowup = TRUE;
+		    }
+		}
+	    } else if (old_c != real_c) {
+		old_c = real_c;
+		_statusline(ALREADY_AT_BEGIN);
+		sleep(MessageSecs);
+	    }
+	    break;
+
+	case  LYK_DOWN_HALF:
+	    if (more) {
+	        newline += (display_lines/2);
+		if (nlinks > 0 && curdoc.link > -1 &&
+		    links[curdoc.link].ly > display_lines/2) {
+		    int i;
+		    newdoc.link = curdoc.link;
+		    for (i = 0; links[i].ly <= (display_lines/2); i++)
+		        --newdoc.link;
+		}
+	    } else if (old_c != real_c) {
+		old_c = real_c;
+		_statusline(ALREADY_AT_END);
+		sleep(MessageSecs);
+	    }
+	    break;
+
+	case LYK_REFRESH:
+	   refresh_screen=TRUE;
+#ifdef VMS
+	   clearok(curscr, TRUE);
+#endif /* VMS */
+	   break;
+
+	case LYK_HOME:
+	    if (curdoc.line > 1)
+	        newline = 1;
+	    else {
+		cmd = LYK_PREV_PAGE;
+		goto new_cmd;
+	    }
+	    break;
+
+	case LYK_END:
+	    if (more) {
+	       newline = MAXINT; /* go to end of file */
+	       arrowup = TRUE;  /* position on last link */
+	    } else {
+		cmd = LYK_NEXT_PAGE;
+		goto new_cmd;
+	    }
+	    break;
+
+	case LYK_PREV_LINK:
+	    if (curdoc.link > 0) {		/* previous link */
+		highlight(OFF, curdoc.link);   /* unhighlight the current link */
+		curdoc.link--;
+
+	    } else if (!more && curdoc.link==0 && newline==1) { /* at the top of list */ 
+		/* if there is only one page of data and the user
+		 * goes off the top, then just move the cursor to
+		 * last link on the page
+		 */
+		highlight(OFF,curdoc.link); /* unhighlight the current link */
+		curdoc.link = nlinks-1;  /* the last link */
+
+	    } else if (curdoc.line > 1) {	/* previous page */
+		/* go back to the previous page */
+		newline -= (display_lines);
+		arrowup = TRUE;
+
+	    } else if (old_c != real_c) {
+		old_c = real_c;
+		_statusline(ALREADY_AT_FIRST);
+		sleep(MessageSecs);
+	    }
+	    break;
+
+	case LYK_NEXT_LINK:
+	    if (curdoc.link < nlinks-1) {	/* next link */
+		highlight(OFF, curdoc.link);
+#ifdef FASTTAB
+		/*
+		 * Move to different textarea if TAB in textarea.
+		 */
+		if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
+                    links[curdoc.link].form->type == F_TEXTAREA_TYPE &&
+                    c=='\t') {
+		    int thisgroup = links[curdoc.link].form->number;
+		    char *thisname = links[curdoc.link].form->name;
+
+		    do curdoc.link++;
+		    while ((curdoc.link < nlinks-1) &&
+			   links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
+			   links[curdoc.link].form->type == F_TEXTAREA_TYPE &&
+			   links[curdoc.link].form->number == thisgroup &&
+			   sametext(links[curdoc.link].form->name, thisname));
+		} else {
+		    curdoc.link++;
+		}
+#else
+		curdoc.link++;
+#endif /* FASTTAB */
+	    /*
+	     * At the bottom of list and there is only one page. 
+	     * Move to the top link on the page.
+	     */
+	    } else if (!more && newline == 1 && curdoc.link == nlinks-1) {
+		highlight(OFF,curdoc.link); 
+		curdoc.link = 0;
+
+            } else if (more) {  /* next page */
+                 newline += (display_lines);
+
+	    } else if (old_c != real_c) {
+		old_c = real_c;
+		_statusline(ALREADY_AT_END);
+		sleep(MessageSecs);
+	    }
+	    break;
+
+        case LYK_UP_LINK:
+            if (curdoc.link > 0) {  /* more links above? */
+                int i, newlink = -1;
+                for (i = curdoc.link; i >= 0; i--) {
+                    if (links[i].ly < links[curdoc.link].ly) {
+                        newlink = i;
+                        break;
+                    }
+		}
+                if (newlink > -1) {
+                    highlight(OFF, curdoc.link);
+                    curdoc.link = newlink;
+#ifdef NOTDEFINED
+                } else if (!more && newline == 1 && curdoc.link == 0) {
+                    highlight(OFF, curdoc.link);
+                    curdoc.link = (nlinks-1);
+                } else if (more) {  /* next page */
+                        newline += (display_lines);
+                }
+#else
+		} else if (old_c != real_c) {
+		    old_c = real_c;
+		    _statusline(NO_LINKS_ABOVE);
+		    sleep(MessageSecs);
+		}
+#endif /* NOTDEFINED */
+
+#ifdef NOTDEFINED
+            /* at the bottom of list and there is only one page
+             * move to the top link on the page
+             */
+            } else if (!more && newline == 1 && curdoc.link == (nlinks-1)) {
+                highlight(OFF, curdoc.link);
+                curdoc.link = 0;
+#endif /* NOTDEFINED */
+
+            } else if (curdoc.line > 1 && newline > 1) {  /* previous page */
+                    newline -= (display_lines);
+		    arrowup = TRUE;
+
+	    } else if (old_c != real_c) {
+		old_c = real_c;
+		_statusline(ALREADY_AT_BEGIN);
+		sleep(MessageSecs);
+            }
+            break;
+
+	case LYK_DOWN_LINK:
+	    if (curdoc.link < (nlinks-1)) {	/* more links? */
+		int i, newlink = -1;
+		for (i = curdoc.link; i < nlinks; i++)
+		   if (links[i].ly > links[curdoc.link].ly) {
+			newlink = i;
+			break;
+		   }
+			
+		if (newlink > -1) {
+                    highlight(OFF, curdoc.link);
+                    curdoc.link = newlink;
+#ifdef NOTDEFINED
+		} else if (!more &&
+			   newline == 1 && curdoc.link == (nlinks-1)) {
+                    highlight(OFF, curdoc.link);
+                    curdoc.link = 0;
+#endif /* NOTDEFINED */
+                } else if (more) {  /* next page */
+                        newline += (display_lines);
+		} else if (old_c != real_c) {
+		    old_c = real_c;
+		    _statusline(NO_LINKS_BELOW);
+		    sleep(MessageSecs);
+		    break;
+		}
+#ifdef NOTDEFINED
+            /* at the bottom of list and there is only one page
+             * move to the top link on the page
+             */
+            } else if (!more && newline == 1 && curdoc.link == (nlinks-1)) {
+                highlight(OFF, curdoc.link);
+                curdoc.link = 0;
+#endif /* NOTDEFINED */
+            } else if (more) {  /* next page */
+                    newline += (display_lines);
+
+	    } else if (old_c != real_c) {
+		old_c = real_c;
+		_statusline(ALREADY_AT_END);
+		sleep(MessageSecs);
+            }
+            break;
+
+	case LYK_RIGHT_LINK:
+	    if (curdoc.link<nlinks-1 &&
+			links[curdoc.link].ly == links[curdoc.link+1].ly) {
+                highlight(OFF,curdoc.link);
+		curdoc.link++;
+	    }
+	    break;
+
+	case LYK_LEFT_LINK:
+	    if (curdoc.link>0 &&
+			links[curdoc.link].ly == links[curdoc.link-1].ly) {
+                highlight(OFF,curdoc.link);
+		curdoc.link--;
+	    }
+	    break;
+
+	case LYK_HISTORY: 	/* show the history page */
+	    if (strcmp(curdoc.title, HISTORY_PAGE_TITLE)) {
+		/*
+		 *  Don't do this if already viewing history page.
+		 *
+		 *  Push the current file so that the history list
+		 *  contains the current file for printing purposes.
+		 *  Pop the file afterwards to prevent multiple copies.
+		 */
+		if (TRACE && LYCursesON) {
+		    move(LYlines-1, LYcols-1);  /* make sure cursor is down */
+#ifdef USE_SLANG
+		    addstr("\n");
+#endif /* USE_SLANG */
+		    refresh();
+		}
+                LYpush(&curdoc);
+
+		/*
+		 *  Print history options to file.
+		 */
+	    	if (showhistory(&newdoc.address) < 0)
+		    break;
+ 		FREE(curdoc.address);  /* so it doesn't get pushed */
+		FREE(newdoc.post_data);
+		FREE(newdoc.post_content_type);
+		newdoc.isHEAD = FALSE;
+
+                LYpop(&curdoc);
+
+		refresh_screen=TRUE;
+		if (LYValidate || check_realm) {
+		    LYPermitURL = TRUE;
+		}
+	        break; 
+	    } /* end if strncmp */
+	    /*
+	     *  Don't put break here so that if the backspace key
+	     *  is pressed in the history page, we fall though,
+	     *  i.e., it acts like a left arrow.
+	     */
+
+	case LYK_PREV_DOC:			 /* back up a level */
+	    if (nhist > 0) {  /* if there is anything to go back to */
+		/*
+		 *  Set newdoc.address to empty to pop a file.
+		 */
+		FREE(newdoc.address);
+#ifdef DIRED_SUPPORT
+		if (lynx_edit_mode)
+		    HTuncache_current_document();
+#endif /* DIRED_SUPPORT */
+	    } else if (child_lynx == TRUE) {
+	   	return(0); /* exit on left arrow in main screen */ 
+
+	    } else if (old_c != real_c) {
+		old_c = real_c;
+		_statusline(ALREADY_AT_FIRST);
+		sleep(MessageSecs);
+	    }
+	    break;
+
+	case LYK_NOCACHE: /* Force submission of form or link with no-cache */
+	    if (nlinks > 0) {
+	        if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
+	            links[curdoc.link].form->type != F_SUBMIT_TYPE) {
+		    if (old_c == real_c)
+		        break;
+		    old_c = real_c;
+		    _statusline(NOT_ON_SUBMIT_OR_LINK);
+		    sleep(MessageSecs);
+		    break;
+	        } else {
+	            LYforce_no_cache = TRUE;
+		    reloading = TRUE;
+		}
+	    } /* fall through to LYK_ACTIVATE */
+
+	case LYK_ACTIVATE:			/* follow a link */
+	    if (nlinks > 0) {
+	        if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
+		        /*
+			 * Don't try to submit forms with bad actions. - FM
+			 */
+			if (links[curdoc.link].form->type == F_SUBMIT_TYPE ||
+			   links[curdoc.link].form->type ==
+			   			       F_TEXT_SUBMIT_TYPE) {
+			   /*
+			    * Do nothing if it's disabled. - FM
+			    */
+			   if (links[curdoc.link].form->disabled == YES)
+			       break;
+			   /*
+			    * Make sure we have an action. - FM
+			    */
+			   if (!links[curdoc.link].form->submit_action ||
+			       *links[curdoc.link].form->submit_action
+			       					== '\0') {
+			       _statusline(NO_FORM_ACTION);
+			       sleep(MessageSecs);
+			       break;
+			    }
+		            /*
+			     * Check for no_mail if the form action
+			     * is a mailto URL. - FM
+			     */
+			    if (links[curdoc.link].form->submit_method
+			             == URL_MAIL_METHOD && no_mail) {
+			        HTAlert(FORM_MAILTO_DISALLOWED);
+			        break;
+			    }
+			    /*
+			     *  Make sure this isn't a spoof in an account
+			     *  with restrictions on file URLs. - FM
+			     */
+			    if (no_file_url &&
+			        !strncasecomp(
+				    links[curdoc.link].form->submit_action,
+				    "file:", 5)) {
+				HTAlert(FILE_ACTIONS_DISALLOWED);
+				break;
+			    }
+#ifdef NOTDEFINED /* We're disabling form inputs instead of using this. - FM */
+		            /*
+			     *  Check for enctype and let user know we
+			     *  don't yet support multipart/form-data - FM
+			     */
+			    if (links[curdoc.link].form->submit_enctype) {
+			        if (!strcmp(
+				      links[curdoc.link].form->submit_enctype,
+				      "multipart/form-data")) {
+				    HTAlert(
+	"Enctype multipart/form-data not yet supported!  Cannot submit.");
+				    break;
+				}
+			    }
+#endif /* NOTDEFINED */
+			    if (check_realm) {
+			        LYPermitURL = TRUE;
+			    }
+			    if (no_filereferer == TRUE &&
+			        !strncasecomp(curdoc.address, "file:", 5)) {
+				LYNoRefererForThis = TRUE;
+			    }
+			}
+		        c = change_form_link(&links[curdoc.link],
+					     FORM_UP, &newdoc, &refresh_screen,
+					     links[curdoc.link].form->name,
+					     links[curdoc.link].form->value);
+			goto new_keyboard_input;
+
+	        } else {   /* Not a forms link */
+		    /*
+		     *  Make sure this isn't a spoof in an account
+		     *  with restrictions on file URLs. - FM
+		     */
+		    if (no_file_url &&
+		        !strncasecomp(links[curdoc.link].lname, "file:", 5)) {
+			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))) {
+			    HTAlert(FILE_BOOKMARKS_DISALLOWED);
+			    break;
+			}
+		    }
+		    /*
+		     *  Follow a normal link or anchor. 
+		     */
+		    StrAllocCopy(newdoc.address, links[curdoc.link].lname);
+		    StrAllocCopy(newdoc.title, links[curdoc.link].hightext);
+		    /*
+		     * Might be an anchor in the same doc from a POST
+		     * form.  If so, dont't free the content. -- FM
+		     */
+		    if (are_different(&curdoc, &newdoc)) {
+		        FREE(newdoc.post_data);
+		        FREE(newdoc.post_content_type);
+		    }
+		    if (!no_jump && lynxjumpfile &&
+		        !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))) ||
+			       (lynxjumpfile &&
+			        !strcmp(lynxjumpfile, curdoc.address))) {
+		        LYUserSpecifiedURL = TRUE;
+		    } else if (no_filereferer == TRUE &&
+		    	       !strncasecomp(curdoc.address, "file:", 5)) {
+			LYNoRefererForThis = TRUE;
+		    }
+		    newdoc.link = 0;
+		    force_load = TRUE;  /* force MainLoop to reload */
+#ifdef DIRED_SUPPORT
+		    if (lynx_edit_mode) {
+			  HTuncache_current_document();
+			  HTUnEscape(newdoc.address);
+			  strip_trailing_slash(newdoc.address);
+		    }
+#endif /* DIRED_SUPPORT */
+		}
+	    }
+	    break;
+
+	case LYK_GOTO:   /* 'g' to goto a random URL  */
+	 
+	    if (no_goto && !LYValidate) {
+	        if (old_c != real_c) {
+	   	    old_c = real_c;
+	    	    _statusline(GOTO_DISALLOWED);
+		    sleep(MessageSecs);
+		}
+		break;
+	    }
+	 
+	    StrAllocCopy(temp, user_input_buffer);
+	    if (!goto_buffer)
+	        *user_input_buffer = '\0';
+
+	    URLTotal = (Goto_URLs ? HTList_count(Goto_URLs) : 0);
+	    if (goto_buffer && *user_input_buffer) {
+		recall = ((URLTotal > 1) ? RECALL : NORECALL);
+		URLNum = 0;
+		FirstURLRecall = FALSE;
+	    } else {
+		recall = ((URLTotal >= 1) ? RECALL : NORECALL);
+		URLNum = URLTotal;
+		FirstURLRecall = TRUE;
+	    }
+
+	    /*
+	     * Ask the user.
+	     */
+	    _statusline(URL_TO_OPEN);
+	    if ((ch=LYgetstr(user_input_buffer, VISIBLE,
+	    		     sizeof(user_input_buffer), recall)) < 0 ) {
+		/*
+		 * User cancelled the Goto via ^G.
+		 * Restore user_input_buffer and break. - FM
+		 */
+		strcpy(user_input_buffer, temp);
+		FREE(temp);
+		_statusline(CANCELLED);
+		sleep(InfoSecs);
+		break;
+	    }
+
+check_recall:
+	    /*
+	     * Get rid of leading spaces (and any other spaces).
+	     */
+	    collapse_spaces(user_input_buffer);
+	    if (*user_input_buffer == '\0' &&
+	        !(recall && (ch == UPARROW || ch == DNARROW))) {
+		strcpy(user_input_buffer, temp);
+		FREE(temp);
+		_statusline(CANCELLED);
+		sleep(InfoSecs);
+	        break;
+	    }
+	    if (recall && ch == UPARROW) {
+	        if (FirstURLRecall) {
+		    /*
+		     * Use last URL in the list. - FM
+		     */
+		    FirstURLRecall = FALSE;
+		    URLNum = 0;
+		} else {
+		    /*
+		     * Go back to the previous URL in the list. - FM
+		     */
+		    URLNum++;
+		}
+		if (URLNum >= URLTotal)
+		    /*
+		     * Roll around to the last URL in the list. - FM
+		     */
+		    URLNum = 0;
+		if ((cp=(char *)HTList_objectAt(Goto_URLs,
+	    					    URLNum)) != NULL) {
+		    strcpy(user_input_buffer, cp);
+		    if (goto_buffer && *temp &&
+		        !strcmp(temp, user_input_buffer)) { 
+		        _statusline(EDIT_CURRENT_GOTO);
+		    } else if ((goto_buffer && URLTotal == 2) ||
+			       (!goto_buffer && URLTotal == 1)) {
+			_statusline(EDIT_THE_PREV_GOTO);
+		    } else {
+			_statusline(EDIT_A_PREV_GOTO);
+		    }
+		    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
+			 */
+			strcpy(user_input_buffer, temp);
+			FREE(temp);
+			_statusline(CANCELLED);
+			sleep(InfoSecs);
+			break;
+		    }
+		    goto check_recall;
+		}
+	    } else if (recall && ch == DNARROW) {
+	        if (FirstURLRecall) {
+		    /*
+		     * Use the first URL in the list. - FM
+		     */
+		    FirstURLRecall = FALSE;
+		    URLNum = URLTotal - 1;
+		} else {
+		    /*
+		     * Advance to the next URL in the list. - FM
+		     */
+		    URLNum--;
+		}
+		if (URLNum < 0)
+		    /*
+		     * Roll around to the first URL in the list. - FM
+		     */
+		    URLNum = URLTotal - 1;
+		if ((cp=(char *)HTList_objectAt(Goto_URLs,
+	    					    URLNum)) != NULL) {
+		    strcpy(user_input_buffer, cp);
+		    if (goto_buffer && *temp &&
+		        !strcmp(temp, user_input_buffer)) { 
+		        _statusline(EDIT_CURRENT_GOTO);
+		    } else if ((goto_buffer && URLTotal == 2) ||
+			       (!goto_buffer && URLTotal == 1)) {
+			_statusline(EDIT_THE_PREV_GOTO);
+		    } else {
+			_statusline(EDIT_A_PREV_GOTO);
+		    }
+		    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
+			 */
+			strcpy(user_input_buffer, temp);
+			FREE(temp);
+			_statusline(CANCELLED);
+			sleep(InfoSecs);
+			break;
+		    }
+		    goto check_recall;
+		}
+	    }
+
+	    /*
+	     * If its not a URL then make it one.
+	     */
+	    if (!is_url(user_input_buffer)) {
+	        char *user_input_string = NULL;
+	        if (TRACE)
+		    fprintf(stderr, "\n'%s' is not a URL\n",
+		    			user_input_buffer);
+		StrAllocCopy(user_input_string, user_input_buffer);
+		LYConvertToURL(&user_input_string);
+		strcpy(user_input_buffer, user_input_string);
+		FREE(user_input_string);
+	    }
+	    if ((no_file_url || no_goto_file) &&
+	        !strncmp(user_input_buffer,"file:",5)) {
+                _statusline(GOTO_FILE_DISALLOWED);
+                sleep(MessageSecs);
+
+#ifdef EXEC_LINKS
+            } else if ((no_shell || no_goto_lynxexec ||
+	    		local_exec_on_local_files) &&
+#else
+            } else if ((no_shell || no_goto_lynxexec) &&
+#endif /* EXEC_LINKS */
+	    	       !strncmp(user_input_buffer, "lynxexec:",9)) {
+                _statusline(GOTO_EXEC_DISALLOWED);
+                sleep(MessageSecs);
+
+#ifdef EXEC_LINKS
+            } else if ((no_shell || no_goto_lynxprog ||
+	    		local_exec_on_local_files) &&
+#else
+            } else if ((no_shell || no_goto_lynxprog) &&
+#endif /* EXEC_LINKS */
+	    	       !strncmp(user_input_buffer, "lynxprog:",9)) {
+                _statusline(GOTO_PROG_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if ((no_shell || no_goto_lynxcgi) &&
+	    	       !strncmp(user_input_buffer, "lynxcgi:", 8)) {
+                _statusline(GOTO_CGI_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (LYValidate &&
+		       strncmp(user_input_buffer, "http:", 5) &&
+		       strncmp(user_input_buffer, "https:", 6)) {
+                _statusline(GOTO_NON_HTTP_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_cso &&
+	    	       !strncmp(user_input_buffer, "cso:", 4)) {
+                _statusline(GOTO_CSO_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_finger &&
+	    	       !strncmp(user_input_buffer, "finger:", 7)) {
+                _statusline(GOTO_FINGER_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_ftp &&
+	    	       !strncmp(user_input_buffer, "ftp:", 4)) {
+                _statusline(GOTO_FTP_DISALLOWED);
+                sleep(MessageSecs);
+
+             } else if (no_goto_gopher &&
+	    	       !strncmp(user_input_buffer, "gopher:", 7)) {
+                _statusline(GOTO_GOPHER_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_http &&
+	    	       !strncmp(user_input_buffer, "http:", 5)) {
+                _statusline(GOTO_HTTP_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_https &&
+	    	       !strncmp(user_input_buffer, "https:", 6)) {
+                _statusline(GOTO_HTTPS_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_mailto &&
+	    	       !strncmp(user_input_buffer, "mailto:", 7)) {
+                _statusline(GOTO_MAILTO_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_news &&
+	    	       !strncmp(user_input_buffer, "news:", 5)) {
+                _statusline(GOTO_NEWS_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_nntp &&
+	    	       !strncmp(user_input_buffer, "nntp:", 5)) {
+                _statusline(GOTO_NNTP_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_rlogin &&
+	    	       !strncmp(user_input_buffer, "rlogin:", 7)) {
+                _statusline(GOTO_RLOGIN_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_snews &&
+	    	       !strncmp(user_input_buffer, "snews:", 6)) {
+                _statusline(GOTO_SNEWS_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_telnet &&
+	    	       !strncmp(user_input_buffer, "telnet:", 7)) {
+                _statusline(GOTO_TELNET_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_tn3270 &&
+	    	       !strncmp(user_input_buffer, "tn3270:", 7)) {
+                _statusline(GOTO_TN3270_DISALLOWED);
+                sleep(MessageSecs);
+
+            } else if (no_goto_wais &&
+	    	       !strncmp(user_input_buffer, "wais:", 5)) {
+                _statusline(GOTO_WAIS_DISALLOWED);
+                sleep(MessageSecs);
+
+           } else {
+		/* make a name for this new URL */
+	        StrAllocCopy(newdoc.title, "A URL specified by the user");
+
+		/*
+		 * If it's a file URL and the host is defaulted,
+		 * force in "//localhost".  We need this until
+		 * all the other Lynx code which performs security
+		 * checks based on the "localhost" string is changed
+		 * to assume "//localhost" when a host field is not
+		 * present in file URLs - FM
+		 */
+		if (!strncmp(user_input_buffer, "file:", 5)) {
+		    if (user_input_buffer[5] == '\0') {
+		        strcat(user_input_buffer, "//localhost");
+		    } else if (!strcmp(user_input_buffer, "file://")) {
+		        strcat(user_input_buffer, "localhost");
+		    } else if (!strncmp(user_input_buffer, "file:///", 8)) {
+		        StrAllocCopy(temp, (user_input_buffer+7));
+		        strcpy(user_input_buffer, "file://localhost");
+		        strcat(user_input_buffer, temp);
+		        FREE(temp);
+		    } else if (!strncmp(user_input_buffer, "file:/", 6) &&
+		    	      user_input_buffer[6] != '/') {
+		        StrAllocCopy(temp, (user_input_buffer+5));
+		        strcpy(user_input_buffer, "file://localhost");
+		        strcat(user_input_buffer, temp);
+		        FREE(temp);
+		    }
+		}
+
+		/*
+		 * No path in a file://localhost URL means a
+		 * directory listing for the current default. - FM
+		 */
+		if (!strcmp(user_input_buffer, "file://localhost")) {
+#ifdef VMS
+		    strcat(user_input_buffer, HTVMS_wwwName(getenv("PATH")));
+#else
+		    char curdir[DIRNAMESIZE];
+#ifdef NO_GETCWD
+		    getwd (curdir);
+#else
+		    getcwd (curdir, DIRNAMESIZE);
+#endif /* NO_GETCWD */
+		    strcat(user_input_buffer, curdir);
+#endif /* VMS */
+		}
+
+#ifdef VMS
+		/*
+		 * On VMS, a file://localhost/ URL means
+		 * a listing for the login directory. - FM
+		 */
+		if (!strcmp(user_input_buffer, "file://localhost/"))
+		    strcat(user_input_buffer,
+		    	   (HTVMS_wwwName((char *)Home_Dir())+1));
+#endif /* VMS */
+
+	        StrAllocCopy(newdoc.address, user_input_buffer);
+		newdoc.isHEAD = FALSE;
+		/*
+		 * 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);
+		}
+		force_load = TRUE;
+		LYUserSpecifiedURL = TRUE;
+#ifdef DIRED_SUPPORT
+		if (lynx_edit_mode) 
+		    HTuncache_current_document();
+#endif /* DIRED_SUPPORT */
+		HTAddGotoURL(user_input_buffer);
+	    } 
+	    break;
+
+	case LYK_HELP:			/* show help file */
+	    if (!STREQ(curdoc.address, helpfile)) {
+	        StrAllocCopy(newdoc.address, helpfile);  /* set the filename */
+		/* make a name for this help file */
+	        StrAllocCopy(newdoc.title, "Help Screen");
+		FREE(newdoc.post_data);
+		FREE(newdoc.post_content_type);
+		newdoc.isHEAD = FALSE;
+	    }
+	    break;
+
+	case LYK_INDEX:  /* index file */
+	    /* make sure we are not in the index already */
+	    if (!STREQ(curdoc.address, indexfile)) {
+
+	        if (indexfile[0]=='\0') { /* no defined index */
+			if (old_c != real_c)	{
+				old_c = real_c;
+		    		_statusline(NO_INDEX_FILE);
+		    		sleep(MessageSecs);
+			}
+
+	        } else {
+	            StrAllocCopy(newdoc.address, indexfile);
+	            StrAllocCopy(newdoc.title, "System Index"); /* name it */
+		    FREE(newdoc.post_data);
+		    FREE(newdoc.post_content_type);
+		    newdoc.isHEAD = FALSE;
+	        } /* end else */
+	    }  /* end if */
+	    break;
+
+#ifdef NOT_USED
+	case LYK_FORM_UP:  /* change form */
+	    break;	   /* not implemented */
+	    if (lynx_mode == FORMS_LYNX_MODE) {
+		if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
+		    c = change_form_link(&links[curdoc.link],
+					 FORM_UP, &newdoc, &refresh_screen,
+					 links[curdoc.link].form->name,
+					 links[curdoc.link].form->value);
+		    /*
+		     *	Code to handle multiple submit buttons?
+		     *	Taken out due to bug it causes.
+		    if (links[curdoc.link].form->type == F_SUBMIT_TYPE)	{
+			curdoc.address = NULL;
+		    }
+		     */
+		    goto new_keyboard_input;
+		} else {
+		    _statusline("'X' can only toggle a form link");
+		}
+	    } else {
+		_statusline("'X' only toggles in forms mode");
+	    }
+	    break;	
+
+	case LYK_FORM_DOWN:  /* change form */
+	    break;	     /* not implemented */
+	    if (lynx_mode==FORMS_LYNX_MODE) {
+		if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
+		    c = change_form_link(&links[curdoc.link],
+					 FORM_DOWN,&newdoc,&refresh_screen,
+					 links[curdoc.link].form->name,
+					 links[curdoc.link].form->value);
+		    goto new_keyboard_input;
+		} else {
+		    _statusline("'Z' can only toggle a form link");
+		}
+	    } else {
+		_statusline("'Z' only toggles in forms mode");
+	    }
+	    break;	
+#endif /* NOT_USED */
+
+	case LYK_MAIN_MENU:	/* return to main screen */
+	    /* if its already the homepage then don't reload it */
+	    if (!STREQ(curdoc.address,homepage)) {
+		
+		_statusline(CONFIRM_MAIN_SCREEN);
+		c = LYgetch();
+		if (TOUPPER(c)=='Y') {
+	            StrAllocCopy(newdoc.address, homepage);
+                    StrAllocCopy(newdoc.title, "Entry into main screen");
+		    FREE(newdoc.post_data);
+		    FREE(newdoc.post_content_type);
+		    newdoc.isHEAD = FALSE;
+	            highlight(OFF,curdoc.link); 
+#ifdef DIRED_SUPPORT
+		    if (lynx_edit_mode)
+		      HTuncache_current_document();
+#endif /* DIRED_SUPPORT */
+		}
+#ifdef VMS
+		if (HadVMSInterrupt)
+		    HadVMSInterrupt = FALSE;
+#endif /* VMS */
+	    } else {
+		if (old_c != real_c)	{
+			old_c = real_c;
+			_statusline(IN_MAIN_SCREEN);
+			sleep(MessageSecs);
+		}
+	    }
+	    break;
+
+	case LYK_OPTIONS:     /* options screen */
+
+#ifdef DIRED_SUPPORT
+	    c = dir_list_style;
+#endif /* DIRED_SUPPORT */
+	    options(); /* do the options stuff */
+
+	    if (keypad_mode_flag != keypad_mode ||
+#ifdef DIRED_SUPPORT
+		c != dir_list_style ||
+#endif /* DIRED_SUPPORT */
+		HTfileSortMethod_flag != HTfileSortMethod ||
+		CurrentCharSet_flag != current_char_set ||
+		show_dotfiles_flag != show_dotfiles ||
+		LYRawMode_flag != LYRawMode ||
+		strcmp(CurrentUserAgent, (LYUserAgent ?
+					  LYUserAgent : ""))) {
+		HTuncache_current_document();
+		StrAllocCopy(newdoc.address, curdoc.address);
+		FREE(curdoc.address);
+		keypad_mode_flag = keypad_mode;
+		HTfileSortMethod_flag = HTfileSortMethod;
+		CurrentCharSet_flag = current_char_set;
+		show_dotfiles_flag = show_dotfiles;
+		LYRawMode_flag = LYRawMode;
+		StrAllocCopy(CurrentUserAgent, (LYUserAgent ?
+						LYUserAgent : ""));
+	    }
+	    refresh_screen = TRUE; /* to repaint screen */
+	    break;
+
+	case LYK_INDEX_SEARCH: /* search for a user string */
+	     if (is_www_index) {
+               /* perform a database search */
+
+		/* do_www_search will try to go out and get the document
+		 * if it returns yes a new document was returned and is
+		 * named in the newdoc.address
+		 */
+		newdoc.isHEAD = FALSE;
+		if (do_www_search(&newdoc) == NORMAL) {
+		   /* Yah, the search succeeded. */
+		   if (TRACE && LYCursesON) {
+		      move(LYlines-1, LYcols-1); /* make sure cursor is down */
+#ifdef USE_SLANG
+		      addstr("\n");
+#endif /* USE_SLANG */
+		      refresh();
+		}
+                   LYpush(&curdoc);
+		   /* Make the curdoc.address the newdoc.address so that
+		    * getfile doesn't try to get the newdoc.address.
+		    * Since we have already gotton it.
+		    */ 
+		   StrAllocCopy(curdoc.address, newdoc.address);
+		   StrAllocCopy(newdoc.post_data, curdoc.post_data);
+		   curdoc.line = -1;
+		   newline = 0;
+		   refresh_screen = TRUE; /* redisplay it */
+		} else if (use_this_url_instead != NULL) {
+		   /* Got back a redirecting URL. Check it out. */
+		   _user_message("Using %s", use_this_url_instead);
+		   /* Make a name for this URL */
+	           StrAllocCopy(newdoc.title, "A URL specified by redirection");
+	           StrAllocCopy(newdoc.address, use_this_url_instead);
+		   FREE(newdoc.post_data);
+		   FREE(newdoc.post_content_type);
+		   newdoc.isHEAD = FALSE;
+	           FREE(use_this_url_instead);
+		   force_load = TRUE;
+		   break;
+		} else {
+		   /* Yuk, the search failed.  Restore the old file. */
+		   StrAllocCopy(newdoc.address, curdoc.address);  
+		   StrAllocCopy(newdoc.post_data, curdoc.post_data);
+		   newdoc.isHEAD = curdoc.isHEAD;
+		}
+	     } else if (old_c != real_c)	{
+		old_c = real_c;
+		_statusline(NOT_ISINDEX);
+		sleep(MessageSecs);
+	     }
+	     break;
+
+	case LYK_WHEREIS: /* search within the document */
+  	/* search for the next occurrence of the user string */
+	case LYK_NEXT:
+            /* user search */
+	    if (cmd != LYK_NEXT) {
+	        /* 
+		 * Reset prev_target to force prompting
+		 * for a new search string and to turn
+		 * off highlighting in no search string
+		 * is entered by the user.
+		 */
+	        *prev_target = '\0';
+	        textsearch(&curdoc, prev_target, FALSE);
+	    } else {
+	        /*
+		 * When the third argument is TRUE, the previous
+		 * search string, if any, will be recalled from
+		 * a buffer, loaded into prev_target, and used
+		 * for the search without prompting for a new
+		 * search string.  This allows the LYK_NEXT
+		 * command to repeat a search in a new document,
+		 * after prev_target was reset on fetch of that
+		 * document.
+		 */
+	        textsearch(&curdoc, prev_target, TRUE);
+	    }
+	    
+	    /*
+	     * Force a redraw to ensure highlighting of hits
+	     * even when found on the same page, or clearing
+	     * of highlighting is the default search string
+	     * was erased without replacement. - FM
+	     */
+	    refresh_screen = TRUE;
+	    break;
+
+	case LYK_COMMENT:  /* reply by mail */
+	   if (!owner_address) {
+		if (old_c != real_c)	{
+			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 {
+		_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 */
+	          }
+	       }
+	   }
+	   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);
+		    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);
+	      }
+	   }
+	   break;
+
+	case LYK_MODIFY:  /* rename a file or directory */
+           if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
+	      int ret;
+
+	      ret = local_modify(&curdoc, &newdoc.address);
+	      if (ret == PERMIT_FORM_RESULT) {      /* Permit form thrown up */
+		 refresh_screen=TRUE;
+	      } else if (ret) {
+		 HTuncache_current_document();
+		 StrAllocCopy(newdoc.address, curdoc.address);
+		 FREE(curdoc.address);	
+		 newdoc.line = curdoc.line;
+		 newdoc.link = curdoc.link;
+		 clear();
+	      }
+	   }
+           break;
+
+	case LYK_CREATE:  /* create a new file or directory */
+           if (lynx_edit_mode && !no_dired_support) {
+	      if (local_create(&curdoc)) {
+		 HTuncache_current_document();
+		 StrAllocCopy(newdoc.address, curdoc.address);
+		 FREE(curdoc.address);	
+		 newdoc.line = curdoc.line;
+		 newdoc.link = curdoc.link > -1 ? curdoc.link : 0;
+		 clear();
+	      }
+	   }
+           break;
+#endif /* DIRED_SUPPORT */
+
+	case LYK_EDIT:  /* edit */
+	    if (no_editor) {
+		if (old_c != real_c)	{
+		    old_c = real_c;
+		    _statusline(EDIT_DISABLED);
+		    sleep(MessageSecs);
+		}
+		break;
+	    }
+
+#ifdef DIRED_SUPPORT
+
+/* Allow the user to edit the link rather than curdoc in edit mode */
+
+	   if (lynx_edit_mode && editor && *editor != '\0' &&
+	   			!no_dired_support) {
+	      if (nlinks > 0) {
+		 cp = links[curdoc.link].lname;
+		 if (is_url(cp) == FILE_URL_TYPE) {
+		    tp = cp;
+		    if (!strncmp(tp,"file://localhost",16))
+		       tp += 16;
+		    else if (!strncmp(tp,"file:",5))
+		       tp += 5;
+		    strcpy(tmpbuf,tp);
+		    HTUnEscape(tmpbuf);
+		    if (stat(tmpbuf,&dir_info) == -1) {
+		       _statusline(NO_STATUS);
+		       sleep(AlertSecs);
+		    } else {
+		       if (((dir_info.st_mode) & S_IFMT) == S_IFREG) {
+			  strcpy(tmpbuf,cp);
+			  HTUnEscape(tmpbuf);
+			  if (edit_current_file(tmpbuf,curdoc.link,newline))
+			  {
+			    	HTuncache_current_document();
+			  	StrAllocCopy(newdoc.address, curdoc.address);
+			  	FREE(curdoc.address);
+#ifdef NO_SEEK_OLD_POSITION
+				/* Go to top of file */
+				newdoc.line = 1;
+				newdoc.link = 0;
+#else
+				/* Seek old position, which probably changed */
+				newdoc.line =
+					((curdoc.line > 0) ? curdoc.line : 1);
+				newdoc.link =
+					((curdoc.link > -1) ? curdoc.link : 0);
+#endif /* NO_SEEK_OLD_POSITION */
+			  	clear();  /* clear the screen */
+			  }
+			}
+		    }
+		 }
+	      }
+	   } else
+#endif /* DIRED_SUPPORT */
+	   if (editor && *editor != '\0') {
+		if (edit_current_file(newdoc.address, curdoc.link, newline))
+		{
+	            	HTuncache_current_document();
+			LYforce_no_cache = TRUE;  /*force the document to be reloaded*/
+	        	FREE(curdoc.address); /* so it doesn't get pushed */
+#ifdef NO_SEEK_OLD_POSITION
+			/* Go to top of file */
+			newdoc.line = 1;
+			newdoc.link = 0;
+#else
+			/* Seek old position, which probably changed */
+			newdoc.line = curdoc.line;
+			newdoc.link = curdoc.link;
+#endif /* NO_SEEK_OLD_POSITION */
+			clear();  /* clear the screen */
+		}
+
+	   } else {
+		if (old_c != real_c)	{
+			old_c = real_c;
+			_statusline(NO_EDITOR);
+			sleep(MessageSecs);
+		}
+	   }
+	   break;
+
+	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)
+		local_remove(&curdoc);
+	    else
+#endif /* DIRED_SUPPORT */
+
+	    if (bookmark_page && (strstr(curdoc.address, bookmark_page) ||
+			!strcmp(curdoc.title, MOSAIC_BOOKMARK_TITLE))) {
+		_statusline(CONFIRM_BOOKMARK_DELETE);
+             	c = LYgetch();
+                if (TOUPPER(c) != 'Y')
+                    break;
+                remove_bookmark_link(links[curdoc.link].anchor_number-1);
+	    } else {	/* behave like REFRESH for backward compatability */
+	        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;
+	    break;
+
+#ifdef DIRED_SUPPORT
+	case LYK_INSTALL:  /* install a file into system area */
+	   if (lynx_edit_mode && nlinks > 0 && !no_dired_support)
+	      local_install(NULL, links[curdoc.link].lname, &newdoc.address);
+	   break;
+#endif /* DIRED_SUPPORT */
+
+	case LYK_INFO:  /* show document info */
+	   /* don't do if already viewing info page */	
+	   if (strcmp(curdoc.title, SHOWINFO_TITLE)) {
+	        showinfo(&curdoc, lines_in_file, &newdoc, owner_address);
+		LYforce_no_cache = TRUE;
+		if (LYValidate || check_realm)
+		    LYPermitURL = TRUE;
+            } else {
+		/* if already in info page; get out */
+		cmd = LYK_PREV_DOC;
+		goto new_cmd;
+	    }
+            break;
+
+	case LYK_PRINT:  /* print the file */
+	    if (LYValidate) {
+		if (old_c != real_c)	{
+		    old_c = real_c;
+		    _statusline(PRINT_DISABLED);
+		    sleep(MessageSecs);
+		}
+		break;
+	    }
+
+	    /* don't do if already viewing print options page */	
+	    if (strcmp(curdoc.title, PRINT_OPTIONS_TITLE)) {	
+
+                if (print_options(&newdoc.address, lines_in_file) < 0)
+		    break;
+		if (check_realm)
+		    LYPermitURL = TRUE;
+	        refresh_screen=TRUE;  /* redisplay */
+	    }
+	    break;
+
+	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 (showlist(&newdoc.address, TRUE) < 0)
+		    break;
+		refresh_screen=TRUE;  /* redisplay */
+		if (LYValidate || check_realm) {
+		    LYPermitURL = TRUE;
+		    StrAllocCopy(lynxlistfile, newdoc.address);
+		}
+	    }
+	    break;
+
+	case LYK_TOOLBAR:  /* go to Toolbar or Banner in current document */
+	    if (!HText_hasToolbar(HTMainText)) {
+		if (old_c != real_c) {
+		    old_c = real_c;
+		    _statusline(NO_TOOLBAR);
+		    sleep(MessageSecs);
+		}
+	    } else if (old_c != real_c) {
+	        old_c = real_c;
+		if ((cp = strchr(curdoc.address, '#')) != NULL)
+		    *cp = '\0';
+		toolbar = (char *)malloc(strlen(curdoc.address) +
+	    				 strlen(LYToolbarName) + 2);
+		sprintf(toolbar, "%s#%s", curdoc.address, LYToolbarName);
+		if (cp)
+		    *cp = '#';
+		StrAllocCopy(newdoc.address, toolbar);
+		FREE(toolbar);
+		force_load = TRUE;  /* force MainLoop to reload */
+	    }
+	    break;
+
+#ifdef DIRED_SUPPORT
+       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)) {
+	        dired_options(&curdoc,&newdoc.address);
+	        refresh_screen=TRUE;  /* redisplay */
+	    }
+	    break;
+#endif /* DIRED_SUPPORT */
+
+	case LYK_ADD_BOOKMARK:  /* a to add link to bookmark file */
+	    if (LYValidate) {
+		if (old_c != real_c)	{
+		    old_c = real_c;
+		    _statusline(BOOKMARKS_DISABLED);
+		    sleep(MessageSecs);
+		}
+		break;
+	    }
+
+	    if (strcmp(curdoc.title, HISTORY_PAGE_TITLE) &&
+	        strcmp(curdoc.title, SHOWINFO_TITLE) && 
+	        strcmp(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) &&
+#endif /* DIRED_SUPPORT */
+	        strcmp(curdoc.title, DOWNLOAD_OPTIONS_TITLE) &&
+	        strcmp(curdoc.title, LIST_PAGE_TITLE)) {
+
+		if (nlinks > 0) {
+		    if (curdoc.post_data == NULL) {
+		        /*
+			 *  Document doesn't have POST content, so
+			 *  we can save either that of the link. - FM
+			 */
+		        _statusline(BOOK_D_L_OR_CANCEL);
+			c = LYgetch();
+			if (TOUPPER(c) == 'D') {
+			    save_bookmark_link(curdoc.address, curdoc.title);
+			    break;
+			}
+		    } else {
+		        /*
+			 *  Only offer the link in a document
+			 *  with POST content. - FM
+			 */
+		        _statusline(BOOK_L_OR_CANCEL);
+			c = LYgetch();
+		    }
+		    if (TOUPPER(c) == 'L') {
+		        /*
+			 *  User does want to save the link. - FM
+			 */
+			if (links[curdoc.link].type != WWW_FORM_LINK_TYPE) {
+			    save_bookmark_link(links[curdoc.link].lname, 
+					       links[curdoc.link].hightext);
+			} else {
+			    _statusline(NOBOOK_FORM_FIELD);
+			    sleep(MessageSecs);
+			}
+		    }
+		} else if (curdoc.post_data != NULL) {
+		    /*
+		     *  No links, and document has POST content. - FM
+		     */
+		    _statusline(NOBOOK_POST_FORM);
+		    sleep(MessageSecs);
+		} else {
+		    _statusline(BOOK_D_OR_CANCEL);
+		    c = LYgetch();
+		    if (TOUPPER(c) == 'D')
+		        save_bookmark_link(curdoc.address, curdoc.title);
+		}
+	    } else {
+		if (old_c != real_c)	{
+			old_c = real_c;
+			_statusline(NOBOOK_HSML);
+			sleep(MessageSecs);
+		}
+	    }
+	    break;
+
+	case LYK_VIEW_BOOKMARK:   /* v to view home page */
+	    if (LYValidate) {
+		if (old_c != real_c)	{
+		    old_c = real_c;
+		    _statusline(BOOKMARKS_DISABLED);
+		    sleep(MessageSecs);
+		}
+		break;
+	    }
+
+	    /* see if a bookmark exists
+	     * if it does replace newdoc.address with it's name 
+	     */
+	    if (get_bookmark_filename(&newdoc.address) != NULL) {
+		LYforce_HTML_mode = TRUE;  /* force HTML */
+		LYforce_no_cache = TRUE;  /*force the document to be reloaded*/
+		StrAllocCopy(newdoc.title, "Bookmark File");
+		FREE(newdoc.post_data);
+		FREE(newdoc.post_content_type);
+		newdoc.isHEAD = FALSE;
+		if (check_realm) {
+		    StrAllocCopy(lynxbookfile, newdoc.address);
+		}
+	    } else {
+		if (old_c != real_c)	{
+			old_c = real_c;
+			_statusline(BOOKMARKS_NOT_OPEN);
+       			sleep(MessageSecs);
+		}
+	    }
+	    break;
+
+	case LYK_SHELL:  /* shell escape */
+	    if (!no_shell) {
+	        stop_curses();
+		printf(SPAWNING_MSG);
+	        fflush(stdout);
+#ifdef VMS
+		system("");
+#else
+	        system("exec $SHELL");
+#endif /* VMS */
+	        start_curses();
+	        refresh_screen=TRUE;  /* for a showpage */
+	    } else {
+		if (old_c != real_c)	{
+			old_c = real_c;
+			_statusline(SPAWNING_DISABLED);
+			sleep(MessageSecs);
+		}
+	    }
+	    break;
+
+	case LYK_DOWNLOAD:
+	    /* don't do if both download and disk_save are restricted */
+	    if (LYValidate ||
+	        (no_download && !override_no_download && no_disk_save)) {
+		if (old_c != real_c)	{
+		    old_c = real_c;
+		    _statusline(DOWNLOAD_DISABLED);
+		    sleep(MessageSecs);
+		}
+		break;
+	    }
+
+	    /* don't do if already viewing download options page */	
+	    if (0==strcmp(curdoc.title, DOWNLOAD_OPTIONS_TITLE))
+	        break;
+
+	    if (nlinks > 0) {
+                if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
+		    if (old_c != real_c)	{
+			old_c = real_c;
+			_statusline(NO_DOWNLOAD_INPUT);
+			sleep(MessageSecs);
+		    }
+
+		} else if (0==strcmp(curdoc.title, PRINT_OPTIONS_TITLE)) {
+		    if (old_c != real_c)	{
+			old_c = real_c;
+			_statusline(NO_DOWNLOAD_PRINT_OP);
+			sleep(MessageSecs);
+		    }
+
+#ifdef DIRED_SUPPORT
+		} else if (0==strcmp(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)) {
+		    if (old_c != real_c)	{
+			old_c = real_c;
+			_statusline(NO_DOWNLOAD_PERMIT_OP);
+			sleep(MessageSecs);
+		    }
+
+                } else if (lynx_edit_mode && !no_dired_support) {
+		    /* Don't bother making a /tmp copy of the local file */
+		    StrAllocCopy(temp, newdoc.address);
+                    StrAllocCopy(newdoc.address, links[curdoc.link].lname);
+                    if (LYdownload_options(&newdoc.address,
+		    			   links[curdoc.link].lname) < 0)
+			StrAllocCopy(newdoc.address, temp);
+		    FREE(temp);
+#endif /* DIRED_SUPPORT */
+
+		} else if (0==strcmp(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);
+		    FREE(newdoc.post_data);
+		    FREE(newdoc.post_content_type);
+		    if (history[number].post_data)
+		        StrAllocCopy(newdoc.post_data,
+				     history[number].post_data);
+		    if (history[number].post_content_type)
+		        StrAllocCopy(newdoc.post_content_type,
+				     history[number].post_content_type);
+		    newdoc.isHEAD = history[number].isHEAD;
+                    newdoc.link = 0;
+	            HTOutputFormat = HTAtom_for("www/download");
+		    LYUserSpecifiedURL = TRUE;
+		    /*force the document to be reloaded*/
+		    LYforce_no_cache = TRUE;  
+		    force_load = TRUE;  /* force MainLoop to reload */
+		    
+		} else if (!strncasecomp(links[curdoc.link].lname,
+					 "data:", 5)) {
+		    if (old_c != real_c) {
+			old_c = real_c;
+			HTAlert(UNSUPPORTED_DATA_URL);
+		    }
+
+                } else {   /* Not a forms, options or history link */
+                    /*
+		     * Follow a normal link or anchor.  Note that
+		     * if it's an anchor within the same document,
+		     * entire document will be downloaded
+		     */
+                    StrAllocCopy(newdoc.address, links[curdoc.link].lname);
+                    StrAllocCopy(newdoc.title, links[curdoc.link].hightext);
+		    /*
+		     * Might be an anchor in the same doc from a POST
+		     * form.  If so, don't free the content. -- FM
+		     */
+		    if (are_different(&curdoc, &newdoc)) {
+			FREE(newdoc.post_data);
+			FREE(newdoc.post_content_type);
+			newdoc.isHEAD = FALSE;
+		    }
+                    newdoc.link = 0;
+	            HTOutputFormat = HTAtom_for("www/download");
+		    /*force the document to be reloaded*/
+		    LYforce_no_cache = TRUE;  
+		    force_load = TRUE;  /* force MainLoop to reload */
+                }
+            } else if (old_c != real_c)	{
+		old_c = real_c;
+		_statusline(NO_DOWNLOAD_CHOICE);
+		sleep(MessageSecs);
+	    }
+	    break;
+
+#ifdef DIRED_SUPPORT
+	  case LYK_UPLOAD:
+	    /* don't do if already viewing upload options page */	
+	    if (0==strcmp(curdoc.title, UPLOAD_OPTIONS_TITLE))
+	        break;
+
+	    if (lynx_edit_mode && !no_dired_support) {
+                LYUpload_options((char **)&newdoc.address,
+				 (char *)curdoc.address);
+	     }
+	    break;
+#endif /* DIRED_SUPPORT */
+
+	case LYK_TRACE_TOGGLE:
+	    if (WWW_TraceFlag)
+		WWW_TraceFlag = FALSE;	
+	    else 
+		WWW_TraceFlag = TRUE;	
+
+	    _statusline(WWW_TraceFlag ? TRACE_ON : TRACE_OFF);
+	    sleep(MessageSecs);
+	    break;
+
+	case LYK_IMAGE_TOGGLE:
+	    if (clickable_images)
+		clickable_images = FALSE;	
+	    else 
+		clickable_images = TRUE;	
+
+	    _statusline(clickable_images ?
+	    	     CLICKABLE_IMAGES_ON : CLICKABLE_IMAGES_OFF);
+	    sleep(MessageSecs);
+	    cmd = LYK_RELOAD;
+	    goto new_cmd;
+	    break;
+
+	case LYK_INLINE_TOGGLE:
+	    if (pseudo_inline_alts)
+		pseudo_inline_alts = FALSE;	
+	    else 
+		pseudo_inline_alts = TRUE;	
+
+	    _statusline(pseudo_inline_alts ?
+	    	     PSEUDO_INLINE_ALTS_ON : PSEUDO_INLINE_ALTS_OFF);
+	    sleep(MessageSecs);
+	    cmd = LYK_RELOAD;
+	    goto new_cmd;
+	    break;
+
+	case LYK_RAW_TOGGLE:
+	    if (LYUseDefaultRawMode)
+		LYUseDefaultRawMode = FALSE;
+	    else
+	        LYUseDefaultRawMode = TRUE;
+	    _statusline(LYRawMode ? RAWMODE_OFF : RAWMODE_ON);
+ 	    HTMLSetCharacterHandling(current_char_set);	
+	    LYRawMode_flag = LYRawMode;
+ 	    sleep(MessageSecs);
+	    cmd = LYK_RELOAD;
+	    goto new_cmd;
+	    break;
+
+	case LYK_HEAD:
+	    if (nlinks > 0 &&
+	        (links[curdoc.link].type != WWW_FORM_LINK_TYPE ||
+	    	 links[curdoc.link].form->type == F_SUBMIT_TYPE)) {
+	        _statusline(HEAD_D_L_OR_CANCEL);
+		c = LYgetch();
+		if (TOUPPER(c) == 'D') {
+		    if (strncmp(curdoc.address, "http", 4)) {
+		        _statusline(DOC_NOT_HTTP_URL);
+			sleep(MessageSecs);
+		    } else {
+		        HEAD_request = TRUE;
+			LYforce_no_cache = TRUE;
+			if (HTLoadedDocumentIsHEAD()) {
+	            	    HTuncache_current_document();
+			    FREE(curdoc.address);
+			}
+		    }
+		    break;
+		} else if (TOUPPER(c) == 'L') {
+		    if (links[curdoc.link].type != WWW_FORM_LINK_TYPE &&
+		    	strncmp(links[curdoc.link].lname, "http", 4)) {
+		        _statusline(LINK_NOT_HTTP_URL);
+			sleep(MessageSecs);
+		    } else if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
+		    	       links[curdoc.link].form->disabled) {
+			_statusline(FORM_ACTION_DISABLED);
+			sleep(MessageSecs);
+		    } else if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
+		    	       strncmp(links[curdoc.link].form->submit_action,
+								 "http", 4)) {
+			_statusline(FORM_ACTION_NOT_HTTP_URL);
+			sleep(MessageSecs);
+		    } else {
+			HEAD_request = TRUE;
+			LYforce_no_cache = TRUE;
+			cmd = LYK_ACTIVATE;
+			goto new_cmd;
+		    }
+		    break;
+		}
+		break;
+	    } else {
+	        if (nlinks > 0) {
+		    _statusline(HEAD_D_OR_CANCEL);
+	            c = LYgetch();
+		} else {
+		    c = 'D';
+		}
+		if (TOUPPER(c) == 'D') {
+		    if (strncmp(curdoc.address, "http", 4)) {
+		        _statusline(DOC_NOT_HTTP_URL);
+			sleep(MessageSecs);
+		    } else {
+		        HEAD_request = TRUE;
+			LYforce_no_cache = TRUE;
+			if (HTLoadedDocumentIsHEAD()) {
+	            	    HTuncache_current_document();
+			    FREE(curdoc.address);
+			}
+		    }
+		}
+	    }
+	    break;	
+
+	case LYK_DO_NOTHING:
+	    /* pretty self explanitory */
+	    break;
+
+	case LYK_TOGGLE_HELP:
+    	    if (user_mode==NOVICE_MODE) {
+	        toggle_novice_line();
+	        noviceline(more);
+	    }
+	    break;
+
+	case LYK_KEYMAP:
+	    if (old_c != real_c) {
+	        old_c = real_c;
+		StrAllocCopy(newdoc.address, "LYNXKEYMAP:");
+	        FREE(newdoc.post_data);
+	        FREE(newdoc.post_content_type);
+		newdoc.isHEAD = FALSE;
+		/*
+		 * If vi_keys changed, the keymap did too,
+		 * so force no cache, and reset the flag. - FM
+		 */
+		if (vi_keys_flag != vi_keys ||
+		    emacs_keys_flag != emacs_keys) {
+		    LYforce_no_cache = TRUE;
+		    vi_keys_flag = vi_keys;
+		    emacs_keys_flag = emacs_keys;
+		}
+#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
+		/* Remember whether we are in dired menu
+		 * so we can display the right keymap.
+		 * Don't cache the keymap because it changes. - EF
+		 */
+		if (!no_dired_support) {
+		    prev_lynx_edit_mode = lynx_edit_mode;
+		    LYforce_no_cache = TRUE;
+		}
+#endif /* DIRED_SUPPORT && OK_OVERRIDE */
+	    }
+	    break;
+
+	case LYK_JUMP:
+	    {
+	      char *ret;
+
+	      if (no_jump || JThead == NULL) {
+	          if (old_c != real_c) {
+	   	      old_c = real_c;
+		      if (no_jump)
+	    	          _statusline(JUMP_DISALLOWED);
+		      else
+		          _statusline(NO_JUMPFILE);
+		      sleep(MessageSecs);
+		  }
+	      } else {
+		  LYJumpFileURL = TRUE;
+	          if ((ret = LYJump(c)) != NULL) {
+#ifdef PERMIT_GOTO_FROM_JUMP
+		      if (!strncasecomp(ret, "Go ", 3)) {
+		          LYJumpFileURL = FALSE;
+			  StrAllocCopy(temp, user_input_buffer);
+			  URLTotal = (Goto_URLs ? HTList_count(Goto_URLs) : 0);
+			  recall = ((URLTotal >= 1) ? RECALL : NORECALL);
+			  URLNum = URLTotal;
+			  FirstURLRecall = TRUE;
+			  if (!strcasecomp(ret, "Go :")) {
+			      if (recall) {
+			          ch = UPARROW;
+				  goto check_recall;
+			      }
+			      FREE(temp);
+			      statusline(NO_RANDOM_URLS_YET);
+			      sleep(MessageSecs);
+			      break;
+			  }
+			  ret = HTParse((ret+3), startfile, PARSE_ALL);
+			  strcpy(user_input_buffer, ret);
+			  FREE(ret);
+			  goto check_recall;
+		      }
+#endif /* PERMIT_GOTO_FROM_JUMP */
+		      ret = HTParse(ret, startfile, PARSE_ALL);
+		      StrAllocCopy(newdoc.address, ret);
+		      StrAllocCopy(lynxjumpfile, ret);
+		      FREE(newdoc.post_data);
+	    	      FREE(newdoc.post_content_type);
+		      newdoc.isHEAD = FALSE;
+		      FREE(ret);
+		      LYUserSpecifiedURL = TRUE;
+		  } else {
+		      LYJumpFileURL = FALSE;
+		  }
+	      }
+	      break;
+	    }
+
+#ifdef NOT_USED
+	case LYK_VERSION:
+	    if (old_c != real_c) {
+	        char version[128];
+		old_c = real_c;
+		sprintf(version, "*** %s Version %s ***",
+	      			 LYNX_NAME, LYNX_VERSION);
+	        statusline(version);
+	        sleep(AlertMessage);
+	    }
+	    break;
+#endif /* NOT_USED */
+
+	} /* end of BIG switch */
+    }
+}
+
+PRIVATE int are_different ARGS2(document *,doc1, document *,doc2)
+{
+    char *cp1, *cp2;
+
+    /*
+     * Do we have two addresses?
+     */
+    if (!doc1->address || !doc2->address)
+	return (TRUE);
+
+    /*
+     *  Do they differ in the type of request?
+     */
+    if (doc1->isHEAD != doc2->isHEAD)
+        return (TRUE);
+
+    /*
+     * See if the addresses are different, making sure
+     * we're not tripped up by multiple anchors in the
+     * the same document from a POST form. -- FM
+     */
+    if ((cp1 = strchr(doc1->address, '#')) != NULL)
+        *cp1 = '\0';
+    if ((cp2 = strchr(doc2->address, '#')) != NULL)
+        *cp2 = '\0';
+    /* 
+     * Are the base addresses different?
+     */
+    if (strcmp(doc1->address, doc2->address))
+      {
+        if (cp1)
+	    *cp1 = '#';
+        if (cp2)
+	    *cp2 = '#';
+	return(TRUE);
+      }
+    if (cp1)
+        *cp1 = '#';
+    if (cp2)
+        *cp2 = '#';
+
+    /*
+     * Do the docs have different contents?
+     */
+    if (doc1->post_data)
+      {
+	if (doc2->post_data)
+	  {
+	    if (strcmp(doc1->post_data, doc2->post_data))
+		return(TRUE);
+	  }
+	else
+	    return(TRUE);
+      }
+    else
+        if (doc2->post_data)
+	    return(TRUE);
+
+    /*
+     * We'll assume the two documents in fact are the same.
+     */
+    return(FALSE);
+}
+
+/* 
+ * Utility for freeing the list of goto URLs. - FM
+ */
+PUBLIC void HTGotoURLs_free NOARGS
+{
+    char *url;
+    HTList *cur = Goto_URLs;
+
+    if (!cur)
+        return;
+
+    while (NULL != (url = (char *)HTList_nextObject(cur))) {
+	FREE(url);
+    }
+    HTList_delete(Goto_URLs);
+    Goto_URLs = NULL;
+    return;
+}
+
+/* 
+ * Utility for listing Goto URLs, making any
+ * repeated URLs the most current in the list. - FM
+ */
+PUBLIC void HTAddGotoURL ARGS1(char *, url)
+{
+    char *new;
+    char *old;
+    HTList *cur;
+
+    if (!(url && *url))
+        return;
+
+    if ((new = (char *)calloc(1, (strlen(url) + 1))) == NULL)
+    	outofmem(__FILE__, "HTAddGotoURL");
+    strcpy(new, url);
+
+    if (!Goto_URLs) {
+        Goto_URLs = HTList_new();
+	atexit(HTGotoURLs_free);
+	HTList_addObject(Goto_URLs, new);
+	return;
+    }
+
+    cur = Goto_URLs;
+    while (NULL != (old = (char *)HTList_nextObject(cur))) {
+	if (!strcmp(old, new)) {
+	    HTList_removeObject(Goto_URLs, old);
+	    FREE(old);
+	    break;
+	}
+    }
+    HTList_addObject(Goto_URLs, new);
+
+    return;
+}