Blame src/LYBookmark.c

Packit f574b8
/*
Packit f574b8
 * $LynxId: LYBookmark.c,v 1.78 2018/03/18 19:27:30 tom Exp $
Packit f574b8
 */
Packit f574b8
#include <HTUtils.h>
Packit f574b8
#include <HTAlert.h>
Packit f574b8
#include <HTFile.h>
Packit f574b8
#include <LYUtils.h>
Packit f574b8
#include <LYStrings.h>
Packit f574b8
#include <LYBookmark.h>
Packit f574b8
#include <LYGlobalDefs.h>
Packit f574b8
#include <LYClean.h>
Packit f574b8
#include <LYKeymap.h>
Packit f574b8
#include <LYCharUtils.h>	/* need for META charset */
Packit f574b8
#include <UCAux.h>
Packit f574b8
#include <LYCharSets.h>		/* need for LYHaveCJKCharacterSet */
Packit f574b8
#include <LYCurses.h>
Packit f574b8
#include <GridText.h>
Packit f574b8
#include <HTCJK.h>
Packit f574b8
Packit f574b8
#ifdef VMS
Packit f574b8
#include <nam.h>
Packit f574b8
#endif /* VMS */
Packit f574b8
Packit f574b8
#include <LYLeaks.h>
Packit f574b8
Packit f574b8
char *MBM_A_subbookmark[MBM_V_MAXFILES + 1];
Packit f574b8
char *MBM_A_subdescript[MBM_V_MAXFILES + 1];
Packit f574b8
Packit f574b8
static BOOLEAN is_mosaic_hotlist = FALSE;
Packit f574b8
static const char *convert_mosaic_bookmark_file(const char *filename_buffer);
Packit f574b8
Packit f574b8
int LYindex2MBM(int n)
Packit f574b8
{
Packit f574b8
    static char MBMcodes[MBM_V_MAXFILES + 2] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Packit f574b8
Packit f574b8
    return n >= 0 && n <= MBM_V_MAXFILES ? MBMcodes[n] : '?';
Packit f574b8
}
Packit f574b8
Packit f574b8
int LYMBM2index(int ch)
Packit f574b8
{
Packit f574b8
    if ((ch = TOUPPER(ch)) > 0) {
Packit f574b8
	const char *letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Packit f574b8
	const char *result = StrChr(letters, ch);
Packit f574b8
Packit f574b8
	if (result != 0
Packit f574b8
	    && (result - letters) <= MBM_V_MAXFILES)
Packit f574b8
	    return (int) (result - letters);
Packit f574b8
    }
Packit f574b8
    return -1;
Packit f574b8
}
Packit f574b8
Packit f574b8
static void show_bookmark_not_defined(void)
Packit f574b8
{
Packit f574b8
    char *string_buffer = 0;
Packit f574b8
Packit f574b8
    HTSprintf0(&string_buffer,
Packit f574b8
	       BOOKMARK_FILE_NOT_DEFINED,
Packit f574b8
	       key_for_func(LYK_OPTIONS));
Packit f574b8
    LYMBM_statusline(string_buffer);
Packit f574b8
    FREE(string_buffer);
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Tries to open a bookmark file for reading, which may be the default, or
Packit f574b8
 * based on offering the user a choice from the MBM_A_subbookmark[] array.  If
Packit f574b8
 * successful the file is closed, and the filename in system path specs is
Packit f574b8
 * returned, the URL is allocated into *URL, and the MBM_A_subbookmark[]
Packit f574b8
 * filepath is allocated into the BookmarkPage global.  Returns a zero-length
Packit f574b8
 * pointer to flag a cancel, or a space to flag an undefined selection, without
Packit f574b8
 * allocating into *URL or BookmarkPage.  Returns NULL with allocating into
Packit f574b8
 * BookmarkPage but not *URL is the selection is valid but the file doesn't yet
Packit f574b8
 * exist.  - FM
Packit f574b8
 */
Packit f574b8
const char *get_bookmark_filename(char **URL)
Packit f574b8
{
Packit f574b8
    static char filename_buffer[LY_MAXPATH];
Packit f574b8
    char *string_buffer = 0;
Packit f574b8
    FILE *fp;
Packit f574b8
    int MBM_tmp;
Packit f574b8
Packit f574b8
    /*
Packit f574b8
     * Multi_Bookmarks support.  - FMG & FM
Packit f574b8
     * Let user select a bookmark file.
Packit f574b8
     */
Packit f574b8
    MBM_tmp = select_multi_bookmarks();
Packit f574b8
    if (MBM_tmp == -2)
Packit f574b8
	/*
Packit f574b8
	 * Zero-length pointer flags a cancel.  - FM
Packit f574b8
	 */
Packit f574b8
	return ("");
Packit f574b8
    if (MBM_tmp == -1) {
Packit f574b8
	show_bookmark_not_defined();
Packit f574b8
	/*
Packit f574b8
	 * Space flags an undefined selection.  - FMG
Packit f574b8
	 */
Packit f574b8
	return (" ");
Packit f574b8
    } else {
Packit f574b8
	/*
Packit f574b8
	 * Save the filepath as a global.  The system path will be loaded into
Packit f574b8
	 * to the (static) filename_buffer as the return value, the URL will be
Packit f574b8
	 * allocated into *URL, and we also need the filepath available to
Packit f574b8
	 * calling functions.  This is all pitifully non-reentrant, a la the
Packit f574b8
	 * original Lynx, and should be redesigned someday.  - FM
Packit f574b8
	 */
Packit f574b8
	StrAllocCopy(BookmarkPage, MBM_A_subbookmark[MBM_tmp]);
Packit f574b8
    }
Packit f574b8
Packit f574b8
    /*
Packit f574b8
     * Seek it in the home path.  - FM
Packit f574b8
     */
Packit f574b8
    LYAddPathToHome(filename_buffer,
Packit f574b8
		    sizeof(filename_buffer),
Packit f574b8
		    BookmarkPage);
Packit f574b8
    CTRACE((tfp, "\nget_bookmark_filename: SEEKING %s\n   AS %s\n\n",
Packit f574b8
	    BookmarkPage, filename_buffer));
Packit f574b8
    if ((fp = fopen(filename_buffer, TXT_R)) != NULL) {
Packit f574b8
	/*
Packit f574b8
	 * We now have the file open.
Packit f574b8
	 * Check if it is a mosaic hotlist.
Packit f574b8
	 */
Packit f574b8
	if (LYSafeGets(&string_buffer, fp) != 0
Packit f574b8
	    && *LYTrimNewline(string_buffer) != '\0'
Packit f574b8
	    && !StrNCmp(string_buffer, "ncsa-xmosaic-hotlist-format-1", 29)) {
Packit f574b8
	    const char *newname;
Packit f574b8
Packit f574b8
	    /*
Packit f574b8
	     * It is a mosaic hotlist file.
Packit f574b8
	     */
Packit f574b8
	    is_mosaic_hotlist = TRUE;
Packit f574b8
	    newname = convert_mosaic_bookmark_file(filename_buffer);
Packit f574b8
	    LYLocalFileToURL(URL, newname);
Packit f574b8
	} else {
Packit f574b8
	    is_mosaic_hotlist = FALSE;
Packit f574b8
	    LYLocalFileToURL(URL, filename_buffer);
Packit f574b8
	}
Packit f574b8
	FREE(string_buffer);
Packit f574b8
	LYCloseInput(fp);
Packit f574b8
Packit f574b8
	return (filename_buffer);	/* bookmark file exists */
Packit f574b8
    }
Packit f574b8
    return (NULL);
Packit f574b8
Packit f574b8
}				/* big end */
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Converts a Mosaic hotlist file into an HTML file for handling as a Lynx
Packit f574b8
 * bookmark file.  - FM
Packit f574b8
 */
Packit f574b8
static const char *convert_mosaic_bookmark_file(const char *filename_buffer)
Packit f574b8
{
Packit f574b8
    static char newfile[LY_MAXPATH];
Packit f574b8
    FILE *fp, *nfp;
Packit f574b8
    char *buf = NULL;
Packit f574b8
    int line = -2;
Packit f574b8
Packit f574b8
    (void) LYRemoveTemp(newfile);
Packit f574b8
    if ((nfp = LYOpenTemp(newfile, HTML_SUFFIX, "w")) == NULL) {
Packit f574b8
	LYMBM_statusline(NO_TEMP_FOR_HOTLIST);
Packit f574b8
	LYSleepAlert();
Packit f574b8
	return ("");
Packit f574b8
    }
Packit f574b8
Packit f574b8
    if ((fp = fopen(filename_buffer, TXT_R)) == NULL)
Packit f574b8
	return ("");		/* should always open */
Packit f574b8
Packit f574b8
    fprintf(nfp, "<head>\n<title>%s</title>\n</head>\n", MOSAIC_BOOKMARK_TITLE);
Packit f574b8
    fprintf(nfp, "%s\n\n

\n

    \n", gettext("\
Packit f574b8
     This file is an HTML representation of the X Mosaic hotlist file.\n\
Packit f574b8
     Outdated or invalid links may be removed by using the\n\
Packit f574b8
     remove bookmark command, it is usually the 'R' key but may have\n\
Packit f574b8
     been remapped by you or your system administrator."));
Packit f574b8
Packit f574b8
    while ((LYSafeGets(&buf, fp)) != NULL) {
Packit f574b8
	if (line >= 0) {
Packit f574b8
	    LYTrimNewline(buf);
Packit f574b8
	    if ((line % 2) == 0) {	/* even lines */
Packit f574b8
		if (*buf != '\0') {
Packit f574b8
		    strtok(buf, " ");	/* kill everything after the space */
Packit f574b8
		    fprintf(nfp, "
  • ", buf); /* the URL */
  • Packit f574b8
    		}
    Packit f574b8
    	    } else {		/* odd lines */
    Packit f574b8
    		fprintf(nfp, "%s\n", buf);	/* the title */
    Packit f574b8
    	    }
    Packit f574b8
    	}
    Packit f574b8
    	/* else - ignore the line (this gets rid of first two lines) */
    Packit f574b8
    	line++;
    Packit f574b8
        }
    Packit f574b8
        LYCloseTempFP(nfp);
    Packit f574b8
        LYCloseInput(fp);
    Packit f574b8
        return (newfile);
    Packit f574b8
    }
    Packit f574b8
    Packit f574b8
    static BOOLEAN havevisible(const char *Title);
    Packit f574b8
    static BOOLEAN have8bit(const char *Title);
    Packit f574b8
    static char *title_convert8bit(const char *Title);
    Packit f574b8
    Packit f574b8
    /*
    Packit f574b8
     * Adds a link to a bookmark file, creating the file if it doesn't already
    Packit f574b8
     * exist, and making sure that no_cache is set for a pre-existing, cached file,
    Packit f574b8
     * so that the change will be evident on return to to that file.  - FM
    Packit f574b8
     */
    Packit f574b8
    void save_bookmark_link(const char *address,
    Packit f574b8
    			const char *title)
    Packit f574b8
    {
    Packit f574b8
        FILE *fp;
    Packit f574b8
        BOOLEAN first_time = FALSE;
    Packit f574b8
        const char *filename;
    Packit f574b8
        char *bookmark_URL = NULL;
    Packit f574b8
        char filename_buffer[LY_MAXPATH];
    Packit f574b8
        char *Address = NULL;
    Packit f574b8
        char *Title = NULL;
    Packit f574b8
        int i, c;
    Packit f574b8
        bstring *string_data = NULL;
    Packit f574b8
        bstring *tmp_data = NULL;
    Packit f574b8
        DocAddress WWWDoc;
    Packit f574b8
        HTParentAnchor *tmpanchor;
    Packit f574b8
        HText *text;
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * Make sure we were passed something to save.  - FM
    Packit f574b8
         */
    Packit f574b8
        if (isEmpty(address)) {
    Packit f574b8
    	HTAlert(MALFORMED_ADDRESS);
    Packit f574b8
    	return;
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * Offer a choice of bookmark files, or get the default.  - FMG
    Packit f574b8
         */
    Packit f574b8
        filename = get_bookmark_filename(&bookmark_URL);
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * If filename is NULL, must create a new file.  If filename is a space, an
    Packit f574b8
         * invalid bookmark file was selected, or if zero-length, the user
    Packit f574b8
         * cancelled.  Ignore request in both cases.  Otherwise, make a copy before
    Packit f574b8
         * anything might change the static get_bookmark_filename() buffer.  - FM
    Packit f574b8
         */
    Packit f574b8
        if (filename == NULL) {
    Packit f574b8
    	first_time = TRUE;
    Packit f574b8
    	filename_buffer[0] = '\0';
    Packit f574b8
        } else {
    Packit f574b8
    	if (*filename == '\0' || !strcmp(filename, " ")) {
    Packit f574b8
    	    FREE(bookmark_URL);
    Packit f574b8
    	    return;
    Packit f574b8
    	}
    Packit f574b8
    	LYStrNCpy(filename_buffer, filename, sizeof(filename_buffer) - 1);
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * If BookmarkPage is NULL, something went wrong, so ignore the request.  -
    Packit f574b8
         * FM
    Packit f574b8
         */
    Packit f574b8
        if (isEmpty(BookmarkPage)) {
    Packit f574b8
    	FREE(bookmark_URL);
    Packit f574b8
    	return;
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * If the link will be added to the same bookmark file, get confirmation. 
    Packit f574b8
         * - FM
    Packit f574b8
         */
    Packit f574b8
        if (LYMultiBookmarks != MBM_OFF) {
    Packit f574b8
    	const char *url = HTLoadedDocumentURL();
    Packit f574b8
    	const char *page = ((*BookmarkPage == '.')
    Packit f574b8
    			    ? (BookmarkPage + 1)
    Packit f574b8
    			    : BookmarkPage);
    Packit f574b8
    Packit f574b8
    	if (strstr(url, page) != NULL) {
    Packit f574b8
    	    LYMBM_statusline(MULTIBOOKMARKS_SELF);
    Packit f574b8
    	    c = LYgetch_single();
    Packit f574b8
    	    if (c != 'L') {
    Packit f574b8
    		FREE(bookmark_URL);
    Packit f574b8
    		return;
    Packit f574b8
    	    }
    Packit f574b8
    	}
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * Allow user to change the title.  - FM
    Packit f574b8
         */
    Packit f574b8
        do {
    Packit f574b8
    	if (HTCJK == JAPANESE) {
    Packit f574b8
    	    switch (kanji_code) {
    Packit f574b8
    	    case EUC:
    Packit f574b8
    		BStrAlloc(tmp_data, MAX_LINE + 2 * (int) strlen(title));
    Packit f574b8
    		TO_EUC((const unsigned char *) title, (unsigned char *) tmp_data->str);
    Packit f574b8
    		break;
    Packit f574b8
    	    case SJIS:
    Packit f574b8
    		BStrAlloc(tmp_data, MAX_LINE + (int) strlen(title));
    Packit f574b8
    		TO_SJIS((const unsigned char *) title, (unsigned char *) tmp_data->str);
    Packit f574b8
    		break;
    Packit f574b8
    	    default:
    Packit f574b8
    		break;
    Packit f574b8
    	    }
    Packit f574b8
    	    BStrCopy0(string_data, tmp_data ? tmp_data->str : title);
    Packit f574b8
    	} else {
    Packit f574b8
    	    BStrCopy0(string_data, title);
    Packit f574b8
    	}
    Packit f574b8
    	LYReduceBlanks(string_data->str);
    Packit f574b8
    	LYMBM_statusline(TITLE_PROMPT);
    Packit f574b8
    	LYgetBString(&string_data, FALSE, 0, NORECALL);
    Packit f574b8
    	if (isBEmpty(string_data)) {
    Packit f574b8
    	    LYMBM_statusline(CANCELLED);
    Packit f574b8
    	    LYSleepMsg();
    Packit f574b8
    	    FREE(bookmark_URL);
    Packit f574b8
    	    return;
    Packit f574b8
    	}
    Packit f574b8
        } while (!havevisible(string_data->str));
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * Create the Title with any left-angle-brackets converted to < entities
    Packit f574b8
         * and any ampersands converted to & entities.  - FM
    Packit f574b8
         *
    Packit f574b8
         * Convert 8-bit letters to &#xUUUU to avoid dependencies from display
    Packit f574b8
         * character set which may need changing.  Do NOT convert any 8-bit chars
    Packit f574b8
         * if we have CJK display.  - LP
    Packit f574b8
         */
    Packit f574b8
        LYformTitle(&Title, string_data->str);
    Packit f574b8
        LYEntify(&Title, TRUE);
    Packit f574b8
        if (UCSaveBookmarksInUnicode &&
    Packit f574b8
    	have8bit(Title) && (!LYHaveCJKCharacterSet)) {
    Packit f574b8
    	char *p = title_convert8bit(Title);
    Packit f574b8
    Packit f574b8
    	if (p != 0) {
    Packit f574b8
    	    FREE(Title);
    Packit f574b8
    	    Title = p;
    Packit f574b8
    	}
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * Create the bookmark file, if it doesn't exist already, Otherwise, open
    Packit f574b8
         * the pre-existing bookmark file.  - FM
    Packit f574b8
         */
    Packit f574b8
        SetDefaultMode(O_TEXT);
    Packit f574b8
        if (first_time) {
    Packit f574b8
    	/*
    Packit f574b8
    	 * Seek it in the home path.  - FM
    Packit f574b8
    	 */
    Packit f574b8
    	LYAddPathToHome(filename_buffer,
    Packit f574b8
    			sizeof(filename_buffer),
    Packit f574b8
    			BookmarkPage);
    Packit f574b8
        }
    Packit f574b8
        CTRACE((tfp, "\nsave_bookmark_link: SEEKING %s\n   AS %s\n\n",
    Packit f574b8
    	    BookmarkPage, filename_buffer));
    Packit f574b8
        if ((fp = fopen(filename_buffer, (first_time ? TXT_W : TXT_A))) == NULL) {
    Packit f574b8
    	LYMBM_statusline(BOOKMARK_OPEN_FAILED);
    Packit f574b8
    	LYSleepAlert();
    Packit f574b8
    	FREE(Title);
    Packit f574b8
    	FREE(bookmark_URL);
    Packit f574b8
    	return;
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * Convert all ampersands in the address to & entities.  - FM
    Packit f574b8
         */
    Packit f574b8
        StrAllocCopy(Address, address);
    Packit f574b8
        LYEntify(&Address, FALSE);
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * If we created a new bookmark file, write the headers.  - FM
    Packit f574b8
         * Once and forever...
    Packit f574b8
         */
    Packit f574b8
        if (first_time) {
    Packit f574b8
    	fprintf(fp, "<head>\n");
    Packit f574b8
    #if defined(SH_EX) && !defined(_WINDOWS)	/* 1997/12/11 (Thu) 19:13:40 */
    Packit f574b8
    	if (HTCJK != JAPANESE)
    Packit f574b8
    	    LYAddMETAcharsetToFD(fp, -1);
    Packit f574b8
    	else
    Packit f574b8
    	    fprintf(fp, "<META %s %s>\n",
    Packit f574b8
    		    "http-equiv=\"content-type\"",
    Packit f574b8
    		    "content=\"" STR_HTML ";charset=iso-2022-jp\"");
    Packit f574b8
    #else
    Packit f574b8
    	LYAddMETAcharsetToFD(fp, -1);
    Packit f574b8
    #endif /* !_WINDOWS */
    Packit f574b8
    	fprintf(fp, "<title>%s</title>\n</head>\n", BOOKMARK_TITLE);
    Packit f574b8
    #ifdef _WINDOWS
    Packit f574b8
    	fprintf(fp,
    Packit f574b8
    		gettext("     You can delete links by the 'R' key
    \n
      \n"));
    Packit f574b8
    #else
    Packit f574b8
    	fprintf(fp, "%s
    \n%s\n\n\n\n

    \n

      \n",
    Packit f574b8
    		gettext("\
    Packit f574b8
         You can delete links using the remove bookmark command.  It is usually\n\
    Packit f574b8
         the 'R' key but may have been remapped by you or your system\n\
    Packit f574b8
         administrator."),
    Packit f574b8
    		gettext("\
    Packit f574b8
         This file also may be edited with a standard text editor to delete\n\
    Packit f574b8
         outdated or invalid links, or to change their order."),
    Packit f574b8
    		gettext("\
    Packit f574b8
    Note: if you edit this file manually\n\
    Packit f574b8
          you should not change the format within the lines\n\
    Packit f574b8
          or add other HTML markup.\n\
    Packit f574b8
          Make sure any bookmark link is saved as a single line."));
    Packit f574b8
    #endif /* _WINDOWS */
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * Add the bookmark link, in Mosaic hotlist or Lynx format.  - FM
    Packit f574b8
         */
    Packit f574b8
        if (is_mosaic_hotlist) {
    Packit f574b8
    	time_t NowTime = time(NULL);
    Packit f574b8
    	char *TimeString = (char *) ctime(&NowTime);
    Packit f574b8
    Packit f574b8
    	/*
    Packit f574b8
    	 * TimeString has a \n at the end.
    Packit f574b8
    	 */
    Packit f574b8
    	fprintf(fp, "%s %s%s\n", Address, TimeString, Title);
    Packit f574b8
        } else {
    Packit f574b8
    	fprintf(fp, "
  • %s\n", Address, Title);
  • Packit f574b8
        }
    Packit f574b8
        LYCloseOutput(fp);
    Packit f574b8
    Packit f574b8
        SetDefaultMode(O_BINARY);
    Packit f574b8
        /*
    Packit f574b8
         * If this is a cached bookmark file, set nocache for it so we'll see the
    Packit f574b8
         * new bookmark link when that cache is retrieved.  - FM
    Packit f574b8
         */
    Packit f574b8
        if (!first_time && nhist > 0 && bookmark_URL) {
    Packit f574b8
    	for (i = 0; i < nhist; i++) {
    Packit f574b8
    	    if (HDOC(i).bookmark &&
    Packit f574b8
    		!strcmp(HDOC(i).address, bookmark_URL)) {
    Packit f574b8
    		WWWDoc.address = HDOC(i).address;
    Packit f574b8
    		WWWDoc.post_data = NULL;
    Packit f574b8
    		WWWDoc.post_content_type = NULL;
    Packit f574b8
    		WWWDoc.bookmark = HDOC(i).bookmark;
    Packit f574b8
    		WWWDoc.isHEAD = FALSE;
    Packit f574b8
    		WWWDoc.safe = FALSE;
    Packit f574b8
    		tmpanchor = HTAnchor_findAddress(&WWWDoc);
    Packit f574b8
    		if ((text = (HText *) HTAnchor_document(tmpanchor)) != NULL) {
    Packit f574b8
    		    HText_setNoCache(text);
    Packit f574b8
    		}
    Packit f574b8
    		break;
    Packit f574b8
    	    }
    Packit f574b8
    	}
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * Clean up and report success.
    Packit f574b8
         */
    Packit f574b8
        BStrFree(string_data);
    Packit f574b8
        BStrFree(tmp_data);
    Packit f574b8
        FREE(Title);
    Packit f574b8
        FREE(Address);
    Packit f574b8
        FREE(bookmark_URL);
    Packit f574b8
        LYMBM_statusline(OPERATION_DONE);
    Packit f574b8
        LYSleepMsg();
    Packit f574b8
    }
    Packit f574b8
    Packit f574b8
    /*
    Packit f574b8
     * Remove a link from a bookmark file.  The calling function is expected to
    Packit f574b8
     * have used get_filename_link(), pass us the link number as cur, the
    Packit f574b8
     * MBM_A_subbookmark[] string as cur_bookmark_page, and to have set up no_cache
    Packit f574b8
     * itself.  - FM
    Packit f574b8
     */
    Packit f574b8
    void remove_bookmark_link(int cur,
    Packit f574b8
    			  char *cur_bookmark_page)
    Packit f574b8
    {
    Packit f574b8
        FILE *fp, *nfp;
    Packit f574b8
        char *buf = NULL;
    Packit f574b8
        int n;
    Packit f574b8
    Packit f574b8
    #ifdef VMS
    Packit f574b8
        char filename_buffer[NAM$C_MAXRSS + 12];
    Packit f574b8
        char newfile[NAM$C_MAXRSS + 12];
    Packit f574b8
    Packit f574b8
    #define keep_tempfile FALSE
    Packit f574b8
    #else
    Packit f574b8
        char filename_buffer[LY_MAXPATH];
    Packit f574b8
        char newfile[LY_MAXPATH];
    Packit f574b8
        BOOLEAN keep_tempfile = FALSE;
    Packit f574b8
    Packit f574b8
    #ifdef UNIX
    Packit f574b8
        struct stat stat_buf;
    Packit f574b8
        BOOLEAN regular = FALSE;
    Packit f574b8
    #endif /* UNIX */
    Packit f574b8
    #endif /* VMS */
    Packit f574b8
        char homepath[LY_MAXPATH];
    Packit f574b8
    Packit f574b8
        CTRACE((tfp, "remove_bookmark_link: deleting link number: %d\n", cur));
    Packit f574b8
    Packit f574b8
        if (!cur_bookmark_page)
    Packit f574b8
    	return;
    Packit f574b8
        LYAddPathToHome(filename_buffer,
    Packit f574b8
    		    sizeof(filename_buffer),
    Packit f574b8
    		    cur_bookmark_page);
    Packit f574b8
        CTRACE((tfp, "\nremove_bookmark_link: SEEKING %s\n   AS %s\n\n",
    Packit f574b8
    	    cur_bookmark_page, filename_buffer));
    Packit f574b8
        if ((fp = fopen(filename_buffer, TXT_R)) == NULL) {
    Packit f574b8
    	HTAlert(BOOKMARK_OPEN_FAILED_FOR_DEL);
    Packit f574b8
    	return;
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        LYAddPathToHome(homepath, sizeof(homepath), "");
    Packit f574b8
        if ((nfp = LYOpenScratch(newfile, homepath)) == 0) {
    Packit f574b8
    	LYCloseInput(fp);
    Packit f574b8
    	HTAlert(BOOKSCRA_OPEN_FAILED_FOR_DEL);
    Packit f574b8
    	return;
    Packit f574b8
        }
    Packit f574b8
    #ifdef UNIX
    Packit f574b8
        /*
    Packit f574b8
         * Explicitly preserve bookmark file mode on Unix.  - DSL
    Packit f574b8
         */
    Packit f574b8
        if (stat(filename_buffer, &stat_buf) == 0) {
    Packit f574b8
    	regular = (BOOLEAN) (S_ISREG(stat_buf.st_mode) && stat_buf.st_nlink == 1);
    Packit f574b8
    	(void) chmod(newfile, HIDE_CHMOD);
    Packit f574b8
    	if ((nfp = LYReopenTemp(newfile)) == NULL) {
    Packit f574b8
    	    (void) LYCloseInput(fp);
    Packit f574b8
    	    HTAlert(BOOKTEMP_REOPEN_FAIL_FOR_DEL);
    Packit f574b8
    	    return;
    Packit f574b8
    	}
    Packit f574b8
        }
    Packit f574b8
    #endif /* UNIX */
    Packit f574b8
    Packit f574b8
        if (is_mosaic_hotlist) {
    Packit f574b8
    	int del_line = cur * 2;	/* two lines per entry */
    Packit f574b8
    Packit f574b8
    	n = -3;			/* skip past cookie and name lines */
    Packit f574b8
    	while (LYSafeGets(&buf, fp) != NULL) {
    Packit f574b8
    	    n++;
    Packit f574b8
    	    if (n == del_line || n == del_line + 1)
    Packit f574b8
    		continue;	/* remove two lines */
    Packit f574b8
    	    if (fputs(buf, nfp) == EOF)
    Packit f574b8
    		goto failure;
    Packit f574b8
    	}
    Packit f574b8
    Packit f574b8
        } else {
    Packit f574b8
    	char *cp;
    Packit f574b8
    	BOOLEAN retain;
    Packit f574b8
    	int seen;
    Packit f574b8
    Packit f574b8
    	n = -1;
    Packit f574b8
    	while (LYSafeGets(&buf, fp) != NULL) {
    Packit f574b8
    	    int keep_ol = FALSE;
    Packit f574b8
    Packit f574b8
    	    retain = TRUE;
    Packit f574b8
    	    seen = 0;
    Packit f574b8
    	    cp = buf;
    Packit f574b8
    	    if ((cur == 0) && LYstrstr(cp, "
    1. "))
    Packit f574b8
    		keep_ol = TRUE;	/* Do not erase, this corrects a bug in an
    Packit f574b8
    				   older version */
    Packit f574b8
    	    while (n < cur && (cp = LYstrstr(cp, "
    Packit f574b8
    		seen++;
    Packit f574b8
    		if (++n == cur) {
    Packit f574b8
    		    if (seen != 1 || !LYstrstr(buf, "") ||
    Packit f574b8
    			LYstrstr((cp + 1), "
    Packit f574b8
    			HTAlert(BOOKMARK_LINK_NOT_ONE_LINE);
    Packit f574b8
    			goto failure;
    Packit f574b8
    		    }
    Packit f574b8
    		    CTRACE((tfp, "remove_bookmark_link: skipping link %d\n", n));
    Packit f574b8
    		    if (keep_ol)
    Packit f574b8
    			fprintf(nfp, "
      \n");
    Packit f574b8
    		    retain = FALSE;
    Packit f574b8
    		}
    Packit f574b8
    		cp += 8;
    Packit f574b8
    	    }
    Packit f574b8
    	    if (retain && fputs(buf, nfp) == EOF)
    Packit f574b8
    		goto failure;
    Packit f574b8
    	}
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        FREE(buf);
    Packit f574b8
        CTRACE((tfp, "remove_bookmark_link: files: %s %s\n",
    Packit f574b8
    	    newfile, filename_buffer));
    Packit f574b8
    Packit f574b8
        LYCloseInput(fp);
    Packit f574b8
        fp = NULL;
    Packit f574b8
        if (fflush(nfp) == EOF) {
    Packit f574b8
    	CTRACE((tfp, "fflush(nfp): %s", LYStrerror(errno)));
    Packit f574b8
    	goto failure;
    Packit f574b8
        }
    Packit f574b8
        LYCloseTempFP(nfp);
    Packit f574b8
        nfp = NULL;
    Packit f574b8
    #if defined(DOSPATH) || defined(__EMX__)
    Packit f574b8
        remove(filename_buffer);
    Packit f574b8
    #endif /* DOSPATH */
    Packit f574b8
    Packit f574b8
    #ifdef UNIX
    Packit f574b8
        /*
    Packit f574b8
         * By copying onto the bookmark file, rather than renaming it, we can
    Packit f574b8
         * preserve the original ownership of the file, provided that it is
    Packit f574b8
         * writable by the current process.
    Packit f574b8
         *
    Packit f574b8
         * Changed to copy 1998-04-26 -- gil
    Packit f574b8
         *
    Packit f574b8
         * But if the copy fails, for example because the filesystem is full, we
    Packit f574b8
         * are left with a corrupt bookmark file.  Changed back to use the previous
    Packit f574b8
         * mechanism [try rename(), then mv for EXDEV], except in usual cases (not
    Packit f574b8
         * a regular file e.g., symbolic link, or has hard links).  This will let
    Packit f574b8
         * bookmarks survive a filesystem full condition in the "normal" case
    Packit f574b8
         * (bookmark is on same filesystem as home directory, is a regular file,
    Packit f574b8
         * has no additional hard links).
    Packit f574b8
         *
    Packit f574b8
         * If we first tried LYCopyFile, and that fails, also fall back to trying
    Packit f574b8
         * the other stuff.  That gives a chance to recover in case the LYCopyFile
    Packit f574b8
         * left a corrupt target file.
    Packit f574b8
         *
    Packit f574b8
         * If there is an error, and that error may mean that the bookmark file has
    Packit f574b8
         * been corrupted, don't remove the temporary newfile (which should always
    Packit f574b8
         * be uncorrupted) in place, it may still be used to recover manually.  If
    Packit f574b8
         * this applies, produce an additional message to that effect.  The temp
    Packit f574b8
         * file will still be removed by normal program exit cleanup.  - kw
    Packit f574b8
         * 1999-11-12
    Packit f574b8
         */
    Packit f574b8
        if (!regular) {
    Packit f574b8
    	if (LYCopyFile(newfile, filename_buffer) == 0) {
    Packit f574b8
    	    (void) LYRemoveTemp(newfile);
    Packit f574b8
    	    return;
    Packit f574b8
    	}
    Packit f574b8
    	LYSleepAlert();		/* give a chance to see error from cp - kw */
    Packit f574b8
    	HTUserMsg(BOOKTEMP_COPY_FAIL);
    Packit f574b8
    	keep_tempfile = TRUE;
    Packit f574b8
        }
    Packit f574b8
    #endif /* UNIX */
    Packit f574b8
    Packit f574b8
        if (rename(newfile, filename_buffer) != -1) {
    Packit f574b8
    #ifdef MULTI_USER_UNIX
    Packit f574b8
    	if (regular)
    Packit f574b8
    	    chmod(filename_buffer, stat_buf.st_mode & 07777);
    Packit f574b8
    #endif
    Packit f574b8
    	HTSYS_purge(filename_buffer);
    Packit f574b8
    	return;
    Packit f574b8
        } else {
    Packit f574b8
    #ifndef VMS
    Packit f574b8
    	/*
    Packit f574b8
    	 * Rename won't work across file systems.  Check if this is the case
    Packit f574b8
    	 * and do something appropriate.  Used to be ODD_RENAME
    Packit f574b8
    	 */
    Packit f574b8
    #if defined(_WINDOWS) || defined(WIN_EX)
    Packit f574b8
    #if defined(WIN_EX)
    Packit f574b8
    	if (GetLastError() == ERROR_NOT_SAME_DEVICE)
    Packit f574b8
    #else /* !_WIN_EX */
    Packit f574b8
    	if (errno == ENOTSAM)
    Packit f574b8
    #endif /* _WIN_EX */
    Packit f574b8
    	{
    Packit f574b8
    	    if (rename(newfile, filename_buffer) != 0) {
    Packit f574b8
    		if (LYCopyFile(newfile, filename_buffer) == 0)
    Packit f574b8
    		    remove(newfile);
    Packit f574b8
    	    }
    Packit f574b8
    	}
    Packit f574b8
    #else
    Packit f574b8
    	if (errno == EXDEV) {
    Packit f574b8
    	    static const char MV_FMT[] = "%s %s %s";
    Packit f574b8
    	    char *buffer = 0;
    Packit f574b8
    	    const char *program;
    Packit f574b8
    Packit f574b8
    	    if ((program = HTGetProgramPath(ppMV)) != NULL) {
    Packit f574b8
    		HTAddParam(&buffer, MV_FMT, 1, program);
    Packit f574b8
    		HTAddParam(&buffer, MV_FMT, 2, newfile);
    Packit f574b8
    		HTAddParam(&buffer, MV_FMT, 3, filename_buffer);
    Packit f574b8
    		HTEndParam(&buffer, MV_FMT, 3);
    Packit f574b8
    		if (LYSystem(buffer) == 0) {
    Packit f574b8
    #ifdef MULTI_USER_UNIX
    Packit f574b8
    		    if (regular)
    Packit f574b8
    			chmod(filename_buffer, stat_buf.st_mode & 07777);
    Packit f574b8
    #endif
    Packit f574b8
    		    FREE(buffer);
    Packit f574b8
    		    return;
    Packit f574b8
    		}
    Packit f574b8
    	    }
    Packit f574b8
    	    FREE(buffer);
    Packit f574b8
    	    keep_tempfile = TRUE;
    Packit f574b8
    	    goto failure;
    Packit f574b8
    	}
    Packit f574b8
    	CTRACE((tfp, "rename(): %s", LYStrerror(errno)));
    Packit f574b8
    #endif /* _WINDOWS */
    Packit f574b8
    #endif /* !VMS */
    Packit f574b8
    Packit f574b8
    #ifdef VMS
    Packit f574b8
    	HTAlert(ERROR_RENAMING_SCRA);
    Packit f574b8
    #else
    Packit f574b8
    	HTAlert(ERROR_RENAMING_TEMP);
    Packit f574b8
    #endif /* VMS */
    Packit f574b8
    	if (TRACE)
    Packit f574b8
    	    perror("renaming the file");
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
      failure:
    Packit f574b8
        FREE(buf);
    Packit f574b8
        HTAlert(BOOKMARK_DEL_FAILED);
    Packit f574b8
        if (nfp)
    Packit f574b8
    	LYCloseTempFP(nfp);
    Packit f574b8
        if (fp != NULL)
    Packit f574b8
    	LYCloseInput(fp);
    Packit f574b8
        if (keep_tempfile) {
    Packit f574b8
    	HTUserMsg2(gettext("File may be recoverable from %s during this session"),
    Packit f574b8
    		   newfile);
    Packit f574b8
        } else {
    Packit f574b8
    	(void) LYRemoveTemp(newfile);
    Packit f574b8
        }
    Packit f574b8
    }
    Packit f574b8
    Packit f574b8
    /*
    Packit f574b8
     * Allows user to select sub-bookmarks files.  - FMG & FM
    Packit f574b8
     */
    Packit f574b8
    int select_multi_bookmarks(void)
    Packit f574b8
    {
    Packit f574b8
        int c;
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * If not enabled, pick the "default" (0).
    Packit f574b8
         */
    Packit f574b8
        if (LYMultiBookmarks == MBM_OFF || LYHaveSubBookmarks() == FALSE) {
    Packit f574b8
    	if (MBM_A_subbookmark[0])	/* If it exists! */
    Packit f574b8
    	    return (0);
    Packit f574b8
    	else
    Packit f574b8
    	    return (-1);
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * For ADVANCED users, we can just mess with the status line to save the 2
    Packit f574b8
         * redraws of the screen, if LYMBMAdvnced is TRUE.  '=' will still show the
    Packit f574b8
         * screen and let them do it the "long" way.
    Packit f574b8
         */
    Packit f574b8
        if (LYMultiBookmarks == MBM_ADVANCED && user_mode == ADVANCED_MODE) {
    Packit f574b8
    	LYMBM_statusline(MULTIBOOKMARKS_SELECT);
    Packit f574b8
          get_advanced_choice:
    Packit f574b8
    	c = LYgetch();
    Packit f574b8
    #ifdef VMS
    Packit f574b8
    	if (HadVMSInterrupt) {
    Packit f574b8
    	    HadVMSInterrupt = FALSE;
    Packit f574b8
    	    c = LYCharINTERRUPT2;
    Packit f574b8
    	}
    Packit f574b8
    #endif /* VMS */
    Packit f574b8
    	if (LYisNonAlnumKeyname(c, LYK_PREV_DOC) || LYCharIsINTERRUPT_HARD(c)) {
    Packit f574b8
    	    /*
    Packit f574b8
    	     * Treat left-arrow, ^G, or ^C as cancel.
    Packit f574b8
    	     */
    Packit f574b8
    	    return (-2);
    Packit f574b8
    	}
    Packit f574b8
    	if (LYisNonAlnumKeyname(c, LYK_REFRESH)) {
    Packit f574b8
    	    /*
    Packit f574b8
    	     * Refresh the screen.
    Packit f574b8
    	     */
    Packit f574b8
    	    lynx_force_repaint();
    Packit f574b8
    	    LYrefresh();
    Packit f574b8
    	    goto get_advanced_choice;
    Packit f574b8
    	}
    Packit f574b8
    	if (LYisNonAlnumKeyname(c, LYK_ACTIVATE)) {
    Packit f574b8
    	    /*
    Packit f574b8
    	     * Assume default bookmark file on ENTER or right-arrow.
    Packit f574b8
    	     */
    Packit f574b8
    	    return (MBM_A_subbookmark[0] ? 0 : -1);
    Packit f574b8
    	}
    Packit f574b8
    	switch (c) {
    Packit f574b8
    	case '=':
    Packit f574b8
    	    /*
    Packit f574b8
    	     * Get the choice via the menu.
    Packit f574b8
    	     */
    Packit f574b8
    	    return (select_menu_multi_bookmarks());
    Packit f574b8
    Packit f574b8
    	default:
    Packit f574b8
    	    /*
    Packit f574b8
    	     * Convert to an array index, act on it if valid.
    Packit f574b8
    	     * Otherwise, get another keystroke.
    Packit f574b8
    	     */
    Packit f574b8
    	    if ((c = LYMBM2index(c)) < 0) {
    Packit f574b8
    		goto get_advanced_choice;
    Packit f574b8
    	    }
    Packit f574b8
    	}
    Packit f574b8
    	/*
    Packit f574b8
    	 * See if we have a bookmark like that.
    Packit f574b8
    	 */
    Packit f574b8
    	return (MBM_A_subbookmark[c] ? c : -1);
    Packit f574b8
        } else {
    Packit f574b8
    	/*
    Packit f574b8
    	 * Get the choice via the menu.
    Packit f574b8
    	 */
    Packit f574b8
    	return (select_menu_multi_bookmarks());
    Packit f574b8
        }
    Packit f574b8
    }
    Packit f574b8
    Packit f574b8
    /*
    Packit f574b8
     * Allows user to select sub-bookmarks files.  - FMG & FM
    Packit f574b8
     */
    Packit f574b8
    int select_menu_multi_bookmarks(void)
    Packit f574b8
    {
    Packit f574b8
        int c, d, MBM_tmp_count, MBM_allow;
    Packit f574b8
        int MBM_screens, MBM_from, MBM_to, MBM_current;
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         * If not enabled, pick the "default" (0).
    Packit f574b8
         */
    Packit f574b8
        if (LYMultiBookmarks == MBM_OFF)
    Packit f574b8
    	return (0);
    Packit f574b8
    Packit f574b8
        /*
    Packit f574b8
         *        Filip M. Gieszczykiewicz (filipg@paranoia.com) & FM
    Packit f574b8
         *  ---------------------------------------------------
    Packit f574b8
         * MBM_A_subbookmark[n] - Hold values of the respective "multi_bookmarkn"
    Packit f574b8
         * in the lynxrc file.
    Packit f574b8
         *
    Packit f574b8
         * MBM_A_subdescript[n] - Hold description entries in the lynxrc file.
    Packit f574b8
         *
    Packit f574b8
         * Note: MBM_A_subbookmark[0] is defined to be same value as
    Packit f574b8
         *       "bookmark_file" in the lynxrc file and/or the startup
    Packit f574b8
         *       "bookmark_page".
    Packit f574b8
         *
    Packit f574b8
         * We make the display of bookmarks depend on rows we have available.
    Packit f574b8
         *
    Packit f574b8
         * We load BookmarkPage with the valid MBM_A_subbookmark[n] via
    Packit f574b8
         * get_bookmark_filename().  Otherwise, that function returns a zero-length
    Packit f574b8
         * string to indicate a cancel, a single space to indicate an invalid
    Packit f574b8
         * choice, or NULL to indicate an inaccessible file.
    Packit f574b8
         */
    Packit f574b8
        MBM_allow = (LYlines - 7);	/* We need 7 for header and footer */
    Packit f574b8
        /*
    Packit f574b8
         * Screen big enough?
    Packit f574b8
         */
    Packit f574b8
        if (MBM_allow <= 0) {
    Packit f574b8
    	/*
    Packit f574b8
    	 * Too small.
    Packit f574b8
    	 */
    Packit f574b8
    	HTAlert(MULTIBOOKMARKS_SMALL);
    Packit f574b8
    	return (-2);
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        MBM_screens = (MBM_V_MAXFILES / MBM_allow) + 1;	/* int rounds off low. */
    Packit f574b8
    Packit f574b8
        MBM_current = 1;		/* Gotta start somewhere :-) */
    Packit f574b8
    Packit f574b8
        for (;;) {
    Packit f574b8
    	MBM_from = MBM_allow * MBM_current - MBM_allow;
    Packit f574b8
    	if (MBM_from < 0)
    Packit f574b8
    	    MBM_from = 0;	/* 0 is default bookmark... */
    Packit f574b8
    	if (MBM_current != 1)
    Packit f574b8
    	    MBM_from++;
    Packit f574b8
    Packit f574b8
    	MBM_to = (MBM_allow * MBM_current);
    Packit f574b8
    	if (MBM_to > MBM_V_MAXFILES)
    Packit f574b8
    	    MBM_to = MBM_V_MAXFILES;
    Packit f574b8
    Packit f574b8
    	/*
    Packit f574b8
    	 * Display menu of bookmarks.  NOTE that we avoid printw()'s to
    Packit f574b8
    	 * increase the chances that any non-ASCII or multibyte/CJK characters
    Packit f574b8
    	 * will be handled properly.  - FM
    Packit f574b8
    	 */
    Packit f574b8
    	LYclear();
    Packit f574b8
    	LYmove(1, 5);
    Packit f574b8
    	lynx_start_h1_color();
    Packit f574b8
    	if (MBM_screens > 1) {
    Packit f574b8
    	    char *shead_buffer = 0;
    Packit f574b8
    Packit f574b8
    	    HTSprintf0(&shead_buffer,
    Packit f574b8
    		       MULTIBOOKMARKS_SHEAD_MASK, MBM_current, MBM_screens);
    Packit f574b8
    	    LYaddstr(shead_buffer);
    Packit f574b8
    	    FREE(shead_buffer);
    Packit f574b8
    	} else {
    Packit f574b8
    	    LYaddstr(MULTIBOOKMARKS_SHEAD);
    Packit f574b8
    	}
    Packit f574b8
    Packit f574b8
    	lynx_stop_h1_color();
    Packit f574b8
    Packit f574b8
    	MBM_tmp_count = 0;
    Packit f574b8
    	for (c = MBM_from; c <= MBM_to; c++) {
    Packit f574b8
    	    LYmove(3 + MBM_tmp_count, 5);
    Packit f574b8
    	    LYaddch((chtype) LYindex2MBM(c));
    Packit f574b8
    	    LYaddstr(" : ");
    Packit f574b8
    	    if (MBM_A_subdescript[c])
    Packit f574b8
    		LYaddstr(MBM_A_subdescript[c]);
    Packit f574b8
    	    LYmove(3 + MBM_tmp_count, 36);
    Packit f574b8
    	    LYaddch('(');
    Packit f574b8
    	    if (MBM_A_subbookmark[c])
    Packit f574b8
    		LYaddstr(MBM_A_subbookmark[c]);
    Packit f574b8
    	    LYaddch(')');
    Packit f574b8
    	    MBM_tmp_count++;
    Packit f574b8
    	}
    Packit f574b8
    Packit f574b8
    	/*
    Packit f574b8
    	 * Don't need to show it if it all fits on one screen!
    Packit f574b8
    	 */
    Packit f574b8
    	if (MBM_screens > 1) {
    Packit f574b8
    	    LYmove(LYlines - 2, 0);
    Packit f574b8
    	    LYaddstr("'");
    Packit f574b8
    	    lynx_start_bold();
    Packit f574b8
    	    LYaddstr("[");
    Packit f574b8
    	    lynx_stop_bold();
    Packit f574b8
    	    LYaddstr("' ");
    Packit f574b8
    	    LYaddstr(PREVIOUS);
    Packit f574b8
    	    LYaddstr(", '");
    Packit f574b8
    	    lynx_start_bold();
    Packit f574b8
    	    LYaddstr("]");
    Packit f574b8
    	    lynx_stop_bold();
    Packit f574b8
    	    LYaddstr("' ");
    Packit f574b8
    	    LYaddstr(NEXT_SCREEN);
    Packit f574b8
    	}
    Packit f574b8
    Packit f574b8
    	LYMBM_statusline(MULTIBOOKMARKS_SAVE);
    Packit f574b8
    Packit f574b8
    	for (;;) {
    Packit f574b8
    	    c = LYgetch();
    Packit f574b8
    #ifdef VMS
    Packit f574b8
    	    if (HadVMSInterrupt) {
    Packit f574b8
    		HadVMSInterrupt = FALSE;
    Packit f574b8
    		c = 7;
    Packit f574b8
    	    }
    Packit f574b8
    #endif /* VMS */
    Packit f574b8
    Packit f574b8
    	    if ((d = LYMBM2index(c)) >= 0) {
    Packit f574b8
    		/*
    Packit f574b8
    		 * See if we have a bookmark like that.
    Packit f574b8
    		 */
    Packit f574b8
    		if (non_empty(MBM_A_subbookmark[d]))
    Packit f574b8
    		    return (d);
    Packit f574b8
    Packit f574b8
    		show_bookmark_not_defined();
    Packit f574b8
    		LYMBM_statusline(MULTIBOOKMARKS_SAVE);
    Packit f574b8
    	    } else if (LYisNonAlnumKeyname(c, LYK_PREV_DOC) ||
    Packit f574b8
    		       c == 7 || c == 3) {
    Packit f574b8
    		/*
    Packit f574b8
    		 * Treat left-arrow, ^G, or ^C as cancel.
    Packit f574b8
    		 */
    Packit f574b8
    		return (-2);
    Packit f574b8
    	    } else if (LYisNonAlnumKeyname(c, LYK_REFRESH)) {
    Packit f574b8
    		/*
    Packit f574b8
    		 * Refresh the screen.
    Packit f574b8
    		 */
    Packit f574b8
    		lynx_force_repaint();
    Packit f574b8
    		LYrefresh();
    Packit f574b8
    	    } else if (LYisNonAlnumKeyname(c, LYK_ACTIVATE)) {
    Packit f574b8
    		/*
    Packit f574b8
    		 * Assume default bookmark file on ENTER or right-arrow.
    Packit f574b8
    		 */
    Packit f574b8
    		return (MBM_A_subbookmark[0] ? 0 : -1);
    Packit f574b8
    	    } else if ((c == ']' || LYisNonAlnumKeyname(c, LYK_NEXT_PAGE)) &&
    Packit f574b8
    		       MBM_screens > 1) {
    Packit f574b8
    		/*
    Packit f574b8
    		 * Next range, if available.
    Packit f574b8
    		 */
    Packit f574b8
    		if (++MBM_current > MBM_screens)
    Packit f574b8
    		    MBM_current = 1;
    Packit f574b8
    		break;
    Packit f574b8
    	    }
    Packit f574b8
    Packit f574b8
    	    else if ((c == '[' || LYisNonAlnumKeyname(c, LYK_PREV_PAGE)) &&
    Packit f574b8
    		     MBM_screens > 1) {
    Packit f574b8
    		/*
    Packit f574b8
    		 * Previous range, if available.
    Packit f574b8
    		 */
    Packit f574b8
    		if (--MBM_current <= 0)
    Packit f574b8
    		    MBM_current = MBM_screens;
    Packit f574b8
    		break;
    Packit f574b8
    	    }
    Packit f574b8
    	}
    Packit f574b8
        }
    Packit f574b8
    }
    Packit f574b8
    Packit f574b8
    /*
    Packit f574b8
     * This function returns TRUE if we have sub-bookmarks defined.  Otherwise
    Packit f574b8
     * (i.e., only the default bookmark file is defined), it returns FALSE.  - FM
    Packit f574b8
     */
    Packit f574b8
    BOOLEAN LYHaveSubBookmarks(void)
    Packit f574b8
    {
    Packit f574b8
        int i;
    Packit f574b8
    Packit f574b8
        for (i = 1; i < MBM_V_MAXFILES; i++) {
    Packit f574b8
    	if (non_empty(MBM_A_subbookmark[i]))
    Packit f574b8
    	    return (TRUE);
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        return (FALSE);
    Packit f574b8
    }
    Packit f574b8
    Packit f574b8
    /*
    Packit f574b8
     * This function passes a string to _statusline(), making sure it is at the
    Packit f574b8
     * bottom of the screen if LYMultiBookmarks is not MBM_OFF, otherwise, letting
    Packit f574b8
     * it go to the normal statusline position based on the current user mode.  We
    Packit f574b8
     * want to use _statusline() so that any multibyte/CJK characters in the string
    Packit f574b8
     * will be handled properly.  - FM
    Packit f574b8
     */
    Packit f574b8
    void LYMBM_statusline(const char *text)
    Packit f574b8
    {
    Packit f574b8
        if (LYMultiBookmarks != MBM_OFF && user_mode == NOVICE_MODE) {
    Packit f574b8
    	LYStatusLine = (LYlines - 1);
    Packit f574b8
    	_statusline(text);
    Packit f574b8
    	LYStatusLine = -1;
    Packit f574b8
        } else {
    Packit f574b8
    	_statusline(text);
    Packit f574b8
        }
    Packit f574b8
    }
    Packit f574b8
    Packit f574b8
    /*
    Packit f574b8
     * Check whether we have any visible (non-blank) chars.
    Packit f574b8
     */
    Packit f574b8
    static BOOLEAN havevisible(const char *Title)
    Packit f574b8
    {
    Packit f574b8
        BOOLEAN result = FALSE;
    Packit f574b8
        const char *p = Title;
    Packit f574b8
        unsigned char c;
    Packit f574b8
        long unicode;
    Packit f574b8
    Packit f574b8
        for (; *p; p++) {
    Packit f574b8
    	c = UCH(TOASCII(*p));
    Packit f574b8
    	if (c > 32 && c < 127) {
    Packit f574b8
    	    result = TRUE;
    Packit f574b8
    	    break;
    Packit f574b8
    	}
    Packit f574b8
    	if (c <= 32 || c == 127)
    Packit f574b8
    	    continue;
    Packit f574b8
    	if (LYHaveCJKCharacterSet || !UCCanUniTranslateFrom(current_char_set)) {
    Packit f574b8
    	    result = TRUE;
    Packit f574b8
    	    break;
    Packit f574b8
    	}
    Packit f574b8
    	unicode = UCTransToUni(*p, current_char_set);
    Packit f574b8
    	if (unicode == ucNeedMore)
    Packit f574b8
    	    continue;
    Packit f574b8
    	if (unicode > 32 && unicode < 127) {
    Packit f574b8
    	    result = TRUE;
    Packit f574b8
    	    break;
    Packit f574b8
    	}
    Packit f574b8
    	if (unicode <= 32 || unicode == 0xa0 || unicode == 0xad)
    Packit f574b8
    	    continue;
    Packit f574b8
    	if (unicode < 0x2000 || unicode >= 0x200f) {
    Packit f574b8
    	    result = TRUE;
    Packit f574b8
    	    break;
    Packit f574b8
    	}
    Packit f574b8
        }
    Packit f574b8
        return (result);
    Packit f574b8
    }
    Packit f574b8
    Packit f574b8
    /*
    Packit f574b8
     * Check whether string have 8 bit chars.
    Packit f574b8
     */
    Packit f574b8
    static BOOLEAN have8bit(const char *Title)
    Packit f574b8
    {
    Packit f574b8
        const char *p = Title;
    Packit f574b8
    Packit f574b8
        for (; *p; p++) {
    Packit f574b8
    	if (UCH(*p) > 127)
    Packit f574b8
    	    return (TRUE);
    Packit f574b8
        }
    Packit f574b8
        return (FALSE);		/* if we came here */
    Packit f574b8
    }
    Packit f574b8
    Packit f574b8
    /*
    Packit f574b8
     * Ok, title have 8-bit characters and they are in display charset.  Bookmarks
    Packit f574b8
     * is a permanent file.  To avoid dependencies from display character set which
    Packit f574b8
     * may be changed with time we store 8-bit characters as numeric character
    Packit f574b8
     * reference (NCR), so where the character encoded as unicode number in form of
    Packit f574b8
     * &#xUUUU;
    Packit f574b8
     *
    Packit f574b8
     * To make bookmarks more readable for human (&#xUUUU certainly not) we add a
    Packit f574b8
     * comment with '7-bit approximation' from the converted string.  This is a
    Packit f574b8
     * valid HTML and bookmarks code.
    Packit f574b8
     *
    Packit f574b8
     * We do not want use META charset tag in bookmarks file:  it will never be
    Packit f574b8
     * changed later :-(
    Packit f574b8
     *
    Packit f574b8
     * NCR's translation is part of I18N and HTML4.0 supported starting with Lynx
    Packit f574b8
     * 2.7.2, Netscape 4.0 and MSIE 4.0.  Older versions fail.
    Packit f574b8
     */
    Packit f574b8
    static char *title_convert8bit(const char *Title)
    Packit f574b8
    {
    Packit f574b8
        const char *p = Title;
    Packit f574b8
        char *p0;
    Packit f574b8
        char *q;
    Packit f574b8
        char *comment = NULL;
    Packit f574b8
        char *ncr = NULL;
    Packit f574b8
        char *buf = NULL;
    Packit f574b8
        int charset_in = current_char_set;
    Packit f574b8
        int charset_out = UCGetLYhndl_byMIME("us-ascii");
    Packit f574b8
    Packit f574b8
        for (; *p; p++) {
    Packit f574b8
    	char temp[2];
    Packit f574b8
    Packit f574b8
    	LYStrNCpy(temp, p, sizeof(temp) - 1);
    Packit f574b8
    	if (UCH(*temp) <= 127) {
    Packit f574b8
    	    StrAllocCat(comment, temp);
    Packit f574b8
    	    StrAllocCat(ncr, temp);
    Packit f574b8
    	} else if (charset_out >= 0) {
    Packit f574b8
    	    long unicode;
    Packit f574b8
    	    char replace_buf[32];
    Packit f574b8
    Packit f574b8
    	    if (UCTransCharStr(replace_buf, (int) sizeof(replace_buf), *temp,
    Packit f574b8
    			       charset_in, charset_out, YES) > 0)
    Packit f574b8
    		StrAllocCat(comment, replace_buf);
    Packit f574b8
    Packit f574b8
    	    unicode = UCTransToUni(*temp, charset_in);
    Packit f574b8
    Packit f574b8
    	    StrAllocCat(ncr, "&#");
    Packit f574b8
    	    sprintf(replace_buf, "%ld", unicode);
    Packit f574b8
    	    StrAllocCat(ncr, replace_buf);
    Packit f574b8
    	    StrAllocCat(ncr, ";");
    Packit f574b8
    	}
    Packit f574b8
        }
    Packit f574b8
    Packit f574b8
        if (comment != NULL) {
    Packit f574b8
    	/*
    Packit f574b8
    	 * Cleanup comment, collapse multiple dashes into one dash, skip '>'.
    Packit f574b8
    	 */
    Packit f574b8
    	for (q = p0 = comment; *p0; p0++) {
    Packit f574b8
    	    if (UCH(TOASCII(*p0)) >= 32 &&
    Packit f574b8
    		*p0 != '>' &&
    Packit f574b8
    		(q == comment || *p0 != '-' || *(q - 1) != '-')) {
    Packit f574b8
    		*q++ = *p0;
    Packit f574b8
    	    }
    Packit f574b8
    	}
    Packit f574b8
    	*q = '\0';
    Packit f574b8
    Packit f574b8
    	/*
    Packit f574b8
    	 * valid bookmark should be a single line (no linebreaks!).
    Packit f574b8
    	 */
    Packit f574b8
    	StrAllocCat(buf, "
    Packit f574b8
    	StrAllocCat(buf, comment);
    Packit f574b8
    	StrAllocCat(buf, " -->");
    Packit f574b8
    	StrAllocCat(buf, ncr);
    Packit f574b8
    Packit f574b8
    	FREE(comment);
    Packit f574b8
        }
    Packit f574b8
        FREE(ncr);
    Packit f574b8
        return (buf);
    Packit f574b8
    }
    Packit f574b8
    Packit f574b8
    /*
    Packit f574b8
     * Since this is the "Default Bookmark File", we save it as a global, and as
    Packit f574b8
     * the first MBM_A_subbookmark entry.
    Packit f574b8
     */
    Packit f574b8
    void set_default_bookmark_page(char *value)
    Packit f574b8
    {
    Packit f574b8
        if (value != 0) {
    Packit f574b8
    	if (bookmark_page == NULL
    Packit f574b8
    	    || strcmp(bookmark_page, value)) {
    Packit f574b8
    	    StrAllocCopy(bookmark_page, value);
    Packit f574b8
    	}
    Packit f574b8
    	StrAllocCopy(BookmarkPage, bookmark_page);
    Packit f574b8
    	StrAllocCopy(MBM_A_subbookmark[0], bookmark_page);
    Packit f574b8
    	StrAllocCopy(MBM_A_subdescript[0], MULTIBOOKMARKS_DEFAULT);
    Packit f574b8
        }
    Packit f574b8
    }