Blame src/LYHistory.c

Packit f574b8
/*
Packit f574b8
 * $LynxId: LYHistory.c,v 1.90 2018/03/05 22:32:14 tom Exp $
Packit f574b8
 */
Packit f574b8
#include <HTUtils.h>
Packit f574b8
#include <HTTP.h>
Packit f574b8
#include <GridText.h>
Packit f574b8
#include <HTAlert.h>
Packit f574b8
#include <HText.h>
Packit f574b8
#include <LYGlobalDefs.h>
Packit f574b8
#include <LYUtils.h>
Packit f574b8
#include <LYHistory.h>
Packit f574b8
#include <LYPrint.h>
Packit f574b8
#include <LYDownload.h>
Packit f574b8
#include <LYOptions.h>
Packit f574b8
#include <LYKeymap.h>
Packit f574b8
#include <LYList.h>
Packit f574b8
#include <LYShowInfo.h>
Packit f574b8
#include <LYStrings.h>
Packit f574b8
#include <LYCharUtils.h>
Packit f574b8
#include <LYCharSets.h>
Packit f574b8
#include <LYrcFile.h>
Packit f574b8
#ifdef DISP_PARTIAL
Packit f574b8
#include <LYMainLoop.h>
Packit f574b8
#endif
Packit f574b8
Packit f574b8
#ifdef DIRED_SUPPORT
Packit f574b8
#include <LYUpload.h>
Packit f574b8
#include <LYLocal.h>
Packit f574b8
#endif /* DIRED_SUPPORT */
Packit f574b8
Packit f574b8
#include <LYexit.h>
Packit f574b8
#include <LYLeaks.h>
Packit f574b8
#include <HTCJK.h>
Packit f574b8
Packit f574b8
HTList *Visited_Links = NULL;	/* List of safe popped docs. */
Packit f574b8
int Visited_Links_As = VISITED_LINKS_AS_LATEST | VISITED_LINKS_REVERSE;
Packit f574b8
Packit f574b8
static VisitedLink *PrevVisitedLink = NULL;	/* NULL on auxillary */
Packit f574b8
static VisitedLink *PrevActiveVisitedLink = NULL;	/* Last non-auxillary */
Packit f574b8
static VisitedLink Latest_first;
Packit f574b8
static VisitedLink Latest_last;
Packit f574b8
static VisitedLink *Latest_tree;
Packit f574b8
static VisitedLink *First_tree;
Packit f574b8
static VisitedLink *Last_by_first;
Packit f574b8
Packit f574b8
int nhist_extra;
Packit f574b8
Packit f574b8
#ifdef LY_FIND_LEAKS
Packit f574b8
static int already_registered_free_messages_stack = 0;
Packit f574b8
static int already_registered_clean_all_history = 0;
Packit f574b8
#endif
Packit f574b8
Packit f574b8
#ifdef LY_FIND_LEAKS
Packit f574b8
/*
Packit f574b8
 * Utility for freeing the list of visited links.  - FM
Packit f574b8
 */
