#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;
}