home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / lynx2.8.1dev.10.tar.gz / lynx2.8.1dev.10.tar / lynx2-8 / src / LYBookmark.c < prev    next >
C/C++ Source or Header  |  1998-05-02  |  24KB  |  944 lines

  1. #include <HTUtils.h>
  2. #include <tcp.h>
  3. #include <HTAlert.h>
  4. #include <LYUtils.h>
  5. #include <LYStrings.h>
  6. #include <LYBookmark.h>
  7. #include <LYGlobalDefs.h>
  8. #include <LYSignal.h>
  9. #include <LYSystem.h>
  10. #include <LYKeymap.h>
  11. #include <LYCharUtils.h>
  12. #include <LYCurses.h>
  13. #include <GridText.h>
  14.  
  15. #ifdef DOSPATH
  16. #include <HTDOS.h>
  17. #endif
  18. #ifdef VMS
  19. #include <HTVMSUtils.h>
  20. #include <nam.h>
  21. extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */
  22. #endif /* VMS */
  23.  
  24. #include <LYLeaks.h>
  25.  
  26. #define FREE(x) if (x) {free(x); x = NULL;}
  27.  
  28. PUBLIC char *MBM_A_subbookmark[MBM_V_MAXFILES+1];
  29. PUBLIC char *MBM_A_subdescript[MBM_V_MAXFILES+1];
  30.  
  31. PRIVATE BOOLEAN is_mosaic_hotlist = FALSE;
  32. PRIVATE char * convert_mosaic_bookmark_file PARAMS((char *filename_buffer));
  33.  
  34. /*
  35.  *  Tries to open a bookmark file for reading, which may be
  36.  *  the default, or based on offering the user a choice from
  37.  *  the MBM_A_subbookmark[] array.  If successful the file is
  38.  *  closed, and the filename in system path specs is returned,
  39.  *  the URL is allocated into *URL, and the MBM_A_subbookmark[]
  40.  *  filepath is allocated into the BookmarkPage global.  Returns
  41.  *  a zero-length pointer to flag a cancel, or a space to flag
  42.  *  an undefined selection, without allocating into *URL or
  43.  *  BookmarkPage.  Returns NULL with allocating into BookmarkPage
  44.  *  but not *URL is the selection is valid but the file doesn't
  45.  *  yet exist. - FM
  46.  */
  47. PUBLIC char * get_bookmark_filename ARGS1(
  48.     char **,    URL)
  49. {
  50.     char URL_buffer[256];
  51.     static char filename_buffer[256];
  52.     char string_buffer[256];
  53.     FILE *fp;
  54.     int MBM_tmp;
  55.  
  56.     /*
  57.      *    Multi_Bookmarks support. - FMG & FM
  58.      *    Let user select a bookmark file.
  59.      */
  60.     MBM_tmp = select_multi_bookmarks();
  61.     if (MBM_tmp == -2)
  62.     /*
  63.      *  Zero-length pointer flags a cancel. - FM
  64.      */
  65.     return("");
  66.     if (MBM_tmp == -1) {
  67.     sprintf(string_buffer,
  68.         BOOKMARK_FILE_NOT_DEFINED,
  69.         key_for_func(LYK_OPTIONS));
  70.     _statusline(string_buffer);
  71.     sleep(AlertSecs);
  72.     /*
  73.      *  Space flags an undefined selection. - FMG
  74.      */
  75.     return(" ");
  76.     } else {
  77.     /*
  78.      *  Save the filepath as a global.  The system path will be
  79.      *  loaded into to the (static) filename_buffer as the return
  80.      *  value, the URL will be allocated into *URL, and we also
  81.      *  need the filepath available to calling functions.  This
  82.      *  is all pitifully non-reentrant, a la the original Lynx,
  83.      *  and should be redesigned someday. - FM
  84.      */
  85.     StrAllocCopy(BookmarkPage, MBM_A_subbookmark[MBM_tmp]);
  86.     }
  87.  
  88.     /*
  89.      *    Seek it in the home path. - FM
  90.      */
  91.     filename_buffer[255] = '\0';
  92.     LYAddPathToHome(filename_buffer,
  93.             sizeof(filename_buffer),
  94.             BookmarkPage);
  95.     CTRACE(tfp, "\nget_bookmark_filename: SEEKING %s\n   AS %s\n\n",
  96.         BookmarkPage, filename_buffer);
  97.     if ((fp = fopen(filename_buffer,"r")) != NULL) {
  98.     goto success;
  99.     }
  100.  
  101.     /*
  102.      *    Failure.
  103.      */
  104.     return(NULL);
  105.  
  106. success:
  107.     /*
  108.      *    We now have the file open.
  109.      *    Check if it is a mosaic hotlist.
  110.      */
  111.     if (fgets(string_buffer, 255, fp) &&
  112.     !strncmp(string_buffer, "ncsa-xmosaic-hotlist-format-1", 29)) {
  113.     char *newname;
  114.     /*
  115.      *  It is a mosaic hotlist file.
  116.      */
  117.     is_mosaic_hotlist = TRUE;
  118.     fclose(fp);
  119.     newname = convert_mosaic_bookmark_file(filename_buffer);
  120. #ifdef DOSPATH
  121.     sprintf(URL_buffer, "file://localhost/%s",
  122.         HTDOS_wwwName((char *)newname));
  123. #else
  124. #ifdef VMS
  125.     sprintf(URL_buffer,"file://localhost%s",
  126.         HTVMS_wwwName((char *)newname));
  127. #else
  128. #ifdef __EMX__
  129.     sprintf(URL_buffer,"file://localhost/%s", newname);
  130. #else
  131.     sprintf(URL_buffer,"file://localhost%s", newname);
  132. #endif /* __EMX__ */
  133. #endif /* VMS */
  134. #endif /* DOSPATH */
  135.     } else {
  136.     fclose(fp);
  137.     is_mosaic_hotlist = FALSE;
  138. #ifdef DOSPATH
  139.     sprintf(URL_buffer,"file://localhost/%s",
  140.         HTDOS_wwwName((char *)filename_buffer));
  141. #else
  142. #ifdef VMS
  143.     sprintf(URL_buffer,"file://localhost%s",
  144.         HTVMS_wwwName((char *)filename_buffer));
  145. #else
  146. #ifdef __EMX__
  147.     sprintf(URL_buffer,"file://localhost/%s", filename_buffer);
  148. #else
  149.     sprintf(URL_buffer,"file://localhost%s", filename_buffer);
  150. #endif /* __EMX__ */
  151. #endif /* VMS */
  152. #endif /* DOSPATH */
  153.     }
  154.  
  155.     StrAllocCopy(*URL, URL_buffer);
  156.     return(filename_buffer);  /* bookmark file exists */
  157.  
  158. } /* big end */
  159.  
  160. /*
  161.  *  Converts a Mosaic hotlist file into an HTML
  162.  *  file for handling as a Lynx bookmark file. - FM
  163.  */
  164. PRIVATE char * convert_mosaic_bookmark_file ARGS1(
  165.     char *,     filename_buffer)
  166. {
  167.     static char newfile[256];
  168.     static BOOLEAN first = TRUE;
  169.     FILE *fp, *nfp;
  170.     char buf[BUFSIZ];
  171.     int line = -2;
  172.     char *endline;
  173.  
  174.     if (first) {
  175.     tempname(newfile, NEW_FILE);
  176.     first = FALSE;
  177. #ifdef VMS
  178.     } else {
  179.     remove(newfile);   /* Remove duplicates on VMS. */
  180. #endif /* VMS */
  181.     }
  182.  
  183.     if ((nfp = fopen(newfile, "w")) == NULL) {
  184.     LYMBM_statusline(NO_TEMP_FOR_HOTLIST);
  185.     sleep(AlertSecs);
  186.     return ("");
  187.     }
  188.  
  189.     if ((fp = fopen(filename_buffer, "r")) == NULL)
  190.     return ("");  /* should always open */
  191.  
  192.     fprintf(nfp,"<head>\n<title>%s</title>\n</head>\n",MOSAIC_BOOKMARK_TITLE);
  193.     fprintf(nfp,"\
  194.      This file is an HTML representation of the X Mosaic hotlist file.\n\
  195.      Outdated or invalid links may be removed by using the\n\
  196.      remove bookmark command, it is usually the 'R' key but may have\n\
  197.      been remapped by you or your system administrator.\n\n<p>\n<ol>\n");
  198.  
  199.     while (fgets(buf, sizeof(buf), fp) != NULL) {
  200.     if(line >= 0) {
  201.         endline = &buf[strlen(buf)-1];
  202.         if(*endline == '\n')
  203.         *endline = '\0';
  204.         if((line % 2) == 0) { /* even lines */
  205.         if(*buf != '\0') {
  206.             strtok(buf," "); /* kill everything after the space */
  207.             fprintf(nfp,"<LI><a href=\"%s\">",buf); /* the URL */
  208.         }
  209.         } else { /* odd lines */
  210.         fprintf(nfp,"%s</a>\n",buf);  /* the title */
  211.         }
  212.     }
  213.     /* else - ignore the line (this gets rid of first two lines) */
  214.     line++;
  215.     }
  216.     fclose(nfp);
  217.     fclose(fp);
  218.     return(newfile);
  219. }
  220.  
  221. /*
  222.  *  Adds a link to a bookmark file, creating the file
  223.  *  if it doesn't already exist, and making sure that
  224.  *  no_cache is set for a pre-existing, cached file,
  225.  *  so that the change will be evident on return to
  226.  *  to that file. - FM
  227.  */
  228. PUBLIC void save_bookmark_link ARGS2(
  229.     char *,     address,
  230.     char *,     title)
  231. {
  232.     FILE *fp;
  233.     BOOLEAN first_time = FALSE;
  234.     char *filename;
  235.     char *bookmark_URL = NULL;
  236.     char filename_buffer[256];
  237.     char string_buffer[256];
  238.     char *Address = NULL;
  239.     char *Title = NULL;
  240.     int i, c;
  241.     DocAddress WWWDoc;
  242.     HTParentAnchor *tmpanchor;
  243.     HText *text;
  244.  
  245.     /*
  246.      *    Make sure we were passed something to save. - FM
  247.      */
  248.     if (!(address && *address)) {
  249.     HTAlert(MALFORMED_ADDRESS);
  250.     return;
  251.     }
  252.  
  253.     /*
  254.      *    Offer a choice of bookmark files,
  255.      *    or get the default. - FMG
  256.      */
  257.     filename = get_bookmark_filename(&bookmark_URL);
  258.  
  259.     /*
  260.      *    If filename is NULL, must create a new file.  If
  261.      *    filename is a space, an invalid bookmark file was
  262.      *    selected, or if zero-length, the user cancelled.
  263.      *    Ignore request in both cases.  Otherwise, make
  264.      *    a copy before anything might change the static
  265.      *    get_bookmark_filename() buffer. - FM
  266.      */
  267.     if (filename == NULL) {
  268.     first_time = TRUE;
  269.     filename_buffer[0] = '\0';
  270.     } else {
  271.     if (*filename == '\0' || !strcmp(filename," ")) {
  272.         FREE(bookmark_URL);
  273.         return;
  274.     }
  275.     strcpy(filename_buffer, filename);
  276.     }
  277.  
  278.     /*
  279.      *    If BookmarkPage is NULL, something went
  280.      *    wrong, so ignore the request. - FM
  281.      */
  282.     if (BookmarkPage == NULL) {
  283.     FREE(bookmark_URL);
  284.     return;
  285.     }
  286.  
  287.     /*
  288.      *    If the link will be added to the same
  289.      *    bookmark file, get confirmation. - FM
  290.      */
  291.     if (LYMultiBookmarks == TRUE &&
  292.     strstr(HTLoadedDocumentURL(),
  293.            (*BookmarkPage == '.' ?
  294.             (BookmarkPage+1) : BookmarkPage)) != NULL) {
  295.     LYMBM_statusline(MULTIBOOKMARKS_SELF);
  296.     c = LYgetch();
  297.     if (TOUPPER(c) != 'L') {
  298.         FREE(bookmark_URL);
  299.         return;
  300.     }
  301.     }
  302.  
  303.     /*
  304.      *    Allow user to change the title. - FM
  305.      */
  306.     string_buffer[255] = '\0';
  307.     LYstrncpy(string_buffer, title, 255);
  308.     convert_to_spaces(string_buffer, FALSE);
  309.     LYMBM_statusline(TITLE_PROMPT);
  310.     LYgetstr(string_buffer, VISIBLE, sizeof(string_buffer), NORECALL);
  311.     if (*string_buffer == '\0') {
  312.     LYMBM_statusline(CANCELLED);
  313.     sleep(MessageSecs);
  314.     FREE(bookmark_URL);
  315.     return;
  316.     }
  317.  
  318.     /*
  319.      *    Create the Title with any left-angle-brackets
  320.      *    converted to < entities and any ampersands
  321.      *    converted to & entities.  - FM
  322.      */
  323.     StrAllocCopy(Title, string_buffer);
  324.     LYEntify(&Title, TRUE);
  325.  
  326.     /*
  327.      *    Create the bookmark file, if it doesn't exist already,
  328.      *    Otherwise, open the pre-existing bookmark file. - FM
  329.      */
  330. #if defined(__DJGPP__) || defined(_WINDOWS)
  331.     _fmode = O_TEXT;
  332. #endif /* __DJGPP__  or _WINDOWS */
  333.     if (first_time) {
  334.     /*
  335.      *  Seek it in the home path. - FM
  336.      */
  337.     LYAddPathToHome(filename_buffer,
  338.             sizeof(filename_buffer),
  339.             BookmarkPage);
  340.     }
  341.     CTRACE(tfp, "\nsave_bookmark_link: SEEKING %s\n   AS %s\n\n",
  342.         BookmarkPage, filename_buffer);
  343.     if ((fp = fopen(filename_buffer, (first_time ? "w" : "a+"))) == NULL) {
  344.     LYMBM_statusline(BOOKMARK_OPEN_FAILED);
  345.     sleep(AlertSecs);
  346.     FREE(bookmark_URL);
  347.     return;
  348.     }
  349.  
  350.     /*
  351.      *    Convert all ampersands in the address to & entities. - FM
  352.      */
  353.     StrAllocCopy(Address, address);
  354.     LYEntify(&Address, FALSE);
  355.  
  356.     /*
  357.      *    If we created a new bookmark file, write the headers. - FM
  358.      */
  359.     if (first_time) {
  360.     fprintf(fp,"<head>\n");
  361.     LYAddMETAcharsetToFD(fp, -1);
  362.     fprintf(fp,"<title>%s</title>\n</head>\n",BOOKMARK_TITLE);
  363.     fprintf(fp,"\
  364.      You can delete links using the remove bookmark command.  It is usually\n\
  365.      the 'R' key but may have been remapped by you or your system\n\
  366.      administrator.<br>\n\
  367.      This file also may be edited with a standard text editor to delete\n\
  368.      outdated or invalid links, or to change their order, but you should\n\
  369.      not change the format within the lines or add other HTML markup.\n\n\
  370.      <p>\n<ol>\n");
  371.     }
  372.  
  373.     /*
  374.      *    Add the bookmark link, in Mosaic hotlist or Lynx format. - FM
  375.      */
  376.     if (is_mosaic_hotlist) {
  377.     time_t NowTime = time(NULL);
  378.     char *TimeString = (char *)ctime (&NowTime);
  379.     /*
  380.      *  TimeString has a \n at the end.
  381.      */
  382.     fprintf(fp,"%s %s%s\n", Address, TimeString, Title);
  383.     } else {
  384.     fprintf(fp,"<LI><a href=\"%s\">%s</a>\n", Address, Title);
  385.     }
  386.     fclose(fp);
  387.  
  388. #if defined(__DJGPP__) || defined(_WINDOWS)
  389.     _fmode = O_BINARY;
  390. #endif /* __DJGPP__ or _WINDOWS */
  391.     /*
  392.      *    If this is a cached bookmark file, set nocache for
  393.      *    it so we'll see the new bookmark link when that
  394.      *    cache is retrieved. - FM
  395.      */
  396.     if (!first_time && nhist > 0 && bookmark_URL) {
  397.     for (i = 0; i < nhist; i++) {
  398.         if (history[i].bookmark &&
  399.         !strcmp(history[i].address, bookmark_URL)) {
  400.         WWWDoc.address = history[i].address;
  401.         WWWDoc.post_data = NULL;
  402.         WWWDoc.post_content_type = NULL;
  403.         WWWDoc.bookmark = history[i].bookmark;
  404.         WWWDoc.isHEAD = FALSE;
  405.         WWWDoc.safe = FALSE;
  406.         if (((tmpanchor = HTAnchor_parent(
  407.                     HTAnchor_findAddress(&WWWDoc)
  408.                          )) != NULL) &&
  409.             (text = (HText *)HTAnchor_document(tmpanchor)) != NULL) {
  410.             HText_setNoCache(text);
  411.         }
  412.         break;
  413.         }
  414.     }
  415.     }
  416.  
  417.     /*
  418.      *    Clean up and report success.
  419.      */
  420.     FREE(Title);
  421.     FREE(Address);
  422.     FREE(bookmark_URL);
  423.     LYMBM_statusline(OPERATION_DONE);
  424.     sleep(MessageSecs);
  425. }
  426.  
  427. /*
  428.  *  Remove a link from a bookmark file.  The calling
  429.  *  function is expected to have used get_filename_link(),
  430.  *  pass us the link number as cur, the MBM_A_subbookmark[]
  431.  *  string as cur_bookmark_page, and to have set up no_cache
  432.  *  itself. - FM
  433.  */
  434. PUBLIC void remove_bookmark_link ARGS2(
  435.     int,        cur,
  436.     char *,     cur_bookmark_page)
  437. {
  438.     FILE *fp, *nfp;
  439.     char buf[BUFSIZ];
  440.     int n;
  441. #ifdef VMS
  442.     char filename_buffer[NAM$C_MAXRSS+12];
  443.     char newfile[NAM$C_MAXRSS+12];
  444. #else
  445.     char filename_buffer[256];
  446.     char newfile[256];
  447.     struct stat stat_buf;
  448.     mode_t mode;
  449. #endif /* VMS */
  450.  
  451.     CTRACE(tfp, "remove_bookmark_link: deleting link number: %d\n", cur);
  452.  
  453.     if (!cur_bookmark_page)
  454.     return;
  455.     LYAddPathToHome(filename_buffer,
  456.             sizeof(filename_buffer),
  457.             cur_bookmark_page);
  458.     CTRACE(tfp, "\nremove_bookmark_link: SEEKING %s\n   AS %s\n\n",
  459.         cur_bookmark_page, filename_buffer);
  460.     if ((fp = fopen(filename_buffer, "r")) == NULL) {
  461.     _statusline(BOOKMARK_OPEN_FAILED_FOR_DEL);
  462.     sleep(AlertSecs);
  463.     return;
  464.     }
  465.  
  466. #ifdef VMS
  467.     sprintf(newfile, "%s-%d", filename_buffer, getpid());
  468. #else
  469.     tempname(newfile, NEW_FILE);
  470. #endif /* VMS */
  471.     if ((nfp = LYNewTxtFile(newfile)) == NULL) {
  472.     fclose(fp);
  473. #ifdef VMS
  474.     _statusline(BOOKSCRA_OPEN_FAILED_FOR_DEL);
  475. #else
  476.     _statusline(BOOKTEMP_OPEN_FAILED_FOR_DEL);
  477. #endif /* VMS */
  478.     sleep(AlertSecs);
  479.     return;
  480.     }
  481.  
  482. #ifdef UNIX
  483.     /*
  484.      *    Explicitly preserve bookmark file mode on Unix. - DSL
  485.      */
  486.     if (stat(filename_buffer, &stat_buf) == 0) {
  487.     mode = ((stat_buf.st_mode & 0777) | 0600); /* make it writable */
  488.     (void) fclose(nfp);
  489.     nfp = NULL;
  490.     (void) chmod(newfile, mode);
  491.     if ((nfp = fopen(newfile, "a")) == NULL) {
  492.         (void) fclose(fp);
  493.         _statusline(BOOKTEMP_REOPEN_FAIL_FOR_DEL);
  494.         sleep(AlertSecs);
  495.         return;
  496.     }
  497.     }
  498. #endif /* UNIX */
  499.  
  500.     if (is_mosaic_hotlist) {
  501.     int del_line = cur*2;  /* two lines per entry */
  502.     n = -3;  /* skip past cookie and name lines */
  503.     while (fgets(buf, sizeof(buf), fp) != NULL) {
  504.         n++;
  505.         if (n == del_line || n == del_line+1)
  506.         continue;  /* remove two lines */
  507.         if (fputs(buf, nfp) == EOF)
  508.         goto failure;
  509.     }
  510.  
  511.     } else {
  512.     char *cp;
  513.     BOOLEAN retain;
  514.     int seen;
  515.  
  516.     n = -1;
  517.     while (fgets(buf, sizeof(buf), fp) != NULL) {
  518.         retain = TRUE;
  519.         seen = 0;
  520.         cp = buf;
  521.         while (n < cur && (cp = LYstrstr(cp, "<a href="))) {
  522.         seen++;
  523.         if (++n == cur) {
  524.             if (seen != 1 || !LYstrstr(buf, "</a>") ||
  525.             LYstrstr((cp + 1), "<a href=")) {
  526.             _statusline(BOOKMARK_LINK_NOT_ONE_LINE);
  527.             sleep(AlertSecs);
  528.             goto failure;
  529.             }
  530.             CTRACE(tfp, "remove_bookmark_link: skipping link %d\n", n);
  531.             retain = FALSE;
  532.         }
  533.         cp += 8;
  534.         }
  535.         if (retain && fputs(buf, nfp) == EOF)
  536.         goto failure;
  537.     }
  538.     }
  539.  
  540.     CTRACE(tfp, "remove_bookmark_link: files: %s %s\n",
  541.             newfile, filename_buffer);
  542.  
  543.     fclose(fp);
  544.     fp = NULL;
  545.     fclose(nfp);
  546.     nfp = NULL;
  547. #ifdef DOSPATH
  548.     remove(filename_buffer);
  549. #endif /* DOSPATH */
  550.  
  551. #ifdef UNIX
  552.     /*
  553.      *    By copying onto the bookmark file, rather than renaming it, we
  554.      *    can preserve the original ownership of the file, provided that
  555.      *    it is writable by the current process.
  556.      *    Changed to copy  1998-04-26 -- gil
  557.      */
  558.     {   char buffer[3072];
  559.  
  560.     sprintf(buffer, "%s %s %s && %s %s",
  561.         COPY_PATH, newfile, filename_buffer,
  562.         RM_PATH, newfile);
  563.  
  564.     CTRACE(tfp, "remove_bookmark_link: %s\n", buffer);
  565.     if( system( buffer ) ) {
  566.         _statusline(BOOKTEMP_COPY_FAIL);
  567.         sleep(AlertSecs);
  568.     } else {
  569.         return;
  570.     }
  571.     }
  572. #else  /* UNIX */
  573.     if (rename(newfile, filename_buffer) != -1) {
  574. #ifdef VMS
  575.     char VMSfilename[256];
  576.     /*
  577.      *  Purge lower version of file.
  578.      */
  579.     sprintf(VMSfilename, "%s;-1", filename_buffer);
  580.     while (remove(VMSfilename) == 0)
  581.         ;
  582.     /*
  583.      *  Reset version number.
  584.      */
  585.     sprintf(VMSfilename, "%s;1", filename_buffer);
  586.     rename(filename_buffer, VMSfilename);
  587. #endif /* VMS */
  588.     return;
  589.     } else {
  590. #ifndef VMS
  591.     /*
  592.      *  Rename won't work across file systems.
  593.      *  Check if this is the case and do something appropriate.
  594.      *  Used to be ODD_RENAME
  595.      */
  596. #ifdef _WINDOWS
  597.     if (errno == ENOTSAM)
  598. #else
  599.     if (errno == EXDEV)
  600. #endif /* WINDOWS */
  601.     {
  602.         char buffer[2048];
  603.         sprintf(buffer, "%s %s %s", MV_PATH, newfile, filename_buffer);
  604.         system(buffer);
  605.         return;
  606.     }
  607. #endif /* !VMS */
  608.  
  609. #ifdef VMS
  610.     _statusline(ERROR_RENAMING_SCRA);
  611. #else
  612.     _statusline(ERROR_RENAMING_TEMP);
  613. #endif /* VMS */
  614.     if (TRACE)
  615.         perror("renaming the file");
  616.     sleep(AlertSecs);
  617.     }
  618. #endif /* UNIX */
  619.  
  620. failure:
  621.     _statusline(BOOKMARK_DEL_FAILED);
  622.     sleep(AlertSecs);
  623.     if (nfp != NULL)
  624.     fclose(nfp);
  625.     if (fp != NULL)
  626.     fclose(fp);
  627.     remove(newfile);
  628. }
  629.  
  630. /*
  631.  *  Allows user to select sub-bookmarks files. - FMG & FM
  632.  */
  633. PUBLIC int select_multi_bookmarks NOARGS
  634. {
  635.     int c;
  636.  
  637.     /*
  638.      *    If not enabled, pick the "default" (0).
  639.      */
  640.     if (LYMultiBookmarks == FALSE || LYHaveSubBookmarks() == FALSE) {
  641.     if (MBM_A_subbookmark[0]) /* If it exists! */
  642.         return(0);
  643.     else
  644.         return(-1);
  645.     }
  646.  
  647.     /*
  648.      *    For ADVANCED users, we can just mess with the status line to save
  649.      *    the 2 redraws of the screen, if LYMBMAdvnced is TRUE.  '=' will
  650.      *    still show the screen and let them do it the "long" way.
  651.      */
  652.     if (LYMBMAdvanced && user_mode == ADVANCED_MODE) {
  653.     LYMBM_statusline(MULTIBOOKMARKS_SELECT);
  654. get_advanced_choice:
  655.     c = LYgetch();
  656. #ifdef VMS
  657.     if (HadVMSInterrupt) {
  658.         HadVMSInterrupt = FALSE;
  659.         c = 7;
  660.     }
  661. #endif /* VMS */
  662.     if (LYisNonAlnumKeyname(c, LYK_PREV_DOC) ||
  663.         c == 7 || c == 3) {
  664.         /*
  665.          *    Treat left-arrow, ^G, or ^C as cancel.
  666.          */
  667.         return(-2);
  668.     }
  669.     if (LYisNonAlnumKeyname(c, LYK_REFRESH)) {
  670.         /*
  671.          *    Refresh the screen.
  672.          */
  673.         lynx_force_repaint();
  674.         refresh();
  675.         goto get_advanced_choice;
  676.     }
  677.     if (LYisNonAlnumKeyname(c, LYK_ACTIVATE)) {
  678.         /*
  679.          *    Assume default bookmark file on ENTER or right-arrow.
  680.          */
  681.         return (MBM_A_subbookmark[0] ? 0 : -1);
  682.     }
  683.     switch (c) {
  684.         case '=':
  685.         /*
  686.          *  Get the choice via the menu.
  687.          */
  688.         return(select_menu_multi_bookmarks());
  689.  
  690.         default:
  691.         /*
  692.          *  Convert to an array index, act on it if valid.
  693.          *  Otherwise, get another keystroke.
  694.          */
  695.         c = TOUPPER(c) - 'A';
  696.         if (c < 0 || c > MBM_V_MAXFILES) {
  697.             goto get_advanced_choice;
  698.         }
  699.     }
  700.     /*
  701.      *  See if we have a bookmark like that.
  702.      */
  703.     return (MBM_A_subbookmark[c] ? c : -1);
  704.     } else {
  705.     /*
  706.      *  Get the choice via the menu.
  707.      */
  708.     return(select_menu_multi_bookmarks());
  709.     }
  710. }
  711.  
  712. /*
  713.  *  Allows user to select sub-bookmarks files. - FMG & FM
  714.  */
  715. PUBLIC int select_menu_multi_bookmarks NOARGS
  716. {
  717.     int c, MBM_tmp_count, MBM_allow;
  718.     int MBM_screens, MBM_from, MBM_to, MBM_current;
  719.     char string_buffer[256];
  720.     char shead_buffer[256];
  721.  
  722.     /*
  723.      *    If not enabled, pick the "default" (0).
  724.      */
  725.     if (LYMultiBookmarks == FALSE)
  726.     return(0);
  727.  
  728.     /*
  729.      *    Filip M. Gieszczykiewicz (filipg@paranoia.com) & FM
  730.      *    ---------------------------------------------------
  731.      *    LYMultiBookmarks - TRUE when multi_support enabled.
  732.      *
  733.      *    MBM_A_subbookmark[n] - Hold values of the respective
  734.      *    "multi_bookmarkn" in the lynxrc file.
  735.      *
  736.      *    MBM_A_subdescript[n] - Hold description entries in the
  737.      *    lynxrc file.
  738.      *
  739.      *    Note: MBM_A_subbookmark[0] is defined to be same value as
  740.      *          "bookmark_file" in the lynxrc file and/or the startup
  741.      *          "bookmark_page".
  742.      *
  743.      *    We make the display of bookmarks depend on rows we have
  744.      *    available.
  745.      *
  746.      *    We load BookmarkPage with the valid MBM_A_subbookmark[n]
  747.      *    via get_bookmark_filename().  Otherwise, that function
  748.      *    returns a zero-length string to indicate a cancel, a
  749.      *    single space to indicate an invalid choice, or NULL to
  750.      *    indicate an inaccessible file.
  751.      */
  752.     MBM_allow=(LYlines-7);    /* We need 7 for header and footer */
  753.     /*
  754.      *    Screen big enough?
  755.      */
  756.     if (MBM_allow <= 0) {
  757.     /*
  758.      *  Too small.
  759.      */
  760.     _statusline(MULTIBOOKMARKS_SMALL);
  761.     sleep(AlertSecs);
  762.     return (-2);
  763.     }
  764.     /*
  765.      *    Load the bad choice message buffer.
  766.      */
  767.     sprintf(string_buffer,
  768.         BOOKMARK_FILE_NOT_DEFINED,
  769.         key_for_func(LYK_OPTIONS));
  770.  
  771.     MBM_screens = (MBM_V_MAXFILES/MBM_allow)+1; /* int rounds off low. */
  772.  
  773.     MBM_current = 1; /* Gotta start somewhere :-) */
  774.  
  775. draw_bookmark_choices:
  776.     MBM_from = MBM_allow * MBM_current - MBM_allow;
  777.     if (MBM_from < 0)
  778.     MBM_from = 0; /* 0 is default bookmark... */
  779.     if (MBM_current != 1)
  780.     MBM_from++;
  781.  
  782.     MBM_to = (MBM_allow * MBM_current);
  783.     if (MBM_to > MBM_V_MAXFILES)
  784.     MBM_to = MBM_V_MAXFILES;
  785.  
  786.     /*
  787.      *    Display menu of bookmarks.  NOTE that we avoid printw()'s
  788.      *    to increase the chances that any non-ASCII or multibyte/CJK
  789.      *    characters will be handled properly. - FM
  790.      */
  791.     clear();
  792.     move(1, 5);
  793.     lynx_start_h1_color ();
  794.     if (MBM_screens > 1) {
  795.     sprintf(shead_buffer,
  796.         MULTIBOOKMARKS_SHEAD_MASK, MBM_current, MBM_screens);
  797.     addstr(shead_buffer);
  798.     } else {
  799.     addstr(MULTIBOOKMARKS_SHEAD);
  800.     }
  801.  
  802.    lynx_stop_h1_color ();
  803.  
  804.     MBM_tmp_count = 0;
  805.     for (c = MBM_from; c <= MBM_to; c++) {
  806.     move(3+MBM_tmp_count, 5);
  807.     addch((unsigned char)(c + 'A'));
  808.     addstr(" : ");
  809.     if (MBM_A_subdescript[c])
  810.         addstr(MBM_A_subdescript[c]);
  811.     move(3+MBM_tmp_count,36);
  812.     addch('(');
  813.     if (MBM_A_subbookmark[c])
  814.         addstr(MBM_A_subbookmark[c]);
  815.     addch(')');
  816.     MBM_tmp_count++;
  817.     }
  818.  
  819.     /*
  820.      *    Don't need to show it if it all fits on one screen!
  821.      */
  822.     if (MBM_screens > 1) {
  823.     move(LYlines-2, 0);
  824.     addstr("'");
  825.     standout();
  826.     addstr("[");
  827.     standend();
  828.     addstr("' ");
  829.     addstr(PREVIOUS);
  830.     addstr(", '");
  831.     standout();
  832.     addstr("]");
  833.     standend();
  834.     addstr("' ");
  835.     addstr(NEXT_SCREEN);
  836.     }
  837.  
  838.     LYMBM_statusline(MULTIBOOKMARKS_SAVE);
  839. get_bookmark_choice:
  840.     c = LYgetch();
  841. #ifdef VMS
  842.     if (HadVMSInterrupt) {
  843.     HadVMSInterrupt = FALSE;
  844.     c = 7;
  845.     }
  846. #endif /* VMS */
  847.  
  848.     if (LYisNonAlnumKeyname(c, LYK_PREV_DOC) ||
  849.     c == 7 || c == 3) {
  850.     /*
  851.      *  Treat left-arrow, ^G, or ^C as cancel.
  852.      */
  853.     return(-2);
  854.     }
  855.  
  856.     if (LYisNonAlnumKeyname(c, LYK_REFRESH)) {
  857.     /*
  858.      *  Refresh the screen.
  859.      */
  860.     lynx_force_repaint();
  861.     refresh();
  862.     goto get_bookmark_choice;
  863.     }
  864.  
  865.     if (LYisNonAlnumKeyname(c, LYK_ACTIVATE)) {
  866.     /*
  867.      *  Assume default bookmark file on ENTER or right-arrow.
  868.      */
  869.     return(MBM_A_subbookmark[0] ? 0 : -1);
  870.     }
  871.  
  872.     /*
  873.      *    Next range, if available.
  874.      */
  875.     if ((c == ']' ||  LYisNonAlnumKeyname(c, LYK_NEXT_PAGE)) &&
  876.     MBM_screens > 1) {
  877.     if (++MBM_current > MBM_screens)
  878.         MBM_current = 1;
  879.     goto draw_bookmark_choices;
  880.     }
  881.  
  882.     /*
  883.      *    Previous range, if available.
  884.      */
  885.     if ((c == '[' ||  LYisNonAlnumKeyname(c, LYK_PREV_PAGE)) &&
  886.     MBM_screens > 1) {
  887.     if (--MBM_current <= 0)
  888.         MBM_current = MBM_screens;
  889.     goto draw_bookmark_choices;
  890.     }
  891.  
  892.     c = TOUPPER(c) - 'A';
  893.     /*
  894.      *    See if we have a bookmark like that.
  895.      */
  896.     if (c < 0 || c > MBM_V_MAXFILES) {
  897.     goto get_bookmark_choice;
  898.     } else if (!MBM_A_subbookmark[c]) {
  899.     LYMBM_statusline(string_buffer);
  900.     sleep(AlertSecs);
  901.     LYMBM_statusline(MULTIBOOKMARKS_SAVE);
  902.     goto get_bookmark_choice;
  903.     } else {
  904.     return(c);
  905.     }
  906. }
  907.  
  908. /*
  909.  *  This function returns TRUE if we have sub-bookmarks defined.
  910.  *  Otherwise (i.e., only the default bookmark file is defined),
  911.  *  it returns FALSE. - FM
  912.  */
  913. PUBLIC BOOLEAN LYHaveSubBookmarks NOARGS
  914. {
  915.     int i;
  916.  
  917.     for (i = 1; i < MBM_V_MAXFILES; i++) {
  918.     if (MBM_A_subbookmark[i] != NULL && *MBM_A_subbookmark[i] != '\0')
  919.         return(TRUE);
  920.     }
  921.  
  922.     return(FALSE);
  923. }
  924.  
  925. /*
  926.  *  This function passes a string to _statusline(), making
  927.  *  sure it is at the bottom of the screen if LYMultiBookmarks
  928.  *  is TRUE, otherwise, letting it go to the normal statusline
  929.  *  position based on the current user mode.  We want to use
  930.  *  _statusline() so that any multibyte/CJK characters in the
  931.  *  string will be handled properly. - FM
  932.  */
  933.  PUBLIC void LYMBM_statusline  ARGS1(
  934.     char *,     text)
  935. {
  936.     if (LYMultiBookmarks == TRUE && user_mode == NOVICE_MODE) {
  937.     LYStatusLine = (LYlines - 1);
  938.     _statusline(text);
  939.     LYStatusLine = -1;
  940.     } else {
  941.     _statusline(text);
  942.     }
  943. }
  944.