diff options
Diffstat (limited to 'src/LYMainLoop.c')
-rw-r--r-- | src/LYMainLoop.c | 3240 |
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; +} |