Packit f574b8
static void Visited_Links_free(void)
Packit f574b8
{
Packit f574b8
    VisitedLink *vl;
Packit f574b8
    HTList *cur = Visited_Links;
Packit f574b8
Packit f574b8
    PrevVisitedLink = NULL;
Packit f574b8
    PrevActiveVisitedLink = NULL;
Packit f574b8
    if (!cur)
Packit f574b8
	return;
Packit f574b8
Packit f574b8
    while (NULL != (vl = (VisitedLink *) HTList_nextObject(cur))) {
Packit f574b8
	FREE(vl->address);
Packit f574b8
	FREE(vl->title);
Packit f574b8
	FREE(vl);
Packit f574b8
    }
Packit f574b8
    HTList_delete(Visited_Links);
Packit f574b8
    Visited_Links = NULL;
Packit f574b8
    Latest_last.prev_latest = &Latest_first;
Packit f574b8
    Latest_first.next_latest = &Latest_last;
Packit f574b8
    Last_by_first = Latest_tree = First_tree = 0;
Packit f574b8
    return;
Packit f574b8
}
Packit f574b8
#endif /* LY_FIND_LEAKS */
Packit f574b8
Packit f574b8
#ifdef DEBUG
Packit f574b8
static void trace_history(const char *tag)
Packit f574b8
{
Packit f574b8
    if (TRACE) {
Packit f574b8
	CTRACE((tfp, "HISTORY %s %d/%d (%d extra)\n",
Packit f574b8
		tag, nhist, size_history, nhist_extra));
Packit f574b8
	CTRACE_FLUSH(tfp);
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
#else
Packit f574b8
#define trace_history(tag)	/* nothing */
Packit f574b8
#endif /* DEBUG */
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Utility for listing visited links, making any repeated links the most
Packit f574b8
 * current in the list.  - FM
Packit f574b8
 */
Packit f574b8
void LYAddVisitedLink(DocInfo *doc)
Packit f574b8
{
Packit f574b8
    VisitedLink *tmp;
Packit f574b8
    HTList *cur;
Packit f574b8
    const char *title = (doc->title ? doc->title : NO_TITLE);
Packit f574b8
Packit f574b8
    if (isEmpty(doc->address)) {
Packit f574b8
	PrevVisitedLink = NULL;
Packit f574b8
	return;
Packit f574b8
    }
Packit f574b8
Packit f574b8
    /*
Packit f574b8
     * Exclude POST or HEAD replies, and bookmark, menu or list files.  - FM
Packit f574b8
     */
Packit f574b8
    if (doc->post_data || doc->isHEAD || doc->bookmark ||
Packit f574b8
	(			/* special url or a temp file */
Packit f574b8
	    (!StrNCmp(doc->address, "LYNX", 4) ||
Packit f574b8
	     !StrNCmp(doc->address, "file://localhost/", 17)))) {
Packit f574b8
	int related = 1;	/* First approximation only */
Packit f574b8
Packit f574b8
	if (LYIsUIPage(doc->address, UIP_HISTORY) ||
Packit f574b8
	    LYIsUIPage(doc->address, UIP_VLINKS) ||
Packit f574b8
	    LYIsUIPage(doc->address, UIP_SHOWINFO) ||
Packit f574b8
	    isLYNXMESSAGES(doc->address) ||
Packit f574b8
	    ((related = 0) != 0) ||
Packit f574b8
#ifdef DIRED_SUPPORT
Packit f574b8
	    LYIsUIPage(doc->address, UIP_DIRED_MENU) ||
Packit f574b8
	    LYIsUIPage(doc->address, UIP_UPLOAD_OPTIONS) ||
Packit f574b8
	    LYIsUIPage(doc->address, UIP_PERMIT_OPTIONS) ||
Packit f574b8
#endif /* DIRED_SUPPORT */
Packit f574b8
	    LYIsUIPage(doc->address, UIP_PRINT_OPTIONS) ||
Packit f574b8
	    LYIsUIPage(doc->address, UIP_DOWNLOAD_OPTIONS) ||
Packit f574b8
	    LYIsUIPage(doc->address, UIP_OPTIONS_MENU) ||
Packit f574b8
	    isLYNXEDITMAP(doc->address) ||
Packit f574b8
	    isLYNXKEYMAP(doc->address) ||
Packit f574b8
	    LYIsUIPage(doc->address, UIP_LIST_PAGE) ||
Packit f574b8
#ifdef USE_ADDRLIST_PAGE
Packit f574b8
	    LYIsUIPage(doc->address, UIP_ADDRLIST_PAGE) ||
Packit f574b8
#endif
Packit f574b8
	    LYIsUIPage(doc->address, UIP_CONFIG_DEF) ||
Packit f574b8
	    LYIsUIPage(doc->address, UIP_LYNXCFG) ||
Packit f574b8
	    isLYNXCOOKIE(doc->address) ||
Packit f574b8
	    LYIsUIPage(doc->address, UIP_TRACELOG)) {
Packit f574b8
	    if (!related)
Packit f574b8
		PrevVisitedLink = NULL;
Packit f574b8
	    return;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
Packit f574b8
    if (!Visited_Links) {
Packit f574b8
	Visited_Links = HTList_new();
Packit f574b8
#ifdef LY_FIND_LEAKS
Packit f574b8
	atexit(Visited_Links_free);
Packit f574b8
#endif
Packit f574b8
	Latest_last.prev_latest = &Latest_first;
Packit f574b8
	Latest_first.next_latest = &Latest_last;
Packit f574b8
	Latest_last.next_latest = NULL;		/* Find bugs quick! */
Packit f574b8
	Latest_first.prev_latest = NULL;
Packit f574b8
	Last_by_first = Latest_tree = First_tree = NULL;
Packit f574b8
    }
Packit f574b8
Packit f574b8
    cur = Visited_Links;
Packit f574b8
    while (NULL != (tmp = (VisitedLink *) HTList_nextObject(cur))) {
Packit f574b8
	if (!strcmp(NonNull(tmp->address),
Packit f574b8
		    NonNull(doc->address))) {
Packit f574b8
	    PrevVisitedLink = PrevActiveVisitedLink = tmp;
Packit f574b8
	    /* Already visited.  Update the last-visited info. */
Packit f574b8
	    if (tmp->next_latest == &Latest_last)	/* optimization */
Packit f574b8
		return;
Packit f574b8
Packit f574b8
	    /* Remove from "latest" chain */
Packit f574b8
	    tmp->prev_latest->next_latest = tmp->next_latest;
Packit f574b8
	    tmp->next_latest->prev_latest = tmp->prev_latest;
Packit f574b8
Packit f574b8
	    /* Insert at the end of the "latest" chain */
Packit f574b8
	    Latest_last.prev_latest->next_latest = tmp;
Packit f574b8
	    tmp->prev_latest = Latest_last.prev_latest;
Packit f574b8
	    tmp->next_latest = &Latest_last;
Packit f574b8
	    Latest_last.prev_latest = tmp;
Packit f574b8
	    return;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
Packit f574b8
    if ((tmp = typecalloc(VisitedLink)) == NULL)
Packit f574b8
	outofmem(__FILE__, "LYAddVisitedLink");
Packit f574b8
Packit f574b8
    StrAllocCopy(tmp->address, doc->address);
Packit f574b8
    LYformTitle(&(tmp->title), title);
Packit f574b8
Packit f574b8
    /* First-visited chain */
Packit f574b8
    HTList_appendObject(Visited_Links, tmp);	/* At end */
Packit f574b8
    tmp->prev_first = Last_by_first;
Packit f574b8
    Last_by_first = tmp;
Packit f574b8
Packit f574b8
    /* Tree structure */
Packit f574b8
    if (PrevVisitedLink) {
Packit f574b8
	VisitedLink *a = PrevVisitedLink;
Packit f574b8
	VisitedLink *b = a->next_tree;
Packit f574b8
	int l = PrevVisitedLink->level;
Packit f574b8
Packit f574b8
	/* Find last on the deeper levels */
Packit f574b8
	while (b && b->level > l)
Packit f574b8
	    a = b, b = b->next_tree;
Packit f574b8
Packit f574b8
	if (!b)			/* a == Latest_tree */
Packit f574b8
	    Latest_tree = tmp;
Packit f574b8
	tmp->next_tree = a->next_tree;
Packit f574b8
	a->next_tree = tmp;
Packit f574b8
Packit f574b8
	tmp->level = PrevVisitedLink->level + 1;
Packit f574b8
    } else {
Packit f574b8
	if (Latest_tree)
Packit f574b8
	    Latest_tree->next_tree = tmp;
Packit f574b8
	tmp->level = 0;
Packit f574b8
	tmp->next_tree = NULL;
Packit f574b8
	Latest_tree = tmp;
Packit f574b8
    }
Packit f574b8
    PrevVisitedLink = PrevActiveVisitedLink = tmp;
Packit f574b8
    if (!First_tree)
Packit f574b8
	First_tree = tmp;
Packit f574b8
Packit f574b8
    /* "latest" chain */
Packit f574b8
    Latest_last.prev_latest->next_latest = tmp;
Packit f574b8
    tmp->prev_latest = Latest_last.prev_latest;
Packit f574b8
    tmp->next_latest = &Latest_last;
Packit f574b8
    Latest_last.prev_latest = tmp;
Packit f574b8
Packit f574b8
    return;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Returns true if this is a page that we would push onto the stack if not
Packit f574b8
 * forced.  If docurl is NULL, only the title is considered; otherwise also
Packit f574b8
 * check the URL whether it is (likely to be) a generated special page.
Packit f574b8
 */
Packit f574b8
BOOLEAN LYwouldPush(const char *title,
Packit f574b8
		    const char *docurl)
Packit f574b8
{
Packit f574b8
    BOOLEAN rc = FALSE;
Packit f574b8
Packit f574b8
    /*
Packit f574b8
     * All non-pushable generated pages have URLs that begin with
Packit f574b8
     * "file://localhost/" and end with HTML_SUFFIX.  - kw
Packit f574b8
     */
Packit f574b8
    if (docurl) {
Packit f574b8
	size_t ulen;
Packit f574b8
Packit f574b8
	if (StrNCmp(docurl, "file://localhost/", 17) != 0 ||
Packit f574b8
	    (ulen = strlen(docurl)) <= strlen(HTML_SUFFIX) ||
Packit f574b8
	    strcmp(docurl + ulen - strlen(HTML_SUFFIX), HTML_SUFFIX) != 0) {
Packit f574b8
	    /*
Packit f574b8
	     * If it is not a local HTML file, it may be a Web page that
Packit f574b8
	     * accidentally has the same title.  So return TRUE now.  - kw
Packit f574b8
	     */
Packit f574b8
	    return TRUE;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
Packit f574b8
    if (docurl) {
Packit f574b8
	rc = (BOOLEAN)
Packit f574b8
	    !(LYIsUIPage(docurl, UIP_HISTORY)
Packit f574b8
	      || LYIsUIPage(docurl, UIP_PRINT_OPTIONS)
Packit f574b8
#ifdef DIRED_SUPPORT
Packit f574b8
	      || LYIsUIPage(docurl, UIP_DIRED_MENU)
Packit f574b8
	      || LYIsUIPage(docurl, UIP_UPLOAD_OPTIONS)
Packit f574b8
	      || LYIsUIPage(docurl, UIP_PERMIT_OPTIONS)
Packit f574b8
#endif /* DIRED_SUPPORT */
Packit f574b8
	    );
Packit f574b8
    } else {
Packit f574b8
	rc = (BOOLEAN)
Packit f574b8
	    !(!strcmp(title, HISTORY_PAGE_TITLE)
Packit f574b8
	      || !strcmp(title, PRINT_OPTIONS_TITLE)
Packit f574b8
#ifdef DIRED_SUPPORT
Packit f574b8
	      || !strcmp(title, DIRED_MENU_TITLE)
Packit f574b8
	      || !strcmp(title, UPLOAD_OPTIONS_TITLE)
Packit f574b8
	      || !strcmp(title, PERMIT_OPTIONS_TITLE)
Packit f574b8
#endif /* DIRED_SUPPORT */
Packit f574b8
	    );
Packit f574b8
    }
Packit f574b8
    return rc;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Free post-data for 'DocInfo'
Packit f574b8
 */
Packit f574b8
void LYFreePostData(DocInfo *doc)
Packit f574b8
{
Packit f574b8
    BStrFree(doc->post_data);
Packit f574b8
    FREE(doc->post_content_type);
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Free strings associated with a 'DocInfo' struct.
Packit f574b8
 */
Packit f574b8
void LYFreeDocInfo(DocInfo *doc)
Packit f574b8
{
Packit f574b8
    FREE(doc->title);
Packit f574b8
    FREE(doc->address);
Packit f574b8
    FREE(doc->bookmark);
Packit f574b8
    LYFreePostData(doc);
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Free the information in the last history entry.
Packit f574b8
 */
Packit f574b8
static void clean_extra_history(void)
Packit f574b8
{
Packit f574b8
    trace_history("clean_extra_history");
Packit f574b8
    nhist += nhist_extra;
Packit f574b8
    while (nhist_extra > 0) {
Packit f574b8
	nhist--;
Packit f574b8
	LYFreeDocInfo(&HDOC(nhist));
Packit f574b8
	nhist_extra--;
Packit f574b8
    }
Packit f574b8
    trace_history("...clean_extra_history");
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Free the entire history stack, for auditing memory leaks.
Packit f574b8
 */
Packit f574b8
#ifdef LY_FIND_LEAKS
Packit f574b8
static void clean_all_history(void)
Packit f574b8
{
Packit f574b8
    trace_history("clean_all_history");
Packit f574b8
    clean_extra_history();
Packit f574b8
    while (nhist > 0) {
Packit f574b8
	nhist--;
Packit f574b8
	LYFreeDocInfo(&HDOC(nhist));
Packit f574b8
    }
Packit f574b8
    trace_history("...clean_all_history");
Packit f574b8
}
Packit f574b8
#endif
Packit f574b8
Packit f574b8
/* FIXME What is the relationship to are_different() from the mainloop?! */
Packit f574b8
static int are_identical(HistInfo * doc, DocInfo *doc1)
Packit f574b8
{
Packit f574b8
    return (STREQ(doc1->address, doc->hdoc.address)
Packit f574b8
	    && BINEQ(doc1->post_data, doc->hdoc.post_data)
Packit f574b8
	    && !strcmp(NonNull(doc1->bookmark),
Packit f574b8
		       NonNull(doc->hdoc.bookmark))
Packit f574b8
	    && doc1->isHEAD == doc->hdoc.isHEAD);
Packit f574b8
}
Packit f574b8
Packit f574b8
void LYAllocHistory(int entries)
Packit f574b8
{
Packit f574b8
    CTRACE((tfp, "LYAllocHistory %d vs %d\n", entries, size_history));
Packit f574b8
    if (entries + 1 >= size_history) {
Packit f574b8
	unsigned want;
Packit f574b8
	int save = size_history;
Packit f574b8
Packit f574b8
	size_history = (entries + 2) * 2;
Packit f574b8
	want = (unsigned) size_history *(unsigned) sizeof(*history);
Packit f574b8
Packit f574b8
	if (history == 0) {
Packit f574b8
	    history = typeMallocn(HistInfo, want);
Packit f574b8
	} else {
Packit f574b8
	    history = typeRealloc(HistInfo, history, want);
Packit f574b8
	}
Packit f574b8
	if (history == 0)
Packit f574b8
	    outofmem(__FILE__, "LYAllocHistory");
Packit f574b8
Packit f574b8
	while (save < size_history) {
Packit f574b8
	    memset(&history[save++], 0, sizeof(history[0]));
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
    CTRACE((tfp, "...LYAllocHistory %d vs %d\n", entries, size_history));
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Push the current filename, link and line number onto the history list.
Packit f574b8
 */
Packit f574b8
int LYpush(DocInfo *doc, int force_push)
Packit f574b8
{
Packit f574b8
    /*
Packit f574b8
     * Don't push NULL file names.
Packit f574b8
     */
Packit f574b8
    if (*doc->address == '\0')
Packit f574b8
	return 0;
Packit f574b8
Packit f574b8
    /*
Packit f574b8
     * Check whether this is a document we don't push unless forced.  - FM
Packit f574b8
     */
Packit f574b8
    if (!force_push) {
Packit f574b8
	/*
Packit f574b8
	 * Don't push the history, printer, or download lists.
Packit f574b8
	 */
Packit f574b8
	if (!LYwouldPush(doc->title, doc->address)) {
Packit f574b8
	    if (!LYforce_no_cache)
Packit f574b8
		LYoverride_no_cache = TRUE;
Packit f574b8
	    return 0;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
Packit f574b8
    /*
Packit f574b8
     * If file is identical to one before it, don't push it.
Packit f574b8
     * But do not duplicate it if there is only one on the stack,
Packit f574b8
     * note that HDOC() starts from 0, so nhist should be > 0.
Packit f574b8
     */
Packit f574b8
    if (nhist >= 1 && are_identical(&(history[nhist - 1]), doc)) {
Packit f574b8
	if (HDOC(nhist - 1).internal_link == doc->internal_link) {
Packit f574b8
	    /* But it is nice to have the last position remembered!
Packit f574b8
	       - kw */
Packit f574b8
	    HDOC(nhist - 1).link = doc->link;
Packit f574b8
	    HDOC(nhist - 1).line = doc->line;
Packit f574b8
	    return 0;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
Packit f574b8
    /*
Packit f574b8
     * If file is identical to the current document, just move the pointer.
Packit f574b8
     */
Packit f574b8
    if (nhist_extra >= 1 && are_identical(&(history[nhist]), doc)) {
Packit f574b8
	HDOC(nhist).link = doc->link;
Packit f574b8
	HDOC(nhist).line = doc->line;
Packit f574b8
	nhist_extra--;
Packit f574b8
	LYAllocHistory(nhist);
Packit f574b8
	nhist++;
Packit f574b8
	trace_history("LYpush: just move the cursor");
Packit f574b8
	return 1;
Packit f574b8
    }
Packit f574b8
Packit f574b8
    clean_extra_history();
Packit f574b8
#ifdef LY_FIND_LEAKS
Packit f574b8
    if (!already_registered_clean_all_history) {
Packit f574b8
	already_registered_clean_all_history = 1;
Packit f574b8
	atexit(clean_all_history);
Packit f574b8
    }
Packit f574b8
#endif
Packit f574b8
Packit f574b8
    /*
Packit f574b8
     * OK, push it...
Packit f574b8
     */
Packit f574b8
    LYAllocHistory(nhist);
Packit f574b8
    HDOC(nhist).link = doc->link;
Packit f574b8
    HDOC(nhist).line = doc->line;
Packit f574b8
Packit f574b8
    HDOC(nhist).title = NULL;
Packit f574b8
    LYformTitle(&(HDOC(nhist).title), doc->title);
Packit f574b8
Packit f574b8
    HDOC(nhist).address = NULL;
Packit f574b8
    StrAllocCopy(HDOC(nhist).address, doc->address);
Packit f574b8
Packit f574b8
    HDOC(nhist).post_data = NULL;
Packit f574b8
    BStrCopy(HDOC(nhist).post_data, doc->post_data);
Packit f574b8
Packit f574b8
    HDOC(nhist).post_content_type = NULL;
Packit f574b8
    StrAllocCopy(HDOC(nhist).post_content_type, doc->post_content_type);
Packit f574b8
Packit f574b8
    HDOC(nhist).bookmark = NULL;
Packit f574b8
    StrAllocCopy(HDOC(nhist).bookmark, doc->bookmark);
Packit f574b8
Packit f574b8
    HDOC(nhist).isHEAD = doc->isHEAD;
Packit f574b8
    HDOC(nhist).safe = doc->safe;
Packit f574b8
Packit f574b8
    HDOC(nhist).internal_link = FALSE;	/* by default */
Packit f574b8
    history[nhist].intern_seq_start = -1;	/* by default */
Packit f574b8
    if (doc->internal_link) {
Packit f574b8
	/* Now some tricky stuff: if the caller thinks that the doc
Packit f574b8
	   to push was the result of following an internal
Packit f574b8
	   (fragment) link, we check whether we believe it.
Packit f574b8
	   It is only accepted as valid if the immediately preceding
Packit f574b8
	   item on the history stack is actually the same document
Packit f574b8
	   except for fragment and location info.  I.e. the Parent
Packit f574b8
	   Anchors are the same.
Packit f574b8
	   Also of course this requires that this is not the first
Packit f574b8
	   history item. - kw */
Packit f574b8
	if (nhist > 0) {
Packit f574b8
	    DocAddress WWWDoc;
Packit f574b8
	    HTParentAnchor *thisparent, *thatparent = NULL;
Packit f574b8
Packit f574b8
	    WWWDoc.address = doc->address;
Packit f574b8
	    WWWDoc.post_data = doc->post_data;
Packit f574b8
	    WWWDoc.post_content_type = doc->post_content_type;
Packit f574b8
	    WWWDoc.bookmark = doc->bookmark;
Packit f574b8
	    WWWDoc.isHEAD = doc->isHEAD;
Packit f574b8
	    WWWDoc.safe = doc->safe;
Packit f574b8
	    thisparent =
Packit f574b8
		HTAnchor_findAddress(&WWWDoc);
Packit f574b8
	    /* Now find the ParentAnchor for the previous history
Packit f574b8
	     * item - kw
Packit f574b8
	     */
Packit f574b8
	    if (thisparent) {
Packit f574b8
		/* If the last-pushed item is a LYNXIMGMAP but THIS one
Packit f574b8
		 * isn't, compare the physical URLs instead. - kw
Packit f574b8
		 */
Packit f574b8
		if (isLYNXIMGMAP(HDOC(nhist - 1).address) &&
Packit f574b8
		    !isLYNXIMGMAP(doc->address)) {
Packit f574b8
		    WWWDoc.address = HDOC(nhist - 1).address + LEN_LYNXIMGMAP;
Packit f574b8
		    /*
Packit f574b8
		     * If THIS item is a LYNXIMGMAP but the last-pushed one
Packit f574b8
		     * isn't, fake it by using THIS item's address for
Packit f574b8
		     * thatparent... - kw
Packit f574b8
		     */
Packit f574b8
		} else if (isLYNXIMGMAP(doc->address) &&
Packit f574b8
			   !isLYNXIMGMAP(HDOC(nhist - 1).address)) {
Packit f574b8
		    char *temp = NULL;
Packit f574b8
Packit f574b8
		    StrAllocCopy(temp, STR_LYNXIMGMAP);
Packit f574b8
		    StrAllocCat(temp, doc->address + LEN_LYNXIMGMAP);
Packit f574b8
		    WWWDoc.address = temp;
Packit f574b8
		    WWWDoc.post_content_type = HDOC(nhist - 1).post_content_type;
Packit f574b8
		    WWWDoc.bookmark = HDOC(nhist - 1).bookmark;
Packit f574b8
		    WWWDoc.isHEAD = HDOC(nhist - 1).isHEAD;
Packit f574b8
		    WWWDoc.safe = HDOC(nhist - 1).safe;
Packit f574b8
		    thatparent =
Packit f574b8
			HTAnchor_findAddress(&WWWDoc);
Packit f574b8
		    FREE(temp);
Packit f574b8
		} else {
Packit f574b8
		    WWWDoc.address = HDOC(nhist - 1).address;
Packit f574b8
		}
Packit f574b8
		if (!thatparent) {	/* if not yet done */
Packit f574b8
		    WWWDoc.post_data = HDOC(nhist - 1).post_data;
Packit f574b8
		    WWWDoc.post_content_type = HDOC(nhist - 1).post_content_type;
Packit f574b8
		    WWWDoc.bookmark = HDOC(nhist - 1).bookmark;
Packit f574b8
		    WWWDoc.isHEAD = HDOC(nhist - 1).isHEAD;
Packit f574b8
		    WWWDoc.safe = HDOC(nhist - 1).safe;
Packit f574b8
		    thatparent =
Packit f574b8
			HTAnchor_findAddress(&WWWDoc);
Packit f574b8
		}
Packit f574b8
		/* In addition to equality of the ParentAnchors, require
Packit f574b8
		 * that IF we have a HTMainText (i.e., it wasn't just
Packit f574b8
		 * HTuncache'd by mainloop), THEN it has to be consistent
Packit f574b8
		 * with what we are trying to push.
Packit f574b8
		 *
Packit f574b8
		 * This may be overkill...  - kw
Packit f574b8
		 */
Packit f574b8
		if (thatparent == thisparent &&
Packit f574b8
		    (!HTMainText || HTMainAnchor == thisparent)
Packit f574b8
		    ) {
Packit f574b8
		    HDOC(nhist).internal_link = TRUE;
Packit f574b8
		    history[nhist].intern_seq_start =
Packit f574b8
			history[nhist - 1].intern_seq_start >= 0 ?
Packit f574b8
			history[nhist - 1].intern_seq_start : nhist - 1;
Packit f574b8
		    CTRACE((tfp, "\nLYpush: pushed as internal link, OK\n"));
Packit f574b8
		}
Packit f574b8
	    }
Packit f574b8
	}
Packit f574b8
	if (!HDOC(nhist).internal_link) {
Packit f574b8
	    CTRACE((tfp, "\nLYpush: push as internal link requested, %s\n",
Packit f574b8
		    "but didn't check out!"));
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
    CTRACE((tfp, "\nLYpush[%d]: address:%s\n        title:%s\n",
Packit f574b8
	    nhist, doc->address, doc->title));
Packit f574b8
    nhist++;
Packit f574b8
    return 1;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Pop the previous filename, link and line number from the history list.
Packit f574b8
 */
Packit f574b8
void LYpop(DocInfo *doc)
Packit f574b8
{
Packit f574b8
    if (nhist > 0) {
Packit f574b8
	clean_extra_history();
Packit f574b8
	nhist--;
Packit f574b8
Packit f574b8
	LYFreeDocInfo(doc);
Packit f574b8
Packit f574b8
	*doc = HDOC(nhist);
Packit f574b8
Packit f574b8
#ifdef DISP_PARTIAL
Packit f574b8
	/* assume we pop the 'doc' to show it soon... */
Packit f574b8
	LYSetNewline(doc->line);	/* reinitialize */
Packit f574b8
#endif /* DISP_PARTIAL */
Packit f574b8
	CTRACE((tfp, "LYpop[%d]: address:%s\n     title:%s\n",
Packit f574b8
		nhist, doc->address, doc->title));
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Move to the previous filename, link and line number from the history list.
Packit f574b8
 */
Packit f574b8
void LYhist_prev(DocInfo *doc)
Packit f574b8
{
Packit f574b8
    trace_history("LYhist_prev");
Packit f574b8
    if (nhist > 0 && (nhist_extra || nhist < size_history)) {
Packit f574b8
	nhist--;
Packit f574b8
	nhist_extra++;
Packit f574b8
	LYpop_num(nhist, doc);
Packit f574b8
	trace_history("...LYhist_prev");
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Called before calling LYhist_prev().
Packit f574b8
 */
Packit f574b8
void LYhist_prev_register(DocInfo *doc)
Packit f574b8
{
Packit f574b8
    trace_history("LYhist_prev_register");
Packit f574b8
    if (nhist > 1) {
Packit f574b8
	if (nhist_extra) {	/* Make something to return back */
Packit f574b8
	    /* Store the new position */
Packit f574b8
	    HDOC(nhist).link = doc->link;
Packit f574b8
	    HDOC(nhist).line = doc->line;
Packit f574b8
	} else if (LYpush(doc, 0)) {
Packit f574b8
	    nhist--;
Packit f574b8
	    nhist_extra++;
Packit f574b8
	}
Packit f574b8
	trace_history("...LYhist_prev_register");
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Move to the next filename, link and line number from the history.
Packit f574b8
 */
Packit f574b8
int LYhist_next(DocInfo *doc, DocInfo *newdoc)
Packit f574b8
{
Packit f574b8
    if (nhist_extra <= 1)	/* == 1 when we are the last one */
Packit f574b8
	return 0;
Packit f574b8
    /* Store the new position */
Packit f574b8
    HDOC(nhist).link = doc->link;
Packit f574b8
    HDOC(nhist).line = doc->line;
Packit f574b8
    LYAllocHistory(nhist);
Packit f574b8
    nhist++;
Packit f574b8
    nhist_extra--;
Packit f574b8
    LYpop_num(nhist, newdoc);
Packit f574b8
    return 1;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Pop the specified hist entry, link and line number from the history list but
Packit f574b8
 * don't actually remove the entry, just return it.
Packit f574b8
 * (This procedure is badly named :)
Packit f574b8
 */
Packit f574b8
void LYpop_num(int number,
Packit f574b8
	       DocInfo *doc)
Packit f574b8
{
Packit f574b8
    if (number >= 0 && (nhist + nhist_extra) > number) {
Packit f574b8
	doc->link = HDOC(number).link;
Packit f574b8
	doc->line = HDOC(number).line;
Packit f574b8
	StrAllocCopy(doc->title, HDOC(number).title);
Packit f574b8
	StrAllocCopy(doc->address, HDOC(number).address);
Packit f574b8
	BStrCopy(doc->post_data, HDOC(number).post_data);
Packit f574b8
	StrAllocCopy(doc->post_content_type, HDOC(number).post_content_type);
Packit f574b8
	StrAllocCopy(doc->bookmark, HDOC(number).bookmark);
Packit f574b8
	doc->isHEAD = HDOC(number).isHEAD;
Packit f574b8
	doc->safe = HDOC(number).safe;
Packit f574b8
	doc->internal_link = HDOC(number).internal_link;	/* ?? */
Packit f574b8
#ifdef DISP_PARTIAL
Packit f574b8
	/* assume we pop the 'doc' to show it soon... */
Packit f574b8
	LYSetNewline(doc->line);	/* reinitialize */
Packit f574b8
#endif /* DISP_PARTIAL */
Packit f574b8
	if (TRACE) {
Packit f574b8
	    CTRACE((tfp, "LYpop_num(%d)\n", number));
Packit f574b8
	    CTRACE((tfp, "  link    %d\n", doc->link));
Packit f574b8
	    CTRACE((tfp, "  line    %d\n", doc->line));
Packit f574b8
	    CTRACE((tfp, "  title   %s\n", NonNull(doc->title)));
Packit f574b8
	    CTRACE((tfp, "  address %s\n", NonNull(doc->address)));
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * This procedure outputs the history buffer into a temporary file.
Packit f574b8
 */
Packit f574b8
int showhistory(char **newfile)
Packit f574b8
{
Packit f574b8
    static char tempfile[LY_MAXPATH] = "\0";
Packit f574b8
    char *Title = NULL;
Packit f574b8
    int x = 0;
Packit f574b8
    FILE *fp0;
Packit f574b8
Packit f574b8
    if ((fp0 = InternalPageFP(tempfile, TRUE)) == 0)
Packit f574b8
	return (-1);
Packit f574b8
Packit f574b8
    LYLocalFileToURL(newfile, tempfile);
Packit f574b8
Packit f574b8
    LYforce_HTML_mode = TRUE;	/* force this file to be HTML */
Packit f574b8
    LYforce_no_cache = TRUE;	/* force this file to be new */
Packit f574b8
Packit f574b8
    BeginInternalPage(fp0, HISTORY_PAGE_TITLE, HISTORY_PAGE_HELP);
Packit f574b8
Packit f574b8
    fprintf(fp0, "

[%s]\n",

Packit f574b8
	    STR_LYNXMESSAGES, STATUSLINES_TITLE);
Packit f574b8
Packit f574b8
    fprintf(fp0, "
\n");
Packit f574b8
Packit f574b8
    fprintf(fp0, "%s\n", gettext("You selected:"));
Packit f574b8
    for (x = nhist + nhist_extra - 1; x >= 0; x--) {
Packit f574b8
	/*
Packit f574b8
	 * The number of the document in the hist stack, its title in a link,
Packit f574b8
	 * and its address.  - FM
Packit f574b8
	 */
Packit f574b8
	if (HDOC(x).title != NULL) {
Packit f574b8
	    StrAllocCopy(Title, HDOC(x).title);
Packit f574b8
	    LYEntify(&Title, TRUE);
Packit f574b8
	    LYTrimLeading(Title);
Packit f574b8
	    LYTrimTrailing(Title);
Packit f574b8
	    if (*Title == '\0')
Packit f574b8
		StrAllocCopy(Title, NO_TITLE);
Packit f574b8
	} else {
Packit f574b8
	    StrAllocCopy(Title, NO_TITLE);
Packit f574b8
	}
Packit f574b8
	fprintf(fp0,
Packit f574b8
		"%s%d. <tab id=t%d>%s\n",
Packit f574b8
		(x > 99 ? "" : x < 10 ? "  " : " "),
Packit f574b8
		x, x, STR_LYNXHIST, x, Title);
Packit f574b8
	if (HDOC(x).address != NULL) {
Packit f574b8
	    StrAllocCopy(Title, HDOC(x).address);
Packit f574b8
	    LYEntify(&Title, TRUE);
Packit f574b8
	} else {
Packit f574b8
	    StrAllocCopy(Title, gettext("(no address)"));
Packit f574b8
	}
Packit f574b8
	if (HDOC(x).internal_link) {
Packit f574b8
	    if (history[x].intern_seq_start == history[nhist - 1].intern_seq_start)
Packit f574b8
		StrAllocCat(Title, gettext(" (internal)"));
Packit f574b8
	    else
Packit f574b8
		StrAllocCat(Title, gettext(" (was internal)"));
Packit f574b8
	}
Packit f574b8
	fprintf(fp0, "<tab to=t%d>%s\n", x, Title);
Packit f574b8
    }
Packit f574b8
    fprintf(fp0, "\n");
Packit f574b8
    EndInternalPage(fp0);
Packit f574b8
Packit f574b8
    LYCloseTempFP(fp0);
Packit f574b8
    FREE(Title);
Packit f574b8
    return (0);
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * This function makes the history page seem like any other type of file since
Packit f574b8
 * more info is needed than can be provided by the normal link structure.  We
Packit f574b8
 * saved out the history number to a special URL.
Packit f574b8
 *
Packit f574b8
 * The info looks like:  LYNXHIST:#
Packit f574b8
 */
Packit f574b8
BOOLEAN historytarget(DocInfo *newdoc)
Packit f574b8
{
Packit f574b8
    int number;
Packit f574b8
    DocAddress WWWDoc;
Packit f574b8
    HTParentAnchor *tmpanchor;
Packit f574b8
    HText *text;
Packit f574b8
    BOOLEAN treat_as_intern = FALSE;
Packit f574b8
Packit f574b8
    if ((!newdoc || !newdoc->address) ||
Packit f574b8
	strlen(newdoc->address) < 10 || !isdigit(UCH(*(newdoc->address + 9))))
Packit f574b8
	return (FALSE);
Packit f574b8
Packit f574b8
    if ((number = atoi(newdoc->address + 9)) > nhist + nhist_extra || number < 0)
Packit f574b8
	return (FALSE);
Packit f574b8
Packit f574b8
    /*
Packit f574b8
     * Optimization: assume we came from the History Page,
Packit f574b8
     * so never return back - always a new version next time.
Packit f574b8
     * But check first whether HTMainText is really the History
Packit f574b8
     * Page document - in some obscure situations this may not be
Packit f574b8
     * the case.  If HTMainText seems to be a History Page document,
Packit f574b8
     * also check that it really hasn't been pushed. - LP, kw
Packit f574b8
     */
Packit f574b8
    if (HTMainText && nhist > 0 &&
Packit f574b8
	!strcmp(HTLoadedDocumentTitle(), HISTORY_PAGE_TITLE) &&
Packit f574b8
	LYIsUIPage3(HTLoadedDocumentURL(), UIP_HISTORY, 0) &&
Packit f574b8
	strcmp(HTLoadedDocumentURL(), HDOC(nhist - 1).address)) {
Packit f574b8
	HTuncache_current_document();	/* don't waste the cache */
Packit f574b8
    }
Packit f574b8
Packit f574b8
    LYpop_num(number, newdoc);
Packit f574b8
    if (((newdoc->internal_link &&
Packit f574b8
	  history[number].intern_seq_start == history[nhist - 1].intern_seq_start)
Packit f574b8
	 || (number < nhist - 1 &&
Packit f574b8
	     HDOC(nhist - 1).internal_link &&
Packit f574b8
	     number == history[nhist - 1].intern_seq_start))
Packit f574b8
	&& !(LYforce_no_cache == TRUE && LYoverride_no_cache == FALSE)) {
Packit f574b8
	if (track_internal_links) {
Packit f574b8
	    LYforce_no_cache = FALSE;
Packit f574b8
	    LYinternal_flag = TRUE;
Packit f574b8
	    newdoc->internal_link = TRUE;
Packit f574b8
	    treat_as_intern = TRUE;
Packit f574b8
	}
Packit f574b8
    } else {
Packit f574b8
	newdoc->internal_link = FALSE;
Packit f574b8
    }
Packit f574b8
    /*
Packit f574b8
     * If we have POST content, and have LYresubmit_posts set or have no_cache
Packit f574b8
     * set or do not still have the text cached, ask the user whether to
Packit f574b8
     * resubmit the form.  - FM
Packit f574b8
     */
Packit f574b8
    if (newdoc->post_data != NULL) {
Packit f574b8
	WWWDoc.address = newdoc->address;
Packit f574b8
	WWWDoc.post_data = newdoc->post_data;
Packit f574b8
	WWWDoc.post_content_type = newdoc->post_content_type;
Packit f574b8
	WWWDoc.bookmark = newdoc->bookmark;
Packit f574b8
	WWWDoc.isHEAD = newdoc->isHEAD;
Packit f574b8
	WWWDoc.safe = newdoc->safe;
Packit f574b8
	tmpanchor = HTAnchor_findAddress(&WWWDoc);
Packit f574b8
	text = (HText *) HTAnchor_document(tmpanchor);
Packit f574b8
	if (((((LYresubmit_posts == TRUE) ||
Packit f574b8
	       (LYforce_no_cache == TRUE &&
Packit f574b8
		LYoverride_no_cache == FALSE)) &&
Packit f574b8
	      !(treat_as_intern && !reloading)) ||
Packit f574b8
	     text == NULL) &&
Packit f574b8
	    (isLYNXIMGMAP(newdoc->address) ||
Packit f574b8
	     HTConfirm(CONFIRM_POST_RESUBMISSION) == TRUE)) {
Packit f574b8
	    LYforce_no_cache = TRUE;
Packit f574b8
	    LYoverride_no_cache = FALSE;
Packit f574b8
	} else if (text != NULL) {
Packit f574b8
	    LYforce_no_cache = FALSE;
Packit f574b8
	    LYoverride_no_cache = TRUE;
Packit f574b8
	} else {
Packit f574b8
	    HTInfoMsg(CANCELLED);
Packit f574b8
	    return (FALSE);
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
Packit f574b8
    if (number != 0)
Packit f574b8
	StrAllocCat(newdoc->title, gettext(" (From History)"));
Packit f574b8
    return (TRUE);
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * This procedure outputs the Visited Links list into a temporary file.  - FM
Packit f574b8
 * Returns links's number to make active (1-based), or 0 if not required.
Packit f574b8
 */
Packit f574b8
int LYShowVisitedLinks(char **newfile)
Packit f574b8
{
Packit f574b8
    static char tempfile[LY_MAXPATH] = "\0";
Packit f574b8
    char *Title = NULL;
Packit f574b8
    char *Address = NULL;
Packit f574b8
    int x, tot;
Packit f574b8
    FILE *fp0;
Packit f574b8
    VisitedLink *vl;
Packit f574b8
    HTList *cur = Visited_Links;
Packit f574b8
    int offset;
Packit f574b8
    int ret = 0;
Packit f574b8
    const char *arrow, *post_arrow;
Packit f574b8
Packit f574b8
    if (!cur)
Packit f574b8
	return (-1);
Packit f574b8
Packit f574b8
    if ((fp0 = InternalPageFP(tempfile, TRUE)) == 0)
Packit f574b8
	return (-1);
Packit f574b8
Packit f574b8
    LYLocalFileToURL(newfile, tempfile);
Packit f574b8
    LYRegisterUIPage(*newfile, UIP_VLINKS);
Packit f574b8
Packit f574b8
    LYforce_HTML_mode = TRUE;	/* force this file to be HTML */
Packit f574b8
    LYforce_no_cache = TRUE;	/* force this file to be new */
Packit f574b8
Packit f574b8
    BeginInternalPage(fp0, VISITED_LINKS_TITLE, VISITED_LINKS_HELP);
Packit f574b8
Packit f574b8
#ifndef NO_OPTION_FORMS
Packit f574b8
    fprintf(fp0, "<form action=\"%s\" method=\"post\">\n", STR_LYNXOPTIONS);
Packit f574b8
    LYMenuVisitedLinks(fp0, FALSE);
Packit f574b8
    fprintf(fp0, "<input type=\"submit\" value=\"Accept Changes\">\n");
Packit f574b8
    fprintf(fp0, "</form>\n");
Packit f574b8
    fprintf(fp0, "

\n");

Packit f574b8
#endif
Packit f574b8
Packit f574b8
    fprintf(fp0, "
\n");
Packit f574b8
    fprintf(fp0, "%s\n",
Packit f574b8
	    gettext("You visited (POSTs, bookmark, menu and list files excluded):"));
Packit f574b8
    if (Visited_Links_As & VISITED_LINKS_REVERSE)
Packit f574b8
	tot = x = HTList_count(Visited_Links);
Packit f574b8
    else
Packit f574b8
	tot = x = -1;
Packit f574b8
Packit f574b8
    if (Visited_Links_As & VISITED_LINKS_AS_TREE) {
Packit f574b8
	vl = First_tree;
Packit f574b8
    } else if (Visited_Links_As & VISITED_LINKS_AS_LATEST) {
Packit f574b8
	if (Visited_Links_As & VISITED_LINKS_REVERSE)
Packit f574b8
	    vl = Latest_last.prev_latest;
Packit f574b8
	else
Packit f574b8
	    vl = Latest_first.next_latest;
Packit f574b8
	if (vl == &Latest_last || vl == &Latest_first)
Packit f574b8
	    vl = NULL;
Packit f574b8
    } else {
Packit f574b8
	if (Visited_Links_As & VISITED_LINKS_REVERSE)
Packit f574b8
	    vl = Last_by_first;
Packit f574b8
	else
Packit f574b8
	    vl = (VisitedLink *) HTList_nextObject(cur);
Packit f574b8
    }
Packit f574b8
    while (NULL != vl) {
Packit f574b8
	/*
Packit f574b8
	 * The number of the document (most recent highest), its title in a
Packit f574b8
	 * link, and its address.  - FM
Packit f574b8
	 */
Packit f574b8
	post_arrow = arrow = "";
Packit f574b8
	if (Visited_Links_As & VISITED_LINKS_REVERSE)
Packit f574b8
	    x--;
Packit f574b8
	else
Packit f574b8
	    x++;
Packit f574b8
	if (vl == PrevActiveVisitedLink) {
Packit f574b8
	    if (Visited_Links_As & VISITED_LINKS_REVERSE)
Packit f574b8
		ret = tot - x + 2;
Packit f574b8
	    else
Packit f574b8
		ret = x + 3;
Packit f574b8
	}
Packit f574b8
	if (vl == PrevActiveVisitedLink) {
Packit f574b8
	    post_arrow = "";
Packit f574b8
	    /* Otherwise levels 0 and 1 look the same when with arrow: */
Packit f574b8
	    arrow = (vl->level && (Visited_Links_As & VISITED_LINKS_AS_TREE))
Packit f574b8
		? "==>" : "=>";
Packit f574b8
	    StrAllocCat(*newfile, "#current");
Packit f574b8
	}
Packit f574b8
	if (Visited_Links_As & VISITED_LINKS_AS_TREE) {
Packit f574b8
	    offset = 2 * vl->level;
Packit f574b8
	    if (offset > 24)
Packit f574b8
		offset = (offset + 24) / 2;
Packit f574b8
	    if (offset > LYcols * 3 / 4)
Packit f574b8
		offset = LYcols * 3 / 4;
Packit f574b8
	} else
Packit f574b8
	    offset = (x > 99 ? 0 : x < 10 ? 2 : 1);
Packit f574b8
	if (non_empty(vl->title)) {
Packit f574b8
	    StrAllocCopy(Title, vl->title);
Packit f574b8
	    LYEntify(&Title, TRUE);
Packit f574b8
	    LYTrimLeading(Title);
Packit f574b8
	    LYTrimTrailing(Title);
Packit f574b8
	    if (*Title == '\0')
Packit f574b8
		StrAllocCopy(Title, NO_TITLE);
Packit f574b8
	} else {
Packit f574b8
	    StrAllocCopy(Title, NO_TITLE);
Packit f574b8
	}
Packit f574b8
	if (non_empty(vl->address)) {
Packit f574b8
	    StrAllocCopy(Address, vl->address);
Packit f574b8
	    LYEntify(&Address, FALSE);
Packit f574b8
	    fprintf(fp0,
Packit f574b8
		    "%-*s%s%d. <tab id=t%d>%s\n",
Packit f574b8
		    offset, arrow, post_arrow,
Packit f574b8
		    x, x, Address, Title);
Packit f574b8
	} else {
Packit f574b8
	    fprintf(fp0,
Packit f574b8
		    "%-*s%s%d. <tab id=t%d>%s\n",
Packit f574b8
		    offset, arrow, post_arrow,
Packit f574b8
		    x, x, Title);
Packit f574b8
	}
Packit f574b8
	if (Address != NULL) {
Packit f574b8
	    StrAllocCopy(Address, vl->address);
Packit f574b8
	    LYEntify(&Address, TRUE);
Packit f574b8
	}
Packit f574b8
	fprintf(fp0, "<tab to=t%d>%s\n", x,
Packit f574b8
		((Address != NULL) ? Address : gettext("(no address)")));
Packit f574b8
	if (Visited_Links_As & VISITED_LINKS_AS_TREE)
Packit f574b8
	    vl = vl->next_tree;
Packit f574b8
	else if (Visited_Links_As & VISITED_LINKS_AS_LATEST) {
Packit f574b8
	    if (Visited_Links_As & VISITED_LINKS_REVERSE)
Packit f574b8
		vl = vl->prev_latest;
Packit f574b8
	    else
Packit f574b8
		vl = vl->next_latest;
Packit f574b8
	    if (vl == &Latest_last || vl == &Latest_first)
Packit f574b8
		vl = NULL;
Packit f574b8
	} else {
Packit f574b8
	    if (Visited_Links_As & VISITED_LINKS_REVERSE)
Packit f574b8
		vl = vl->prev_first;
Packit f574b8
	    else
Packit f574b8
		vl = (VisitedLink *) HTList_nextObject(cur);
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
    fprintf(fp0, "\n");
Packit f574b8
    EndInternalPage(fp0);
Packit f574b8
Packit f574b8
    LYCloseTempFP(fp0);
Packit f574b8
    FREE(Title);
Packit f574b8
    FREE(Address);
Packit f574b8
    return (ret);
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Keep cycled buffer for statusline messages.
Packit f574b8
 * But allow user to change how big it will be from userdefs.h
Packit f574b8
 */
Packit f574b8
#ifndef STATUSBUFSIZE
Packit f574b8
#define STATUSBUFSIZE   40
Packit f574b8
#endif
Packit f574b8
Packit f574b8
int status_buf_size = STATUSBUFSIZE;
Packit f574b8
Packit f574b8
static char **buffstack;
Packit f574b8
static int topOfStack = 0;
Packit f574b8
Packit f574b8
#ifdef LY_FIND_LEAKS
Packit f574b8
static void free_messages_stack(void)
Packit f574b8
{
Packit f574b8
    if (buffstack != 0) {
Packit f574b8
	topOfStack = status_buf_size;
Packit f574b8
Packit f574b8
	while (--topOfStack >= 0) {
Packit f574b8
	    FREE(buffstack[topOfStack]);
Packit f574b8
	}
Packit f574b8
	FREE(buffstack);
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
#endif
Packit f574b8
Packit f574b8
static void to_stack(char *str)
Packit f574b8
{
Packit f574b8
    /*
Packit f574b8
     * Cycle buffer:
Packit f574b8
     */
Packit f574b8
    if (topOfStack >= status_buf_size) {
Packit f574b8
	topOfStack = 0;
Packit f574b8
    }
Packit f574b8
Packit f574b8
    /*
Packit f574b8
     * Register string.
Packit f574b8
     */
Packit f574b8
    if (buffstack == 0)
Packit f574b8
	buffstack = typecallocn(char *, (size_t) status_buf_size);
Packit f574b8
Packit f574b8
    FREE(buffstack[topOfStack]);
Packit f574b8
    buffstack[topOfStack] = str;
Packit f574b8
    topOfStack++;
Packit f574b8
#ifdef LY_FIND_LEAKS
Packit f574b8
    if (!already_registered_free_messages_stack) {
Packit f574b8
	already_registered_free_messages_stack = 1;
Packit f574b8
	atexit(free_messages_stack);
Packit f574b8
    }
Packit f574b8
#endif
Packit f574b8
    if (topOfStack >= status_buf_size) {
Packit f574b8
	topOfStack = 0;
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Dump statusline messages into the buffer.
Packit f574b8
 * Called from mainloop() when exit immediately with an error:
Packit f574b8
 * can not access startfile (first_file) so a couple of alert messages
Packit f574b8
 * will be very useful on exit.
Packit f574b8
 * (Don't expect everyone will look a trace log in case of difficulties:))
Packit f574b8
 */
Packit f574b8
void LYstatusline_messages_on_exit(char **buf)
Packit f574b8
{
Packit f574b8
    int i;
Packit f574b8
Packit f574b8
    if (buffstack != 0) {
Packit f574b8
	StrAllocCat(*buf, "\n");
Packit f574b8
	/* print messages in chronological order:
Packit f574b8
	 * probably a single message but let's do it.
Packit f574b8
	 */
Packit f574b8
	i = topOfStack - 1;
Packit f574b8
	while (++i < status_buf_size) {
Packit f574b8
	    if (buffstack[i] != NULL) {
Packit f574b8
		StrAllocCat(*buf, buffstack[i]);
Packit f574b8
		StrAllocCat(*buf, "\n");
Packit f574b8
	    }
Packit f574b8
	}
Packit f574b8
	i = -1;
Packit f574b8
	while (++i < topOfStack) {
Packit f574b8
	    if (buffstack[i] != NULL) {
Packit f574b8
		StrAllocCat(*buf, buffstack[i]);
Packit f574b8
		StrAllocCat(*buf, "\n");
Packit f574b8
	    }
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
void LYstore_message2(const char *message,
Packit f574b8
		      const char *argument)
Packit f574b8
{
Packit f574b8
Packit f574b8
    if (message != NULL) {
Packit f574b8
	char *temp = NULL;
Packit f574b8
Packit f574b8
	HTSprintf0(&temp, message, NonNull(argument));
Packit f574b8
	to_stack(temp);
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
void LYstore_message(const char *message)
Packit f574b8
{
Packit f574b8
    if (message != NULL) {
Packit f574b8
	char *temp = NULL;
Packit f574b8
Packit f574b8
	StrAllocCopy(temp, message);
Packit f574b8
	to_stack(temp);
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/*     LYLoadMESSAGES
Packit f574b8
 *     --------------
Packit f574b8
 *     Create a text/html stream with a list of recent statusline messages.
Packit f574b8
 *     LYNXMESSAGES:/ internal page.
Packit f574b8
 *     [implementation based on LYLoadKeymap()].
Packit f574b8
 */
Packit f574b8
Packit f574b8
static int LYLoadMESSAGES(const char *arg GCC_UNUSED,
Packit f574b8
			  HTParentAnchor *anAnchor,
Packit f574b8
			  HTFormat format_out,
Packit f574b8
			  HTStream *sink)
Packit f574b8
{
Packit f574b8
    HTFormat format_in = WWW_HTML;
Packit f574b8
    HTStream *target = NULL;
Packit f574b8
    char *buf = NULL;
Packit f574b8
    int nummsg = 0;
Packit f574b8
Packit f574b8
    int i;
Packit f574b8
    char *temp = NULL;
Packit f574b8
Packit f574b8
    if (buffstack != 0) {
Packit f574b8
	i = status_buf_size;
Packit f574b8
	while (--i >= 0) {
Packit f574b8
	    if (buffstack[i] != NULL)
Packit f574b8
		nummsg++;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
Packit f574b8
    /*
Packit f574b8
     * Set up the stream.  - FM
Packit f574b8
     */
Packit f574b8
    target = HTStreamStack(format_in, format_out, sink, anAnchor);
Packit f574b8
Packit f574b8
    if (target == NULL) {
Packit f574b8
	HTSprintf0(&buf, CANNOT_CONVERT_I_TO_O,
Packit f574b8
		   HTAtom_name(format_in), HTAtom_name(format_out));
Packit f574b8
	HTAlert(buf);
Packit f574b8
	FREE(buf);
Packit f574b8
	return (HT_NOT_LOADED);
Packit f574b8
    }
Packit f574b8
    anAnchor->no_cache = TRUE;
Packit f574b8
Packit f574b8
#define PUTS(buf)    (*target->isa->put_block)(target, buf, (int) strlen(buf))
Packit f574b8
Packit f574b8
    HTSprintf0(&buf, "<html>\n<head>\n");
Packit f574b8
    PUTS(buf);
Packit f574b8
    /*
Packit f574b8
     * This page is a list of messages in display character set.
Packit f574b8
     */
Packit f574b8
    HTSprintf0(&buf, "<META %s content=\"" STR_HTML ";charset=%s\">\n",
Packit f574b8
	       "http-equiv=\"content-type\"",
Packit f574b8
	       LYCharSet_UC[current_char_set].MIMEname);
Packit f574b8
    PUTS(buf);
Packit f574b8
    HTSprintf0(&buf, "<title>%s</title>\n</head>\n<body>\n",
Packit f574b8
	       STATUSLINES_TITLE);
Packit f574b8
    PUTS(buf);
Packit f574b8
Packit f574b8
    if (nummsg != 0) {
Packit f574b8
	HTSprintf0(&buf, "
    \n");
Packit f574b8
	PUTS(buf);
Packit f574b8
	/* print messages in reverse order: */
Packit f574b8
	i = topOfStack;
Packit f574b8
	while (--i >= 0) {
Packit f574b8
	    if (buffstack[i] != NULL) {
Packit f574b8
		StrAllocCopy(temp, buffstack[i]);
Packit f574b8
		LYEntify(&temp, TRUE);
Packit f574b8
		HTSprintf0(&buf, "
  • %s\n", nummsg, temp);
  • Packit f574b8
    		nummsg--;
    Packit f574b8
    		PUTS(buf);
    Packit f574b8
    	    }
    Packit f574b8
    	}
    Packit f574b8
    	i = status_buf_size;
    Packit f574b8
    	while (--i >= topOfStack) {
    Packit f574b8
    	    if (buffstack[i] != NULL) {
    Packit f574b8
    		StrAllocCopy(temp, buffstack[i]);
    Packit f574b8
    		LYEntify(&temp, TRUE);
    Packit f574b8
    		HTSprintf0(&buf, "
  • %s\n", nummsg, temp);
  • Packit f574b8
    		nummsg--;
    Packit f574b8
    		PUTS(buf);
    Packit f574b8
    	    }
    Packit f574b8
    	}
    Packit f574b8
    	FREE(temp);
    Packit f574b8
    	HTSprintf0(&buf, "\n</body>\n</html>\n");
    Packit f574b8
        } else {
    Packit f574b8
    	HTSprintf0(&buf, "

    %s\n</body>\n</html>\n",

    Packit f574b8
    		   gettext("(No messages yet)"));
    Packit f574b8
        }
    Packit f574b8
        PUTS(buf);
    Packit f574b8
    Packit f574b8
        (*target->isa->_free) (target);
    Packit f574b8
        FREE(buf);
    Packit f574b8
        return (HT_LOADED);
    Packit f574b8
    }
    Packit f574b8
    Packit f574b8
    #ifdef GLOBALDEF_IS_MACRO
    Packit f574b8
    #define _LYMESSAGES_C_GLOBALDEF_1_INIT { "LYNXMESSAGES", LYLoadMESSAGES, 0}
    Packit f574b8
    GLOBALDEF(HTProtocol, LYLynxStatusMessages, _LYMESSAGES_C_GLOBALDEF_1_INIT);
    Packit f574b8
    #else
    Packit f574b8
    GLOBALDEF HTProtocol LYLynxStatusMessages =
    Packit f574b8
    {"LYNXMESSAGES", LYLoadMESSAGES, 0};
    Packit f574b8
    #endif /* GLOBALDEF_IS_MACRO */