/*
* $LynxId: LYMainLoop.c,v 1.250 2023/01/05 09:17:16 tom Exp $
*/
#include <HTUtils.h>
#include <HTAccess.h>
#include <HTParse.h>
#include <HTList.h>
#include <HTML.h>
#include <HTFTP.h>
#include <HTFile.h>
#include <HTTP.h>
#include <HTAABrow.h>
#include <HTNews.h>
#include <LYCurses.h>
#include <LYStyle.h>
#include <LYGlobalDefs.h>
#include <HTAlert.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 <LYKeymap.h>
#include <LYJump.h>
#include <LYDownload.h>
#include <LYList.h>
#include <LYMap.h>
#include <LYTraversal.h>
#include <LYCharSets.h>
#include <LYCharUtils.h>
#include <LYCookie.h>
#include <LYMainLoop.h>
#include <LYPrettySrc.h>
#ifdef USE_SESSIONS
#include <LYSession.h>
#endif
#ifdef KANJI_CODE_OVERRIDE
#include <HTCJK.h>
#endif
#ifdef PREVENT_KEYBOARD_WRAPAROUND
#define HandleForwardWraparound() \
*old_c = real_c; \
HTInfoMsg(ALREADY_AT_END)
#define HandleReverseWraparound() \
*old_c = real_c; \
HTInfoMsg(ALREADY_AT_BEGIN)
#else
#define HandleForwardWraparound() \
LYSetNewline(1)
#define HandleReverseWraparound() \
int i; \
i = HText_getNumOfLines() - display_lines + 2; \
if (i >= 1 && Newline != i) { \
LYSetNewline(i); \
*arrowup = TRUE; \
}
#endif
#define LinkIsTextarea(linkNumber) \
(links[linkNumber].type == WWW_FORM_LINK_TYPE && \
links[linkNumber].l_form->type == F_TEXTAREA_TYPE)
#define LinkIsTextLike(linkNumber) \
(links[linkNumber].type == WWW_FORM_LINK_TYPE && \
F_TEXTLIKE(links[linkNumber].l_form->type))
#ifdef KANJI_CODE_OVERRIDE
char *str_kcode(HTkcode code)
{
char *p;
static char buff[8];
if (current_char_set == TRANSPARENT) {
p = "THRU";
} else if (!LYRawMode) {
p = "RAW";
} else {
switch (code) {
case NOKANJI:
p = "AUTO";
break;
case EUC:
p = "EUC+";
break;
case SJIS:
p = "SJIS";
break;
case JIS:
p = " JIS";
break;
default:
p = " ???";
break;
}
}
if (no_table_center) {
buff[0] = '!';
strcpy(buff + 1, p);
} else {
strcpy(buff, p);
}
return buff;
}
#endif
#ifdef WIN_EX
static char *str_sjis(char *to, char *from)
{
if (!LYRawMode) {
strcpy(to, from);
#ifdef KANJI_CODE_OVERRIDE
} else if (last_kcode == EUC) {
EUC_TO_SJIS(from, to);
} else if (last_kcode == SJIS) {
strcpy(to, from);
#endif
} else {
TO_SJIS((unsigned char *) from, (unsigned char *) to);
}
return to;
}
static void set_ws_title(char *str)
{
SetConsoleTitle(str);
}
#endif /* WIN_EX */
#if defined(USE_EXTERNALS) || defined(WIN_EX)
#include <LYExtern.h>
#endif
#ifdef __EMX__
#include <io.h>
#endif
#ifdef DIRED_SUPPORT
#include <LYLocal.h>
#include <LYUpload.h>
#endif /* DIRED_SUPPORT */
#include <LYexit.h>
#include <LYLeaks.h>
/* two constants: */
HTLinkType *HTInternalLink = 0;
HTAtom *WWW_SOURCE = 0;
#define NONINTERNAL_OR_PHYS_DIFFERENT(p,n) \
((track_internal_links && \
(!curdoc.internal_link || are_phys_different(p,n))) || \
are_different(p,n))
#define NO_INTERNAL_OR_DIFFERENT(c,n) \
(track_internal_links || are_different(c,n))
static void exit_immediately_with_error_message(int state, int first_file);
static void status_link(const char *curlink_name, int show_more, int show_indx);
static void show_main_statusline(const LinkInfo curlink, int for_what);
static void form_noviceline(int);
static int are_different(DocInfo *doc1, DocInfo *doc2);
static int are_phys_different(DocInfo *doc1, DocInfo *doc2);
#define FASTTAB
static int sametext(char *een,
char *twee)
{
if (een && twee)
return (strcmp(een, twee) == 0);
return TRUE;
}
HTList *Goto_URLs = NULL; /* List of Goto URLs */
char *LYRequestTitle = NULL; /* newdoc.title in calls to getfile() */
char *LYRequestReferer = NULL; /* Referer, may be set in getfile() */
static bstring *prev_target = NULL;
#ifdef DISP_PARTIAL
BOOLEAN display_partial = FALSE; /* could be enabled in HText_new() */
int NumOfLines_partial = 0; /* number of lines displayed in partial mode */
#endif
static int Newline = 0;
static DocInfo newdoc;
static DocInfo curdoc;
static char *traversal_host = NULL;
static char *traversal_link_to_add = NULL;
static char *owner_address = NULL; /* Holds the responsible owner's address */
static char *ownerS_address = NULL; /* Holds owner's address during source fetch */
#ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
static BOOL textinput_activated = FALSE;
#else
#define textinput_activated TRUE /* a current text input is always active */
#endif
#ifdef INACTIVE_INPUT_STYLE_VH
BOOL textinput_redrawn = FALSE;
/*must be public since used in LYhighlight(..) */
#endif
#ifdef LY_FIND_LEAKS
/*
* Function for freeing allocated mainloop() variables. - FM
*/
static void free_mainloop_variables(void)
{
LYFreeDocInfo(&newdoc);
LYFreeDocInfo(&curdoc);
#ifdef USE_COLOR_STYLE
FREE(curdoc.style);
FREE(newdoc.style);
#endif
FREE(traversal_host);
FREE(traversal_link_to_add);
FREE(owner_address);
FREE(ownerS_address);
#ifdef DIRED_SUPPORT
clear_tags();
reset_dired_menu();
#endif /* DIRED_SUPPORT */
FREE(WWW_Download_File); /* LYGetFile.c/HTFWriter.c */
FREE(LYRequestReferer);
return;
}
#endif /* LY_FIND_LEAKS */
#ifndef NO_LYNX_TRACE
static void TracelogOpenFailed(void)
{
WWW_TraceFlag = FALSE;
if (LYCursesON) {
HTUserMsg(TRACELOG_OPEN_FAILED);
} else {
fprintf(stderr, "%s\n", TRACELOG_OPEN_FAILED);
exit_immediately(EXIT_FAILURE);
}
}
static BOOLEAN LYReopenTracelog(BOOLEAN *trace_flag_ptr)
{
CTRACE((tfp, "\nTurning off TRACE for fetch of log.\n"));
LYCloseTracelog();
if ((LYTraceLogFP = LYAppendToTxtFile(LYTraceLogPath)) == NULL) {
TracelogOpenFailed();
return FALSE;
}
if (TRACE) {
WWW_TraceFlag = FALSE;
*trace_flag_ptr = TRUE;
}
return TRUE;
}
static void turn_trace_back_on(BOOLEAN *trace_flag_ptr)
{
if (*trace_flag_ptr == TRUE) {
WWW_TraceFlag = TRUE;
*trace_flag_ptr = FALSE;
fprintf(tfp, "Turning TRACE back on.\n\n");
}
}
#else
#define LYReopenTracelog(flag) TRUE
#define turn_trace_back_on(flag) /*nothing */
#endif /* NO_LYNX_TRACE */
FILE *TraceFP(void)
{
#ifndef NO_LYNX_TRACE
if (LYTraceLogFP != 0) {
return LYTraceLogFP;
}
#endif /* NO_LYNX_TRACE */
return stderr;
}
BOOLEAN LYOpenTraceLog(void)
{
#ifndef NO_LYNX_TRACE
if (TRACE && LYUseTraceLog && LYTraceLogFP == NULL) {
/*
* If we can't open it for writing, give up. Otherwise, on VMS close
* it, delete it and any versions from previous sessions so they don't
* accumulate, and open it again. - FM
*/
if ((LYTraceLogFP = LYNewTxtFile(LYTraceLogPath)) == NULL) {
TracelogOpenFailed();
return FALSE;
}
#ifdef VMS
LYCloseTracelog();
HTSYS_remove(LYTraceLogPath);
if ((LYTraceLogFP = LYNewTxtFile(LYTraceLogPath)) == NULL) {
TracelogOpenFailed();
return FALSE;
}
#endif /* VMS */
fflush(stdout);
fflush(stderr);
fprintf(tfp, "\t\t%s (%s)\n\n", LYNX_TRACELOG_TITLE, LYNX_VERSION);
/*
* If TRACE is on, indicate whether the anonymous restrictions are set.
* - FM, LP, kw
*
* This is only a summary for convenience - it doesn't take the case of
* individual -restrictions= options into account. - kw
*/
if (LYValidate) {
if (LYRestricted && had_restrictions_default) {
CTRACE((tfp,
"Validate and some anonymous restrictions are set.\n"));
} else if (had_restrictions_default) {
CTRACE((tfp,
"Validate restrictions set, restriction \"default\" was given.\n"));
} else if (LYRestricted) {
CTRACE((tfp,
"Validate restrictions set, additional anonymous restrictions ignored.\n"));
} else {
CTRACE((tfp, "Validate restrictions are set.\n"));
}
/* But none of the above can actually happen, since there should
* never be a Trace Log with -validate. If it appears in a log
* file something went wrong! */
} else if (LYRestricted) {
if (had_restrictions_all) {
CTRACE((tfp,
"Anonymous restrictions set, restriction \"all\" was given.\n"));
} else {
CTRACE((tfp, "Anonymous restrictions are set.\n"));
}
} else if (had_restrictions_all && had_restrictions_default) {
CTRACE((tfp, "Restrictions \"all\" and \"default\" were given.\n"));
} else if (had_restrictions_default) {
CTRACE((tfp, "Restriction \"default\" was given.\n"));
} else if (had_restrictions_all) {
CTRACE((tfp, "\"all\" restrictions are set.\n"));
}
}
#endif /* NO_LYNX_TRACE */
return TRUE;
}
void LYCloseTracelog(void)
{
#ifndef NO_LYNX_TRACE
if (LYTraceLogFP != 0) {
fflush(stdout);
fflush(stderr);
fclose(LYTraceLogFP);
LYTraceLogFP = 0;
}
#endif /* NO_LYNX_TRACE */
}
void handle_LYK_TRACE_TOGGLE(void)
{
#ifndef NO_LYNX_TRACE
WWW_TraceFlag = (BOOLEAN) !WWW_TraceFlag;
if (LYOpenTraceLog())
HTUserMsg(WWW_TraceFlag ? TRACE_ON : TRACE_OFF);
#else
HTUserMsg(TRACE_DISABLED);
#endif /* NO_LYNX_TRACE */
}
void LYSetNewline(int value)
{
Newline = value;
}
#define LYSetNewline(value) Newline = value
int LYGetNewline(void)
{
return Newline;
}
#define LYGetNewline() Newline
void LYChgNewline(int adjust)
{
LYSetNewline(Newline + adjust);
}
#define LYChgNewline(adjust) Newline += (adjust)
#ifdef USE_SOURCE_CACHE
static BOOLEAN from_source_cache = FALSE;
/*
* Like HTreparse_document(), but also set the flag.
*/
static BOOLEAN reparse_document(void)
{
BOOLEAN result;
from_source_cache = TRUE; /* set for LYMainLoop_pageDisplay() */
if ((result = HTreparse_document()) != FALSE) {
from_source_cache = TRUE; /* set for mainloop refresh */
} else {
from_source_cache = FALSE;
}
return result;
}
#endif /* USE_SOURCE_CACHE */
/*
* Prefer reparsing if we can, but reload if we must - to force regeneration
* of the display.
*/
static BOOLEAN reparse_or_reload(int *cmd)
{
#ifdef USE_SOURCE_CACHE
if (reparse_document()) {
return FALSE;
}
#endif
*cmd = LYK_RELOAD;
return TRUE;
}
/*
* Functions for setting the current address
*/
static void set_address(DocInfo *doc, const char *address)
{
StrAllocCopy(doc->address, address);
}
static void copy_address(DocInfo *dst, DocInfo *src)
{
StrAllocCopy(dst->address, src->address);
}
static void free_address(DocInfo *doc)
{
FREE(doc->address);
}
static void move_address(DocInfo *dst, DocInfo *src)
{
copy_address(dst, src);
free_address(src);
}
#ifdef DISP_PARTIAL
/*
* This is for traversal call from within partial mode in LYUtils.c
* and HTFormat.c It simply calls HText_pageDisplay() but utilizes
* LYMainLoop.c static variables to manage proper newline position
* in case of #fragment
*/
BOOL LYMainLoop_pageDisplay(int line_num)
{
const char *pound;
int prev_newline = LYGetNewline();
/*
* Override Newline with a new value if user scrolled the document while
* loading (in LYUtils.c).
*/
LYSetNewline(line_num);
#ifdef USE_SOURCE_CACHE
/*
* reparse_document() acts on 'curdoc' which always on top of the
* history stack: no need to resolve #fragment position since
* we already know it (curdoc.line).
* So bypass here. Sorry for possible confusion...
*/
if (!from_source_cache)
#endif
/*
* If the requested URL has the #fragment, and we are not popped
* from the history stack, and have not scrolled the document yet -
* we should calculate correct newline position for the fragment.
* (This is a bit suboptimal since HTFindPoundSelector() traverse
* anchors list each time, so we have a quadratic complexity
* and may load CPU in a worst case).
*/
if (display_partial
&& newdoc.line == 1 && line_num == 1 && prev_newline == 1
&& (pound = findPoundSelector(newdoc.address))
&& *pound && *(pound + 1)) {
if (HTFindPoundSelector(pound + 1)) {
/* HTFindPoundSelector will initialize www_search_result */
LYSetNewline(www_search_result);
} else {
LYSetNewline(prev_newline); /* restore ??? */
return NO; /* no repaint */
}
}
HText_pageDisplay(LYGetNewline(), prev_target->str);
return YES;
}
#endif /* DISP_PARTIAL */
static BOOL set_curdoc_link(int nextlink)
{
BOOL result = FALSE;
if (curdoc.link != nextlink
&& nextlink >= 0
&& nextlink < nlinks) {
if (curdoc.link >= 0 && curdoc.link < nlinks) {
LYhighlight(FALSE, curdoc.link, prev_target->str);
result = TRUE;
}
curdoc.link = nextlink;
}
return result;
}
/*
* Setup newdoc to jump to the given line.
*
* FIXME: prefer to also jump to the link given in a URL fragment, but the
* interface of getfile() does not provide that ability yet.
*/
static void goto_line(int nextline)
{
int n;
int old_link = newdoc.link;
newdoc.link = 0;
for (n = 0; n < nlinks; ++n) {
if (nextline == links[n].anchor_line_num + 1) {
CTRACE((tfp, "top_of_screen %d\n", HText_getTopOfScreen() + 1));
CTRACE((tfp, "goto_line(%d) -> link %d -> %d\n", nextline,
old_link, n));
newdoc.link = n;
break;
}
}
}
#ifdef USE_MOUSE
static void set_curdoc_link_by_mouse(int nextlink)
{
if (set_curdoc_link(nextlink)) {
LYhighlight(TRUE, nextlink, prev_target->str);
LYmsec_delay(20);
}
}
#else
#define set_curdoc_link_by_mouse(nextlink) set_curdoc_link(nextlink)
#endif
static int do_change_link(void)
{
#ifdef USE_MOUSE
/* Is there a mouse-clicked link waiting? */
int mouse_tmp = get_mouse_link();
/* If yes, use it as the link */
if (mouse_tmp != -1) {
if (mouse_tmp < 0 || mouse_tmp >= nlinks) {
char *msgtmp = NULL;
HTSprintf0(&msgtmp,
gettext("Internal error: Invalid mouse link %d!"),
mouse_tmp);
HTAlert(msgtmp);
FREE(msgtmp);
return (-1); /* indicates unexpected error */
}
set_curdoc_link_by_mouse(mouse_tmp);
}
#endif /* USE_MOUSE */
return (0); /* indicates OK */
}
#ifdef DIRED_SUPPORT
#define DIRED_UNCACHE_1 if (LYAutoUncacheDirLists < 1) /*nothing*/ ;\
else HTuncache_current_document()
#define DIRED_UNCACHE_2 if (LYAutoUncacheDirLists < 2) /*nothing*/ ;\
else HTuncache_current_document()
#endif /* DIRED_SUPPORT */
static void do_check_goto_URL(bstring **user_input,
char **old_user_input,
BOOLEAN *force_load)
{
static BOOLEAN always = TRUE;
/* *INDENT-OFF* */
static struct {
const char *name;
BOOLEAN *flag;
} table[] = {
{ STR_FILE_URL, &no_file_url },
{ STR_FILE_URL, &no_goto_file },
{ STR_LYNXEXEC, &no_goto_lynxexec },
{ STR_LYNXPROG, &no_goto_lynxprog },
{ STR_LYNXCGI, &no_goto_lynxcgi },
{ STR_CSO_URL, &no_goto_cso },
{ STR_FINGER_URL, &no_goto_finger },
{ STR_FTP_URL, &no_goto_ftp },
{ STR_GOPHER_URL, &no_goto_gopher },
{ STR_HTTP_URL, &no_goto_http },
{ STR_HTTPS_URL, &no_goto_https },
{ STR_MAILTO_URL, &no_goto_mailto },
{ STR_RLOGIN_URL, &no_goto_rlogin },
{ STR_TELNET_URL, &no_goto_telnet },
{ STR_TN3270_URL, &no_goto_tn3270 },
{ STR_WAIS_URL, &no_goto_wais },
#ifndef DISABLE_BIBP
{ STR_BIBP_URL, &no_goto_bibp },
#endif
#ifndef DISABLE_NEWS
{ STR_NEWS_URL, &no_goto_news },
{ STR_NNTP_URL, &no_goto_nntp },
{ STR_SNEWS_URL, &no_goto_snews },
#endif
#ifdef EXEC_LINKS
{ STR_LYNXEXEC, &local_exec_on_local_files },
{ STR_LYNXPROG, &local_exec_on_local_files },
#endif /* EXEC_LINKS */
{ STR_LYNXCFG, &no_goto_configinfo },
{ STR_LYNXCFLAGS, &no_goto_configinfo },
{ STR_LYNXCOOKIE, &always },
#ifdef USE_CACHEJAR
{ STR_LYNXCACHE, &always },
#endif
{ STR_LYNXDIRED, &always },
{ STR_LYNXDOWNLOAD, &always },
{ STR_LYNXOPTIONS, &always },
{ STR_LYNXPRINT, &always },
};
/* *INDENT-ON* */
unsigned n;
BOOLEAN found = FALSE;
/* allow going to anchors */
if ((*user_input)->str[0] == '#') {
if ((*user_input)->str[1] &&
HTFindPoundSelector((*user_input)->str + 1)) {
/* HTFindPoundSelector will initialize www_search_result,
so we do nothing else. */
HTAddGotoURL((*user_input)->str);
trimPoundSelector(curdoc.address);
StrAllocCat(curdoc.address, (*user_input)->str);
}
} else {
/*
* If it's not a URL then make it one.
*/
StrAllocCopy(*old_user_input, (*user_input)->str);
LYEnsureAbsoluteURL(old_user_input, "", TRUE);
BStrCopy0((*user_input), *old_user_input);
FREE(*old_user_input);
for (n = 0; n < TABLESIZE(table); n++) {
if (*(table[n].flag)
&& !StrNCmp((*user_input)->str,
table[n].name,
strlen(table[n].name))) {
found = TRUE;
HTUserMsg2(GOTO_XXXX_DISALLOWED, table[n].name);
break;
}
}
if (found) {
;
} else if (LYValidate &&
!isHTTP_URL((*user_input)->str) &&
!isHTTPS_URL((*user_input)->str)) {
HTUserMsg(GOTO_NON_HTTP_DISALLOWED);
} else {
set_address(&newdoc, (*user_input)->str);
newdoc.isHEAD = FALSE;
/*
* 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)) {
/*
* Make a name for this new URL.
*/
StrAllocCopy(newdoc.title,
gettext("A URL specified by the user"));
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
*force_load = TRUE;
#ifdef DIRED_SUPPORT
if (lynx_edit_mode) {
DIRED_UNCACHE_2;
}
#endif /* DIRED_SUPPORT */
}
LYUserSpecifiedURL = TRUE;
HTAddGotoURL(newdoc.address);
}
}
}
/* returns FALSE if user cancelled input or URL was invalid, TRUE otherwise */
static BOOL do_check_recall(int ch,
bstring **user_input,
char **old_user_input,
int URLTotal,
int *URLNum,
RecallType recall,
BOOLEAN *FirstURLRecall)
{
char *cp;
BOOL ret = FALSE;
if (*old_user_input == 0)
StrAllocCopy(*old_user_input, "");
for (;;) {
#ifdef WIN_EX /* 1998/10/11 (Sun) 10:41:05 */
int len = (int) strlen((*user_input)->str);
if (len >= 3) {
if (len < MAX_LINE - 1
&& LYIsHtmlSep((*user_input)->str[len - 3])
&& LYIsDosDrive((*user_input)->str + len - 2))
LYAddPathSep0((*user_input)->str);
} else if (len == 2 && (*user_input)->str[1] == ':') {
if (LYIsDosDrive((*user_input)->str)) {
LYAddPathSep0((*user_input)->str);
} else {
HTUserMsg2(WWW_ILLEGAL_URL_MESSAGE, (*user_input)->str);
BStrCopy0((*user_input), *old_user_input);
FREE(*old_user_input);
ret = FALSE;
break;
}
}
#endif
/*
* Get rid of leading spaces (and any other spaces).
*/
LYTrimAllStartfile((*user_input)->str);
if (isBEmpty(*user_input) &&
!(recall && (ch == UPARROW_KEY || ch == DNARROW_KEY))) {
BStrCopy0((*user_input), *old_user_input);
FREE(*old_user_input);
HTInfoMsg(CANCELLED);
ret = FALSE;
break;
}
if (recall && ch == UPARROW_KEY) {
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 += 1;
}
if (*URLNum >= URLTotal)
/*
* Roll around to the last URL in the list. - FM
*/
*URLNum = 0;
if ((cp = (char *) HTList_objectAt(Goto_URLs,
*URLNum)) != NULL) {
BStrCopy0((*user_input), cp);
if (goto_buffer
&& **old_user_input
&& !strcmp(*old_user_input, (*user_input)->str)) {
_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 = LYgetBString(user_input, FALSE, 0, recall)) < 0) {
/*
* User cancelled the Goto via ^G. Restore
* user_input and break. - FM
*/
BStrCopy0((*user_input), *old_user_input);
FREE(*old_user_input);
HTInfoMsg(CANCELLED);
ret = FALSE;
break;
}
continue;
}
} else if (recall && ch == DNARROW_KEY) {
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 -= 1;
}
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) {
BStrCopy0((*user_input), cp);
if (goto_buffer && **old_user_input &&
!strcmp(*old_user_input, (*user_input)->str)) {
_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 = LYgetBString(user_input, FALSE, 0, recall)) < 0) {
/*
* User cancelled the Goto via ^G. Restore
* user_input and break. - FM
*/
BStrCopy0((*user_input), *old_user_input);
FREE(*old_user_input);
HTInfoMsg(CANCELLED);
ret = FALSE;
break;
}
continue;
}
} else {
ret = TRUE;
break;
}
}
return ret;
}
static void do_cleanup_after_delete(void)
{
HTuncache_current_document();
move_address(&newdoc, &curdoc);
newdoc.line = curdoc.line;
if (curdoc.link == nlinks - 1) {
/*
* We deleted the last link on the page. - FM
*/
newdoc.link = curdoc.link - 1;
} else {
newdoc.link = curdoc.link;
}
}
static int find_link_near_col(int col,
int delta)
{
int i;
for (i = curdoc.link; delta > 0 ? (i < nlinks) : (i >= 0); i += delta) {
if ((links[i].ly - links[curdoc.link].ly) * delta > 0) {
int cy = links[i].ly, best = -1, dist = 1000000;
while ((delta > 0 ? (i < nlinks) : (i >= 0)) && cy == links[i].ly) {
int cx = links[i].lx;
const char *text = LYGetHiliteStr(i, 0);
if (text != NULL)
cx += (int) strlen(text) / 2;
cx -= col;
if (cx < 0)
cx = -cx;
if (cx < dist) {
dist = cx;
best = i;
}
i += delta;
}
return (best);
}
}
return (-1);
}
/*
* This is a special feature to traverse every http link derived from startfile
* and check for errors or create crawl output 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!).
*/
static int DoTraversal(int c,
BOOLEAN *crawl_ok)
{
BOOLEAN rlink_rejected = FALSE;
BOOLEAN rlink_exists;
BOOLEAN rlink_allowed;
rlink_exists = (BOOL) (nlinks > 0 &&
links[curdoc.link].type != WWW_FORM_LINK_TYPE &&
links[curdoc.link].lname != NULL);
if (rlink_exists) {
rlink_rejected = lookup_reject(links[curdoc.link].lname);
if (!rlink_rejected &&
traversal_host &&
links[curdoc.link].lname) {
if (!isLYNXIMGMAP(links[curdoc.link].lname)) {
rlink_allowed = (BOOL) !StrNCmp(traversal_host,
links[curdoc.link].lname,
strlen(traversal_host));
} else {
rlink_allowed = (BOOL) !StrNCmp(traversal_host,
links[curdoc.link].lname + LEN_LYNXIMGMAP,
strlen(traversal_host));
}
} else {
rlink_allowed = FALSE;
}
} else {
rlink_allowed = FALSE;
}
if (rlink_exists && rlink_allowed) {
if (lookup_link(links[curdoc.link].lname)) {
if (more_links ||
(curdoc.link > -1 && curdoc.link < nlinks - 1)) {
c = DNARROW_KEY;
} else {
if (STREQ(curdoc.title, "Entry into main screen") ||
(nhist <= 0)) {
if (!dump_output_immediately) {
cleanup();
exit_immediately(EXIT_FAILURE);
}
c = -1;
} else {
c = LTARROW_KEY;
}
}
} else {
StrAllocCopy(traversal_link_to_add,
links[curdoc.link].lname);
if (!isLYNXIMGMAP(traversal_link_to_add))
*crawl_ok = TRUE;
c = RTARROW_KEY;
}
} else { /* no good right link, so only down and left arrow ok */
if (rlink_exists /* && !rlink_rejected */ )
/* uncomment in previous line to avoid duplicates - kw */
add_to_reject_list(links[curdoc.link].lname);
if (more_links ||
(curdoc.link > -1 && curdoc.link < nlinks - 1)) {
c = DNARROW_KEY;
} 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();
exit_immediately(EXIT_FAILURE);
}
c = -1;
} else {
c = LTARROW_KEY;
}
}
}
CTRACE((tfp, "DoTraversal(%d:%d) -> %s\n",
nlinks > 0 ? curdoc.link : 0,
nlinks,
LYKeycodeToString(c, FALSE)));
return c;
}
static BOOLEAN check_history(void)
{
const char *base;
if (!curdoc.post_data)
/*
* Normal case - List Page is not associated with post data. - kw
*/
return TRUE;
if (nhist > 0
&& !LYresubmit_posts
&& HDOC(nhist - 1).post_data
&& BINEQ(curdoc.post_data, HDOC(nhist - 1).post_data)
&& (base = HText_getContentBase()) != 0) {
char *text = !isLYNXIMGMAP(HDOC(nhist - 1).address)
? HDOC(nhist - 1).address
: HDOC(nhist - 1).address + LEN_LYNXIMGMAP;
if (!StrNCmp(base, text, strlen(base))) {
/*
* Normal case - as best as we can check, the document at the top
* of the history stack seems to be the document the List Page is
* about (or a LYNXIMGMAP derived from it), and LYresubmit_posts is
* not set, so don't prompt here. If we actually have to repeat a
* POST because, against expectations, the underlying document
* isn't cached any more, HTAccess will prompt for confirmation,
* unless we had LYK_NOCACHE -kw
*/
return TRUE;
}
}
return FALSE;
}
static int handle_LYK_ACTIVATE(int *c,
int cmd GCC_UNUSED,
BOOLEAN *try_internal GCC_UNUSED,
BOOLEAN *refresh_screen,
BOOLEAN *force_load,
int real_cmd)
{
if (do_change_link() == -1) {
LYforce_no_cache = FALSE;
reloading = FALSE;
return 1; /* mouse stuff was confused, ignore - kw */
}
if (nlinks > 0) {
if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
#ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
if (real_cmd == LYK_ACTIVATE && textfields_need_activation &&
F_TEXTLIKE(links[curdoc.link].l_form->type)) {
textinput_activated = TRUE;
show_main_statusline(links[curdoc.link], FOR_INPUT);
textfields_need_activation = textfields_activation_option;
return 0;
}
#endif
/*
* Don't try to submit forms with bad actions. - FM
*/
if (links[curdoc.link].l_form->type == F_SUBMIT_TYPE ||
links[curdoc.link].l_form->type == F_IMAGE_SUBMIT_TYPE ||
links[curdoc.link].l_form->type == F_TEXT_SUBMIT_TYPE) {
/*
* Do nothing if it's disabled. - FM
*/
if (links[curdoc.link].l_form->disabled == YES) {
HTOutputFormat = WWW_PRESENT;
LYforce_no_cache = FALSE;
reloading = FALSE;
return 0;
}
/*
* Make sure we have an action. - FM
*/
if (isEmpty(links[curdoc.link].l_form->submit_action)) {
HTUserMsg(NO_FORM_ACTION);
HTOutputFormat = WWW_PRESENT;
LYforce_no_cache = FALSE;
reloading = FALSE;
return 0;
}
/*
* Check for no_mail if the form action is a mailto URL. - FM
*/
if (links[curdoc.link].l_form->submit_method
== URL_MAIL_METHOD && no_mail) {
HTAlert(FORM_MAILTO_DISALLOWED);
HTOutputFormat = WWW_PRESENT;
LYforce_no_cache = FALSE;
reloading = FALSE;
return 0;
}
/*
* Make sure this isn't a spoof in an account with restrictions
* on file URLs. - FM
*/
if (no_file_url &&
isFILE_URL(links[curdoc.link].l_form->submit_action)) {
HTAlert(FILE_ACTIONS_DISALLOWED);
HTOutputFormat = WWW_PRESENT;
LYforce_no_cache = FALSE;
reloading = FALSE;
return 0;
}
/*
* Make sure this isn't a spoof attempt via an internal URL. -
* FM
*/
if (isLYNXCOOKIE(links[curdoc.link].l_form->submit_action) ||
isLYNXCACHE(links[curdoc.link].l_form->submit_action) ||
#ifdef DIRED_SUPPORT
#ifdef OK_PERMIT
(isLYNXDIRED(links[curdoc.link].l_form->submit_action) &&
(no_dired_support ||
strncasecomp((links[curdoc.link].l_form->submit_action
+ 10),
"//PERMIT_LOCATION", 17) ||
!LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS))) ||
#else
isLYNXDIRED(links[curdoc.link].l_form->submit_action) ||
#endif /* OK_PERMIT */
#endif /* DIRED_SUPPORT */
isLYNXDOWNLOAD(links[curdoc.link].l_form->submit_action) ||
isLYNXHIST(links[curdoc.link].l_form->submit_action) ||
isLYNXEDITMAP(links[curdoc.link].l_form->submit_action) ||
isLYNXKEYMAP(links[curdoc.link].l_form->submit_action) ||
isLYNXIMGMAP(links[curdoc.link].l_form->submit_action) ||
isLYNXPRINT(links[curdoc.link].l_form->submit_action) ||
isLYNXEXEC(links[curdoc.link].l_form->submit_action) ||
isLYNXPROG(links[curdoc.link].l_form->submit_action)) {
HTAlert(SPECIAL_ACTION_DISALLOWED);
CTRACE((tfp, "LYMainLoop: Rejected '%s'\n",
links[curdoc.link].l_form->submit_action));
HTOutputFormat = WWW_PRESENT;
LYforce_no_cache = FALSE;
reloading = FALSE;
return 0;
}
#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].l_form->submit_enctype) {
if (!strcmp(links[curdoc.link].l_form->submit_enctype,
"multipart/form-data")) {
HTAlert(gettext("Enctype multipart/form-data not yet supported! Cannot submit."));
HTOutputFormat = WWW_PRESENT;
LYforce_no_cache = FALSE;
reloading = FALSE;
return 0;
}
}
#endif /* NOTDEFINED */
if (check_realm) {
LYPermitURL = TRUE;
}
if (no_filereferer == TRUE && isFILE_URL(curdoc.address)) {
LYNoRefererForThis = TRUE;
}
if (links[curdoc.link].l_form->submit_method != URL_MAIL_METHOD) {
StrAllocCopy(newdoc.title,
LYGetHiliteStr(curdoc.link, 0));
}
}
/*
* Normally we don't get here for text input fields, but it can
* happen as a result of mouse positioning. In that case the
* statusline will not have updated info, so update it now. - kw
*/
if (F_TEXTLIKE(links[curdoc.link].l_form->type)) {
show_formlink_statusline(links[curdoc.link].l_form,
(real_cmd == LYK_NOCACHE ||
real_cmd == LYK_DOWNLOAD ||
real_cmd == LYK_HEAD ||
(real_cmd == LYK_MOUSE_SUBMIT &&
!textinput_activated)) ?
FOR_PANEL : FOR_INPUT);
if (user_mode == NOVICE_MODE &&
textinput_activated &&
(real_cmd == LYK_ACTIVATE ||
real_cmd == LYK_MOUSE_SUBMIT)) {
form_noviceline(FormIsReadonly(links[curdoc.link].l_form));
}
}
*c = change_form_link(curdoc.link,
&newdoc, refresh_screen,
FALSE,
(real_cmd == LYK_MOUSE_SUBMIT ||
real_cmd == LYK_NOCACHE ||
real_cmd == LYK_DOWNLOAD ||
real_cmd == LYK_HEAD));
if (*c != LKC_DONE || *refresh_screen) {
/*
* Cannot have been a submit field for which newdoc was filled
* in. - kw
*/
if ((links[curdoc.link].l_form->type == F_SUBMIT_TYPE ||
links[curdoc.link].l_form->type == F_IMAGE_SUBMIT_TYPE ||
links[curdoc.link].l_form->type == F_TEXT_SUBMIT_TYPE) &&
links[curdoc.link].l_form->submit_method
!= URL_MAIL_METHOD) {
/*
* Try to undo change of newdoc.title done above.
*/
if (HText_getTitle()) {
StrAllocCopy(newdoc.title, HText_getTitle());
} else if (curdoc.title) {
StrAllocCopy(newdoc.title, curdoc.title);
}
}
} else {
if (HTOutputFormat == WWW_DOWNLOAD &&
newdoc.post_data != NULL &&
newdoc.safe == FALSE) {
if ((HText_POSTReplyLoaded(&newdoc) == TRUE) &&
HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
HTInfoMsg(CANCELLED);
HTOutputFormat = WWW_PRESENT;
LYforce_no_cache = FALSE;
copy_address(&newdoc, &curdoc);
StrAllocCopy(newdoc.title, curdoc.title);
BStrCopy(newdoc.post_data, curdoc.post_data);
StrAllocCopy(newdoc.post_content_type,
curdoc.post_content_type);
StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
newdoc.isHEAD = curdoc.isHEAD;
newdoc.safe = curdoc.safe;
newdoc.internal_link = curdoc.internal_link;
return 0;
}
}
/*
* Moved here from earlier to only apply when it should.
* Anyway, why should realm checking be overridden for form
* submissions, this seems to be an unnecessary loophole?? But
* that's the way it was, maybe there is some reason. However,
* at least make sure this doesn't weaken restrictions implied
* by -validate!
* - kw 1999-05-25
*/
if (check_realm && !LYValidate) {
LYPermitURL = TRUE;
}
}
if (*c == LKC_DONE) {
*c = DO_NOTHING;
} else if (*c == 23) {
*c = DO_NOTHING;
*refresh_screen = TRUE;
} else {
/* Avoid getting stuck with repeatedly calling
* handle_LYK_ACTIVATE(), instead of calling change_form_link()
* directly from mainloop(), for text input fields. - kw
*/
switch (LKC_TO_C(*c)) {
case '\n':
case '\r':
default:
if ((real_cmd == LYK_ACTIVATE ||
real_cmd == LYK_MOUSE_SUBMIT) &&
F_TEXTLIKE(links[curdoc.link].l_form->type) &&
textinput_activated) {
return 3;
}
break;
}
}
return 2;
} 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 && isFILE_URL(links[curdoc.link].lname)) {
if (!isFILE_URL(curdoc.address) &&
!((isLYNXEDITMAP(curdoc.address) ||
isLYNXKEYMAP(curdoc.address) ||
isLYNXCOOKIE(curdoc.address) ||
isLYNXCACHE(curdoc.address)) &&
!StrNCmp(links[curdoc.link].lname,
helpfilepath,
strlen(helpfilepath)))) {
HTAlert(FILE_SERVED_LINKS_DISALLOWED);
reloading = FALSE;
return 0;
} else if (curdoc.bookmark != NULL) {
HTAlert(FILE_BOOKMARKS_DISALLOWED);
reloading = FALSE;
return 0;
}
}
/*
* Make sure this isn't a spoof attempt via an internal URL in a
* non-internal document. - FM
*/
if ((isLYNXCOOKIE(links[curdoc.link].lname) &&
(strcmp(NonNull(curdoc.title), COOKIE_JAR_TITLE) ||
!isLYNXCOOKIE(curdoc.address))) ||
#ifdef USE_CACHEJAR
(isLYNXCACHE(links[curdoc.link].lname) &&
(strcmp(NonNull(curdoc.title), CACHE_JAR_TITLE) ||
!isLYNXCACHE(curdoc.address))) ||
#endif
#ifdef DIRED_SUPPORT
(isLYNXDIRED(links[curdoc.link].lname) &&
!LYIsUIPage(curdoc.address, UIP_DIRED_MENU) &&
!LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS) &&
#ifdef OK_INSTALL
!LYIsUIPage(curdoc.address, UIP_INSTALL) &&
#endif /* OK_INSTALL */
!LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS)) ||
#endif /* DIRED_SUPPORT */
(isLYNXDOWNLOAD(links[curdoc.link].lname) &&
!LYIsUIPage(curdoc.address, UIP_DOWNLOAD_OPTIONS)) ||
(isLYNXHIST(links[curdoc.link].lname) &&
!LYIsUIPage(curdoc.address, UIP_HISTORY) &&
!LYIsUIPage(curdoc.address, UIP_LIST_PAGE) &&
!LYIsUIPage(curdoc.address, UIP_ADDRLIST_PAGE)) ||
(isLYNXPRINT(links[curdoc.link].lname) &&
!LYIsUIPage(curdoc.address, UIP_PRINT_OPTIONS))) {
HTAlert(SPECIAL_VIA_EXTERNAL_DISALLOWED);
HTOutputFormat = WWW_PRESENT;
LYforce_no_cache = FALSE;
reloading = FALSE;
return 0;
}
#ifdef USE_EXTERNALS
if (run_external(links[curdoc.link].lname, TRUE)) {
*refresh_screen = TRUE;
return 0;
}
#endif /* USE_EXTERNALS */
/*
* Follow a normal link or anchor.
*/
set_address(&newdoc, links[curdoc.link].lname);
StrAllocCopy(newdoc.title, LYGetHiliteStr(curdoc.link, 0));
/*
* For internal links, retain POST content if present. If we are
* on the List Page, prevent pushing it on the history stack.
* Otherwise set try_internal to signal that the top of the loop
* should attempt to reposition directly, without calling getfile.
* - kw
*/
if (track_internal_links) {
/*
* Might be an internal link anchor in the same doc. If so, take
* the try_internal shortcut if we didn't fall through from
* LYK_NOCACHE. - kw
*/
newdoc.internal_link =
(links[curdoc.link].type == WWW_INTERN_LINK_TYPE);
if (newdoc.internal_link) {
/*
* Special case of List Page document with an internal link
* indication, which may really stand for an internal link
* within the document the List Page is about. - kw
*/
if (LYIsListpageTitle(NonNull(curdoc.title)) &&
(LYIsUIPage(curdoc.address, UIP_LIST_PAGE) ||
LYIsUIPage(curdoc.address, UIP_ADDRLIST_PAGE))) {
if (check_history()) {
LYinternal_flag = TRUE;
} else {
HTLastConfirmCancelled(); /* reset flag */
if (!confirm_post_resub(newdoc.address,
newdoc.title,
((LYresubmit_posts &&
HText_POSTReplyLoaded(&newdoc))
? 1
: 2),
2)) {
if (HTLastConfirmCancelled() ||
(LYresubmit_posts &&
cmd != LYK_NOCACHE &&
!HText_POSTReplyLoaded(&newdoc))) {
/* cancel the whole thing */
LYforce_no_cache = FALSE;
reloading = FALSE;
copy_address(&newdoc, &curdoc);
StrAllocCopy(newdoc.title, curdoc.title);
newdoc.internal_link = curdoc.internal_link;
HTInfoMsg(CANCELLED);
return 1;
} else if (LYresubmit_posts &&
cmd != LYK_NOCACHE) {
/* If LYresubmit_posts is set, and the
answer was No, and the key wasn't
NOCACHE, and we have a cached copy,
then use it. - kw */
LYforce_no_cache = FALSE;
} else {
/* if No, but not ^C or ^G, drop
* the post data. Maybe the link
* wasn't meant to be internal after
* all, here we can recover from that
* assumption. - kw */
LYFreePostData(&newdoc);
newdoc.internal_link = FALSE;
HTAlert(DISCARDING_POST_DATA);
}
}
}
/*
* Don't push the List Page if we follow an internal link
* given by it. - kw
*/
free_address(&curdoc);
} else if (cmd != LYK_NOCACHE) {
*try_internal = TRUE;
}
if (!(LYresubmit_posts && newdoc.post_data))
LYinternal_flag = TRUE;
/* We still set force_load so that history pushing
* etc. will be done. - kw
*/
*force_load = TRUE;
return 1;
} else {
/*
* Free POST content if not an internal link. - kw
*/
LYFreePostData(&newdoc);
}
}
/*
* 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)) {
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
if (isLYNXMESSAGES(newdoc.address))
LYforce_no_cache = TRUE;
}
if (!no_jump && lynxjumpfile && curdoc.address &&
!strcmp(lynxjumpfile, curdoc.address)) {
LYJumpFileURL = TRUE;
LYUserSpecifiedURL = TRUE;
} else if ((curdoc.title &&
(LYIsUIPage(curdoc.address, UIP_HISTORY) ||
!strcmp(curdoc.title, HISTORY_PAGE_TITLE))) ||
curdoc.bookmark != NULL ||
(lynxjumpfile &&
curdoc.address &&
!strcmp(lynxjumpfile, curdoc.address))) {
LYUserSpecifiedURL = TRUE;
} else if (no_filereferer == TRUE &&
curdoc.address != NULL &&
isFILE_URL(curdoc.address)) {
LYNoRefererForThis = TRUE;
}
newdoc.link = 0;
*force_load = TRUE; /* force MainLoop to reload */
#ifdef USE_PRETTYSRC
psrc_view = FALSE; /* we get here if link is not internal */
#endif
#if defined(DIRED_SUPPORT) && !defined(__DJGPP__)
if (lynx_edit_mode) {
DIRED_UNCACHE_2;
/*
* Unescaping any slash chars in the URL, but avoid double
* unescaping and too-early unescaping of other chars. - KW
*/
HTUnEscapeSome(newdoc.address, "/");
/* avoid stripping final slash for root dir - kw */
if (strcasecomp(newdoc.address, "file://localhost/"))
strip_trailing_slash(newdoc.address);
}
#endif /* DIRED_SUPPORT && !__DJGPP__ */
if (isLYNXCOOKIE(curdoc.address)
|| isLYNXCACHE(curdoc.address)) {
HTuncache_current_document();
}
}
}
return 0;
}
/*
* If the given form link does not point to the requested type, search for
* the first link belonging to the form which does. If there are none,
* return null.
*/
#define SameFormAction(form,submit) \
((submit) \
? (F_SUBMITLIKE((form)->type)) \
: ((form)->type == F_RESET_TYPE))
static FormInfo *FindFormAction(FormInfo * given, int submit)
{
FormInfo *result = NULL;
FormInfo *fi;
int i;
if (given == NULL) {
HTAlert(LINK_NOT_IN_FORM);
} else if (SameFormAction(given, submit)) {
result = given;
} else {
for (i = 0; i < nlinks; i++) {
if ((fi = links[i].l_form) != 0 &&
fi->number == given->number &&
(SameFormAction(fi, submit))) {
result = fi;
break;
}
}
}
return result;
}
static FormInfo *MakeFormAction(FormInfo * given, int submit)
{
FormInfo *result = 0;
if (given != 0) {
result = typecalloc(FormInfo);
if (result == NULL)
outofmem(__FILE__, "MakeFormAction");
*result = *given;
if (submit) {
if (result->submit_action == 0) {
PerFormInfo *pfi = HText_PerFormInfo(result->number);
*result = pfi->data;
}
result->type = F_SUBMIT_TYPE;
} else {
result->type = F_RESET_TYPE;
}
result->number = given->number;
}
return result;
}
static void handle_LYK_SUBMIT(int cur, DocInfo *doc, BOOLEAN *refresh_screen)
{
FormInfo *form = FindFormAction(links[cur].l_form, 1);
FormInfo *make = NULL;
char *save_submit_action = NULL;
if (form == 0) {
make = MakeFormAction(links[cur].l_form, 1);
form = make;
}
if (form != 0) {
StrAllocCopy(save_submit_action, form->submit_action);
form->submit_action = HTPrompt(EDIT_SUBMIT_URL, form->submit_action);
if (isEmpty(form->submit_action) ||
(!isLYNXCGI(form->submit_action) &&
StrNCmp(form->submit_action, "http", 4))) {
HTUserMsg(FORM_ACTION_NOT_HTTP_URL);
} else {
HTInfoMsg(SUBMITTING_FORM);
HText_SubmitForm(form, doc, form->name, form->value);
*refresh_screen = TRUE;
}
StrAllocCopy(form->submit_action, save_submit_action);
FREE(make);
}
}
static void handle_LYK_RESET(int cur, BOOLEAN *refresh_screen)
{
FormInfo *form = FindFormAction(links[cur].l_form, 0);
FormInfo *make = NULL;
if (form == 0) {
make = MakeFormAction(links[cur].l_form, 0);
form = make;
}
if (form != 0) {
HTInfoMsg(RESETTING_FORM);
HText_ResetForm(form);
*refresh_screen = TRUE;
FREE(make);
}
}
#ifdef USE_ADDRLIST_PAGE
static BOOLEAN handle_LYK_ADDRLIST(int *cmd)
{
/*
* Don't do if already viewing list addresses page.
*/
if (LYIsUIPage(curdoc.address, UIP_ADDRLIST_PAGE)) {
/*
* Already viewing list page, so get out.
*/
*cmd = LYK_PREV_DOC;
return TRUE;
}
/*
* Print address list page to file.
*/
if (showlist(&newdoc, FALSE) < 0)
return FALSE;
StrAllocCopy(newdoc.title, ADDRLIST_PAGE_TITLE);
/*
* showlist will set newdoc's other fields. It may leave post_data intact
* so the list can be used to follow internal links in the current document
* even if it is a POST response. - kw
*/
if (LYValidate || check_realm) {
LYPermitURL = TRUE;
StrAllocCopy(lynxlistfile, newdoc.address);
}
return FALSE;
}
#endif /* USE_ADDRLIST_PAGE */
static void handle_LYK_ADD_BOOKMARK(BOOLEAN *refresh_screen,
int *old_c,
int real_c)
{
int c;
if (LYValidate) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(BOOKMARKS_DISABLED);
}
return;
}
if (!LYIsUIPage(curdoc.address, UIP_HISTORY) &&
!LYIsUIPage(curdoc.address, UIP_SHOWINFO) &&
!LYIsUIPage(curdoc.address, UIP_PRINT_OPTIONS) &&
#ifdef DIRED_SUPPORT
!LYIsUIPage(curdoc.address, UIP_DIRED_MENU) &&
!LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS) &&
!LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS) &&
#endif /* DIRED_SUPPORT */
!LYIsUIPage(curdoc.address, UIP_DOWNLOAD_OPTIONS) &&
!isLYNXCOOKIE(curdoc.address) &&
!isLYNXCACHE(curdoc.address) &&
!LYIsUIPage(curdoc.address, UIP_OPTIONS_MENU) &&
((nlinks <= 0) ||
(links[curdoc.link].lname != NULL &&
!isLYNXHIST(links[curdoc.link].lname) &&
!isLYNXPRINT(links[curdoc.link].lname) &&
!isLYNXDIRED(links[curdoc.link].lname) &&
!isLYNXDOWNLOAD(links[curdoc.link].lname) &&
!isLYNXCOOKIE(links[curdoc.link].lname) &&
!isLYNXCACHE(links[curdoc.link].lname) &&
!isLYNXPRINT(links[curdoc.link].lname)))) {
if (nlinks > 0) {
if (curdoc.post_data == NULL &&
curdoc.bookmark == NULL &&
!LYIsUIPage(curdoc.address, UIP_LIST_PAGE) &&
!LYIsUIPage(curdoc.address, UIP_ADDRLIST_PAGE) &&
!LYIsUIPage(curdoc.address, UIP_VLINKS)) {
/*
* The document doesn't have POST content, and is not a
* bookmark file, nor is the list or visited links page, so we
* can save either that or the link. - FM
*/
_statusline(BOOK_D_L_OR_CANCEL);
if ((c = LYgetch_single()) == 'D') {
save_bookmark_link(curdoc.address, curdoc.title);
*refresh_screen = TRUE; /* MultiBookmark support */
goto check_add_bookmark_to_self;
}
} else {
if (LYMultiBookmarks == MBM_OFF &&
curdoc.bookmark != NULL &&
strstr(curdoc.address,
(*bookmark_page == '.'
? (bookmark_page + 1)
: bookmark_page)) != NULL) {
/*
* If multiple bookmarks are disabled, offer the L)ink or
* C)ancel, but with wording which indicates that the link
* already exists in this bookmark file. - FM
*/
_statusline(MULTIBOOKMARKS_SELF);
} else if (curdoc.post_data != NULL &&
links[curdoc.link].type == WWW_INTERN_LINK_TYPE) {
/*
* Internal link, and document has POST content.
*/
HTUserMsg(NOBOOK_POST_FORM);
return;
} else {
/*
* Only offer the link in a document with POST content, or
* if the current document is a bookmark file and multiple
* bookmarks are enabled. - FM
*/
_statusline(BOOK_L_OR_CANCEL);
}
c = LYgetch_single();
}
if (c == 'L') {
if (curdoc.post_data != NULL &&
links[curdoc.link].type == WWW_INTERN_LINK_TYPE) {
/*
* Internal link, and document has POST content.
*/
HTUserMsg(NOBOOK_POST_FORM);
return;
}
/*
* User does want to save the link. - FM
*/
if (links[curdoc.link].type != WWW_FORM_LINK_TYPE) {
save_bookmark_link(links[curdoc.link].lname,
LYGetHiliteStr(curdoc.link, 0));
*refresh_screen = TRUE; /* MultiBookmark support */
} else {
HTUserMsg(NOBOOK_FORM_FIELD);
return;
}
} else {
return;
}
} else if (curdoc.post_data != NULL) {
/*
* No links, and document has POST content. - FM
*/
HTUserMsg(NOBOOK_POST_FORM);
return;
} else if (curdoc.bookmark != NULL) {
/*
* It's a bookmark file from which all of the links were deleted.
* - FM
*/
HTUserMsg(BOOKMARKS_NOLINKS);
return;
} else {
_statusline(BOOK_D_OR_CANCEL);
if (LYgetch_single() == 'D') {
save_bookmark_link(curdoc.address, curdoc.title);
*refresh_screen = TRUE; /* MultiBookmark support */
} else {
return;
}
}
check_add_bookmark_to_self:
if (curdoc.bookmark && BookmarkPage &&
!strcmp(curdoc.bookmark, BookmarkPage)) {
HTuncache_current_document();
move_address(&newdoc, &curdoc);
StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
newdoc.line = curdoc.line;
newdoc.link = curdoc.link;
newdoc.internal_link = FALSE;
}
} else {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NOBOOK_HSML);
}
}
}
static void handle_LYK_CLEAR_AUTH(int *old_c,
int real_c)
{
if (*old_c != real_c) {
*old_c = real_c;
if (HTConfirm(CLEAR_ALL_AUTH_INFO)) {
FREE(authentication_info[0]);
FREE(authentication_info[1]);
FREE(proxyauth_info[0]);
FREE(proxyauth_info[1]);
HTClearHTTPAuthInfo();
#ifndef DISABLE_NEWS
HTClearNNTPAuthInfo();
#endif
#ifndef DISABLE_FTP
HTClearFTPPassword();
#endif
HTUserMsg(AUTH_INFO_CLEARED);
} else {
HTUserMsg(CANCELLED);
}
}
}
static int handle_LYK_COMMAND(bstring **user_input)
{
LYKeymapCode ch;
Kcmd *mp;
char *src, *tmp;
BStrCopy0((*user_input), "");
_statusline(": ");
if (LYgetBString(user_input, FALSE, 0, RECALL_CMD) >= 0) {
src = LYSkipBlanks((*user_input)->str);
tmp = LYSkipNonBlanks(src);
*tmp = 0;
ch = ((mp = LYStringToKcmd(src)) != 0) ? mp->code : LYK_UNKNOWN;
CTRACE((tfp, "LYK_COMMAND(%s.%s) = %d\n", src, tmp, (int) ch));
if (ch == 0) {
return *src ? -1 : 0;
}
/* FIXME: reuse the rest of the buffer for parameters */
return ch;
}
return 0;
}
static void handle_LYK_COMMENT(BOOLEAN *refresh_screen,
char **owner_address_p,
int *old_c,
int real_c)
{
int c;
if (!*owner_address_p &&
strncasecomp(curdoc.address, "http", 4)) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_OWNER);
}
} else if (no_mail) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(MAIL_DISALLOWED);
}
} else {
if (HTConfirmDefault(CONFIRM_COMMENT, NO)) {
if (!*owner_address_p) {
/*
* No owner defined, so make a guess and and offer it to the
* user. - FM
*/
char *address = NULL;
char *temp = HTParse(curdoc.address, "", PARSE_PATH);
char *cp;
if (temp != NULL) {
HTUnEscape(temp);
if (LYIsTilde(*temp) && strlen(temp) > 1) {
/*
* It's a ~user URL so guess user@host. - FM
*/
if ((cp = StrChr((temp + 1), '/')) != NULL)
*cp = '\0';
StrAllocCopy(address, STR_MAILTO_URL);
StrAllocCat(address, (temp + 1));
StrAllocCat(address, "@");
}
FREE(temp);
}
if (address == NULL)
/*
* Wasn't a ~user URL so guess WebMaster@host. - FM
*/
StrAllocCopy(address, "mailto:WebMaster@");
temp = HTParse(curdoc.address, "", PARSE_HOST);
StrAllocCat(address, temp);
HTSprintf0(&temp, NO_OWNER_USE, address);
c = HTConfirmDefault(temp, NO);
FREE(temp);
if (c == YES) {
StrAllocCopy(*owner_address_p, address);
FREE(address);
} else {
FREE(address);
return;
}
}
if (is_url(*owner_address_p) != MAILTO_URL_TYPE) {
/*
* The address is a URL. Just follow the link.
*/
set_address(&newdoc, *owner_address_p);
newdoc.internal_link = FALSE;
} else {
/*
* The owner_address is a mailto: URL.
*/
const char *kp = HText_getRevTitle();
const char *id = HText_getMessageID();
char *tmptitle = NULL;
if (!kp && HTMainAnchor) {
kp = HTAnchor_subject(HTMainAnchor);
if (non_empty(kp)) {
if (strncasecomp(kp, "Re: ", 4)) {
StrAllocCopy(tmptitle, "Re: ");
StrAllocCat(tmptitle, kp);
kp = tmptitle;
}
}
}
if (StrChr(*owner_address_p, ':') != NULL)
/*
* Send a reply. The address is after the colon.
*/
reply_by_mail(StrChr(*owner_address_p, ':') + 1,
curdoc.address,
NonNull(kp), id);
else
reply_by_mail(*owner_address_p, curdoc.address,
NonNull(kp), id);
FREE(tmptitle);
*refresh_screen = TRUE; /* to force a showpage */
}
}
}
}
#ifdef USE_CACHEJAR
static BOOLEAN handle_LYK_CACHE_JAR(int *cmd)
{
/*
* Don't do this if already viewing cache jar.
*/
if (!isLYNXCACHE(curdoc.address)) {
set_address(&newdoc, STR_LYNXCACHE "/");
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
LYforce_no_cache = TRUE;
if (LYValidate || check_realm) {
LYPermitURL = TRUE;
}
} else {
/*
* If already in the cache jar, get out.
*/
*cmd = LYK_PREV_DOC;
return TRUE;
}
return FALSE;
}
#endif /* USE_CACHEJAR */
static BOOLEAN handle_LYK_COOKIE_JAR(int *cmd)
{
/*
* Don't do if already viewing the cookie jar.
*/
if (!isLYNXCOOKIE(curdoc.address)) {
set_address(&newdoc, "LYNXCOOKIE:/");
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
LYforce_no_cache = TRUE;
if (LYValidate || check_realm) {
LYPermitURL = TRUE;
}
} else {
/*
* If already in the cookie jar, get out.
*/
*cmd = LYK_PREV_DOC;
return TRUE;
}
return FALSE;
}
#if defined(DIRED_SUPPORT)
static void handle_LYK_CREATE(void)
{
if (lynx_edit_mode && !no_dired_support) {
if (local_create(&curdoc) > 0) {
DIRED_UNCACHE_1;
move_address(&newdoc, &curdoc);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.line = curdoc.line;
newdoc.link = curdoc.link > -1 ? curdoc.link : 0;
LYclear();
}
}
}
#endif /* DIRED_SUPPORT */
static void handle_LYK_DEL_BOOKMARK(BOOLEAN *refresh_screen,
int *old_c,
int real_c)
{
if (curdoc.bookmark != NULL) {
if (HTConfirmDefault(CONFIRM_BOOKMARK_DELETE, NO) != YES)
return;
remove_bookmark_link(links[curdoc.link].anchor_number - 1,
curdoc.bookmark);
} else { /* behave like REFRESH for backward compatibility */
*refresh_screen = TRUE;
if (*old_c != real_c) {
*old_c = real_c;
lynx_force_repaint();
}
return;
}
do_cleanup_after_delete();
}
#if defined(DIRED_SUPPORT) || defined(VMS)
static void handle_LYK_DIRED_MENU(BOOLEAN *refresh_screen,
int *old_c GCC_UNUSED,
int real_c GCC_UNUSED)
{
#ifdef VMS
char *cp, *temp = 0;
const char *test = HTGetProgramPath(ppCSWING);
/*
* Check if the CSwing Directory/File Manager is available. Will be
* disabled if CSWING path is NULL, zero-length, or "none" (case
* insensitive), if no_file_url was set via the file_url restriction, if
* no_goto_file was set for the anonymous account, or if HTDirAccess was
* set to HT_DIR_FORBID or HT_DIR_SELECTIVE via the -nobrowse or -selective
* switches. - FM
*/
if (isEmpty(test) ||
!strcasecomp(test, "none") ||
no_file_url || no_goto_file ||
HTDirAccess == HT_DIR_FORBID ||
HTDirAccess == HT_DIR_SELECTIVE) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(DFM_NOT_AVAILABLE);
}
return;
}
/*
* If we are viewing a local directory listing or a local file which is not
* temporary, invoke CSwing with the URL's directory converted to VMS path
* specs and passed as the argument, so we start up CSwing positioned on
* that node of the directory tree. Otherwise, pass the current default
* directory as the argument. - FM
*/
if (LYisLocalFile(curdoc.address) &&
strncasecomp(curdoc.address,
lynx_temp_space, strlen(lynx_temp_space))) {
/*
* We are viewing a local directory or a local file which is not
* temporary. - FM
*/
struct stat stat_info;
cp = HTParse(curdoc.address, "", PARSE_PATH | PARSE_PUNCTUATION);
HTUnEscape(cp);
if (HTStat(cp, &stat_info) == -1) {
CTRACE((tfp, "mainloop: Can't stat %s\n", cp));
FREE(cp);
HTSprintf0(&temp, "%s []", HTGetProgramPath(ppCSWING));
*refresh_screen = TRUE; /* redisplay */
} else {
char *VMSdir = NULL;
if (S_ISDIR(stat_info.st_mode)) {
/*
* We're viewing a local directory. Make that the CSwing
* argument. - FM
*/
LYAddPathSep(&cp);
StrAllocCopy(VMSdir, HTVMS_name("", cp));
FREE(cp);
} else {
/*
* We're viewing a local file. Make its directory the CSwing
* argument. - FM
*/
StrAllocCopy(VMSdir, HTVMS_name("", cp));
FREE(cp);
if ((cp = strrchr(VMSdir, ']')) != NULL) {
*(cp + 1) = '\0';
} else if ((cp = strrchr(VMSdir, ':')) != NULL) {
*(cp + 1) = '\0';
}
}
HTSprintf0(&temp, "%s %s", HTGetProgramPath(ppCSWING), VMSdir);
FREE(VMSdir);
/*
* Uncache the current document in case we change, move, or delete
* it during the CSwing session. - FM
*/
/* could use DIRED_UNCACHE_1 but it's currently only defined
for dired - kw */
HTuncache_current_document();
move_address(&newdoc, &curdoc);
StrAllocCopy(newdoc.title, NonNull(curdoc.title));
StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
newdoc.line = curdoc.line;
newdoc.link = curdoc.link;
}
} else {
/*
* We're not viewing a local directory or file. Pass CSwing the
* current default directory as an argument and don't uncache the
* current document. - FM
*/
HTSprintf0(&temp, "%s []", HTGetProgramPath(ppCSWING));
*refresh_screen = TRUE; /* redisplay */
}
stop_curses();
LYSystem(temp);
start_curses();
FREE(temp);
#else
/*
* Don't do if not allowed or already viewing the menu.
*/
if (lynx_edit_mode && !no_dired_support &&
!LYIsUIPage(curdoc.address, UIP_DIRED_MENU) &&
strcmp(NonNull(curdoc.title), DIRED_MENU_TITLE)) {
dired_options(&curdoc, &newdoc.address);
*refresh_screen = TRUE; /* redisplay */
}
#endif /* VMS */
}
#endif /* defined(DIRED_SUPPORT) || defined(VMS) */
static int handle_LYK_DOWNLOAD(int *cmd,
int *old_c,
int real_c)
{
/*
* 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;
HTUserMsg(DOWNLOAD_DISABLED);
}
return 0;
}
/*
* Don't do if already viewing download options page.
*/
if (LYIsUIPage(curdoc.address, UIP_DOWNLOAD_OPTIONS))
return 0;
if (do_change_link() == -1)
return 1; /* mouse stuff was confused, ignore - kw */
if (nlinks > 0) {
if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
if (links[curdoc.link].l_form->type == F_SUBMIT_TYPE ||
links[curdoc.link].l_form->type == F_IMAGE_SUBMIT_TYPE ||
links[curdoc.link].l_form->type == F_TEXT_SUBMIT_TYPE) {
if (links[curdoc.link].l_form->submit_method ==
URL_MAIL_METHOD) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_DOWNLOAD_MAILTO_ACTION);
}
return 0;
}
if (isEmpty(links[curdoc.link].l_form->submit_action) ||
isLYNXOPTIONS(links[curdoc.link].l_form->submit_action)) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_DOWNLOAD_SPECIAL);
}
return 0;
}
HTOutputFormat = WWW_DOWNLOAD;
LYforce_no_cache = TRUE;
*cmd = LYK_ACTIVATE;
return 2;
}
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_DOWNLOAD_INPUT);
}
} else if (isLYNXCOOKIE(curdoc.address)) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_DOWNLOAD_COOKIES);
}
} else if (LYIsUIPage(curdoc.address, UIP_PRINT_OPTIONS)) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_DOWNLOAD_PRINT_OP);
}
#ifdef DIRED_SUPPORT
} else if (LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS)) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_DOWNLOAD_UPLOAD_OP);
}
} else if (LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS)) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_DOWNLOAD_PERMIT_OP);
}
} else if (lynx_edit_mode && !no_dired_support &&
!LYstrstr(links[curdoc.link].lname, "/SugFile=")) {
/*
* Don't bother making a /tmp copy of the local file.
*/
static DocInfo temp;
copy_address(&temp, &newdoc);
set_address(&newdoc, links[curdoc.link].lname);
if (LYdownload_options(&newdoc.address,
links[curdoc.link].lname) < 0)
copy_address(&newdoc, &temp);
else
newdoc.internal_link = FALSE;
LYFreeDocInfo(&temp);
#endif /* DIRED_SUPPORT */
} else if (LYIsUIPage(curdoc.address, UIP_HISTORY) &&
isLYNXHIST(links[curdoc.link].lname)) {
int number = atoi(links[curdoc.link].lname + LEN_LYNXHIST);
if (number >= nhist || number < 0) {
HTUserMsg(NO_DOWNLOAD_SPECIAL);
return 0;
}
if ((HDOC(number).post_data != NULL &&
HDOC(number).safe != TRUE) &&
HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
HTInfoMsg(CANCELLED);
return 0;
}
/*
* OK, we download from history page, restore URL from stack.
*/
copy_address(&newdoc, &HDOC(number));
StrAllocCopy(newdoc.title, LYGetHiliteStr(curdoc.link, 0));
StrAllocCopy(newdoc.bookmark, HDOC(number).bookmark);
LYFreePostData(&newdoc);
if (HDOC(number).post_data)
BStrCopy(newdoc.post_data,
HDOC(number).post_data);
if (HDOC(number).post_content_type)
StrAllocCopy(newdoc.post_content_type,
HDOC(number).post_content_type);
newdoc.isHEAD = HDOC(number).isHEAD;
newdoc.safe = HDOC(number).safe;
newdoc.internal_link = FALSE;
newdoc.link = (user_mode == NOVICE_MODE) ? 1 : 0;
HTOutputFormat = WWW_DOWNLOAD;
LYUserSpecifiedURL = TRUE;
/*
* Force the document to be reloaded.
*/
LYforce_no_cache = TRUE;
} else if (!StrNCmp(links[curdoc.link].lname, "data:", 5)) {
if (*old_c != real_c) {
*old_c = real_c;
HTAlert(UNSUPPORTED_DATA_URL);
}
} else if (isLYNXCOOKIE(links[curdoc.link].lname) ||
isLYNXCACHE(links[curdoc.link].lname) ||
isLYNXDIRED(links[curdoc.link].lname) ||
isLYNXDOWNLOAD(links[curdoc.link].lname) ||
isLYNXPRINT(links[curdoc.link].lname) ||
isLYNXOPTIONS(links[curdoc.link].lname) ||
isLYNXHIST(links[curdoc.link].lname) ||
/* handled above if valid - kw */
/* @@@ should next two be downloadable? - kw */
isLYNXHIST(links[curdoc.link].lname) ||
isLYNXCFLAGS(links[curdoc.link].lname) ||
isLYNXEXEC(links[curdoc.link].lname) ||
isLYNXPROG(links[curdoc.link].lname)) {
HTUserMsg(NO_DOWNLOAD_SPECIAL);
} else if (isMAILTO_URL(links[curdoc.link].lname)) {
HTUserMsg(NO_DOWNLOAD_MAILTO_LINK);
/*
* From here on we could have a remote host, so check if that's
* allowed.
*
* We copy all these checks from getfile() to LYK_DOWNLOAD here
* because LYNXDOWNLOAD:// will NOT be pushing the previous
* document into the history stack so preserve getfile() from
* returning a wrong status (NULLFILE).
*/
} else if (local_host_only &&
!(LYisLocalHost(links[curdoc.link].lname) ||
LYisLocalAlias(links[curdoc.link].lname))) {
HTUserMsg(ACCESS_ONLY_LOCALHOST);
} 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.
*/
set_address(&newdoc, links[curdoc.link].lname);
StrAllocCopy(newdoc.title, LYGetHiliteStr(curdoc.link, 0));
/*
* Might be an internal link in the same doc from a POST form. If
* so, don't free the content. - kw
*/
if (track_internal_links) {
if (links[curdoc.link].type != WWW_INTERN_LINK_TYPE) {
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
}
} else {
/*
* 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)) {
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
}
}
newdoc.internal_link = FALSE;
newdoc.link = (user_mode == NOVICE_MODE) ? 1 : 0;
HTOutputFormat = WWW_DOWNLOAD;
/*
* Force the document to be reloaded.
*/
LYforce_no_cache = TRUE;
}
} else if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_DOWNLOAD_CHOICE);
}
return 0;
}
static void handle_LYK_DOWN_xxx(int *old_c,
int real_c,
int scroll_by)
{
int i;
if (more_text) {
LYChgNewline(scroll_by);
if (nlinks > 0 && curdoc.link > -1 &&
links[curdoc.link].ly > scroll_by) {
newdoc.link = curdoc.link;
for (i = 0; links[i].ly <= scroll_by; i++)
--newdoc.link;
}
} else if (*old_c != real_c) {
HandleForwardWraparound();
}
}
static void handle_LYK_DOWN_HALF(int *old_c,
int real_c)
{
handle_LYK_DOWN_xxx(old_c, real_c, display_lines / 2);
}
static void handle_LYK_DOWN_LINK(int *follow_col,
int *old_c,
int real_c)
{
if (curdoc.link < (nlinks - 1)) { /* more links? */
int newlink;
if (*follow_col == -1) {
const char *text = LYGetHiliteStr(curdoc.link, 0);
*follow_col = links[curdoc.link].lx;
if (text != NULL)
*follow_col += (int) strlen(text) / 2;
}
newlink = find_link_near_col(*follow_col, 1);
if (newlink > -1) {
set_curdoc_link(newlink);
} else if (more_text) { /* next page */
LYChgNewline(display_lines);
} else if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_LINKS_BELOW);
return;
}
} else if (more_text) { /* next page */
LYChgNewline(display_lines);
} else if (*old_c != real_c) {
HandleForwardWraparound();
}
}
static void handle_LYK_DOWN_TWO(int *old_c,
int real_c)
{
handle_LYK_DOWN_xxx(old_c, real_c, 2);
}
static int handle_LYK_DWIMEDIT(int *cmd,
int *old_c,
int real_c)
{
#ifdef TEXTAREA_AUTOEXTEDIT
/*
* If we're in a forms TEXTAREA, invoke the editor on *its* contents,
* rather than attempting to edit the html source document. KED
*/
if (nlinks > 0 &&
LinkIsTextarea(curdoc.link)) {
*cmd = LYK_EDITTEXTAREA;
return 2;
}
/*
* If we're in a forms TEXT type, tell user the request is bogus (though in
* reality, without this trap, if the document with the TEXT field is
* local, the editor *would* be invoked on the source .html file; eg, the
* o(ptions) form tempfile).
*
* [This is done to avoid possible user confusion, due to auto invocation
* of the editor on the TEXTAREA's contents via the above if() statement.]
*/
if (nlinks > 0 &&
links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
links[curdoc.link].l_form->type == F_TEXT_TYPE) {
HTUserMsg(CANNOT_EDIT_FIELD);
return 1;
}
if (no_editor) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(ANYEDIT_DISABLED);
}
return 1;
}
#endif /* TEXTAREA_AUTOEXTEDIT */
return 0;
}
static int handle_LYK_ECGOTO(int *ch,
bstring **user_input,
char **old_user_input,
int *old_c,
int real_c)
{
if (no_goto && !LYValidate) {
/*
* Go to not allowed. - FM
*/
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(GOTO_DISALLOWED);
}
return 0;
}
#ifdef DIRED_SUPPORT
if (LYIsUIPage(curdoc.address, UIP_DIRED_MENU) ||
LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS) ||
LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS)) {
/*
* Disallow editing of File Management URLs. - FM
*/
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(EDIT_FM_MENU_URLS_DISALLOWED);
}
return 0;
}
#endif /* DIRED_SUPPORT */
/*
* Save the current user_input string, and load the current
* document's address.
*/
StrAllocCopy(*old_user_input, (*user_input)->str);
BStrCopy0((*user_input), curdoc.address);
/*
* Warn the user if the current document has POST data associated with it.
* - FM
*/
if (curdoc.post_data)
HTAlert(CURRENT_DOC_HAS_POST_DATA);
/*
* Offer the current document's URL for editing. - FM
*/
_statusline(EDIT_CURDOC_URL);
if (((*ch = LYgetBString(user_input, FALSE, 0, RECALL_URL)) >= 0) &&
!isBEmpty(*user_input) &&
strcmp((*user_input)->str, curdoc.address)) {
LYTrimAllStartfile((*user_input)->str);
if (!isBEmpty(*user_input)) {
return 2;
}
}
/*
* User cancelled via ^G, a full deletion, or not modifying the URL. - FM
*/
HTInfoMsg(CANCELLED);
BStrCopy0((*user_input), *old_user_input);
FREE(*old_user_input);
return 0;
}
static void handle_LYK_EDIT(int *old_c,
int real_c)
{
#ifdef DIRED_SUPPORT
char *cp;
char *tp = NULL;
struct stat dir_info;
#endif /* DIRED_SUPPORT */
if (no_editor) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(EDIT_DISABLED);
}
}
#ifdef DIRED_SUPPORT
/*
* Allow the user to edit the link rather than curdoc in edit mode.
*/
else if (lynx_edit_mode &&
non_empty(editor) && !no_dired_support) {
if (nlinks > 0) {
cp = links[curdoc.link].lname;
if (is_url(cp) == FILE_URL_TYPE) {
cp = HTfullURL_toFile(cp);
StrAllocCopy(tp, cp);
FREE(cp);
if (stat(tp, &dir_info) == -1) {
HTAlert(NO_STATUS);
} else {
if (S_ISREG(dir_info.st_mode)) {
StrAllocCopy(tp, links[curdoc.link].lname);
HTUnEscapeSome(tp, "/");
if (edit_current_file(tp, curdoc.link, -1)) {
DIRED_UNCACHE_1;
move_address(&newdoc, &curdoc);
#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 */
LYclear(); /* clear the screen */
}
}
}
FREE(tp);
}
}
}
#endif /* DIRED_SUPPORT */
else if (non_empty(editor)) {
if (edit_current_file(newdoc.address, curdoc.link, LYGetNewline())) {
HTuncache_current_document();
LYforce_no_cache = TRUE; /*force reload of document */
free_address(&curdoc); /* 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 */
LYclear(); /* clear the screen */
}
} else {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_EDITOR);
}
}
}
static void handle_LYK_DWIMHELP(const char **cshelpfile)
{
/*
* Currently a help file different from the main 'helpfile' is shown only
* if current link is a text input form field. - kw
*/
if (curdoc.link >= 0 && curdoc.link < nlinks &&
!FormIsReadonly(links[curdoc.link].l_form) &&
LinkIsTextLike(curdoc.link)) {
*cshelpfile = STR_LYNXEDITMAP;
}
}
static void handle_LYK_EDITMAP(int *old_c,
int real_c)
{
if (*old_c != real_c) {
*old_c = real_c;
set_address(&newdoc, STR_LYNXEDITMAP);
StrAllocCopy(newdoc.title, CURRENT_EDITMAP_TITLE);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
/*
* Remember whether we are in dired menu so we can display the right
* keymap.
*/
if (!no_dired_support) {
prev_lynx_edit_mode = lynx_edit_mode;
}
#endif /* DIRED_SUPPORT && OK_OVERRIDE */
LYforce_no_cache = TRUE;
}
}
static void handle_LYK_EDIT_TEXTAREA(BOOLEAN *refresh_screen,
int *old_c,
int real_c)
{
if (no_editor) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(ANYEDIT_DISABLED);
}
} else if (isEmpty(editor)) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_EDITOR);
}
} else if (LinkIsTextarea(curdoc.link)) {
/*
* if the current link is in a form TEXTAREA, it requires handling
* for the possible multiple lines.
*/
/* stop screen */
stop_curses();
(void) HText_EditTextArea(&links[curdoc.link]);
/*
* TODO:
* Move cursor "n" lines from the current line to position it on the
* 1st trailing blank line in the now edited TEXTAREA. If the target
* line/ anchor requires us to scroll up/down, position the target in
* the approximate center of the screen.
*/
/* curdoc.link += n; */
/* works, except for page crossing, */
/* damnit; why is nothing ever easy */
/* start screen */
start_curses();
*refresh_screen = TRUE;
} else if (LinkIsTextLike(curdoc.link)) {
/*
* other text fields are single-line
*/
stop_curses();
HText_EditTextField(&links[curdoc.link]);
start_curses();
*refresh_screen = TRUE;
} else {
HTInfoMsg(NOT_IN_TEXTAREA_NOEDIT);
}
}
static int handle_LYK_ELGOTO(int *ch,
bstring **user_input,
char **old_user_input,
int *old_c,
int real_c)
{
if (no_goto && !LYValidate) {
/*
* Go to not allowed. - FM
*/
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(GOTO_DISALLOWED);
}
return 0;
}
if (!(nlinks > 0 && curdoc.link > -1) ||
(links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
links[curdoc.link].l_form->type != F_SUBMIT_TYPE &&
links[curdoc.link].l_form->type != F_IMAGE_SUBMIT_TYPE &&
links[curdoc.link].l_form->type != F_TEXT_SUBMIT_TYPE)) {
/*
* No links on page, or not a normal link or form submit button. - FM
*/
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NOT_ON_SUBMIT_OR_LINK);
}
return 0;
}
if ((links[curdoc.link].type == WWW_FORM_LINK_TYPE) &&
(isEmpty(links[curdoc.link].l_form->submit_action))) {
/*
* Form submit button with no ACTION defined. - FM
*/
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_FORM_ACTION);
}
return 0;
}
#ifdef DIRED_SUPPORT
if (isLYNXDIRED(links[curdoc.link].lname) ||
LYIsUIPage(curdoc.address, UIP_DIRED_MENU) ||
LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS) ||
LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS)) {
/*
* Disallow editing of File Management URLs. - FM
*/
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(EDIT_FM_MENU_URLS_DISALLOWED);
}
return 0;
}
#endif /* DIRED_SUPPORT */
/*
* Save the current user_input string, and load the current link's
* address. - FM
*/
StrAllocCopy(*old_user_input, (*user_input)->str);
BStrCopy0((*user_input),
((links[curdoc.link].type == WWW_FORM_LINK_TYPE)
? links[curdoc.link].l_form->submit_action
: links[curdoc.link].lname));
/*
* Offer the current link's URL for editing. - FM
*/
_statusline(EDIT_CURLINK_URL);
if (((*ch = LYgetBString(user_input, FALSE, 0, RECALL_URL)) >= 0) &&
!isBEmpty(*user_input) &&
strcmp((*user_input)->str,
((links[curdoc.link].type == WWW_FORM_LINK_TYPE)
? links[curdoc.link].l_form->submit_action
: links[curdoc.link].lname))) {
LYTrimAllStartfile((*user_input)->str);
if (!isBEmpty(*user_input)) {
return 2;
}
}
/*
* User cancelled via ^G, a full deletion, or not modifying the URL. - FM
*/
HTInfoMsg(CANCELLED);
BStrCopy0((*user_input), *old_user_input);
FREE(*old_user_input);
return 0;
}
#ifdef USE_EXTERNALS
static void handle_LYK_EXTERN_LINK(BOOLEAN *refresh_screen)
{
if ((nlinks > 0) && (links[curdoc.link].lname != NULL)) {
run_external(links[curdoc.link].lname, FALSE);
*refresh_screen = TRUE;
}
}
static void handle_LYK_EXTERN_PAGE(BOOLEAN *refresh_screen)
{
if (curdoc.address != NULL) {
run_external(curdoc.address, FALSE);
*refresh_screen = TRUE;
}
}
#endif
static BOOLEAN handle_LYK_FASTBACKW_LINK(int *cmd,
int *old_c,
int real_c)
{
int samepage = 0, nextlink = curdoc.link;
int res;
BOOLEAN code = FALSE;
if (nlinks > 1) {
/*
* If in textarea, move to first link or textarea group before it if
* there is one on this screen. - kw
*/
if (LinkIsTextarea(curdoc.link)) {
int thisgroup = links[curdoc.link].l_form->number;
char *thisname = links[curdoc.link].l_form->name;
if (curdoc.link > 0 &&
!(LinkIsTextarea(0) &&
links[0].l_form->number == thisgroup &&
sametext(links[0].l_form->name, thisname))) {
do
nextlink--;
while
(LinkIsTextarea(nextlink) &&
links[nextlink].l_form->number == thisgroup &&
sametext(links[nextlink].l_form->name, thisname));
samepage = 1;
} else if (!more_text && LYGetNewline() == 1 &&
(LinkIsTextarea(0) &&
links[0].l_form->number == thisgroup &&
sametext(links[0].l_form->name, thisname)) &&
!(LinkIsTextarea(nlinks - 1) &&
links[nlinks - 1].l_form->number == thisgroup &&
sametext(links[nlinks - 1].l_form->name, thisname))) {
nextlink = nlinks - 1;
samepage = 1;
} else if (!more_text && LYGetNewline() == 1 && curdoc.link > 0) {
nextlink = 0;
samepage = 1;
}
} else if (curdoc.link > 0) {
nextlink--;
samepage = 1;
} else if (!more_text && LYGetNewline() == 1) {
nextlink = nlinks - 1;
samepage = 1;
}
}
if (samepage) {
/*
* If the link as determined so far is part of a group of textarea
* fields, try to use the first of them that's on the screen instead.
* - kw
*/
if (nextlink > 0 &&
LinkIsTextarea(nextlink)) {
int thisgroup = links[nextlink].l_form->number;
char *thisname = links[nextlink].l_form->name;
if (LinkIsTextarea(0) &&
links[0].l_form->number == thisgroup &&
sametext(links[0].l_form->name, thisname)) {
nextlink = 0;
} else
while
(nextlink > 1 &&
LinkIsTextarea(nextlink - 1) &&
links[nextlink - 1].l_form->number == thisgroup &&
sametext(links[nextlink - 1].l_form->name, thisname)) {
nextlink--;
}
}
set_curdoc_link(nextlink);
} else if (LYGetNewline() > 1 && /* need a previous page */
(res = HTGetLinkOrFieldStart(curdoc.link,
&Newline, &newdoc.link,
-1, TRUE)) != NO) {
if (res == LINK_DO_ARROWUP) {
/*
* It says we should use the normal PREV_LINK mechanism, so we'll
* do that. - kw
*/
if (nlinks > 0)
curdoc.link = 0;
*cmd = LYK_PREV_LINK;
code = TRUE;
} else {
LYChgNewline(1); /* our line counting starts with 1 not 0 */
}
} else if (*old_c != real_c) {
*old_c = real_c;
HTInfoMsg(NO_LINKS_ABOVE);
}
return code;
}
static void handle_LYK_FASTFORW_LINK(int *old_c,
int real_c)
{
int samepage = 0, nextlink = curdoc.link;
if (nlinks > 1) {
/*
* If in textarea, move to first link or field after it if there is one
* on this screen. - kw
*/
if (LinkIsTextarea(curdoc.link)) {
int thisgroup = links[curdoc.link].l_form->number;
char *thisname = links[curdoc.link].l_form->name;
if (curdoc.link < nlinks - 1 &&
!(LinkIsTextarea(nlinks - 1) &&
links[nlinks - 1].l_form->number == thisgroup &&
sametext(links[nlinks - 1].l_form->name, thisname))) {
do
nextlink++;
while
(LinkIsTextarea(nextlink) &&
links[nextlink].l_form->number == thisgroup &&
sametext(links[nextlink].l_form->name, thisname));
samepage = 1;
} else if (!more_text && LYGetNewline() == 1 && curdoc.link > 0) {
nextlink = 0;
samepage = 1;
}
} else if (curdoc.link < nlinks - 1) {
nextlink++;
samepage = 1;
} else if (!more_text && LYGetNewline() == 1 && curdoc.link > 0) {
nextlink = 0;
samepage = 1;
}
}
if (samepage) {
set_curdoc_link(nextlink);
} else if (!more_text && LYGetNewline() == 1 && curdoc.link == nlinks - 1) {
/*
* At the bottom of list and there is only one page. Move to the top
* link on the page.
*/
set_curdoc_link(0);
} else if (more_text && /* need a later page */
HTGetLinkOrFieldStart(curdoc.link,
&Newline, &newdoc.link,
1, TRUE) != NO) {
LYChgNewline(1); /* our line counting starts with 1 not 0 */
/* nothing more to do here */
} else if (*old_c != real_c) {
*old_c = real_c;
HTInfoMsg(NO_LINKS_BELOW);
}
return;
}
static void handle_LYK_FIRST_LINK(void)
{
int i = curdoc.link;
for (;;) {
if (--i < 0
|| links[i].ly != links[curdoc.link].ly) {
set_curdoc_link(i + 1);
break;
}
}
}
static BOOLEAN handle_LYK_GOTO(int *ch,
bstring **user_input,
char **old_user_input,
RecallType * recall,
int *URLTotal,
int *URLNum,
BOOLEAN *FirstURLRecall,
int *old_c,
int real_c)
{
if (no_goto && !LYValidate) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(GOTO_DISALLOWED);
}
return FALSE;
}
StrAllocCopy(*old_user_input, (*user_input)->str);
if (!goto_buffer)
BStrCopy0((*user_input), "");
*URLTotal = (Goto_URLs ? HTList_count(Goto_URLs) : 0);
if (goto_buffer && !isBEmpty(*user_input)) {
*recall = ((*URLTotal > 1) ? RECALL_URL : NORECALL);
*URLNum = 0;
*FirstURLRecall = FALSE;
} else {
*recall = ((*URLTotal >= 1) ? RECALL_URL : NORECALL);
*URLNum = *URLTotal;
*FirstURLRecall = TRUE;
}
/*
* Ask the user.
*/
_statusline(URL_TO_OPEN);
if ((*ch = LYgetBString(user_input, FALSE, 0, *recall)) < 0) {
/*
* User cancelled the Goto via ^G. Restore user_input and
* break. - FM
*/
BStrCopy0((*user_input), *old_user_input);
FREE(*old_user_input);
HTInfoMsg(CANCELLED);
return FALSE;
}
return TRUE;
}
static void handle_LYK_GROW_TEXTAREA(BOOLEAN *refresh_screen)
{
/*
* See if the current link is in a form TEXTAREA.
*/
if (LinkIsTextarea(curdoc.link)) {
HText_ExpandTextarea(&links[curdoc.link], TEXTAREA_EXPAND_SIZE);
*refresh_screen = TRUE;
} else {
HTInfoMsg(NOT_IN_TEXTAREA);
}
}
static BOOLEAN handle_LYK_HEAD(int *cmd)
{
int c;
if (nlinks > 0 &&
(links[curdoc.link].type != WWW_FORM_LINK_TYPE ||
links[curdoc.link].l_form->type == F_SUBMIT_TYPE ||
links[curdoc.link].l_form->type == F_IMAGE_SUBMIT_TYPE ||
links[curdoc.link].l_form->type == F_TEXT_SUBMIT_TYPE)) {
/*
* We have links, and the current link is a normal link or a form's
* submit button. - FM
*/
_statusline(HEAD_D_L_OR_CANCEL);
c = LYgetch_single();
if (c == 'D') {
char *scheme = !isLYNXIMGMAP(curdoc.address)
? curdoc.address
: curdoc.address + LEN_LYNXIMGMAP;
if (LYCanDoHEAD(scheme) != TRUE) {
HTUserMsg(DOC_NOT_HTTP_URL);
} else {
/*
* Check if this is a reply from a POST, and if so, seek
* confirmation if the safe element is not set. - FM
*/
if ((curdoc.post_data != NULL &&
curdoc.safe != TRUE) &&
HTConfirm(CONFIRM_POST_DOC_HEAD) == FALSE) {
HTInfoMsg(CANCELLED);
} else {
HEAD_request = TRUE;
LYforce_no_cache = TRUE;
StrAllocCopy(newdoc.title, curdoc.title);
if (HTLoadedDocumentIsHEAD()) {
HText_setNoCache(HTMainText);
free_address(&curdoc);
} else {
StrAllocCat(newdoc.title, " - HEAD");
}
}
}
} else if (c == 'L') {
if (links[curdoc.link].type != WWW_FORM_LINK_TYPE &&
StrNCmp(links[curdoc.link].lname, "http", 4) &&
StrNCmp(links[curdoc.link].lname, "LYNXIMGMAP:http", 15) &&
LYCanDoHEAD(links[curdoc.link].lname) != TRUE &&
(links[curdoc.link].type != WWW_INTERN_LINK_TYPE ||
!curdoc.address ||
StrNCmp(curdoc.address, "http", 4))) {
HTUserMsg(LINK_NOT_HTTP_URL);
} else if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
FormIsReadonly(links[curdoc.link].l_form)) {
HTUserMsg(FORM_ACTION_DISABLED);
} else if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
links[curdoc.link].l_form->submit_action != 0 &&
!isLYNXCGI(links[curdoc.link].l_form->submit_action) &&
StrNCmp(links[curdoc.link].l_form->submit_action,
"http", 4)) {
HTUserMsg(FORM_ACTION_NOT_HTTP_URL);
} else if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
links[curdoc.link].l_form->submit_method ==
URL_POST_METHOD &&
HTConfirm(CONFIRM_POST_LINK_HEAD) == FALSE) {
HTInfoMsg(CANCELLED);
} else {
HEAD_request = TRUE;
LYforce_no_cache = TRUE;
*cmd = LYK_ACTIVATE;
return TRUE;
}
}
} else {
/*
* We can offer only this document for a HEAD request. Check if this
* is a reply from a POST, and if so, seek confirmation if the safe
* element is not set. - FM
*/
if ((curdoc.post_data != NULL &&
curdoc.safe != TRUE) &&
HTConfirm(CONFIRM_POST_DOC_HEAD) == FALSE) {
HTInfoMsg(CANCELLED);
} else {
if (nlinks > 0) {
/*
* The current link is a non-submittable form link, so prompt
* the user to make it clear that the HEAD request would be for
* the current document, not the form link. - FM
*/
_statusline(HEAD_D_OR_CANCEL);
c = LYgetch_single();
} else {
/*
* No links, so we can just assume that the user wants a HEAD
* request for the current document. - FM
*/
c = 'D';
}
if (c == 'D') {
char *scheme = !isLYNXIMGMAP(curdoc.address)
? curdoc.address
: curdoc.address + LEN_LYNXIMGMAP;
/*
* The user didn't cancel, so check if a HEAD request is
* appropriate for the current document. - FM
*/
if (LYCanDoHEAD(scheme) != TRUE) {
HTUserMsg(DOC_NOT_HTTP_URL);
} else {
HEAD_request = TRUE;
LYforce_no_cache = TRUE;
StrAllocCopy(newdoc.title, curdoc.title);
if (HTLoadedDocumentIsHEAD()) {
HText_setNoCache(HTMainText);
free_address(&curdoc);
} else {
StrAllocCat(newdoc.title, " - HEAD");
}
}
}
}
}
return FALSE;
}
static void handle_LYK_HELP(const char **cshelpfile)
{
char *my_value = NULL;
if (*cshelpfile == NULL)
*cshelpfile = helpfile;
StrAllocCopy(my_value, *cshelpfile);
LYEnsureAbsoluteURL(&my_value, *cshelpfile, FALSE);
if (!STREQ(curdoc.address, my_value)) {
/*
* Set the filename.
*/
set_address(&newdoc, my_value);
/*
* Make a name for this help file.
*/
StrAllocCopy(newdoc.title, gettext("Help Screen"));
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
}
FREE(my_value);
*cshelpfile = NULL; /* reset pointer - kw */
}
static void handle_LYK_HISTORICAL(void)
{
#ifdef USE_SOURCE_CACHE
if (!HTcan_reparse_document()) {
#endif
/*
* Check if this is a reply from a POST, and if so, seek confirmation
* of reload if the safe element is not set. - FM
*/
if ((curdoc.post_data != NULL &&
curdoc.safe != TRUE) &&
confirm_post_resub(curdoc.address, NULL, 0, 0) == FALSE) {
HTInfoMsg(WILL_NOT_RELOAD_DOC);
} else {
HText_setNoCache(HTMainText);
move_address(&newdoc, &curdoc);
newdoc.line = curdoc.line;
newdoc.link = curdoc.link;
}
#ifdef USE_SOURCE_CACHE
} /* end if no bypass */
#endif
historical_comments = (BOOLEAN) !historical_comments;
if (minimal_comments) {
HTAlert(historical_comments ?
HISTORICAL_ON_MINIMAL_OFF : HISTORICAL_OFF_MINIMAL_ON);
} else {
HTAlert(historical_comments ?
HISTORICAL_ON_VALID_OFF : HISTORICAL_OFF_VALID_ON);
}
#ifdef USE_SOURCE_CACHE
(void) reparse_document();
#endif
return;
}
static BOOLEAN handle_LYK_HISTORY(int ForcePush)
{
if (curdoc.title && !LYIsUIPage(curdoc.address, UIP_HISTORY)) {
/*
* 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 && !LYUseTraceLog && LYCursesON) {
LYHideCursor(); /* make sure cursor is down */
#ifdef USE_SLANG
LYaddstr("\n");
#endif /* USE_SLANG */
LYrefresh();
}
LYpush(&curdoc, ForcePush);
/*
* Print history options to file.
*/
if (showhistory(&newdoc.address) < 0) {
LYpop(&curdoc);
return TRUE;
}
LYRegisterUIPage(newdoc.address, UIP_HISTORY);
StrAllocCopy(newdoc.title, HISTORY_PAGE_TITLE);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
newdoc.link = 1; /*@@@ bypass "recent statusline messages" link */
free_address(&curdoc); /* so it doesn't get pushed */
if (LYValidate || check_realm) {
LYPermitURL = TRUE;
}
return TRUE;
} /* end if StrNCmp */
return FALSE;
}
static BOOLEAN handle_LYK_IMAGE_TOGGLE(int *cmd)
{
clickable_images = (BOOLEAN) !clickable_images;
HTUserMsg(clickable_images ?
CLICKABLE_IMAGES_ON : CLICKABLE_IMAGES_OFF);
return reparse_or_reload(cmd);
}
static void handle_LYK_INDEX(int *old_c,
int real_c)
{
/*
* 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;
HTUserMsg(NO_INDEX_FILE);
}
} else {
#ifdef KANJI_CODE_OVERRIDE
if (HTCJK == JAPANESE) {
last_kcode = NOKANJI; /* AUTO */
}
#endif
#ifdef USE_PROGRAM_DIR
if (is_url(indexfile) == 0) {
char *tmp = NULL;
HTSprintf0(&tmp, "%s\\%s", program_dir, indexfile);
FREE(indexfile);
LYLocalFileToURL(&indexfile, tmp);
FREE(tmp);
}
#endif
set_address(&newdoc, indexfile);
StrAllocCopy(newdoc.title, gettext("System Index")); /* name it */
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
} /* end else */
} /* end if */
}
static void handle_LYK_INDEX_SEARCH(BOOLEAN *force_load,
int ForcePush,
int *old_c,
int real_c)
{
if (is_www_index) {
/*
* Perform a database search.
*
* do_www_search will try to go out and get the document. If it
* returns TRUE, a new document was returned and is named in the
* newdoc.address.
*/
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
if (do_www_search(&newdoc) == NORMAL) {
/*
* Yah, the search succeeded.
*/
if (TRACE && !LYUseTraceLog && LYCursesON) {
/*
* Make sure cursor is down.
*/
LYHideCursor();
#ifdef USE_SLANG
LYaddstr("\n");
#endif /* USE_SLANG */
LYrefresh();
}
LYpush(&curdoc, ForcePush);
/*
* Make the curdoc.address the newdoc.address so that getfile
* doesn't try to get the newdoc.address. Since we have already
* gotten it.
*/
copy_address(&curdoc, &newdoc);
BStrCopy(newdoc.post_data, curdoc.post_data);
StrAllocCopy(newdoc.post_content_type, curdoc.post_content_type);
newdoc.internal_link = FALSE;
curdoc.line = -1;
LYSetNewline(0);
} else if (use_this_url_instead != NULL) {
/*
* Got back a redirecting URL. Check it out.
*/
HTUserMsg2(WWW_USING_MESSAGE, use_this_url_instead);
/*
* Make a name for this URL.
*/
StrAllocCopy(newdoc.title,
"A URL specified by redirection");
set_address(&newdoc, use_this_url_instead);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
FREE(use_this_url_instead);
*force_load = TRUE;
} else {
/*
* Yuk, the search failed. Restore the old file.
*/
copy_address(&newdoc, &curdoc);
BStrCopy(newdoc.post_data, curdoc.post_data);
StrAllocCopy(newdoc.post_content_type,
curdoc.post_content_type);
StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
newdoc.isHEAD = curdoc.isHEAD;
newdoc.safe = curdoc.safe;
newdoc.internal_link = curdoc.internal_link;
}
} else if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NOT_ISINDEX);
}
}
static BOOLEAN handle_LYK_INFO(int *cmd)
{
/*
* Don't do if already viewing info page.
*/
if (!LYIsUIPage(curdoc.address, UIP_SHOWINFO)) {
if (do_change_link() != -1
&& LYShowInfo(&curdoc, &newdoc, owner_address) >= 0) {
LYRegisterUIPage(newdoc.address, UIP_SHOWINFO);
StrAllocCopy(newdoc.title, SHOWINFO_TITLE);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
LYforce_no_cache = TRUE;
if (LYValidate || check_realm)
LYPermitURL = TRUE;
}
} else {
/*
* If already in info page, get out.
*/
*cmd = LYK_PREV_DOC;
return TRUE;
}
return FALSE;
}
static BOOLEAN handle_LYK_INLINE_TOGGLE(int *cmd)
{
pseudo_inline_alts = (BOOLEAN) !pseudo_inline_alts;
HTUserMsg(pseudo_inline_alts ?
PSEUDO_INLINE_ALTS_ON : PSEUDO_INLINE_ALTS_OFF);
return reparse_or_reload(cmd);
}
static void handle_LYK_INSERT_FILE(BOOLEAN *refresh_screen,
int *old_c,
int real_c)
{
/*
* See if the current link is in a form TEXTAREA.
*/
if (LinkIsTextarea(curdoc.link)) {
/*
* Reject attempts to use this for gaining access to local files when
* such access is restricted: if no_file_url was set via the file_url
* restriction, if no_goto_file was set for the anonymous account, or
* if HTDirAccess was set to HT_DIR_FORBID or HT_DIR_SELECTIVE via the
* -nobrowse or -selective switches, it is assumed that inserting files
* or checking for existence of files needs to be denied. - kw
*/
if (no_file_url || no_goto_file ||
HTDirAccess == HT_DIR_FORBID ||
HTDirAccess == HT_DIR_SELECTIVE) {
if (*old_c != real_c) {
*old_c = real_c;
if (no_goto_file)
HTUserMsg2(GOTO_XXXX_DISALLOWED, STR_FILE_URL);
else
HTUserMsg(NOAUTH_TO_ACCESS_FILES);
HTInfoMsg(FILE_INSERT_CANCELLED);
}
return;
}
(void) HText_InsertFile(&links[curdoc.link]);
/*
* TODO:
* Move cursor "n" lines from the current line to position it on the
* 1st line following the text that was inserted. If the target
* line/anchor requires us to scroll up/down, position the target in
* the approximate center of the screen.
*
* [Current behavior leaves cursor on the same line relative to the
* start of the TEXTAREA that it was on before the insertion. This is
* the same behavior that occurs with (my) editor, so this TODO will
* stay unimplemented.]
*/
*refresh_screen = TRUE;
} else {
HTInfoMsg(NOT_IN_TEXTAREA);
}
}
#if defined(DIRED_SUPPORT) && defined(OK_INSTALL)
static void handle_LYK_INSTALL(void)
{
if (lynx_edit_mode && nlinks > 0 && !no_dired_support)
local_install(NULL, links[curdoc.link].lname, &newdoc.address);
}
#endif
static const char *hexy = "0123456789ABCDEF";
#define HEX(n) hexy[(n) & 0xf]
/*
* URL-encode a parameter which can then be appended to a URI.
* RFC-3986 lists reserved characters, which should be encoded.
*/
static char *urlencode(char *str)
{
char *result = NULL;
char *ptr;
int ch;
if (str != NULL) {
result = malloc(strlen(str) * 3 + 1);
ptr = result;
if (result == NULL)
outofmem(__FILE__, "urlencode");
while ((ch = UCH(*str++)) != 0) {
if (ch == ' ') {
*ptr = '+';
ptr++;
} else if (ch > 127 ||
StrChr(":/?#[]@!$&'()*+,;=", ch) != 0) {
*ptr++ = '%';
*ptr++ = HEX(ch >> 4);
*ptr++ = HEX(ch);
} else {
*ptr++ = (char) ch;
}
}
*ptr = '\0';
}
return result;
}
/*
* Fill in "%s" marker(s) in the url_template by prompting the user for the
* values.
*/
static BOOLEAN check_JUMP_param(char **url_template)
{
int param = 1;
char *subs;
char *result = *url_template;
char *encoded = NULL;
int code = TRUE;
bstring *input = NULL;
CTRACE((tfp, "check_JUMP_param: %s\n", NONNULL(result)));
while (result != NULL && (subs = strstr(result, "%s")) != 0) {
char prompt[MAX_LINE];
RecallType recall = NORECALL;
CTRACE((tfp, "Prompt for query param%d: %s\n", param, result));
sprintf(prompt, gettext("Query parameter %d: "), param++);
statusline(prompt);
BStrCopy0(input, "");
if (encoded)
FREE(encoded);
if (LYgetBString(&input, FALSE, 0, recall) < 0) {
/*
* cancelled via ^G
*/
HTInfoMsg(CANCELLED);
code = FALSE;
break;
} else if ((encoded = urlencode(input->str)) != NULL && *encoded != '\0') {
int subs_at = (int) (subs - result);
int fill_in = (int) strlen(encoded) - 2;
size_t have = strlen(result);
size_t want = strlen(encoded) + have - 1;
int n;
char *update = realloc(result, want + 1);
if (update == 0) {
HTInfoMsg(NOT_ENOUGH_MEMORY);
code = FALSE;
break;
}
CTRACE((tfp, " reply: %s\n", input->str));
CTRACE((tfp, " coded: %s\n", encoded));
result = update;
result[want] = '\0';
for (n = (int) want; (n - fill_in) >= subs_at; --n) {
result[n] = result[n - fill_in];
}
for (n = subs_at; encoded[n - subs_at] != '\0'; ++n) {
result[n] = encoded[n - subs_at];
}
CTRACE((tfp, " subst: %s\n", result));
} else {
HTInfoMsg(CANCELLED);
code = FALSE;
break;
}
}
BStrFree(input);
FREE(encoded);
*url_template = result;
return (BOOLEAN) code;
}
static void fill_JUMP_Params(char **addressp)
{
if (LYJumpFileURL) {
check_JUMP_param(addressp);
}
}
static BOOLEAN handle_LYK_JUMP(int c,
bstring **user_input,
char **old_user_input GCC_UNUSED,
RecallType * recall GCC_UNUSED,
BOOLEAN *FirstURLRecall GCC_UNUSED,
int *URLNum GCC_UNUSED,
int *URLTotal GCC_UNUSED,
int *ch GCC_UNUSED,
int *old_c,
int real_c)
{
char *ret;
if (no_jump || JThead == NULL) {
if (*old_c != real_c) {
*old_c = real_c;
if (no_jump)
HTUserMsg(JUMP_DISALLOWED);
else
HTUserMsg(NO_JUMPFILE);
}
} else {
LYJumpFileURL = TRUE;
if ((ret = LYJump(c)) != NULL) {
#ifdef PERMIT_GOTO_FROM_JUMP
if (!strncasecomp(ret, "Go ", 3)) {
LYJumpFileURL = FALSE;
StrAllocCopy(*old_user_input, (*user_input)->str);
*URLTotal = (Goto_URLs ? HTList_count(Goto_URLs) : 0);
*recall = ((*URLTotal >= 1) ? RECALL_URL : NORECALL);
*URLNum = *URLTotal;
*FirstURLRecall = TRUE;
if (!strcasecomp(ret, "Go :")) {
if (recall) {
*ch = UPARROW_KEY;
return TRUE;
}
FREE(*old_user_input);
HTUserMsg(NO_RANDOM_URLS_YET);
return FALSE;
}
ret = HTParse((ret + 3), startfile, PARSE_ALL);
BStrCopy0((*user_input), ret);
FREE(ret);
return TRUE;
}
#endif /* PERMIT_GOTO_FROM_JUMP */
ret = HTParse(ret, startfile, PARSE_ALL);
if (!LYTrimStartfile(ret)) {
LYRemoveBlanks((*user_input)->str);
}
if (check_JUMP_param(&ret)) {
set_address(&newdoc, ret);
StrAllocCopy(lynxjumpfile, ret);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
LYUserSpecifiedURL = TRUE;
}
FREE(ret);
} else {
LYJumpFileURL = FALSE;
}
}
return FALSE;
}
static void handle_LYK_KEYMAP(BOOLEAN *vi_keys_flag,
BOOLEAN *emacs_keys_flag,
int *old_c,
int real_c)
{
if (*old_c != real_c) {
*old_c = real_c;
set_address(&newdoc, STR_LYNXKEYMAP);
StrAllocCopy(newdoc.title, CURRENT_KEYMAP_TITLE);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = 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.
*/
if (!no_dired_support) {
prev_lynx_edit_mode = lynx_edit_mode;
}
#endif /* DIRED_SUPPORT && OK_OVERRIDE */
LYforce_no_cache = TRUE;
}
}
static void handle_LYK_LAST_LINK(void)
{
int i = curdoc.link;
for (;;) {
if (++i >= nlinks
|| links[i].ly != links[curdoc.link].ly) {
set_curdoc_link(i - 1);
break;
}
}
}
static void handle_LYK_LEFT_LINK(void)
{
if (curdoc.link > 0 &&
links[curdoc.link].ly == links[curdoc.link - 1].ly) {
set_curdoc_link(curdoc.link - 1);
}
}
static BOOLEAN handle_LYK_LIST(int *cmd)
{
/*
* Don't do if already viewing list page.
*/
if (!strcmp(NonNull(curdoc.title), LIST_PAGE_TITLE) &&
LYIsUIPage(curdoc.address, UIP_LIST_PAGE)) {
/*
* Already viewing list page, so get out.
*/
*cmd = LYK_PREV_DOC;
return TRUE;
}
/*
* Print list page to file.
*/
if (showlist(&newdoc, TRUE) < 0)
return FALSE;
StrAllocCopy(newdoc.title, LIST_PAGE_TITLE);
/*
* showlist will set newdoc's other fields. It may leave post_data intact
* so the list can be used to follow internal links in the current document
* even if it is a POST response. - kw
*/
if (LYValidate || check_realm) {
LYPermitURL = TRUE;
StrAllocCopy(lynxlistfile, newdoc.address);
}
return FALSE;
}
static void handle_LYK_MAIN_MENU(int *old_c,
int real_c)
{
/*
* If its already the homepage then don't reload it.
*/
if (!STREQ(curdoc.address, homepage)) {
if (HTConfirmDefault(CONFIRM_MAIN_SCREEN, NO) == YES) {
set_address(&newdoc, homepage);
StrAllocCopy(newdoc.title, gettext("Entry into main screen"));
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
LYhighlight(FALSE, curdoc.link, prev_target->str);
#ifdef DIRED_SUPPORT
if (lynx_edit_mode) {
DIRED_UNCACHE_2;
}
#endif /* DIRED_SUPPORT */
}
} else {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(IN_MAIN_SCREEN);
}
}
}
static void handle_LYK_MINIMAL(void)
{
if (!historical_comments) {
#ifdef USE_SOURCE_CACHE
if (!HTcan_reparse_document()) {
#endif
/*
* Check if this is a reply from a POST, and if so, seek
* confirmation of reload if the safe element is not set. - FM
*/
if ((curdoc.post_data != NULL &&
curdoc.safe != TRUE) &&
confirm_post_resub(curdoc.address, NULL, 0, 0) == FALSE) {
HTInfoMsg(WILL_NOT_RELOAD_DOC);
} else {
HText_setNoCache(HTMainText);
move_address(&newdoc, &curdoc);
newdoc.line = curdoc.line;
newdoc.link = curdoc.link;
}
#ifdef USE_SOURCE_CACHE
} /* end if no bypass */
#endif
}
minimal_comments = (BOOLEAN) !minimal_comments;
if (!historical_comments) {
HTAlert(minimal_comments ?
MINIMAL_ON_IN_EFFECT : MINIMAL_OFF_VALID_ON);
} else {
HTAlert(minimal_comments ?
MINIMAL_ON_BUT_HISTORICAL : MINIMAL_OFF_HISTORICAL_ON);
}
#ifdef USE_SOURCE_CACHE
(void) reparse_document();
#endif
return;
}
#if defined(DIRED_SUPPORT)
static void handle_LYK_MODIFY(BOOLEAN *refresh_screen)
{
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) {
DIRED_UNCACHE_1;
move_address(&newdoc, &curdoc);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
newdoc.line = curdoc.line;
newdoc.link = curdoc.link;
LYclear();
}
}
}
#endif /* DIRED_SUPPORT */
#ifdef EXP_NESTED_TABLES
static BOOLEAN handle_LYK_NESTED_TABLES(int *cmd)
{
nested_tables = (BOOLEAN) !nested_tables;
HTUserMsg(nested_tables ? NESTED_TABLES_ON : NESTED_TABLES_OFF);
return reparse_or_reload(cmd);
}
#endif
static BOOLEAN handle_LYK_OPTIONS(int *cmd,
BOOLEAN *refresh_screen)
{
#ifndef NO_OPTION_MENU
if (!LYUseFormsOptions) {
BOOLEAN LYUseDefaultRawMode_flag = LYUseDefaultRawMode;
BOOLEAN LYSelectPopups_flag = LYSelectPopups;
BOOLEAN verbose_img_flag = verbose_img;
BOOLEAN keypad_mode_flag = (BOOL) keypad_mode;
BOOLEAN show_dotfiles_flag = show_dotfiles;
BOOLEAN user_mode_flag = (BOOL) user_mode;
int CurrentAssumeCharSet_flag = UCLYhndl_for_unspec;
int CurrentCharSet_flag = current_char_set;
int HTfileSortMethod_flag = HTfileSortMethod;
char *CurrentUserAgent = NULL;
char *CurrentNegoLanguage = NULL;
char *CurrentNegoCharset = NULL;
StrAllocCopy(CurrentUserAgent, NonNull(LYUserAgent));
StrAllocCopy(CurrentNegoLanguage, NonNull(language));
StrAllocCopy(CurrentNegoCharset, NonNull(pref_charset));
LYoptions(); /** do the old-style options stuff **/
if (keypad_mode_flag != keypad_mode ||
(user_mode_flag != user_mode &&
(user_mode_flag == NOVICE_MODE ||
user_mode == NOVICE_MODE)) ||
(((HTfileSortMethod_flag != HTfileSortMethod) ||
(show_dotfiles_flag != show_dotfiles)) &&
(isFILE_URL(curdoc.address) ||
isFTP_URL(curdoc.address))) ||
CurrentCharSet_flag != current_char_set ||
CurrentAssumeCharSet_flag != UCLYhndl_for_unspec ||
verbose_img_flag != verbose_img ||
LYUseDefaultRawMode_flag != LYUseDefaultRawMode ||
LYSelectPopups_flag != LYSelectPopups ||
((strcmp(CurrentUserAgent, NonNull(LYUserAgent)) ||
strcmp(CurrentNegoLanguage, NonNull(language)) ||
strcmp(CurrentNegoCharset, NonNull(pref_charset))) &&
(!StrNCmp(curdoc.address, "http", 4) ||
isLYNXCGI(curdoc.address)))) {
BOOLEAN canreparse_post = FALSE;
/*
* Check if this is a reply from a POST, and if so, seek
* confirmation of reload if the safe element is not set. - FM
*/
if ((curdoc.post_data != NULL &&
curdoc.safe != TRUE) &&
#ifdef USE_SOURCE_CACHE
(!(canreparse_post = HTcan_reparse_document())) &&
#endif
confirm_post_resub(curdoc.address, curdoc.title,
2, 1) == FALSE) {
HTInfoMsg(WILL_NOT_RELOAD_DOC);
} else {
copy_address(&newdoc, &curdoc);
if (((strcmp(CurrentUserAgent, NonNull(LYUserAgent)) ||
strcmp(CurrentNegoLanguage, NonNull(language)) ||
strcmp(CurrentNegoCharset, NonNull(pref_charset))) &&
(StrNCmp(curdoc.address, "http", 4) == 0 ||
isLYNXCGI(curdoc.address)))) {
/*
* An option has changed which may influence content
* negotiation, and the resource is from a http or https or
* lynxcgi URL (the only protocols which currently do
* anything with this information). Set reloading = TRUE
* so that proxy caches will be flushed, which is necessary
* until the time when all proxies understand HTTP 1.1
* Vary: and all Servers properly use it... Treat like
* case LYK_RELOAD (see comments there). - KW
*/
reloading = TRUE;
}
if (HTisDocumentSource()) {
srcmode_for_next_retrieval(1);
}
#ifdef USE_SOURCE_CACHE
if (reloading == FALSE) {
/* one more attempt to be smart enough: */
if (reparse_document()) {
FREE(CurrentUserAgent);
FREE(CurrentNegoLanguage);
FREE(CurrentNegoCharset);
return FALSE;
}
}
#endif
if (canreparse_post &&
confirm_post_resub(curdoc.address, curdoc.title,
2, 1) == FALSE) {
if (HTisDocumentSource()) {
srcmode_for_next_retrieval(0);
}
FREE(CurrentUserAgent);
FREE(CurrentNegoLanguage);
FREE(CurrentNegoCharset);
return FALSE;
}
HEAD_request = HTLoadedDocumentIsHEAD();
HText_setNoCache(HTMainText);
newdoc.line = curdoc.line;
newdoc.link = curdoc.link;
LYforce_no_cache = TRUE;
free_address(&curdoc); /* So it doesn't get pushed. */
}
}
FREE(CurrentUserAgent);
FREE(CurrentNegoLanguage);
FREE(CurrentNegoCharset);
*refresh_screen = TRUE; /* to repaint screen */
return FALSE;
} /* end if !LYUseFormsOptions */
#else
(void) refresh_screen;
#endif /* !NO_OPTION_MENU */
#ifndef NO_OPTION_FORMS
/*
* Generally stolen from LYK_COOKIE_JAR. Options menu handling is
* done in postoptions(), called from getfile() currently.
*
* postoptions() is also responsible for reloading the document
* before the 'options menu' but only when (a few) important
* options were changed.
*
* It is critical that post_data is freed here since the
* submission of changed options is done via the same protocol as
* LYNXOPTIONS:
*/
/*
* Don't do if already viewing options page.
*/
if (!LYIsUIPage(curdoc.address, UIP_OPTIONS_MENU)) {
set_address(&newdoc, LYNXOPTIONS_PAGE("/"));
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
LYforce_no_cache = TRUE;
/* change to 'if (check_realm && !LYValidate)' and
make change near top of getfile to forbid
using forms options menu with -validate: - kw */
if (LYValidate || check_realm) {
LYPermitURL = TRUE;
}
} else {
/*
* If already in the options menu, get out.
*/
*cmd = LYK_PREV_DOC;
return TRUE;
}
#else
(void) cmd;
#endif /* !NO_OPTION_FORMS */
return FALSE;
}
static void handle_NEXT_DOC(void)
{
if (LYhist_next(&curdoc, &newdoc)) {
free_address(&curdoc); /* avoid push */
return;
}
HTUserMsg(gettext("No next document present"));
}
static void handle_LYK_NEXT_LINK(int c,
int *old_c,
int real_c)
{
if (curdoc.link < nlinks - 1) { /* next link */
LYhighlight(FALSE, curdoc.link, prev_target->str);
#ifdef FASTTAB
/*
* Move to different textarea if TAB in textarea.
*/
if (LinkIsTextarea(curdoc.link) &&
c == '\t') {
int thisgroup = links[curdoc.link].l_form->number;
char *thisname = links[curdoc.link].l_form->name;
do
curdoc.link++;
while ((curdoc.link < nlinks - 1) &&
LinkIsTextarea(curdoc.link) &&
links[curdoc.link].l_form->number == thisgroup &&
sametext(links[curdoc.link].l_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_text && LYGetNewline() == 1 && curdoc.link == nlinks - 1) {
set_curdoc_link(0);
} else if (more_text) { /* next page */
LYChgNewline(display_lines);
} else if (*old_c != real_c) {
HandleForwardWraparound();
}
}
static void handle_LYK_NEXT_PAGE(int *old_c,
int real_c)
{
if (more_text) {
LYChgNewline(display_lines);
} else if (curdoc.link < nlinks - 1) {
set_curdoc_link(nlinks - 1);
} else if (*old_c != real_c) {
*old_c = real_c;
HTInfoMsg(ALREADY_AT_END);
}
}
static BOOLEAN handle_LYK_NOCACHE(int *old_c,
int real_c)
{
if (nlinks > 0) {
if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
links[curdoc.link].l_form->type != F_SUBMIT_TYPE &&
links[curdoc.link].l_form->type != F_IMAGE_SUBMIT_TYPE &&
links[curdoc.link].l_form->type != F_TEXT_SUBMIT_TYPE) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NOT_ON_SUBMIT_OR_LINK);
}
return FALSE;
} else {
LYforce_no_cache = TRUE;
reloading = TRUE;
}
}
return TRUE;
}
static void handle_LYK_PREV_LINK(int *arrowup,
int *old_c,
int real_c)
{
if (curdoc.link > 0) { /* previous link */
set_curdoc_link(curdoc.link - 1);
} else if (!more_text &&
curdoc.link == 0 && LYGetNewline() == 1) { /* at the top of list */
/*
* If there is only one page of data and the user goes off the top,
* just move the cursor to last link on the page.
*/
set_curdoc_link(nlinks - 1);
} else if (curdoc.line > 1) { /* previous page */
/*
* Go back to the previous page.
*/
int scrollamount = (LYGetNewline() > display_lines
? display_lines
: LYGetNewline() - 1);
LYChgNewline(-scrollamount);
if (scrollamount < display_lines &&
nlinks > 0 && curdoc.link == 0 &&
links[0].ly - 1 + scrollamount <= display_lines) {
newdoc.link = HText_LinksInLines(HTMainText,
1,
scrollamount) - 1;
} else {
*arrowup = TRUE;
}
} else if (*old_c != real_c) {
HandleReverseWraparound();
}
}
#define nhist_1 (nhist - 1) /* workaround for indent */
static int handle_PREV_DOC(int *cmd,
int *old_c,
int real_c)
{
if (nhist > 0) { /* if there is anything to go back to */
/*
* Check if the previous document is a reply from a POST, and if so,
* seek confirmation of resubmission if the safe element is not set and
* the document is not still in the cache or LYresubmit_posts is set.
* If not confirmed and it is not the startfile, pop it so we go to the
* yet previous document, until we're OK or reach the startfile. If we
* reach the startfile and its not OK or we don't get confirmation,
* cancel. - FM
*/
DocAddress WWWDoc;
HTParentAnchor *tmpanchor;
BOOLEAN conf = FALSE, first = TRUE;
HTLastConfirmCancelled(); /* reset flag */
while (nhist > 0) {
conf = FALSE;
if (HDOC(nhist_1).post_data == NULL) {
break;
}
WWWDoc.address = HDOC(nhist_1).address;
WWWDoc.post_data = HDOC(nhist_1).post_data;
WWWDoc.post_content_type =
HDOC(nhist_1).post_content_type;
WWWDoc.bookmark = HDOC(nhist_1).bookmark;
WWWDoc.isHEAD = HDOC(nhist_1).isHEAD;
WWWDoc.safe = HDOC(nhist_1).safe;
tmpanchor = HTAnchor_findAddress(&WWWDoc);
if (HTAnchor_safe(tmpanchor)) {
break;
}
if ((HTAnchor_document(tmpanchor) == NULL &&
(isLYNXIMGMAP(WWWDoc.address) ||
(conf = confirm_post_resub(WWWDoc.address,
HDOC(nhist_1).title,
0, 0))
== FALSE)) ||
((LYresubmit_posts && !conf &&
(NONINTERNAL_OR_PHYS_DIFFERENT((DocInfo *) &history[(nhist_1)],
&curdoc) ||
NONINTERNAL_OR_PHYS_DIFFERENT((DocInfo *) &history[(nhist_1)],
&newdoc))) &&
!confirm_post_resub(WWWDoc.address,
HDOC(nhist_1).title,
2, 2))) {
if (HTLastConfirmCancelled()) {
if (!first && curdoc.internal_link)
free_address(&curdoc);
*cmd = LYK_DO_NOTHING;
return 2;
}
if (nhist == 1) {
HTInfoMsg(CANCELLED);
*old_c = 0;
*cmd = LYK_DO_NOTHING;
return 2;
} else {
HTUserMsg2(WWW_SKIP_MESSAGE, WWWDoc.address);
do { /* Should be LYhist_prev when _next supports */
LYpop(&curdoc); /* skipping of forms */
} while (nhist > 1
&& !are_different((DocInfo *) &history[nhist_1],
&curdoc));
first = FALSE; /* have popped at least one */
continue;
}
} else {
/*
* Break from loop; if user just confirmed to load again
* because document wasn't in cache, set LYforce_no_cache to
* avoid unnecessary repeat question down the road. - kw
*/
if (conf)
LYforce_no_cache = TRUE;
break;
}
}
if (!first)
curdoc.internal_link = FALSE;
/*
* Set newdoc.address to empty to pop a file.
*/
LYhist_prev_register(&curdoc); /* Why not call _prev instead of zeroing address? */
free_address(&newdoc);
#ifdef DIRED_SUPPORT
if (lynx_edit_mode) {
DIRED_UNCACHE_2;
}
#endif /* DIRED_SUPPORT */
} else if (child_lynx == TRUE) {
return (1); /* exit on left arrow in main screen */
} else if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(ALREADY_AT_FIRST);
}
return 0;
}
static void handle_LYK_PREV_PAGE(int *old_c,
int real_c)
{
if (LYGetNewline() > 1) {
LYChgNewline(-display_lines);
} else if (curdoc.link > 0) {
set_curdoc_link(0);
} else if (*old_c != real_c) {
*old_c = real_c;
HTInfoMsg(ALREADY_AT_BEGIN);
}
}
static void handle_LYK_PRINT(BOOLEAN *ForcePush,
int *old_c,
int real_c)
{
if (LYValidate) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(PRINT_DISABLED);
}
return;
}
/*
* Don't do if already viewing print options page.
*/
if (!LYIsUIPage(curdoc.address, UIP_PRINT_OPTIONS)
&& print_options(&newdoc.address,
curdoc.address, HText_getNumOfLines()) >= 0) {
LYRegisterUIPage(newdoc.address, UIP_PRINT_OPTIONS);
StrAllocCopy(newdoc.title, PRINT_OPTIONS_TITLE);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
*ForcePush = TRUE; /* see LYpush() and print_options() */
if (check_realm)
LYPermitURL = TRUE;
}
}
static BOOLEAN handle_LYK_QUIT(void)
{
int c;
if (LYQuitDefaultYes == TRUE) {
c = HTConfirmDefault(REALLY_QUIT, YES);
} else {
c = HTConfirmDefault(REALLY_QUIT, NO);
}
if (LYQuitDefaultYes == TRUE) {
if (c != NO) {
return (TRUE);
} else {
HTInfoMsg(NO_CANCEL);
}
} else if (c == YES) {
return (TRUE);
} else {
HTInfoMsg(NO_CANCEL);
}
return FALSE;
}
static BOOLEAN handle_LYK_RAW_TOGGLE(int *cmd)
{
if (HTLoadedDocumentCharset()) {
HTUserMsg(gettext("charset for this document specified explicitly, sorry..."));
return FALSE;
} else {
LYUseDefaultRawMode = (BOOL) !LYUseDefaultRawMode;
HTUserMsg(LYRawMode ? RAWMODE_OFF : RAWMODE_ON);
HTMLSetCharacterHandling(current_char_set);
return reparse_or_reload(cmd);
}
}
static void handle_LYK_RELOAD(int real_cmd)
{
/*
* Check if this is a reply from a POST, and if so,
* seek confirmation if the safe element is not set. - FM
*/
if ((curdoc.post_data != NULL &&
curdoc.safe != TRUE) &&
HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
HTInfoMsg(CANCELLED);
return;
}
/*
* Check to see if should reload source, or load html
*/
if (HTisDocumentSource()) {
if ((forced_UCLYhdnl = HTMainText_Get_UCLYhndl()) >= 0)
force_old_UCLYhndl_on_reload = TRUE;
srcmode_for_next_retrieval(1);
}
HEAD_request = HTLoadedDocumentIsHEAD();
HText_setNoCache(HTMainText);
/*
* 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)
*/
newdoc.line = curdoc.line;
newdoc.link = curdoc.link;
free_address(&curdoc); /* so it doesn't get pushed */
#ifdef VMS
lynx_force_repaint();
#endif /* VMS */
/*
* Reload should force a cache refresh on a proxy. -- Ari L.
* <luotonen@dxcern.cern.ch>
*
* -- but only if this was really a reload requested by the user, not if we
* jumped here to handle reloading for INLINE_TOGGLE, IMAGE_TOGGLE,
* RAW_TOGGLE, etc. - KW
*/
if (real_cmd == LYK_RELOAD)
reloading = REAL_RELOAD;
return;
}
#ifdef DIRED_SUPPORT
static void handle_LYK_REMOVE(BOOLEAN *refresh_screen)
{
if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
int linkno = curdoc.link; /* may be changed in local_remove - kw */
local_remove(&curdoc);
if (LYAutoUncacheDirLists >= 1)
do_cleanup_after_delete();
else if (curdoc.link != linkno)
*refresh_screen = TRUE;
}
}
#endif /* DIRED_SUPPORT */
static void handle_LYK_RIGHT_LINK(void)
{
if (curdoc.link < nlinks - 1 &&
links[curdoc.link].ly == links[curdoc.link + 1].ly) {
set_curdoc_link(curdoc.link + 1);
}
}
static void handle_LYK_SHELL(BOOLEAN *refresh_screen,
int *old_c,
int real_c)
{
if (!no_shell) {
stop_curses();
printf("%s\r\n", SPAWNING_MSG);
#if defined(__CYGWIN__)
/* handling "exec $SHELL" does not work if $SHELL is null */
if (LYGetEnv("SHELL") == NULL) {
Cygwin_Shell();
} else
#endif
{
static char *shell = NULL;
if (shell == 0)
StrAllocCopy(shell, LYSysShell());
LYSystem(shell);
}
start_curses();
*refresh_screen = TRUE; /* for an HText_pageDisplay() */
} else {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(SPAWNING_DISABLED);
}
}
}
static void handle_LYK_SOFT_DQUOTES(void)
{
#ifdef USE_SOURCE_CACHE
if (!HTcan_reparse_document()) {
#endif
/*
* Check if this is a reply from a POST, and if so, seek confirmation
* of reload if the safe element is not set. - FM
*/
if ((curdoc.post_data != NULL &&
curdoc.safe != TRUE) &&
confirm_post_resub(curdoc.address, NULL, 1, 1) == FALSE) {
HTInfoMsg(WILL_NOT_RELOAD_DOC);
} else {
HText_setNoCache(HTMainText);
move_address(&newdoc, &curdoc);
newdoc.line = curdoc.line;
newdoc.link = curdoc.link;
}
#ifdef USE_SOURCE_CACHE
} /* end if no bypass */
#endif
soft_dquotes = (BOOLEAN) !soft_dquotes;
HTUserMsg(soft_dquotes ?
SOFT_DOUBLE_QUOTE_ON : SOFT_DOUBLE_QUOTE_OFF);
#ifdef USE_SOURCE_CACHE
(void) reparse_document();
#endif
return;
}
#define GetAnchorNumber(link) \
((nlinks > 0 && link >= 0) \
? links[link].anchor_number \
: -1)
#define GetAnchorLineNo(link) \
((nlinks > 0 && link >= 0) \
? links[link].anchor_line_num \
: -1)
/*
* Adjust the top-of-screen line number for the new document if the redisplayed
* screen would not show the given link-number.
*/
#ifdef USE_SOURCE_CACHE
static int wrap_reparse_document(void)
{
int result;
int anchor_number = GetAnchorNumber(curdoc.link);
int old_line_num = HText_getAbsLineNumber(HTMainText, anchor_number);
int old_from_top = old_line_num - LYGetNewline() + 1;
/* get the offset for the current anchor */
int old_offset = ((nlinks > 0 && curdoc.link >= 0)
? links[curdoc.link].sgml_offset
: -1);
CTRACE((tfp, "original anchor %d, topline %d, link %d, offset %d\n",
anchor_number, old_line_num, curdoc.link, old_offset));
/* reparse the document (producing a new anchor list) */
result = reparse_document();
/* readjust top-line and link-number */
if (result && old_offset >= 0) {
int new_anchor = HText_closestAnchor(HTMainText, old_offset);
int new_lineno = HText_getAbsLineNumber(HTMainText, new_anchor);
int top_lineno;
CTRACE((tfp, "old anchor %d -> new anchor %d\n", anchor_number, new_anchor));
if (new_lineno - old_from_top < 0)
old_from_top = new_lineno;
/* Newline and newdoc.line are 1-based,
* but 0-based lines are simpler to work with.
*/
top_lineno = HText_getPreferredTopLine(HTMainText, new_lineno -
old_from_top) + 1;
CTRACE((tfp, "preferred top %d\n", top_lineno));
if (top_lineno != LYGetNewline()) {
LYSetNewline(top_lineno);
newdoc.link = HText_anchorRelativeTo(HTMainText, top_lineno - 1, new_anchor);
curdoc.link = newdoc.link;
CTRACE((tfp,
"adjusted anchor %d, topline %d, link %d, offset %d\n",
new_anchor,
top_lineno,
curdoc.link,
HText_locateAnchor(HTMainText, new_anchor)));
} else {
newdoc.link = curdoc.link;
}
}
return result;
}
#endif /* USE_SOURCE_CACHE */
static void handle_LYK_SOURCE(char **ownerS_address_p)
{
#ifdef USE_SOURCE_CACHE
BOOLEAN canreparse_post = FALSE;
#endif
/*
* Check if this is a reply from a POST, and if so,
* seek confirmation if the safe element is not set. - FM
*/
if ((curdoc.post_data != NULL &&
curdoc.safe != TRUE) &&
#ifdef USE_SOURCE_CACHE
(!(canreparse_post = HTcan_reparse_document())) &&
#endif
(curdoc.isHEAD ? HTConfirm(CONFIRM_POST_RESUBMISSION) :
confirm_post_resub(curdoc.address, curdoc.title, 1, 1)) == FALSE) {
HTInfoMsg(CANCELLED);
return;
}
if (HTisDocumentSource()) {
srcmode_for_next_retrieval(-1);
} else {
if (HText_getOwner())
StrAllocCopy(*ownerS_address_p, HText_getOwner());
LYUCPushAssumed(HTMainAnchor);
srcmode_for_next_retrieval(1);
}
#ifdef USE_SOURCE_CACHE
if (wrap_reparse_document()) {
/*
* These normally get cleaned up after getfile() returns;
* since we're not calling getfile(), we have to clean them
* up ourselves. -dsb
*/
HTOutputFormat = WWW_PRESENT;
#ifdef USE_PRETTYSRC
if (psrc_view)
HTMark_asSource();
psrc_view = FALSE;
#endif
FREE(*ownerS_address_p); /* not used with source_cache */
LYUCPopAssumed(); /* probably a right place here */
HTMLSetCharacterHandling(current_char_set); /* restore now */
return;
} else if (canreparse_post) {
srcmode_for_next_retrieval(0);
LYUCPopAssumed(); /* probably a right place here */
return;
}
#endif
if (curdoc.title)
StrAllocCopy(newdoc.title, curdoc.title);
free_address(&curdoc); /* so it doesn't get pushed */
LYforce_no_cache = TRUE;
}
static void handle_LYK_SWITCH_DTD(void)
{
#ifdef USE_SOURCE_CACHE
BOOLEAN canreparse = FALSE;
if (!(canreparse = HTcan_reparse_document())) {
#endif
/*
* Check if this is a reply from a POST, and if so,
* seek confirmation of reload if the safe element
* is not set. - FM, kw
*/
if ((curdoc.post_data != NULL &&
curdoc.safe != TRUE) &&
confirm_post_resub(curdoc.address, NULL, 1, 1) == FALSE) {
HTInfoMsg(WILL_NOT_RELOAD_DOC);
} else {
/*
* If currently viewing preparsed source, switching to the other
* DTD parsing may show source differences, so stay in source view
* - kw
*/
/* NOTE: this conditional can be considered incorrect -
current behaviour - when viewing source and
LYPreparsedSource==TRUE, pressing ^V will toggle parser mode
AND switch back from the source view to presentation view.-HV
*/
if (HTisDocumentSource() && LYPreparsedSource) {
srcmode_for_next_retrieval(1);
}
HText_setNoCache(HTMainText);
move_address(&newdoc, &curdoc);
newdoc.line = curdoc.line;
newdoc.link = curdoc.link;
}
#ifdef USE_SOURCE_CACHE
} /* end if no bypass */
#endif
Old_DTD = !Old_DTD;
HTSwitchDTD(!Old_DTD);
HTUserMsg(Old_DTD ? USING_DTD_0 : USING_DTD_1);
#ifdef USE_SOURCE_CACHE
if (canreparse) {
if (HTisDocumentSource() && LYPreparsedSource) {
srcmode_for_next_retrieval(1);
}
if (!reparse_document()) {
srcmode_for_next_retrieval(0);
}
}
#endif
return;
}
#ifdef DIRED_SUPPORT
static void handle_LYK_TAG_LINK(void)
{
if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
if (!strcmp(LYGetHiliteStr(curdoc.link, 0), ".."))
return; /* Never tag the parent directory */
if (dir_list_style == MIXED_STYLE) {
if (!strcmp(LYGetHiliteStr(curdoc.link, 0), "../"))
return;
} else if (!StrNCmp(LYGetHiliteStr(curdoc.link, 0), "Up to ", 6))
return;
{
/*
* HTList-based management of tag list, see LYLocal.c - KW
*/
HTList *t1 = tagged;
char *tagname = NULL;
BOOLEAN found = FALSE;
while ((tagname = (char *) HTList_nextObject(t1)) != NULL) {
if (!strcmp(links[curdoc.link].lname, tagname)) {
found = TRUE;
HTList_removeObject(tagged, tagname);
FREE(tagname);
tagflag(FALSE, curdoc.link);
break;
}
}
if (!found) {
if (tagged == NULL)
tagged = HTList_new();
tagname = NULL;
StrAllocCopy(tagname, links[curdoc.link].lname);
HTList_addObject(tagged, tagname);
tagflag(TRUE, curdoc.link);
}
}
if (curdoc.link < nlinks - 1) {
set_curdoc_link(curdoc.link + 1);
} else if (!more_text && LYGetNewline() == 1 && curdoc.link == nlinks
- 1) {
set_curdoc_link(0);
} else if (more_text) { /* next page */
LYChgNewline(display_lines);
}
}
}
#endif /* DIRED_SUPPORT */
static void handle_LYK_TOGGLE_HELP(void)
{
if (user_mode == NOVICE_MODE) {
toggle_novice_line();
noviceline(more_text);
}
}
static void handle_LYK_TOOLBAR(BOOLEAN *try_internal,
BOOLEAN *force_load,
int *old_c,
int real_c)
{
char *cp;
char *toolbar = NULL;
if (!HText_hasToolbar(HTMainText)) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_TOOLBAR);
}
} else if (*old_c != real_c) {
*old_c = real_c;
cp = trimPoundSelector(curdoc.address);
HTSprintf0(&toolbar, "%s#%s", curdoc.address, LYToolbarName);
restorePoundSelector(cp);
set_address(&newdoc, toolbar);
FREE(toolbar);
*try_internal = TRUE;
*force_load = TRUE; /* force MainLoop to reload */
}
}
static void handle_LYK_TRACE_LOG(BOOLEAN *trace_flag_ptr)
{
#ifndef NO_LYNX_TRACE
/*
* Check whether we've started a TRACE log in this session. - FM
*/
if (LYTraceLogFP == NULL) {
HTUserMsg(NO_TRACELOG_STARTED);
return;
}
/*
* Don't do if already viewing the TRACE log. - FM
*/
if (LYIsUIPage(curdoc.address, UIP_TRACELOG))
return;
/*
* If TRACE mode is on, turn it off during this fetch of the TRACE log, so
* we don't enter stuff about this fetch, and set a flag for turning it
* back on when we return to this loop. Note that we'll miss any messages
* about memory exhaustion if it should occur. It seems unlikely that
* anything else bad might happen, but if it does, we'll miss messages
* about that too. We also fflush(), close, and open it again, to make
* sure all stderr messages thus far will be in the log. - FM
*/
if (!LYReopenTracelog(trace_flag_ptr))
return;
LYLocalFileToURL(&(newdoc.address), LYTraceLogPath);
LYRegisterUIPage(newdoc.address, UIP_TRACELOG);
StrAllocCopy(newdoc.title, LYNX_TRACELOG_TITLE);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
if (LYValidate || check_realm) {
LYPermitURL = TRUE;
}
LYforce_no_cache = TRUE;
#else
HTUserMsg(TRACE_DISABLED);
#endif /* NO_LYNX_TRACE */
}
#ifdef DIRED_SUPPORT
static void handle_LYK_UPLOAD(void)
{
/*
* Don't do if already viewing upload options page.
*/
if (LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS))
return;
if (lynx_edit_mode && !no_dired_support) {
LYUpload_options(&(newdoc.address), curdoc.address);
StrAllocCopy(newdoc.title, UPLOAD_OPTIONS_TITLE);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
/*
* Uncache the current listing so that it will be updated to included
* the uploaded file if placed in the current directory. - FM
*/
DIRED_UNCACHE_1;
}
}
#endif /* DIRED_SUPPORT */
static void handle_LYK_UP_xxx(int *arrowup,
int *old_c,
int real_c,
int scroll_by)
{
if (LYGetNewline() > 1) {
if (LYGetNewline() - scroll_by < 1)
scroll_by = LYGetNewline() - 1;
LYChgNewline(-scroll_by);
if (nlinks > 0 && curdoc.link > -1) {
if (links[curdoc.link].ly + scroll_by <= display_lines) {
newdoc.link = curdoc.link +
HText_LinksInLines(HTMainText,
LYGetNewline(),
scroll_by);
} else {
*arrowup = TRUE;
}
}
} else if (*old_c != real_c) {
HandleReverseWraparound();
}
}
static void handle_LYK_UP_HALF(int *arrowup,
int *old_c,
int real_c)
{
handle_LYK_UP_xxx(arrowup, old_c, real_c, display_lines / 2);
}
static void handle_LYK_UP_LINK(int *follow_col,
int *arrowup,
int *old_c,
int real_c)
{
if (curdoc.link > 0 &&
(links[0].ly != links[curdoc.link].ly ||
!HText_LinksInLines(HTMainText, 1, LYGetNewline() - 1))) {
/* more links before this on screen, and first of them on
a different line or no previous links before this screen? */
int newlink;
if (*follow_col == -1) {
const char *text = LYGetHiliteStr(curdoc.link, 0);
*follow_col = links[curdoc.link].lx;
if (text != NULL)
*follow_col += (int) strlen(text) / 2;
}
newlink = find_link_near_col(*follow_col, -1);
if (newlink > -1) {
set_curdoc_link(newlink);
} else if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(NO_LINKS_ABOVE);
}
} else if (curdoc.line > 1 && LYGetNewline() > 1) { /* previous page */
int scrollamount = (LYGetNewline() > display_lines
? display_lines
: LYGetNewline() - 1);
LYChgNewline(-scrollamount);
if (scrollamount < display_lines &&
nlinks > 0 && curdoc.link > -1 &&
links[0].ly - 1 + scrollamount <= display_lines) {
newdoc.link = HText_LinksInLines(HTMainText,
1,
scrollamount) - 1;
} else {
*arrowup = TRUE;
}
} else if (*old_c != real_c) {
HandleReverseWraparound();
}
}
static void handle_LYK_UP_TWO(int *arrowup,
int *old_c,
int real_c)
{
handle_LYK_UP_xxx(arrowup, old_c, real_c, 2);
}
static void handle_LYK_VIEW_BOOKMARK(BOOLEAN *refresh_screen,
int *old_c,
int real_c)
{
const char *cp;
if (LYValidate) {
if (*old_c != real_c) {
*old_c = real_c;
HTUserMsg(BOOKMARKS_DISABLED);
}
return;
}
/*
* See if a bookmark exists. If it does replace newdoc.address with its
* name.
*/
if ((cp = get_bookmark_filename(&newdoc.address)) != NULL) {
if (*cp == '\0' || !strcmp(cp, " ") ||
!strcmp(curdoc.address, newdoc.address)) {
if (LYMultiBookmarks != MBM_OFF)
*refresh_screen = TRUE;
return;
}
#ifdef KANJI_CODE_OVERRIDE
if (HTCJK == JAPANESE) {
last_kcode = NOKANJI; /* AUTO */
}
#endif
LYforce_no_cache = TRUE; /*force the document to be reloaded */
StrAllocCopy(newdoc.title, BOOKMARK_TITLE);
StrAllocCopy(newdoc.bookmark, BookmarkPage);
LYFreePostData(&newdoc);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
} else {
if (*old_c != real_c) {
*old_c = real_c;
LYMBM_statusline(BOOKMARKS_NOT_OPEN);
LYSleepAlert();
if (LYMultiBookmarks != MBM_OFF) {
*refresh_screen = TRUE;
}
}
}
}
static BOOLEAN handle_LYK_VLINKS(int *cmd,
BOOLEAN *newdoc_link_is_absolute)
{
int c;
if (LYIsUIPage(curdoc.address, UIP_VLINKS)) {
/*
* Already viewing visited links page, so get out.
*/
*cmd = LYK_PREV_DOC;
return TRUE;
}
/*
* Print visited links page to file.
*/
c = LYShowVisitedLinks(&newdoc.address);
if (c < 0) {
HTUserMsg(VISITED_LINKS_EMPTY);
return FALSE;
}
StrAllocCopy(newdoc.title, VISITED_LINKS_TITLE);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
if (c > 0) {
/* Select a correct link. */
*newdoc_link_is_absolute = TRUE;
newdoc.link = c - 1;
}
if (LYValidate || check_realm) {
LYPermitURL = TRUE;
StrAllocCopy(lynxlinksfile, newdoc.address);
}
return FALSE;
}
void handle_LYK_WHEREIS(int cmd,
BOOLEAN *refresh_screen)
{
BOOLEAN have_target_onscreen = (BOOLEAN) (!isBEmpty(prev_target) &&
HText_pageHasPrevTarget());
BOOL found;
int oldcur = curdoc.link; /* temporarily remember */
char *remember_old_target = NULL;
if (have_target_onscreen)
StrAllocCopy(remember_old_target, prev_target->str);
else
StrAllocCopy(remember_old_target, "");
if (cmd == LYK_WHEREIS) {
/*
* Reset prev_target to force prompting for a new search string and to
* turn off highlighting if no search string is entered by the user.
*/
BStrCopy0(prev_target, "");
}
found = textsearch(&curdoc, &prev_target,
(cmd == LYK_WHEREIS)
? 0
: ((cmd == LYK_NEXT)
? 1
: -1));
/*
* Force a redraw to ensure highlighting of hits even when found on the
* same page, or clearing of highlighting if the default search string was
* erased without replacement. - FM
*/
/*
* Well let's try to avoid it at least in a few cases
* where it is not needed. - kw
*/
if (www_search_result >= 0 && www_search_result != curdoc.line) {
*refresh_screen = TRUE; /* doesn't really matter */
} else if (!found) {
*refresh_screen = have_target_onscreen;
} else if (!have_target_onscreen && found) {
*refresh_screen = TRUE;
} else if (www_search_result == curdoc.line &&
curdoc.link == oldcur &&
curdoc.link >= 0 && nlinks > 0 &&
links[curdoc.link].ly >= (display_lines / 3)) {
*refresh_screen = TRUE;
} else if ((LYcase_sensitive && 0 != strcmp(prev_target->str,
remember_old_target)) ||
(!LYcase_sensitive && 0 != strcasecomp8(prev_target->str,
remember_old_target))) {
*refresh_screen = TRUE;
}
FREE(remember_old_target);
}
/*
* Get a number from the user and follow that link number.
*/
static void handle_LYK_digit(int c,
BOOLEAN *force_load,
int *old_c,
int real_c,
BOOLEAN *try_internal GCC_UNUSED)
{
int lindx = ((nlinks > 0) ? curdoc.link : 0);
int number;
char *temp = NULL;
/* pass cur line num for use in follow_link_number()
* Note: Current line may not equal links[cur].line
*/
number = curdoc.line;
switch (follow_link_number(c, lindx, &newdoc, &number)) {
case DO_LINK_STUFF:
/*
* Follow a normal link.
*/
set_address(&newdoc, links[lindx].lname);
StrAllocCopy(newdoc.title, LYGetHiliteStr(lindx, 0));
/*
* For internal links, retain POST content if present. If we are on
* the List Page, prevent pushing it on the history stack. Otherwise
* set try_internal to signal that the top of the loop should attempt
* to reposition directly, without calling getfile. - kw
*/
if (track_internal_links) {
if (links[lindx].type == WWW_INTERN_LINK_TYPE) {
LYinternal_flag = TRUE;
newdoc.internal_link = TRUE;
if (LYIsListpageTitle(NonNull(curdoc.title)) &&
(LYIsUIPage(curdoc.address, UIP_LIST_PAGE) ||
LYIsUIPage(curdoc.address, UIP_ADDRLIST_PAGE))) {
if (check_history()) {
LYinternal_flag = TRUE;
} else {
HTLastConfirmCancelled(); /* reset flag */
if (!confirm_post_resub(newdoc.address,
newdoc.title,
((LYresubmit_posts &&
HText_POSTReplyLoaded(&newdoc))
? 1
: 2),
2)) {
if (HTLastConfirmCancelled() ||
(LYresubmit_posts &&
!HText_POSTReplyLoaded(&newdoc))) {
/* cancel the whole thing */
LYforce_no_cache = FALSE;
reloading = FALSE;
copy_address(&newdoc, &curdoc);
StrAllocCopy(newdoc.title, curdoc.title);
newdoc.internal_link = curdoc.internal_link;
HTInfoMsg(CANCELLED);
if (nlinks > 0)
HText_pageDisplay(curdoc.line, prev_target->str);
break;
} else if (LYresubmit_posts) {
/* If LYresubmit_posts is set, and the
answer was No, and we have a cached
copy, then use it. - kw */
LYforce_no_cache = FALSE;
} else {
/* if No, but not ^C or ^G, drop
* the post data. Maybe the link
* wasn't meant to be internal after
* all, here we can recover from that
* assumption. - kw */
LYFreePostData(&newdoc);
newdoc.internal_link = FALSE;
HTAlert(DISCARDING_POST_DATA);
}
}
}
/*
* Don't push the List Page if we follow an internal link given
* by it. - kw
*/
free_address(&curdoc);
} else
*try_internal = TRUE;
if (!(LYresubmit_posts && newdoc.post_data))
LYinternal_flag = TRUE;
*force_load = TRUE;
break;
} else {
/*
* Free POST content if not an internal link. - kw
*/
LYFreePostData(&newdoc);
}
}
/*
* 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)) {
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
if (isLYNXMESSAGES(newdoc.address))
LYforce_no_cache = TRUE;
}
newdoc.internal_link = FALSE;
*force_load = TRUE; /* force MainLoop to reload */
break;
case DO_GOTOLINK_STUFF:
/*
* Position on a normal link, don't follow it. - KW
*/
LYSetNewline(newdoc.line);
newdoc.line = 1;
if (LYGetNewline() == curdoc.line) {
/*
* It's a link in the current page. - FM
*/
if (nlinks > 0 && curdoc.link > -1) {
if (curdoc.link == newdoc.link) {
/*
* It's the current link, and presumably reflects a typo in
* the statusline entry, so issue a statusline message for
* the typo-prone users (like me 8-). - FM
*/
HTSprintf0(&temp, LINK_ALREADY_CURRENT, number);
HTUserMsg(temp);
FREE(temp);
} else {
/*
* It's a different link on this page,
*/
set_curdoc_link(newdoc.link);
newdoc.link = 0;
}
}
}
break; /* nothing more to do */
case DO_GOTOPAGE_STUFF:
/*
* Position on a page in this document. - FM
*/
LYSetNewline(newdoc.line);
newdoc.line = 1;
if (LYGetNewline() == curdoc.line) {
/*
* It's the current page, so issue a statusline message for the
* typo-prone users (like me 8-). - FM
*/
if (LYGetNewline() <= 1) {
HTInfoMsg(ALREADY_AT_BEGIN);
} else if (!more_text) {
HTInfoMsg(ALREADY_AT_END);
} else {
HTSprintf0(&temp, ALREADY_AT_PAGE, number);
HTUserMsg(temp);
FREE(temp);
}
}
break;
case PRINT_ERROR:
*old_c = real_c;
HTUserMsg(BAD_LINK_NUM_ENTERED);
break;
}
return;
}
#ifdef SUPPORT_CHDIR
/* original implementation by VH */
void handle_LYK_CHDIR(void)
{
static bstring *buf = NULL;
char *p = NULL;
if (no_chdir) {
HTUserMsg(CHDIR_DISABLED);
return;
}
_statusline(gettext("cd to:"));
if (LYgetBString(&buf, FALSE, 0, NORECALL) < 0 || isBEmpty(buf)) {
HTInfoMsg(CANCELLED);
return;
}
if (LYIsTilde(buf->str[0]) &&
(LYIsPathSep(buf->str[1]) || buf->str[1] == '\0')) {
HTSprintf0(&p, "%s%s", Home_Dir(), buf->str + 1);
} else {
StrAllocCopy(p, buf->str);
}
CTRACE((tfp, "changing directory to '%s'\n", p));
if (chdir(p)) {
switch (errno) {
case EACCES:
HTInfoMsg(COULD_NOT_ACCESS_DIR);
break;
case ENOENT:
HTInfoMsg(gettext("No such directory"));
break;
case ENOTDIR:
HTInfoMsg(gettext("A component of path is not a directory"));
break;
default:
HTInfoMsg(gettext("failed to change directory"));
break;
}
} else {
#ifdef DIRED_SUPPORT
/*if in dired, load content of other directory */
if (!no_dired_support
&& (lynx_edit_mode || (LYIsUIPage(curdoc.address, UIP_DIRED_MENU)))) {
char buf2[LY_MAXPATH];
char *addr = NULL;
Current_Dir(buf2);
LYLocalFileToURL(&addr, buf2);
newdoc.address = addr;
newdoc.isHEAD = FALSE;
StrAllocCopy(newdoc.title, gettext("A URL specified by the user"));
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
/**force_load = TRUE;*/
if (lynx_edit_mode) {
DIRED_UNCACHE_2;
}
} else
#endif
HTInfoMsg(OPERATION_DONE);
}
FREE(p);
}
static void handle_LYK_PWD(void)
{
char buffer[LY_MAXPATH];
int save_secs = InfoSecs;
BOOLEAN save_wait = no_pause;
if (Secs2SECS(save_secs) < 1)
InfoSecs = SECS2Secs(1);
no_pause = FALSE;
HTInfoMsg(Current_Dir(buffer));
InfoSecs = save_secs;
no_pause = save_wait;
}
#endif
#ifdef USE_CURSES_PADS
/*
* Having jumps larger than this is counter-productive. Indeed, it is natural
* to expect that when the relevant text appears, one would "overshoot" and
* would scroll 3-4 extra full screens. When going back, the "accumulation"
* logic would again start moving in full screens, so one would overshoot
* again, etc.
*
* Going back, one can fix it in 28 keypresses. The relevant text will appear
* on the screen soon enough for the key-repeat to become not that important,
* and we are still moving in smaller steps than when we overshot. Since key
* repeat is not important, even if we overshoot again, it is going to be by 30
* steps, which is easy to fix by reversing the direction again.
*/
static int repeat_to_delta(int n)
{
int threshold = LYcols / 3;
while (threshold > 0) {
if (n >= threshold) {
n = threshold;
break;
}
threshold = (threshold * 2) / 3;
}
return n;
}
static void handle_LYK_SHIFT_LEFT(BOOLEAN *flag, int count)
{
if (!LYwideLines) {
HTAlert(SHIFT_VS_LINEWRAP);
return;
}
if (LYshiftWin > 0) {
LYshiftWin -= repeat_to_delta(count);
*flag = TRUE;
}
if (LYshiftWin < 0)
LYshiftWin = 0;
}
static void handle_LYK_SHIFT_RIGHT(BOOLEAN *flag, int count)
{
if (!LYwideLines) {
HTAlert(SHIFT_VS_LINEWRAP);
return;
}
LYshiftWin += repeat_to_delta(count);
*flag = TRUE;
}
static BOOLEAN handle_LYK_LINEWRAP_TOGGLE(int *cmd,
BOOLEAN *flag)
{
static const char *choices[] =
{
"Try to fit screen width",
"No line wrap in columns",
"Wrap columns at screen width",
"Wrap columns at 3/4 screen width",
"Wrap columns at 2/3 screen width",
"Wrap columns at 1/2 screen width",
"Wrap columns at 1/3 screen width",
"Wrap columns at 1/4 screen width",
NULL
};
static int wrap[] =
{
0,
0,
12, /* In units of 1/12 */
9,
8,
6,
4,
3
};
int c;
int code = FALSE;
CTRACE((tfp, "Entering handle_LYK_LINEWRAP_TOGGLE\n"));
if (LYwin != stdscr) {
/* Somehow the mouse is over the number instead of being over the
name, so we decrease x. */
c = LYChoosePopup(!LYwideLines,
LYlines / 2 - 2,
LYcolLimit / 2 - 6,
choices, (int) TABLESIZE(choices) - 1,
FALSE, TRUE);
/*
* LYhandlePopupList() wasn't really meant to be used outside of
* old-style Options menu processing. One result of mis-using it here
* is that we have to deal with side-effects regarding SIGINT signal
* handler and the term_options global variable. - kw
*/
if (!term_options) {
CTRACE((tfp,
"...setting LYwideLines %d, LYtableCols %d (have %d and %d)\n",
c, wrap[c],
LYwideLines,
LYtableCols));
LYwideLines = c;
LYtableCols = wrap[c];
if (LYwideLines == 0)
LYshiftWin = 0;
*flag = TRUE;
HTUserMsg(LYwideLines ? LINEWRAP_OFF : LINEWRAP_ON);
code = reparse_or_reload(cmd);
}
}
return (BOOLEAN) code;
}
#endif
#ifdef USE_MAXSCREEN_TOGGLE
static BOOLEAN handle_LYK_MAXSCREEN_TOGGLE(int *cmd)
{
static int flag = 0;
CTRACE((tfp, "Entering handle_LYK_MAXSCREEN_TOGGLE\n"));
if (flag) {
CTRACE((tfp, "Calling recoverWindowSize()\n"));
recoverWindowSize();
flag = 0;
} else {
CTRACE((tfp, "Calling maxmizeWindowSize()\n"));
maxmizeWindowSize();
flag = 1;
}
return reparse_or_reload(cmd);
}
#endif
#ifdef LY_FIND_LEAKS
#define CleanupMainLoop() \
BStrFree(prev_target); \
BStrFree(user_input_buffer)
#else
#define CleanupMainLoop() /* nothing */
#endif
/*
* 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(void)
{
#if defined(WIN_EX) /* 1997/10/08 (Wed) 14:52:06 */
char sjis_buff[MAX_LINE];
char temp_buff[sizeof(sjis_buff) * 4];
#endif
int c = 0;
int real_c = 0;
int old_c = 0;
int pending_form_c = -1;
int cmd = LYK_DO_NOTHING, real_cmd = LYK_DO_NOTHING;
int getresult;
int arrowup = FALSE, show_help = FALSE;
bstring *user_input_buffer = NULL;
const char *cshelpfile = NULL;
BOOLEAN first_file = TRUE;
BOOLEAN popped_doc = FALSE;
BOOLEAN refresh_screen = FALSE;
BOOLEAN force_load = FALSE;
BOOLEAN try_internal = FALSE;
BOOLEAN crawl_ok = FALSE;
BOOLEAN vi_keys_flag = vi_keys;
BOOLEAN emacs_keys_flag = emacs_keys;
BOOLEAN trace_mode_flag = FALSE;
BOOLEAN forced_HTML_mode = LYforce_HTML_mode;
char cfile[128];
FILE *cfp;
char *cp;
int ch = 0;
RecallType recall = NORECALL;
int URLTotal = 0;
int URLNum;
BOOLEAN FirstURLRecall = TRUE;
char *temp = NULL;
BOOLEAN ForcePush = FALSE;
BOOLEAN override_LYresubmit_posts = FALSE;
BOOLEAN newdoc_link_is_absolute = FALSE;
BOOLEAN curlink_is_editable;
BOOLEAN use_last_tfpos;
unsigned int len;
int i;
int follow_col = -1, key_count = 0, last_key = 0;
int tmpNewline;
DocInfo tmpDocInfo;
/* "internal" means "within the same document, with certainty". It includes a
* space so it cannot conflict with any (valid) "TYPE" attributes on A
* elements. [According to which DTD, anyway??] - kw
*/
HTInternalLink = HTAtom_for("internal link"); /* init, used as const */
#ifndef WWW_SOURCE
WWW_SOURCE = HTAtom_for(STR_SOURCE); /* init, used as const */
#endif
/*
* 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).
*/
/* initialize some variables */
newdoc.address = NULL;
newdoc.title = NULL;
newdoc.post_data = NULL;
newdoc.post_content_type = NULL;
newdoc.bookmark = NULL;
newdoc.internal_link = FALSE;
curdoc.address = NULL;
curdoc.title = NULL;
curdoc.post_data = NULL;
curdoc.post_content_type = NULL;
curdoc.bookmark = NULL;
curdoc.internal_link = FALSE;
#ifdef USE_COLOR_STYLE
curdoc.style = NULL;
newdoc.style = NULL;
#endif
#ifndef USE_SESSIONS
nhist = 0;
#endif
BStrCopy0(user_input_buffer, "");
BStrCopy0(prev_target, "");
#ifdef LY_FIND_LEAKS
atexit(free_mainloop_variables);
#endif
initialize:
set_address(&newdoc, startfile);
StrAllocCopy(startrealm, startfile);
StrAllocCopy(newdoc.title, gettext("Entry into main screen"));
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.line = 1;
newdoc.link = 0;
#ifdef USE_SLANG
if (TRACE && LYCursesON) {
LYaddstr("\n");
LYrefresh();
}
#endif /* USE_SLANG */
CTRACE((tfp, "Entering mainloop, startfile=%s\n", startfile));
if (form_post_data) {
BStrCopy0(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) {
HTAlert(BOOKMARKS_DISABLED);
bookmark_start = FALSE;
goto initialize;
} else if (traversal) {
HTAlert(BOOKMARKS_NOT_TRAVERSED);
traversal = FALSE;
crawl = FALSE;
bookmark_start = FALSE;
goto initialize;
} else {
const char *cp1;
/*
* See if a bookmark page exists. If it does, replace
* newdoc.address with its name
*/
if ((cp1 = get_bookmark_filename(&newdoc.address)) != NULL &&
*cp1 != '\0' && strcmp(cp1, " ")) {
StrAllocCopy(newdoc.title, BOOKMARK_TITLE);
StrAllocCopy(newdoc.bookmark, BookmarkPage);
StrAllocCopy(startrealm, newdoc.address);
LYFreePostData(&newdoc);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
CTRACE((tfp, "Using bookmarks=%s\n", newdoc.address));
} else {
HTUserMsg(BOOKMARKS_NOT_OPEN);
bookmark_start = FALSE;
goto initialize;
}
}
}
FREE(form_post_data);
FREE(form_get_data);
LYSetDisplayLines();
while (TRUE) {
#ifdef USE_COLOR_STYLE
if (curdoc.style != NULL)
force_load = TRUE;
#endif
/*
* If newdoc.address is different from 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) {
LYHideCursor(); /* make sure cursor is down */
#ifdef USE_SLANG
LYaddstr("\n");
#endif /* USE_SLANG */
LYrefresh();
}
try_again:
/*
* Push the old file onto the history stack if we have a current
* doc and a new address. - FM
*/
if (curdoc.address && newdoc.address) {
/*
* Don't actually push if this is a LYNXDOWNLOAD URL, because
* that returns NORMAL even if it fails due to a spoof attempt
* or file access problem, and we set the newdoc structure
* elements to the curdoc structure elements under case NORMAL.
* - FM
*/
if (!isLYNXDOWNLOAD(newdoc.address)) {
LYpush(&curdoc, ForcePush);
}
} else if (!newdoc.address) {
/*
* If newdoc.address is empty then pop a file and load it. -
* FM
*/
LYhist_prev(&newdoc);
popped_doc = TRUE;
/*
* If curdoc had been reached via an internal
* (fragment) link from what we now have just
* popped into newdoc, then override non-caching in
* all cases. - kw
*/
if (track_internal_links &&
curdoc.internal_link &&
!are_phys_different(&curdoc, &newdoc)) {
LYinternal_flag = TRUE;
LYoverride_no_cache = TRUE;
LYforce_no_cache = FALSE;
try_internal = TRUE;
} else {
/*
* Force a no_cache override unless it's a bookmark file,
* or it has POST content and LYresubmit_posts is set
* without safe also set, and we are not going to another
* position in the current document or restoring the
* previous document due to a NOT_FOUND or NULLFILE return
* value from getfile(). - FM
*/
if ((newdoc.bookmark != NULL) ||
(newdoc.post_data != NULL &&
!newdoc.safe &&
LYresubmit_posts &&
!override_LYresubmit_posts &&
NO_INTERNAL_OR_DIFFERENT(&curdoc, &newdoc))) {
LYoverride_no_cache = FALSE;
} else {
LYoverride_no_cache = TRUE;
}
}
}
override_LYresubmit_posts = FALSE;
if (HEAD_request) {
/*
* Make SURE this is an appropriate request. - FM
*/
if (newdoc.address) {
if (LYCanDoHEAD(newdoc.address) == TRUE) {
newdoc.isHEAD = TRUE;
} else if (isLYNXIMGMAP(newdoc.address)) {
if (LYCanDoHEAD(newdoc.address + LEN_LYNXIMGMAP) == TRUE) {
StrAllocCopy(temp, newdoc.address + LEN_LYNXIMGMAP);
free_address(&newdoc);
newdoc.address = temp;
newdoc.isHEAD = TRUE;
temp = NULL;
}
}
}
try_internal = FALSE;
HEAD_request = FALSE;
}
/*
* If we're getting the TRACE log and it's not new, check whether
* its HText structure has been dumped, and if so, fflush() and
* fclose() it to ensure it's fully updated, and then fopen() it
* again. - FM
*/
if (LYUseTraceLog == TRUE &&
trace_mode_flag == FALSE &&
LYTraceLogFP != NULL &&
LYIsUIPage(newdoc.address, UIP_TRACELOG)) {
DocAddress WWWDoc;
HTParentAnchor *tmpanchor;
WWWDoc.address = newdoc.address;
WWWDoc.post_data = newdoc.post_data;
WWWDoc.post_content_type = newdoc.post_content_type;
WWWDoc.bookmark = newdoc.bookmark;
WWWDoc.isHEAD = newdoc.isHEAD;
WWWDoc.safe = newdoc.safe;
tmpanchor = HTAnchor_findAddress(&WWWDoc);
if ((HText *) HTAnchor_document(tmpanchor) == NULL) {
if (!LYReopenTracelog(&trace_mode_flag)) {
old_c = 0;
cmd = LYK_PREV_DOC;
goto new_cmd;
}
}
}
LYRequestTitle = newdoc.title;
if (newdoc.bookmark)
LYforce_HTML_mode = TRUE;
if (LYValidate &&
startfile_ok &&
newdoc.address && startfile && homepage &&
(!strcmp(newdoc.address, startfile) ||
!strcmp(newdoc.address, homepage))) {
LYPermitURL = TRUE;
}
/* reset these two variables here before getfile()
* so they will be available in partial mode
* (was previously implemented in case NORMAL).
*/
BStrCopy0(prev_target, ""); /* Reset for new coming document */
LYSetNewline(newdoc.line); /* set for LYGetNewline() */
#ifdef USE_PRETTYSRC
psrc_first_tag = TRUE;
#endif
#ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
textfields_need_activation = textfields_activation_option;
#endif
FREE(LYRequestReferer);
/*
* Don't send Referer if we have to load a document again that we
* got from the history stack. We don't know any more how we
* originally got to that page. Using a Referer based on the
* current HTMainText could only be right by coincidence. - kw
* 1999-11-01
*/
if (popped_doc)
LYNoRefererForThis = TRUE;
if (track_internal_links) {
if (try_internal) {
if (newdoc.address &&
isLYNXIMGMAP(newdoc.address)) {
try_internal = FALSE;
} else if (curdoc.address &&
isLYNXIMGMAP(curdoc.address)) {
try_internal = FALSE;
}
}
if (try_internal) {
char *hashp = findPoundSelector(newdoc.address);
if (hashp) {
HTFindPoundSelector(hashp + 1);
}
getresult = (HTMainText != NULL) ? NORMAL : NOT_FOUND;
try_internal = FALSE; /* done */
/* fix up newdoc.address which may have been fragment-only */
if (getresult == NORMAL && (!hashp || hashp == newdoc.address)) {
if (!hashp) {
set_address(&newdoc, HTLoadedDocumentURL());
} else {
StrAllocCopy(temp, HTLoadedDocumentURL());
StrAllocCat(temp, hashp); /* append fragment */
set_address(&newdoc, temp);
FREE(temp);
}
}
} else {
if (newdoc.internal_link && newdoc.address &&
*newdoc.address == '#' && nhist > 0) {
char *cp0;
if (isLYNXIMGMAP(HDOC(nhist_1).address))
cp0 = HDOC(nhist_1).address + LEN_LYNXIMGMAP;
else
cp0 = HDOC(nhist_1).address;
StrAllocCopy(temp, cp0);
(void) trimPoundSelector(temp);
StrAllocCat(temp, newdoc.address);
free_address(&newdoc);
newdoc.address = temp;
temp = NULL;
}
tmpDocInfo = newdoc;
tmpNewline = -1;
fill_JUMP_Params(&newdoc.address);
getresult = getfile(&newdoc, &tmpNewline);
if (!reloading && !popped_doc && (tmpNewline >= 0)) {
LYSetNewline(tmpNewline);
} else {
newdoc.link = tmpDocInfo.link;
}
}
} else {
tmpDocInfo = newdoc;
tmpNewline = -1;
fill_JUMP_Params(&newdoc.address);
getresult = getfile(&newdoc, &tmpNewline);
if (!reloading && !popped_doc && (tmpNewline >= 0)) {
LYSetNewline(tmpNewline);
} else {
newdoc.link = tmpDocInfo.link;
}
}
#ifdef INACTIVE_INPUT_STYLE_VH
textinput_redrawn = FALSE; /* for sure */
#endif
switch (getresult) {
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 */
LYinternal_flag = FALSE; /* Reset to default. - kw */
turn_trace_back_on(&trace_mode_flag);
if (!first_file && !LYCancelledFetch) {
/*
* Do error mail sending and/or traversal stuff. Note that
* the links[] elements may not be valid at this point, if
* we did call HTuncache_current_document! This should not
* have happened for traversal, but for sending error mail
* check that HTMainText exists for this reason. - kw
*/
if (error_logging && nhist > 0 && !popped_doc &&
!LYUserSpecifiedURL &&
HTMainText &&
nlinks > 0 && curdoc.link < nlinks &&
!isLYNXHIST(NonNull(newdoc.address)) &&
!isLYNXCACHE(NonNull(newdoc.address)) &&
!isLYNXCOOKIE(NonNull(newdoc.address))) {
char *mail_owner = NULL;
if (owner_address && isMAILTO_URL(owner_address)) {
mail_owner = owner_address + LEN_MAILTO_URL;
}
/*
* Email a bad link message to the owner of the
* document, or to ALERTMAIL if defined, but NOT to
* lynx-dev (it is rejected in mailmsg). - FM, kw
*/
#ifndef ALERTMAIL
if (mail_owner)
#endif
mailmsg(curdoc.link,
mail_owner,
HDOC(nhist_1).address,
HDOC(nhist_1).title);
}
if (traversal) {
FILE *ofp;
if ((ofp = LYAppendToTxtFile(TRAVERSE_ERRORS)) == NULL) {
if ((ofp = LYNewTxtFile(TRAVERSE_ERRORS)) == NULL) {
perror(NOOPEN_TRAV_ERR_FILE);
exit_immediately(EXIT_FAILURE);
}
}
if (nhist > 0) {
fprintf(ofp,
"%s %s\tin %s\n",
popped_doc ?
newdoc.address : links[curdoc.link].lname,
links[curdoc.link].target,
HDOC(nhist_1).address);
} else {
fprintf(ofp,
"%s %s\t\n",
popped_doc ?
newdoc.address : links[curdoc.link].lname,
links[curdoc.link].target);
}
LYCloseOutput(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.
*/
CleanupMainLoop();
exit_immediately_with_error_message(NOT_FOUND, first_file);
return (EXIT_FAILURE);
}
/* FALLTHRU */
case NULLFILE:
/*
* Not supposed to return any file.
*/
LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
popped_doc = FALSE; /* Was TRUE if popped. - FM */
LYinternal_flag = FALSE; /* Reset to default. - kw */
turn_trace_back_on(&trace_mode_flag);
free_address(&newdoc); /* to pop last doc */
FREE(newdoc.bookmark);
LYJumpFileURL = FALSE;
reloading = FALSE;
LYPermitURL = FALSE;
LYCancelledFetch = FALSE;
ForcePush = FALSE;
LYforce_HTML_mode = FALSE;
force_old_UCLYhndl_on_reload = 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 &&
!LYSameFilename(homepage, startfile)) {
/*
* 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
*/
set_address(&newdoc, homepage);
LYFreePostData(&newdoc);
FREE(newdoc.bookmark);
StrAllocCopy(startfile, homepage);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
newdoc.internal_link = FALSE;
goto try_again;
} else {
CleanupMainLoop();
exit_immediately_with_error_message(NULLFILE, first_file);
return (EXIT_FAILURE);
}
}
/*
* If we're going to pop from history because getfile didn't
* succeed, reset LYforce_no_cache first. This would have been
* done in HTAccess.c if the request got that far, but the URL
* may have been handled or rejected in getfile without taking
* care of that. - kw
*/
LYforce_no_cache = FALSE;
/*
* Retrieval of a newdoc just failed, and just going to
* try_again would pop the next doc from history and try to get
* it without further questions. This may not be the right
* thing to do if we have POST data, so fake a PREV_DOC key if
* it seems that some prompting should be done. This doesn't
* affect the traversal logic, since with traversal POST data
* can never occur. - kw
*/
if (HDOC(nhist - 1).post_data &&
!HDOC(nhist - 1).safe) {
if (HText_POSTReplyLoaded((DocInfo *) &history[(nhist_1)])) {
override_LYresubmit_posts = TRUE;
goto try_again;
}
/* Set newdoc fields, just in case the PREV_DOC gets
* cancelled. - kw
*/
if (!curdoc.address) {
set_address(&newdoc, HTLoadedDocumentURL());
StrAllocCopy(newdoc.title, HTLoadedDocumentTitle());
if (HTMainAnchor
&& HTMainAnchor->post_data) {
BStrCopy(newdoc.post_data,
HTMainAnchor->post_data);
StrAllocCopy(newdoc.post_content_type,
HTMainAnchor->post_content_type);
} else {
BStrFree(newdoc.post_data);
}
newdoc.isHEAD = HTLoadedDocumentIsHEAD();
newdoc.safe = HTLoadedDocumentIsSafe();
newdoc.internal_link = FALSE;
} else {
copy_address(&newdoc, &curdoc);
StrAllocCopy(newdoc.title, curdoc.title);
BStrCopy(newdoc.post_data, curdoc.post_data);
StrAllocCopy(newdoc.post_content_type,
curdoc.post_content_type);
newdoc.isHEAD = curdoc.isHEAD;
newdoc.safe = curdoc.safe;
newdoc.internal_link = curdoc.internal_link;
newdoc.line = curdoc.line;
newdoc.link = curdoc.link;
}
cmd = LYK_PREV_DOC;
goto new_cmd;
}
override_LYresubmit_posts = TRUE;
goto try_again;
case NORMAL:
/*
* Marvelously, we got the document!
*/
LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
LYinternal_flag = FALSE; /* Reset to default. - kw */
turn_trace_back_on(&trace_mode_flag);
/*
* If it's the first file and we're interactive, check whether
* it's a bookmark file which was not accessed via the -book
* switch. - FM
*/
if (((first_file == TRUE) &&
(dump_output_immediately == FALSE) &&
isEmpty(newdoc.bookmark)) &&
((LYisLocalFile(newdoc.address) == TRUE) &&
!(strcmp(NonNull(HText_getTitle()),
BOOKMARK_TITLE))) &&
(temp = HTParse(newdoc.address, "",
PARSE_PATH + PARSE_PUNCTUATION)) != NULL) {
const char *name = wwwName(Home_Dir());
len = (unsigned) strlen(name);
#ifdef VMS
if (!strncasecomp(temp, name, len) &&
strlen(temp) > len)
#else
if (!StrNCmp(temp, name, len) &&
strlen(temp) > len)
#endif /* VMS */
{
/*
* We're interactive and this might be a bookmark file
* entered as a startfile rather than invoked via
* -book. Check if it's in our bookmark file list, and
* if so, reload if with the relevant bookmark elements
* set. - FM
*/
cp = NULL;
if (temp[len] == '/') {
if (StrChr(&temp[(len + 1)], '/')) {
HTSprintf0(&cp, ".%s", &temp[len]);
} else {
StrAllocCopy(cp, &temp[(len + 1)]);
}
} else {
StrAllocCopy(cp, &temp[len]);
}
for (i = 0; i <= MBM_V_MAXFILES; i++) {
if (MBM_A_subbookmark[i] &&
LYSameFilename(cp, MBM_A_subbookmark[i])) {
StrAllocCopy(BookmarkPage,
MBM_A_subbookmark[i]);
break;
}
}
FREE(cp);
if (i <= MBM_V_MAXFILES) {
FREE(temp);
if (LYValidate) {
HTAlert(BOOKMARKS_DISABLED);
CleanupMainLoop();
return (EXIT_FAILURE);
}
if ((temp = HTParse(newdoc.address, "",
PARSE_ACCESS + PARSE_HOST + PARSE_PUNCTUATION))) {
set_address(&newdoc, temp);
HTuncache_current_document();
free_address(&curdoc);
StrAllocCat(newdoc.address,
wwwName(Home_Dir()));
StrAllocCat(newdoc.address, "/");
StrAllocCat(newdoc.address,
(StrNCmp(BookmarkPage, "./", 2) ?
BookmarkPage :
(BookmarkPage + 2)));
StrAllocCopy(newdoc.title, BOOKMARK_TITLE);
StrAllocCopy(newdoc.bookmark, BookmarkPage);
#ifdef USE_COLOR_STYLE
if (curdoc.style)
StrAllocCopy(newdoc.style, curdoc.style);
#endif
StrAllocCopy(startrealm, newdoc.address);
LYFreePostData(&newdoc);
newdoc.isHEAD = FALSE;
newdoc.safe = FALSE;
FREE(temp);
if (!strcmp(homepage, startfile))
StrAllocCopy(homepage, newdoc.address);
StrAllocCopy(startfile, newdoc.address);
CTRACE((tfp, "Reloading as bookmarks=%s\n",
newdoc.address));
goto try_again;
}
}
}
cp = NULL;
}
FREE(temp);
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_link(traversal_link_to_add))
add_to_table(traversal_link_to_add);
FREE(traversal_link_to_add);
}
if (curdoc.address && curdoc.title &&
!isLYNXIMGMAP(curdoc.address))
/*
* Add the address we got to TRAVERSE_FOUND_FILE.
*/
add_to_traverse_list(curdoc.address, curdoc.title);
}
/*
* If this was a LYNXDOWNLOAD, we still have curdoc, not a
* newdoc, so reset the address, title and positioning
* elements. - FM
*/
if (newdoc.address && curdoc.address &&
isLYNXDOWNLOAD(newdoc.address)) {
copy_address(&newdoc, &curdoc);
StrAllocCopy(newdoc.title, NonNull(curdoc.title));
StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
newdoc.line = curdoc.line;
newdoc.link = curdoc.link;
newdoc.internal_link = FALSE; /* can't be true. - kw */
}
/*
* 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.
*
* We already set Newline before getfile() and probably update
* it explicitly if popping from the history stack via LYpop()
* or LYpop_num() within getfile() cycle.
*
* In partial mode, Newline was probably updated in
* LYMainLoop_pageDisplay() if user scrolled the document while
* loading. Incremental loading stage already closed in
* HT*Copy().
*/
#ifdef DISP_PARTIAL
/* Newline = newdoc.line; */
display_partial = FALSE; /* for sure, LYNXfoo:/ may be a problem */
#else
/* Should not be needed either if we remove "DISP_PARTIAL" from
* LYHistory.c, but lets leave it as an important comment for
* now.
*/
/* Newline = newdoc.line; */
#endif
/*
* If we are going to a target line or the first page of a
* popped document, override any www_search line result.
*/
if (LYGetNewline() > 1 || popped_doc == TRUE)
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) {
if (!LYTraceLogFP || trace_mode_flag) {
LYSleepAlert(); /* allow me to look at the results */
}
}
/*
* Set the files the same.
*/
copy_address(&curdoc, &newdoc);
BStrCopy(curdoc.post_data, newdoc.post_data);
StrAllocCopy(curdoc.post_content_type, newdoc.post_content_type);
StrAllocCopy(curdoc.bookmark, newdoc.bookmark);
#ifdef USE_COLOR_STYLE
StrAllocCopy(curdoc.style, HText_getStyle());
if (curdoc.style != NULL)
style_readFromFile(curdoc.style);
#endif
curdoc.isHEAD = newdoc.isHEAD;
curdoc.internal_link = newdoc.internal_link;
/*
* Set the remaining document elements and add to the visited links
* list. - FM
*/
if (ownerS_address != NULL) {
#ifndef USE_PRETTYSRC
if (HTOutputFormat == WWW_SOURCE && !HText_getOwner())
#else
if ((LYpsrc ? psrc_view : HTOutputFormat == WWW_SOURCE)
&& !HText_getOwner())
#endif
HText_setMainTextOwner(ownerS_address);
FREE(ownerS_address);
}
if (HText_getTitle()) {
StrAllocCopy(curdoc.title, HText_getTitle());
} else if (!dump_output_immediately) {
StrAllocCopy(curdoc.title, newdoc.title);
}
StrAllocCopy(owner_address, HText_getOwner());
curdoc.safe = HTLoadedDocumentIsSafe();
if (!dump_output_immediately) {
LYAddVisitedLink(&curdoc);
}
/*
* Reset WWW present mode so that if we were getting the source, we
* get rendered HTML from now on.
*/
HTOutputFormat = WWW_PRESENT;
#ifdef USE_PRETTYSRC
psrc_view = FALSE;
#endif
HTMLSetCharacterHandling(current_char_set); /* restore, for sure? */
/*
* 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; /* set for RELOAD and NOCACHE keys */
HEAD_request = FALSE; /* only set for HEAD requests */
LYPermitURL = FALSE; /* only for LYValidate or check_realm */
ForcePush = FALSE; /* only set for some PRINT requests. */
LYforce_HTML_mode = FALSE;
force_old_UCLYhndl_on_reload = FALSE;
popped_doc = FALSE;
pending_form_c = -1;
}
/* end if (LYforce_no_cache || force_load || are_different(...)) */
if (dump_output_immediately) {
if (crawl) {
print_crawl_to_fd(stdout, curdoc.address, curdoc.title);
} else if (!dump_links_only) {
print_wwwfile_to_fd(stdout, FALSE, FALSE);
}
CleanupMainLoop();
return ((dump_server_status >= 400) ? EXIT_FAILURE : EXIT_SUCCESS);
}
/*
* If the recent_sizechange variable is set to TRUE then the window
* size changed recently.
*/
if (recent_sizechange) {
/*
* First we need to make sure the display library - curses, slang,
* whatever - gets notified about the change, and gets a chance to
* update external structures appropriately. Hopefully the
* stop_curses()/start_curses() sequence achieves this, at least if
* the display library has a way to get the new screen size from
* the OS.
*
* However, at least for ncurses, the update of the internal
* structures will come still too late - the changed screen size is
* detected in doupdate(), which would only be called (indirectly
* through the HText_pageDisplay below) after the WINDOW structures
* are already filled based on the old size. So we notify the
* ncurses library directly here. - kw
*/
#if defined(NCURSES) && defined(HAVE_RESIZETERM) && defined(HAVE_WRESIZE)
resizeterm(LYlines, LYcols);
wresize(LYwin, LYlines, LYcols);
#else
#if 0 /* defined(PDCURSES) && defined(HAVE_XCURSES) */
resize_term(LYlines, LYcols);
if (LYwin != 0)
LYwin = resize_window(LYwin, LYlines, LYcols);
refresh();
#else
stop_curses();
start_curses();
LYclear();
#endif
#endif
refresh_screen = TRUE; /* to force a redraw */
if (HTMainText) /* to REALLY force it... - kw */
HText_setStale(HTMainText);
recent_sizechange = FALSE;
LYSetDisplayLines();
}
if (www_search_result != -1) {
/*
* This was a WWW search, set the line to the result of the search.
*/
LYSetNewline(www_search_result);
www_search_result = -1; /* reset */
}
if (first_file == TRUE) {
/*
* We can never again have the first file.
*/
first_file = FALSE;
/*
* Set the startrealm, and deal as best we can with preserving
* forced HTML mode for a local startfile. - FM
*/
temp = HTParse(curdoc.address, "",
PARSE_ACCESS + PARSE_HOST + PARSE_PUNCTUATION);
if (isEmpty(temp)) {
StrAllocCopy(startrealm, NO_NOTHING);
} else {
StrAllocCopy(startrealm, temp);
FREE(temp);
if (!(temp = HTParse(curdoc.address, "",
PARSE_PATH + PARSE_PUNCTUATION))) {
LYAddHtmlSep(&startrealm);
} else {
if (forced_HTML_mode &&
!dump_output_immediately &&
!curdoc.bookmark &&
isFILE_URL(curdoc.address) &&
strlen(temp) > 1) {
/*
* We forced HTML for a local startfile which is not a
* bookmark file and has a path of at least two
* letters. If it doesn't have a suffix mapped to
* text/html, we'll set the entire path (including the
* lead slash) as a "suffix" mapped to text/html to
* ensure it is always treated as an HTML source file.
* We are counting on a tail match to this full path
* for some other URL fetched during the session having
* too low a probability to worry about, but it could
* happen. - FM
*/
HTAtom *encoding;
if (HTFileFormat(temp, &encoding, NULL) != WWW_HTML) {
HTSetSuffix(temp, STR_HTML, "8bit", 1.0);
}
}
if ((cp = strrchr(temp, '/')) != NULL) {
*(cp + 1) = '\0';
StrAllocCat(startrealm, temp);
}
}
}
FREE(temp);
CTRACE((tfp, "Starting realm is '%s'\n\n", startrealm));
if (traversal) {
/*
* Set up the crawl output stuff.
*/
if (curdoc.address && !lookup_link(curdoc.address)) {
if (!isLYNXIMGMAP(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, NO_NOTHING);
} else if (check_realm) {
StrAllocCopy(traversal_host, startrealm);
} else {
temp = HTParse(curdoc.address, "",
PARSE_ACCESS + PARSE_HOST + PARSE_PUNCTUATION);
if (isEmpty(temp)) {
StrAllocCopy(traversal_host, NO_NOTHING);
} else {
StrAllocCopy(traversal_host, temp);
LYAddHtmlSep(&traversal_host);
}
FREE(temp);
}
CTRACE((tfp, "Traversal host is '%s'\n\n", traversal_host));
}
if (startfile) {
/*
* If homepage was not equated to startfile, make the homepage
* URL the first goto entry. - FM
*/
if (homepage && strcmp(startfile, homepage))
HTAddGotoURL(homepage);
/*
* If we are not starting up with startfile (e.g., had -book),
* or if we are using the startfile and it has no POST content,
* make the startfile URL a goto entry. - FM
*/
if (strcmp(startfile, newdoc.address) ||
newdoc.post_data == NULL)
HTAddGotoURL(startfile);
}
if (TRACE) {
refresh_screen = TRUE;
if (!LYTraceLogFP || trace_mode_flag) {
LYSleepAlert();
}
}
}
#ifdef USE_SOURCE_CACHE
/*
* If the parse settings have changed since this HText was
* generated, we need to reparse and redraw it. -dsb
*
* Should be configured to avoid shock for experienced lynx users.
* Currently enabled for cached sources only.
*/
if (HTdocument_settings_changed()) {
if (HTcan_reparse_document()) {
HTInfoMsg(gettext("Reparsing document under current settings..."));
reparse_document();
} else {
/*
* Urk. I have no idea how to recover from a failure here.
* At a guess, I'll try reloading. -dsb
*/
/* currently disabled ***
HTUserMsg(gettext("Reparsing document under current settings..."));
cmd = LYK_RELOAD;
goto new_cmd;
*/
}
}
if (from_source_cache) {
from_source_cache = FALSE; /* reset */
curdoc.line = -1; /* so curdoc.line != Newline, see below */
}
#endif
/*
* If the curdoc.line is different than Newline then there must have
* been a change since last update. Run HText_pageDisplay() to create
* a fresh screen of text output.
*
* If we got new HTMainText go this way. All display_partial calls
* ends here for final redraw.
*/
if (curdoc.line != LYGetNewline()) {
#ifdef INACTIVE_INPUT_STYLE_VH
textinput_redrawn = FALSE;
#endif
refresh_screen = FALSE;
HText_pageDisplay(LYGetNewline(), prev_target->str);
#ifdef DIRED_SUPPORT
if (lynx_edit_mode && nlinks > 0 && !HTList_isEmpty(tagged))
showtags(tagged);
#endif /* DIRED_SUPPORT */
/*
* Check if there is more info below this page.
*/
more_text = HText_canScrollDown();
if (newdoc.link < 0)
goto_line(LYGetNewline());
LYSetNewline(HText_getTopOfScreen() + 1);
curdoc.line = LYGetNewline();
if (curdoc.title == NULL) {
/*
* If we don't yet have a title, try to get it, or set to that
* for newdoc.title. - FM
*/
if (HText_getTitle()) {
StrAllocCopy(curdoc.title, HText_getTitle());
} else {
StrAllocCopy(curdoc.title, newdoc.title);
}
}
/*
* If the request is to highlight a link which is counted from the
* start of document, correct the link number:
*/
if (newdoc_link_is_absolute) {
newdoc_link_is_absolute = FALSE;
if (curdoc.line > 1)
newdoc.link -= HText_LinksInLines(HTMainText, 1,
curdoc.line - 1);
}
if (arrowup) {
/*
* arrowup 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;
} else if (curdoc.link < 0 && nlinks > 0) {
/*
* We may have popped a doc (possibly in local_dired) which
* didn't have any links when it was pushed, but does have
* links now (e.g., a file was created). Code below
* assumes that curdoc.link is valid and that
* (curdoc.link==-1) only occurs if (nlinks==0) is true. -
* KW
*/
curdoc.link = 0;
}
}
show_help = FALSE; /* reset */
newdoc.line = 1;
newdoc.link = 0;
curdoc.line = LYGetNewline(); /* set */
} else if (newdoc.link < 0) {
newdoc.link = 0; /* ...just in case getfile set this */
}
/*
* Refresh the screen if necessary.
*/
if (refresh_screen) {
#if defined(FANCY_CURSES) || defined (USE_SLANG)
if (enable_scrollback) {
LYclear();
} else {
LYerase();
}
#else
LYclear();
#endif /* FANCY_CURSES || USE_SLANG */
HText_pageDisplay(LYGetNewline(), prev_target->str);
#ifdef DIRED_SUPPORT
if (lynx_edit_mode && nlinks > 0 && !HTList_isEmpty(tagged))
showtags(tagged);
#endif /* DIRED_SUPPORT */
/*
* Check if there is more info below this page.
*/
more_text = HText_canScrollDown();
/*
* Adjust curdoc.link as above; nlinks may have changed, if the
* refresh_screen flag was set as a result of a size change. Code
* below assumes that curdoc.link is valid and that
* (curdoc.link==-1) only occurs if (nlinks==0) is true. - kw
*/
if (curdoc.link >= nlinks) {
curdoc.link = nlinks - 1;
} else if (curdoc.link < 0 && nlinks > 0) {
curdoc.link = 0;
}
if (user_mode == NOVICE_MODE)
noviceline(more_text); /* print help message */
refresh_screen = FALSE;
}
curlink_is_editable = (BOOLEAN)
(nlinks > 0 &&
LinkIsTextLike(curdoc.link));
use_last_tfpos = (BOOLEAN)
(curlink_is_editable &&
(real_cmd == LYK_LPOS_PREV_LINK ||
real_cmd == LYK_LPOS_NEXT_LINK));
#ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
if (!textfields_need_activation)
textinput_activated = TRUE;
#endif
#if defined(WIN_EX) /* 1997/10/08 (Wed) 14:52:06 */
if (nlinks > 0) {
char *p = "LYNX (unknown link type)";
/* Show the URL & kanji code . */
if (strlen(links[curdoc.link].lname) == 0) {
if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
switch (links[curdoc.link].l_form->type) {
case F_TEXT_SUBMIT_TYPE:
case F_SUBMIT_TYPE:
case F_IMAGE_SUBMIT_TYPE:
p = "[SUBMIT]";
break;
case F_PASSWORD_TYPE:
p = "Password";
break;
case F_OPTION_LIST_TYPE:
p = "Option list";
break;
case F_CHECKBOX_TYPE:
p = "Check box";
break;
case F_RADIO_TYPE:
p = "[Radio]";
break;
case F_RESET_TYPE:
p = "[Reset]";
break;
case F_TEXT_TYPE:
p = "Text input";
break;
case F_TEXTAREA_TYPE:
p = "Text input lines";
break;
default:
break;
}
set_ws_title(p);
}
} else {
if (user_mode == ADVANCED_MODE || user_mode == MINIMAL_MODE) {
p = curdoc.title;
} else {
p = links[curdoc.link].lname;
}
if (strlen(p) < ((sizeof(sjis_buff) / 2) - 1)) {
strcpy(temp_buff, p);
if (StrChr(temp_buff, '%')) {
HTUnEscape(temp_buff);
}
str_sjis(sjis_buff, temp_buff);
set_ws_title(LYElideString(sjis_buff, 10));
}
}
} else {
if (strlen(curdoc.address) < sizeof(temp_buff) - 1) {
if (user_mode == ADVANCED_MODE || user_mode == MINIMAL_MODE) {
str_sjis(temp_buff, curdoc.title);
} else {
strcpy(temp_buff, curdoc.address);
}
set_ws_title(HTUnEscape(temp_buff));
}
}
#endif /* WIN_EX */
/*
* Report unread or new mail, if appropriate.
*/
if (check_mail && !no_mail)
LYCheckMail();
/*
* If help is not on the screen, then put a message on the screen to
* tell the user other misc info.
*/
if (!show_help) {
show_main_statusline(links[curdoc.link],
((curlink_is_editable &&
textinput_activated)
? FOR_INPUT
: FOR_PANEL));
} else {
show_help = FALSE;
}
if (nlinks > 0) {
/*
* Highlight current link, unless it is an active text input field.
*/
if (!curlink_is_editable) {
LYhighlight(TRUE, curdoc.link, prev_target->str);
#ifndef INACTIVE_INPUT_STYLE_VH
} else if (!textinput_activated) {
LYhighlight(TRUE, curdoc.link, prev_target->str);
#endif
}
}
if (traversal) {
/*
* Don't go interactively into forms, or accept keystrokes from the
* user
*/
if (crawl && crawl_ok) {
crawl_ok = FALSE;
#ifdef FNAMES_8_3
sprintf(cfile, "lnk%05d.dat", crawl_count);
#else
sprintf(cfile, "lnk%08d.dat", crawl_count);
#endif /* FNAMES_8_3 */
crawl_count = crawl_count + 1;
if ((cfp = LYNewTxtFile(cfile)) != NULL) {
print_crawl_to_fd(cfp, curdoc.address, curdoc.title);
LYCloseOutput(cfp);
} else {
#ifdef UNIX
FILE *fp = (dump_output_immediately
? stderr
: stdout);
#else
FILE *fp = stdout;
#endif
if (!dump_output_immediately)
cleanup();
fprintf(fp,
gettext("Fatal error - could not open output file %s\n"),
cfile);
CleanupMainLoop();
if (!dump_output_immediately) {
exit_immediately(EXIT_FAILURE);
}
return (EXIT_FAILURE);
}
}
} else {
/*
* Normal, non-traversal handling.
*/
if (curlink_is_editable &&
(textinput_activated || pending_form_c != -1)) {
if (pending_form_c != -1) {
real_c = pending_form_c;
pending_form_c = -1;
} else {
/*
* Replace novice lines if in NOVICE_MODE.
*/
if (user_mode == NOVICE_MODE) {
form_noviceline(FormIsReadonly(links[curdoc.link].l_form));
}
real_c = change_form_link(curdoc.link,
&newdoc, &refresh_screen,
use_last_tfpos, FALSE);
}
#ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
if (textfields_need_activation)
textinput_activated = FALSE;
#ifdef INACTIVE_INPUT_STYLE_VH
textinput_redrawn = FALSE;
#endif
#endif
c = (real_c == LKC_DONE) ? DO_NOTHING : LKC_TO_C(real_c);
if (c != DO_NOTHING &&
peek_mouse_link() != -1 && peek_mouse_link() != -2)
old_c = 0;
if (peek_mouse_link() >= 0 &&
LKC_TO_LAC(keymap, real_c) != LYK_CHANGE_LINK) {
do_change_link();
if ((c == '\n' || c == '\r') &&
LinkIsTextLike(curdoc.link) &&
!textfields_need_activation) {
c = DO_NOTHING;
}
#ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
} else if (LinkIsTextarea(curdoc.link)
&& textfields_need_activation
&& !FormIsReadonly(links[curdoc.link].l_form)
&& peek_mouse_link() < 0 &&
(((LKC_TO_LAC(keymap, real_c) == LYK_NEXT_LINK ||
#ifdef TEXTAREA_AUTOGROW
LKC_TO_LAC(keymap, real_c) == LYK_ACTIVATE ||
#endif
LKC_TO_LAC(keymap, real_c) == LYK_LPOS_NEXT_LINK ||
LKC_TO_LAC(keymap, real_c) == LYK_DOWN_LINK) &&
((curdoc.link < nlinks - 1 &&
LinkIsTextarea(curdoc.link + 1)
&& (links[curdoc.link].l_form->number ==
links[curdoc.link + 1].l_form->number)
&& strcmp(links[curdoc.link].l_form->name,
links[curdoc.link + 1].l_form->name)
== 0) ||
(curdoc.link == nlinks - 1 && more_text &&
HText_TAHasMoreLines(curdoc.link, 1)))) ||
((LKC_TO_LAC(keymap, real_c) == LYK_PREV_LINK ||
LKC_TO_LAC(keymap, real_c) == LYK_LPOS_PREV_LINK ||
LKC_TO_LAC(keymap, real_c) == LYK_UP_LINK) &&
((curdoc.link > 0 &&
LinkIsTextarea(curdoc.link - 1)
&& (links[curdoc.link].l_form->number ==
links[curdoc.link - 1].l_form->number) &&
strcmp(links[curdoc.link].l_form->name,
links[curdoc.link - 1].l_form->name) == 0)
|| (curdoc.link == 0 && curdoc.line > 1 &&
HText_TAHasMoreLines(curdoc.link, -1)))))) {
textinput_activated = TRUE;
#ifdef TEXTAREA_AUTOGROW
if ((c == '\n' || c == '\r') &&
LKC_TO_LAC(keymap, real_c) == LYK_ACTIVATE)
c = LAC_TO_LKC0(LYK_NEXT_LINK);
#endif /* TEXTAREA_AUTOGROW */
#endif /* TEXTFIELDS_MAY_NEED_ACTIVATION */
} else
switch (c) {
case '\n':
case '\r':
#ifdef TEXTAREA_AUTOGROW
/*
* If on the bottom line of a TEXTAREA, and the user
* hit the ENTER key, we add a new line/anchor
* automatically, positioning the cursor on it.
*
* If at the bottom of the screen, we effectively
* perform an LYK_DOWN_HALF-like operation, then move
* down to the new line we just added. --KED 02/14/99
*
* [There is some redundancy and non-standard
* indentation in the monster-if() below. This is
* intentional ... to try and improve the
* "readability" (such as it is). Caveat emptor to
* anyone trying to change it.]
*/
if (LinkIsTextarea(curdoc.link)
&& ((curdoc.link == nlinks - 1 &&
!(more_text &&
HText_TAHasMoreLines(curdoc.link, 1)))
||
((curdoc.link < nlinks - 1) &&
!LinkIsTextarea(curdoc.link + 1))
||
((curdoc.link < nlinks - 1) &&
(LinkIsTextarea(curdoc.link + 1)
&& ((links[curdoc.link].l_form->number !=
links[curdoc.link + 1].l_form->number) ||
(strcmp(links[curdoc.link].l_form->name,
links[curdoc.link + 1].l_form->name)
!= 0)))))) {
HText_ExpandTextarea(&links[curdoc.link], 1);
if (links[curdoc.link].ly < display_lines) {
refresh_screen = TRUE;
} else {
LYChgNewline(display_lines / 2);
if (nlinks > 0 && curdoc.link > -1 &&
links[curdoc.link].ly > display_lines / 2) {
newdoc.link = curdoc.link;
for (i = 0;
links[i].ly <= (display_lines / 2);
i++)
--newdoc.link;
newdoc.link++;
}
}
#ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
if (textfields_need_activation) {
textinput_activated = TRUE;
textfields_need_activation = textfields_activation_option;
#ifdef INACTIVE_INPUT_STYLE_VH
textinput_redrawn = TRUE;
#endif
};
#endif
}
#endif /* TEXTAREA_AUTOGROW */
/*
* Make return in input field (if it was returned by
* change_form_link) act as LYK_NEXT_LINK, independent
* of what key (if any) is mapped to LYK_NEXT_LINK. -
* kw
*/
c = LAC_TO_LKC0(LYK_NEXT_LINK);
break;
default:
if (old_c != c && old_c != real_c && c != real_c)
real_c = c;
}
} else {
#if defined(TEXTFIELDS_MAY_NEED_ACTIVATION) && defined(INACTIVE_INPUT_STYLE_VH)
if (curlink_is_editable && !textinput_redrawn) {
/*draw the text entry, but don't activate it */
textinput_redrawn = TRUE;
change_form_link_ex(curdoc.link,
&newdoc, &refresh_screen,
use_last_tfpos, FALSE, TRUE);
if (LYShowCursor) {
LYmove(links[curdoc.link].ly,
((links[curdoc.link].lx > 0) ?
(links[curdoc.link].lx - 1) : 0));
} else {
LYHideCursor();
}
}
#endif /* TEXTFIELDS_MAY_NEED_ACTIVATION && INACTIVE_INPUT_STYLE_VH */
/*
* Get a keystroke from the user. Save the last keystroke to
* avoid redundant error reporting.
*/
real_c = c = LYgetch(); /* get user input */
if (c != last_key)
key_count = 0;
key_count++;
last_key = c;
#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 (LKC_HAS_ESC_MOD(c) && EditBinding(c) != LYE_FORM_PASS) {
/*
* If ESC + <key> was read (and not recognized as a
* terminal escape sequence for another key), ignore the
* ESC modifier and act on <key> only if the line editor
* binding would have passed the same ESC-modified
* lynxkeycode back to us if it had been pressed in a text
* input field. Otherwise set interesting part so that it
* will map to 0, to prevent that ESC + <key> acts like
* <key>, which might be unexpected. - kw
*/
c = (c & ~LKC_MASK) | LAC_TO_LKC(0);
}
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) {
if ((c = DoTraversal(c, &crawl_ok)) < 0) {
CleanupMainLoop();
return (EXIT_FAILURE);
}
}
/* traversal */
#ifdef WIN_EX
if (c == DO_NOTHING)
cmd = LYK_DO_NOTHING;
else
#endif
cmd = LKC_TO_LAC(keymap, c); /* adds 1 to map EOF to 0 */
#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
if (lynx_edit_mode && !no_dired_support && LKC_TO_LAC(key_override, c))
cmd = LKC_TO_LAC(key_override, c);
#endif /* DIRED_SUPPORT && OK_OVERRIDE */
real_cmd = cmd;
/*
* A goto point for new input without going back through the getch()
* loop.
*/
new_cmd:
force_old_UCLYhndl_on_reload = FALSE;
CTRACE_FLUSH(tfp);
if (cmd != LYK_UP_LINK && cmd != LYK_DOWN_LINK)
follow_col = -1;
CTRACE((tfp, "Handling key as %s\n",
((LYKeycodeToKcmd((LYKeymapCode) cmd) != 0)
? LYKeycodeToKcmd((LYKeymapCode) cmd)->name
: "unknown")));
switch (cmd) {
case -1:
HTUserMsg(COMMAND_UNKNOWN);
break;
case 0: /* unmapped character */
default:
if (curdoc.link >= 0 && curdoc.link < nlinks &&
LinkIsTextLike(curdoc.link)) {
#ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
if (textfields_need_activation) {
show_main_statusline(links[curdoc.link], FOR_PANEL);
#ifdef INACTIVE_INPUT_STYLE_VH
textinput_redrawn = FALSE;
#endif
} else
#endif
show_main_statusline(links[curdoc.link], FOR_INPUT);
} else if (more_text) {
HTInfoMsg(MOREHELP);
} else {
HTInfoMsg(HELP);
}
show_help = TRUE;
if (TRACE) {
sprintf(cfile, "%d", c);
LYaddstr(cfile); /* show the user input */
cfile[0] = '\0';
}
break;
case LYK_COMMAND:
cmd = handle_LYK_COMMAND(&user_input_buffer);
goto new_cmd;
case LYK_INTERRUPT:
/*
* No network transmission to interrupt - 'til we multithread.
*/
break;
case LYK_F_LINK_NUM:
c = '\0';
/* FALLTHRU */
case LYK_1: /* FALLTHRU */
case LYK_2: /* FALLTHRU */
case LYK_3: /* FALLTHRU */
case LYK_4: /* FALLTHRU */
case LYK_5: /* FALLTHRU */
case LYK_6: /* FALLTHRU */
case LYK_7: /* FALLTHRU */
case LYK_8: /* FALLTHRU */
case LYK_9:
handle_LYK_digit(c, &force_load, &old_c, real_c, &try_internal);
break;
case LYK_SOURCE: /* toggle view source mode */
handle_LYK_SOURCE(&ownerS_address);
break;
case LYK_CHANGE_CENTER: /* ^Q */
if (no_table_center) {
no_table_center = FALSE;
HTInfoMsg(gettext("TABLE center enable."));
} else {
no_table_center = TRUE;
HTInfoMsg(gettext("TABLE center disable."));
}
/* FALLTHRU */
case LYK_RELOAD: /* control-R to reload and refresh */
handle_LYK_RELOAD(real_cmd);
break;
case LYK_HISTORICAL: /* toggle 'historical' comments parsing */
handle_LYK_HISTORICAL();
break;
case LYK_MINIMAL: /* toggle 'minimal' comments parsing */
handle_LYK_MINIMAL();
break;
case LYK_SOFT_DQUOTES:
handle_LYK_SOFT_DQUOTES();
break;
case LYK_SWITCH_DTD:
handle_LYK_SWITCH_DTD();
break;
case LYK_QUIT: /* quit */
if (handle_LYK_QUIT()) {
CleanupMainLoop();
return (EXIT_SUCCESS);
}
break;
case LYK_ABORT: /* don't ask the user about quitting */
CleanupMainLoop();
return (EXIT_SUCCESS);
case LYK_NEXT_PAGE: /* next page */
handle_LYK_NEXT_PAGE(&old_c, real_c);
break;
case LYK_PREV_PAGE: /* page up */
handle_LYK_PREV_PAGE(&old_c, real_c);
break;
case LYK_UP_TWO:
handle_LYK_UP_TWO(&arrowup, &old_c, real_c);
break;
case LYK_DOWN_TWO:
handle_LYK_DOWN_TWO(&old_c, real_c);
break;
case LYK_UP_HALF:
handle_LYK_UP_HALF(&arrowup, &old_c, real_c);
break;
case LYK_DOWN_HALF:
handle_LYK_DOWN_HALF(&old_c, real_c);
break;
#ifdef CAN_CUT_AND_PASTE
case LYK_TO_CLIPBOARD: /* ^S */
{
char *s;
int ch2;
/* The logic resembles one of ADD_BOOKMARK */
if (nlinks > 0 && links[curdoc.link].lname
&& links[curdoc.link].type != WWW_FORM_LINK_TYPE) {
/* Makes sense to copy a link */
_statusline("Copy D)ocument's or L)ink's URL to clipboard or C)ancel?");
ch2 = LYgetch_single();
if (ch2 == 'D')
s = curdoc.address;
else if (ch2 == 'C')
break;
else
s = links[curdoc.link].lname;
} else
s = curdoc.address;
if (isEmpty(s))
HTInfoMsg(gettext("Current URL is empty."));
if (put_clip(s))
HTInfoMsg(gettext("Copy to clipboard failed."));
else if (s == curdoc.address)
HTInfoMsg(gettext("Document URL put to clipboard."));
else
HTInfoMsg(gettext("Link URL put to clipboard."));
}
break;
case LYK_PASTE_URL:
if (no_goto && !LYValidate) { /* Go to not allowed. - FM */
HTUserMsg(GOTO_DISALLOWED);
} else {
unsigned char *s = (unsigned char *) get_clip_grab(), *e, *t;
char *buf;
int len2;
if (!s)
break;
len2 = (int) strlen((const char *) s);
e = s + len2;
while (s < e && StrChr(" \t\n\r", *s))
s++;
while (s < e && StrChr(" \t\n\r", e[-1]))
e--;
if (s[0] == '<' && e > s && e[-1] == '>') {
s++;
e--;
if (!strncasecomp((const char *) s, "URL:", 4))
s += 4;
}
if (s >= e) {
HTInfoMsg(gettext("No URL in the clipboard."));
break;
}
len = (unsigned) (e - s + 1);
if (len < MAX_LINE)
len = MAX_LINE; /* Required for do_check_goto_URL() */
buf = typeMallocn(char, len);
LYStrNCpy(buf, (const char *) s, (e - s));
t = (unsigned char *) buf;
while (s < e) {
if (StrChr(" \t\n\r", *s)) {
int nl2 = 0; /* Keep whitespace without NL - file names! */
unsigned char *s1 = s;
while (StrChr(" \t\n\r", *s)) {
if (!nl2 && *s == '\n')
nl2 = 1;
s++;
}
if (!nl2) {
while (s1 < s) {
if (*s1 != '\r' && *s1 != '\n')
*t = *s1;
t++, s1++;
}
}
} else
*t++ = *s++;
}
*t = '\0';
get_clip_release();
BStrCopy0(user_input_buffer, buf);
do_check_goto_URL(&user_input_buffer, &temp, &force_load);
free(buf);
}
break;
#endif
#ifdef KANJI_CODE_OVERRIDE
case LYK_CHG_KCODE:
if (LYRawMode && (HTCJK == JAPANESE)) {
switch (last_kcode) {
case NOKANJI:
last_kcode = SJIS;
break;
case SJIS:
last_kcode = EUC;
break;
case EUC:
last_kcode = NOKANJI;
break;
default:
break;
}
}
LYmove(0, 0);
lynx_start_title_color();
LYaddstr(str_kcode(last_kcode));
lynx_stop_title_color();
break;
#endif
case LYK_REFRESH:
refresh_screen = TRUE;
lynx_force_repaint();
break;
case LYK_HOME:
if (curdoc.line > 1) {
LYSetNewline(1);
} else {
cmd = LYK_PREV_PAGE;
goto new_cmd;
}
break;
case LYK_END:
i = HText_getNumOfLines() - display_lines + 2;
if (i >= 1 && LYGetNewline() != i) {
LYSetNewline(i); /* go to end of file */
arrowup = TRUE; /* position on last link */
} else {
cmd = LYK_NEXT_PAGE;
goto new_cmd;
}
break;
case LYK_FIRST_LINK:
handle_LYK_FIRST_LINK();
break;
case LYK_LAST_LINK:
handle_LYK_LAST_LINK();
break;
case LYK_PREV_LINK:
case LYK_LPOS_PREV_LINK:
handle_LYK_PREV_LINK(&arrowup, &old_c, real_c);
break;
case LYK_NEXT_LINK:
case LYK_LPOS_NEXT_LINK:
handle_LYK_NEXT_LINK(c, &old_c, real_c);
break;
case LYK_FASTFORW_LINK:
handle_LYK_FASTFORW_LINK(&old_c, real_c);
break;
case LYK_FASTBACKW_LINK:
if (handle_LYK_FASTBACKW_LINK(&cmd, &old_c, real_c))
goto new_cmd;
break;
case LYK_UP_LINK:
handle_LYK_UP_LINK(&follow_col, &arrowup, &old_c, real_c);
break;
case LYK_DOWN_LINK:
handle_LYK_DOWN_LINK(&follow_col, &old_c, real_c);
break;
case LYK_CHANGE_LINK:
do_change_link();
#if defined(TEXTFIELDS_MAY_NEED_ACTIVATION) && defined(INACTIVE_INPUT_STYLE_VH)
if (textfields_need_activation)
textinput_redrawn = FALSE;
#endif /* TEXTFIELDS_MAY_NEED_ACTIVATION && INACTIVE_INPUT_STYLE_VH */
break;
case LYK_RIGHT_LINK:
handle_LYK_RIGHT_LINK();
break;
case LYK_LEFT_LINK:
handle_LYK_LEFT_LINK();
break;
case LYK_COOKIE_JAR: /* show the cookie jar */
if (handle_LYK_COOKIE_JAR(&cmd))
goto new_cmd;
break;
#ifdef USE_CACHEJAR
case LYK_CACHE_JAR: /* show the cache jar */
if (handle_LYK_CACHE_JAR(&cmd))
goto new_cmd;
break;
#endif
case LYK_HISTORY: /* show the history page */
if (handle_LYK_HISTORY(ForcePush))
break;
/* FALLTHRU */
case LYK_PREV_DOC: /* back up a level */
switch (handle_PREV_DOC(&cmd, &old_c, real_c)) {
case 1:
CleanupMainLoop();
return (EXIT_SUCCESS);
case 2:
goto new_cmd;
}
break;
case LYK_NEXT_DOC: /* undo back up a level */
handle_NEXT_DOC();
break;
case LYK_NOCACHE: /* Force submission of form or link with no-cache */
if (!handle_LYK_NOCACHE(&old_c, real_c))
break;
/* FALLTHRU */
case LYK_ACTIVATE: /* follow a link */
case LYK_MOUSE_SUBMIT: /* follow a link, submit TEXT_SUBMIT input */
switch (handle_LYK_ACTIVATE(&c,
cmd,
&try_internal,
&refresh_screen,
&force_load,
real_cmd)) {
case 1:
continue;
case 2:
goto new_keyboard_input;
case 3:
pending_form_c = c;
break;
}
break;
case LYK_SUBMIT:
handle_LYK_SUBMIT(curdoc.link, &newdoc, &refresh_screen);
break;
case LYK_RESET:
handle_LYK_RESET(curdoc.link, &refresh_screen);
break;
case LYK_ELGOTO: /* edit URL of current link and go to it */
if (handle_LYK_ELGOTO(&ch, &user_input_buffer, &temp, &old_c, real_c))
do_check_goto_URL(&user_input_buffer, &temp, &force_load);
break;
case LYK_ECGOTO: /* edit current URL and go to to it */
if (handle_LYK_ECGOTO(&ch, &user_input_buffer, &temp, &old_c, real_c))
do_check_goto_URL(&user_input_buffer, &temp, &force_load);
break;
case LYK_GOTO: /* 'g' to goto a random URL */
if (handle_LYK_GOTO(&ch, &user_input_buffer, &temp, &recall,
&URLTotal, &URLNum, &FirstURLRecall, &old_c,
real_c)) {
if (do_check_recall(ch, &user_input_buffer, &temp, URLTotal,
&URLNum, recall, &FirstURLRecall))
do_check_goto_URL(&user_input_buffer, &temp, &force_load);
}
break;
case LYK_DWIMHELP: /* show context-dependent help file */
handle_LYK_DWIMHELP(&cshelpfile);
/* FALLTHRU */
case LYK_HELP: /* show help file */
handle_LYK_HELP(&cshelpfile);
break;
case LYK_INDEX: /* index file */
handle_LYK_INDEX(&old_c, real_c);
break;
case LYK_MAIN_MENU: /* return to main screen */
handle_LYK_MAIN_MENU(&old_c, real_c);
break;
#ifdef EXP_NESTED_TABLES
case LYK_NESTED_TABLES:
if (handle_LYK_NESTED_TABLES(&cmd))
goto new_cmd;
break;
#endif
case LYK_OPTIONS: /* options screen */
if (handle_LYK_OPTIONS(&cmd, &refresh_screen))
goto new_cmd;
break;
case LYK_INDEX_SEARCH: /* search for a user string */
handle_LYK_INDEX_SEARCH(&force_load, ForcePush, &old_c, real_c);
break;
case LYK_WHEREIS: /* search within the document */
case LYK_NEXT: /* find the next occurrence in the document */
case LYK_PREV: /* find the previous occurrence in the document */
handle_LYK_WHEREIS(cmd, &refresh_screen);
break;
case LYK_COMMENT: /* reply by mail */
handle_LYK_COMMENT(&refresh_screen, &owner_address, &old_c, real_c);
break;
#ifdef DIRED_SUPPORT
case LYK_TAG_LINK: /* tag or untag the current link */
handle_LYK_TAG_LINK();
break;
case LYK_MODIFY: /* rename a file or directory */
handle_LYK_MODIFY(&refresh_screen);
break;
case LYK_CREATE: /* create a new file or directory */
handle_LYK_CREATE();
break;
#endif /* DIRED_SUPPORT */
case LYK_DWIMEDIT: /* context-dependent edit */
switch (handle_LYK_DWIMEDIT(&cmd, &old_c, real_c)) {
case 1:
continue;
case 2:
goto new_cmd;
}
/* FALLTHRU */
case LYK_EDIT: /* edit */
handle_LYK_EDIT(&old_c, real_c);
break;
case LYK_DEL_BOOKMARK: /* remove a bookmark file link */
handle_LYK_DEL_BOOKMARK(&refresh_screen, &old_c, real_c);
break;
#ifdef DIRED_SUPPORT
case LYK_REMOVE: /* remove files and directories */
handle_LYK_REMOVE(&refresh_screen);
break;
#endif /* DIRED_SUPPORT */
#if defined(DIRED_SUPPORT) && defined(OK_INSTALL)
case LYK_INSTALL: /* install a file into system area */
handle_LYK_INSTALL();
break;
#endif /* DIRED_SUPPORT && OK_INSTALL */
case LYK_INFO: /* show document info */
if (handle_LYK_INFO(&cmd))
goto new_cmd;
break;
case LYK_EDITTEXTAREA: /* use external editor on a TEXTAREA - KED */
handle_LYK_EDIT_TEXTAREA(&refresh_screen, &old_c, real_c);
break;
case LYK_GROWTEXTAREA: /* add new lines to bottom of TEXTAREA - KED */
handle_LYK_GROW_TEXTAREA(&refresh_screen);
break;
case LYK_INSERTFILE: /* insert file in TEXTAREA, above cursor - KED */
handle_LYK_INSERT_FILE(&refresh_screen, &old_c, real_c);
break;
case LYK_PRINT: /* print the file */
handle_LYK_PRINT(&ForcePush, &old_c, real_c);
break;
case LYK_LIST: /* list links in the current document */
if (handle_LYK_LIST(&cmd))
goto new_cmd;
break;
#ifdef USE_ADDRLIST_PAGE
case LYK_ADDRLIST: /* always list URL's (only) */
if (handle_LYK_ADDRLIST(&cmd))
goto new_cmd;
break;
#endif /* USE_ADDRLIST_PAGE */
case LYK_VLINKS: /* list links visited during the current session */
if (handle_LYK_VLINKS(&cmd, &newdoc_link_is_absolute))
goto new_cmd;
break;
case LYK_TOOLBAR: /* go to Toolbar or Banner in current document */
handle_LYK_TOOLBAR(&try_internal, &force_load, &old_c, real_c);
break;
#if defined(DIRED_SUPPORT) || defined(VMS)
case LYK_DIRED_MENU: /* provide full file management menu */
handle_LYK_DIRED_MENU(&refresh_screen, &old_c, real_c);
break;
#endif /* DIRED_SUPPORT || VMS */
#ifdef USE_EXTERNALS
case LYK_EXTERN_LINK: /* use external program on url */
handle_LYK_EXTERN_LINK(&refresh_screen);
break;
case LYK_EXTERN_PAGE: /* use external program on current page */
handle_LYK_EXTERN_PAGE(&refresh_screen);
break;
#endif /* USE_EXTERNALS */
case LYK_ADD_BOOKMARK: /* add link to bookmark file */
handle_LYK_ADD_BOOKMARK(&refresh_screen, &old_c, real_c);
break;
case LYK_VIEW_BOOKMARK: /* v to view home page */
handle_LYK_VIEW_BOOKMARK(&refresh_screen, &old_c, real_c);
break;
case LYK_SHELL: /* (!) shell escape */
handle_LYK_SHELL(&refresh_screen, &old_c, real_c);
break;
case LYK_DOWNLOAD:
switch (handle_LYK_DOWNLOAD(&cmd, &old_c, real_c)) {
case 1:
continue;
case 2:
goto new_cmd;
}
break;
#ifdef DIRED_SUPPORT
case LYK_UPLOAD:
handle_LYK_UPLOAD();
break;
#endif /* DIRED_SUPPORT */
case LYK_TRACE_TOGGLE: /* Toggle TRACE mode. */
handle_LYK_TRACE_TOGGLE();
break;
case LYK_TRACE_LOG: /* View TRACE log. */
handle_LYK_TRACE_LOG(&trace_mode_flag);
break;
case LYK_IMAGE_TOGGLE:
if (handle_LYK_IMAGE_TOGGLE(&cmd))
goto new_cmd;
break;
case LYK_INLINE_TOGGLE:
if (handle_LYK_INLINE_TOGGLE(&cmd))
goto new_cmd;
break;
case LYK_RAW_TOGGLE:
if (handle_LYK_RAW_TOGGLE(&cmd))
goto new_cmd;
break;
case LYK_HEAD:
if (handle_LYK_HEAD(&cmd))
goto new_cmd;
break;
case LYK_TOGGLE_HELP:
handle_LYK_TOGGLE_HELP();
break;
case LYK_EDITMAP:
handle_LYK_EDITMAP(&old_c, real_c);
break;
case LYK_KEYMAP:
handle_LYK_KEYMAP(&vi_keys_flag, &emacs_keys_flag, &old_c, real_c);
break;
case LYK_JUMP:
if (handle_LYK_JUMP(c, &user_input_buffer, &temp, &recall,
&FirstURLRecall, &URLNum, &URLTotal, &ch,
&old_c, real_c)) {
if (do_check_recall(ch, &user_input_buffer, &temp, URLTotal,
&URLNum, recall, &FirstURLRecall))
do_check_goto_URL(&user_input_buffer, &temp, &force_load);
}
break;
case LYK_CLEAR_AUTH:
handle_LYK_CLEAR_AUTH(&old_c, real_c);
break;
case LYK_DO_NOTHING: /* pretty self explanatory */
break;
#ifdef SUPPORT_CHDIR
case LYK_CHDIR:
handle_LYK_CHDIR();
break;
case LYK_PWD:
handle_LYK_PWD();
break;
#endif
#ifdef USE_CURSES_PADS
case LYK_SHIFT_LEFT:
handle_LYK_SHIFT_LEFT(&refresh_screen, key_count);
break;
case LYK_SHIFT_RIGHT:
handle_LYK_SHIFT_RIGHT(&refresh_screen, key_count);
break;
case LYK_LINEWRAP_TOGGLE:
if (handle_LYK_LINEWRAP_TOGGLE(&cmd, &refresh_screen))
goto new_cmd;
break;
#endif
#ifdef USE_MAXSCREEN_TOGGLE
case LYK_MAXSCREEN_TOGGLE:
if (handle_LYK_MAXSCREEN_TOGGLE(&cmd))
goto new_cmd;
break;
#endif
} /* end of BIG switch */
}
}
static int are_different(DocInfo *doc1, DocInfo *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
*/
cp1 = trimPoundSelector(doc1->address);
cp2 = trimPoundSelector(doc2->address);
/*
* Are the base addresses different?
*/
if (strcmp(doc1->address, doc2->address)) {
restorePoundSelector(cp1);
restorePoundSelector(cp2);
return (TRUE);
}
restorePoundSelector(cp1);
restorePoundSelector(cp2);
/*
* Do the docs have different contents?
*/
if (doc1->post_data) {
if (doc2->post_data) {
if (!BINEQ(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);
}
/* This determines whether two docs are _physically_ different,
* meaning they are "from different files". - kw
*/
static int are_phys_different(DocInfo *doc1, DocInfo *doc2)
{
char *cp1, *cp2, *ap1 = doc1->address, *ap2 = doc2->address;
/*
* 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);
/*
* Skip over possible LYNXIMGMAP parts. - kw
*/
if (isLYNXIMGMAP(doc1->address))
ap1 += LEN_LYNXIMGMAP;
if (isLYNXIMGMAP(doc2->address))
ap2 += LEN_LYNXIMGMAP;
/*
* If there isn't any real URL in doc2->address, but maybe just
* a fragment, doc2 is assumed to be an internal reference in
* the same physical document, so return FALSE. - kw
*/
if (*ap2 == '\0' || *ap2 == '#')
return (FALSE);
/*
* 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
*/
cp1 = trimPoundSelector(doc1->address);
cp2 = trimPoundSelector(doc2->address);
/*
* Are the base addresses different?
*/
if (strcmp(ap1, ap2)) {
restorePoundSelector(cp1);
restorePoundSelector(cp2);
return (TRUE);
}
restorePoundSelector(cp1);
restorePoundSelector(cp2);
/*
* Do the docs have different contents?
*/
if (doc1->post_data) {
if (doc2->post_data) {
if (!BINEQ(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
*/
#ifdef LY_FIND_LEAKS
static void HTGotoURLs_free(void)
{
LYFreeStringList(Goto_URLs);
Goto_URLs = NULL;
}
#endif
/*
* Utility for listing Goto URLs, making any repeated URLs the most current in
* the list. - FM
*/
void HTAddGotoURL(char *url)
{
char *mycopy = NULL;
char *old;
HTList *cur;
if (isEmpty(url))
return;
CTRACE((tfp, "HTAddGotoURL %s\n", url));
StrAllocCopy(mycopy, url);
if (!Goto_URLs) {
Goto_URLs = HTList_new();
#ifdef LY_FIND_LEAKS
atexit(HTGotoURLs_free);
#endif
HTList_addObject(Goto_URLs, mycopy);
return;
}
cur = Goto_URLs;
while (NULL != (old = (char *) HTList_nextObject(cur))) {
if (!strcmp(old, mycopy)) {
HTList_removeObject(Goto_URLs, old);
FREE(old);
break;
}
}
HTList_addObject(Goto_URLs, mycopy);
return;
}
/*
* When help is not on the screen, put a message on the screen to tell the user
* other misc info.
*/
static void show_main_statusline(const LinkInfo curlink,
int for_what)
{
/*
* Make sure form novice lines are replaced.
*/
if (user_mode == NOVICE_MODE && for_what != FOR_INPUT) {
noviceline(more_text);
}
if (HTisDocumentSource()) {
/*
* Currently displaying HTML source.
*/
_statusline(SOURCE_HELP);
/*
* If we are in forms mode then explicitly tell the user what each kind
* of link is.
*/
#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 &&
!(curlink.type & WWW_LINK_TYPE)) {
#else
} else if (lynx_mode == FORMS_LYNX_MODE && nlinks > 0 &&
!((user_mode == ADVANCED_MODE || user_mode == MINIMAL_MODE) &&
(curlink.type & WWW_LINK_TYPE))) {
#endif /* NORMAL_NON_FORM_LINK_STATUSLINES_FOR_ALL_USER_MODES */
#endif /* INDICATE_FORMS_MODE_FOR_ALL_LINKS_ON_PAGE */
if (curlink.type == WWW_FORM_LINK_TYPE) {
show_formlink_statusline(curlink.l_form, for_what);
} else {
statusline(NORMAL_LINK_MESSAGE);
}
/*
* Let them know if it's an index -- very rare.
*/
if (is_www_index) {
const char *indx = gettext("-index-");
LYmove(LYlines - 1, LYcolLimit - (int) strlen(indx));
lynx_start_reverse();
LYaddstr(indx);
lynx_stop_reverse();
}
} else if ((user_mode == ADVANCED_MODE) && nlinks > 0) {
/*
* Show the URL or, for some internal links, the fragment
*/
char *cp = NULL;
if (curlink.type == WWW_INTERN_LINK_TYPE &&
!isLYNXIMGMAP(curlink.lname)) {
cp = findPoundSelector(curlink.lname);
}
if (!cp)
cp = curlink.lname;
status_link(cp, more_text, is_www_index);
} else if ((user_mode == MINIMAL_MODE) && nlinks > 0) {
/*
* no URL
*/
status_link("", more_text, is_www_index);
} else if (is_www_index && more_text) {
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_text) {
if (user_mode == NOVICE_MODE)
_statusline(MORE);
else
_statusline(MOREHELP);
} else if (user_mode != MINIMAL_MODE) {
_statusline(HELP);
} else {
_statusline("");
}
/* turn off cursor since now it's probably on statusline -HV */
/* But not if LYShowCursor is on. -show_cursor may be used as a
* workaround to avoid putting the cursor in the last position, for
* curses implementations or terminals that cannot deal with that
* correctly. - kw */
if (!LYShowCursor) {
LYHideCursor();
}
}
/*
* Public function for redrawing the statusline appropriate for the selected
* link. It should only be called at times when curdoc.link, nlinks, and the
* links[] array are valid. - kw
*/
void repaint_main_statusline(int for_what)
{
if (curdoc.link >= 0 && curdoc.link < nlinks)
show_main_statusline(links[curdoc.link], for_what);
}
static void form_noviceline(int disabled)
{
LYmove(LYlines - 2, 0);
LYclrtoeol();
if (!disabled) {
LYaddstr(FORM_NOVICELINE_ONE);
}
LYParkCursor();
if (disabled)
return;
if (EditBinding(FROMASCII('\025')) == LYE_ERASE) {
LYaddstr(FORM_NOVICELINE_TWO);
} else if (EditBinding(FROMASCII('\025')) == LYE_DELBL) {
LYaddstr(FORM_NOVICELINE_TWO_DELBL);
} else {
char *temp = NULL;
char *erasekey = fmt_keys(LYKeyForEditAction(LYE_ERASE), -1);
if (erasekey) {
HTSprintf0(&temp, FORM_NOVICELINE_TWO_VAR, erasekey);
} else {
erasekey = fmt_keys(LYKeyForEditAction(LYE_DELBL), -1);
if (erasekey)
HTSprintf0(&temp,
FORM_NOVICELINE_TWO_DELBL_VAR, erasekey);
}
if (temp) {
LYaddstr(temp);
FREE(temp);
}
FREE(erasekey);
}
}
static void exit_immediately_with_error_message(int state, int first_file)
{
char *buf = 0;
char *buf2 = 0;
if (first_file) {
/* print statusline messages as a hint, if any */
LYstatusline_messages_on_exit(&buf2);
}
if (state == NOT_FOUND) {
HTSprintf0(&buf, "%s\n%s %s\n",
NonNull(buf2),
gettext("lynx: Can't access startfile"),
/*
* hack: if we fail in HTAccess.c
* avoid duplicating URL, oh.
*/
(buf2 && strstr(buf2, gettext("Can't Access"))) ?
"" : startfile);
}
if (state == NULLFILE) {
HTSprintf0(&buf, "%s\n%s\n%s\n",
NonNull(buf2),
gettext("lynx: Start file could not be found or is not text/html or text/plain"),
gettext(" Exiting..."));
}
FREE(buf2);
if (!dump_output_immediately)
cleanup();
if (buf != 0) {
#ifdef UNIX
if (dump_output_immediately) {
fputs(buf, stderr);
} else
#endif /* UNIX */
{
SetOutputMode(O_TEXT);
fputs(buf, stdout);
SetOutputMode(O_BINARY);
}
FREE(buf);
}
if (!dump_output_immediately) {
exit_immediately(EXIT_FAILURE);
}
/* else: return(EXIT_FAILURE) in mainloop */
}
static void status_link(const char *curlink_name,
int show_more,
int show_indx)
{
#define MAX_STATUS (LYcolLimit - 1)
#define MIN_STATUS 0
char format[MAX_LINE];
int prefix = 0;
int length;
*format = 0;
if (show_more && !nomore) {
sprintf(format, "%.*s ",
(int) (sizeof(format) - 2),
gettext("-more-"));
prefix = (int) strlen(format);
}
if (show_indx) {
sprintf(format + prefix, "%.*s ",
((int) sizeof(format) - prefix - 2),
gettext("-index-"));
}
prefix = (int) strlen(format);
length = (int) strlen(curlink_name);
if (prefix > MAX_STATUS || prefix >= MAX_LINE - 10) {
_user_message("%s", format); /* no room for url */
} else {
sprintf(format + prefix, "%%.%ds", MAX_STATUS - prefix);
if ((length + prefix > MAX_STATUS) && long_url_ok) {
char *buf = NULL;
int cut_from_pos;
int cut_to_pos;
int n;
StrAllocCopy(buf, curlink_name);
/*
* Scan to find the final leaf of the URL. Ignore trailing '/'.
*/
for (cut_to_pos = length - 2;
(cut_to_pos > 0) && (buf[cut_to_pos] != '/');
cut_to_pos--) ;
/*
* Jump back to the next leaf to remove.
*/
for (cut_from_pos = cut_to_pos - 4;
(cut_from_pos > 0) && ((buf[cut_from_pos] != '/')
|| ((prefix + cut_from_pos
+ 4
+ (length - cut_to_pos)) >= MAX_STATUS));
cut_from_pos--) ;
/*
* Replace some leaves to '...', if possible, and put the final
* leaf at the end. We assume that one can recognize the link from
* at least MIN_STATUS characters.
*/
if (cut_from_pos > MIN_STATUS) {
for (n = 1; n <= 3; n++)
buf[cut_from_pos + n] = '.';
for (n = 0; cut_to_pos + n <= length; n++)
buf[cut_from_pos + 4 + n] = buf[cut_to_pos + n];
}
_user_message(format, buf);
CTRACE((tfp, "lastline = %s\n", buf)); /* don't forget to erase me */
FREE(buf);
} else { /* show (possibly truncated) url */
_user_message(format, curlink_name);
}
}
}
const char *LYDownLoadAddress(void)
{
return NonNull(newdoc.address);
}