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 / LYDownload.c < prev    next >
C/C++ Source or Header  |  1998-05-03  |  17KB  |  702 lines

  1. #include <HTUtils.h>
  2. #include <tcp.h>
  3. #include <HTParse.h>
  4. #include <HTList.h>
  5. #include <HTAlert.h>
  6. #include <LYCurses.h>
  7. #include <LYUtils.h>
  8. #include <LYGlobalDefs.h>
  9. #include <LYSignal.h>
  10. #include <LYStrings.h>
  11. #include <LYClean.h>
  12. #include <LYGetFile.h>
  13. #include <LYDownload.h>
  14. #include <LYSystem.h>
  15. #ifdef VMS
  16. #include <HTVMSUtils.h>
  17. #endif /* VMS */
  18. #ifdef DOSPATH
  19. #include <HTDOS.h>
  20. #endif
  21.  
  22. #include <LYexit.h>
  23. #include <LYLeaks.h>
  24.  
  25. #define FREE(x) if (x) {free(x); x = NULL;}
  26.  
  27. /*
  28.  *  LYDownload takes a URL and downloads it using a user selected
  29.  *  download program
  30.  *
  31.  *  It parses an incoming link that looks like
  32.  *
  33.  *  LYNXDOWNLOAD://Method=<#>/File=<STRING>/SugFile=<STRING>
  34.  */
  35. #ifdef VMS
  36. #define COPY_COMMAND "copy/nolog/noconf %s %s"
  37. PUBLIC BOOLEAN LYDidRename = FALSE;
  38. #endif /* VMS */
  39.  
  40. PRIVATE char LYValidDownloadFile[256] = "\0";
  41.  
  42. PUBLIC void LYDownload ARGS1(
  43.     char *,     line)
  44. {
  45.     char *Line = NULL, *method, *file, *sug_file = NULL;
  46.     int method_number;
  47.     int count;
  48.     char buffer[512];
  49.     char command[512];
  50.     char *cp, *cp1;
  51.     lynx_html_item_type *download_command = 0;
  52.     int c, len;
  53.     FILE *fp;
  54.     int ch, recall;
  55.     int FnameTotal;
  56.     int FnameNum;
  57.     BOOLEAN FirstRecall = TRUE;
  58.     BOOLEAN SecondS = FALSE;
  59. #ifdef VMS
  60.     extern BOOLEAN HadVMSInterrupt;
  61.     LYDidRename = FALSE;
  62. #endif /* VMS */
  63.  
  64.     /*
  65.      *    Make sure we have a valid download
  66.      *    file comparison string loaded via
  67.      *    the download options menu. - FM
  68.      */
  69.     if (LYValidDownloadFile[0] == '\0') {
  70.     goto failed;
  71.     }
  72.  
  73.     /*
  74.      *    Make a copy of the LYNXDOWNLOAD
  75.      *    internal URL for parsing. - FM
  76.      */
  77.     StrAllocCopy(Line, line);
  78.  
  79.     /*
  80.      *    Parse out the sug_file, Method and the File.
  81.      */
  82.     if ((sug_file = (char *)strstr(Line, "SugFile=")) != NULL) {
  83.     *(sug_file-1) = '\0';
  84.     /*
  85.      *  Go past "SugFile=".
  86.      */
  87.     sug_file += 8;
  88.     }
  89.  
  90.     if ((file = (char *)strstr(Line, "File=")) == NULL)
  91.     goto failed;
  92.     *(file-1) = '\0';
  93.     /*
  94.      *    Go past "File=".
  95.      */
  96.     file += 5;
  97.  
  98.     /*
  99.      *    Make sure that the file string is the one from
  100.      *    the last displayed download options menu. - FM
  101.      */
  102.     if (strcmp(file, LYValidDownloadFile)) {
  103.     goto failed;
  104.     }
  105.  
  106. #ifdef DIRED_SUPPORT
  107.     if (!strncmp(file, "file://localhost", 16))
  108.     file += 16;
  109.     else if (!strncmp(file, "file:", 5))
  110.     file += 5;
  111.     HTUnEscape(file);
  112. #endif /* DIRED_SUPPORT */
  113.  
  114.     if ((method = (char *)strstr(Line, "Method=")) == NULL)
  115.     goto failed;
  116.     /*
  117.      *    Go past "Method=".
  118.      */
  119.     method += 7;
  120.     method_number = atoi(method);
  121.  
  122.     /*
  123.      *    Set up the sug_filenames recall buffer.
  124.      */
  125.     FnameTotal = (sug_filenames ? HTList_count(sug_filenames) : 0);
  126.     recall = ((FnameTotal >= 1) ? RECALL : NORECALL);
  127.     FnameNum = FnameTotal;
  128.  
  129.     if (method_number < 0) {
  130.     /*
  131.      *  Write to local file.
  132.      */
  133.     _statusline(FILENAME_PROMPT);
  134. retry:
  135.     if (sug_file)
  136.         LYstrncpy(buffer, sug_file, ((sizeof(buffer)/2) - 1));
  137.     else
  138.         *buffer = '\0';
  139. check_recall:
  140.     if ((ch = LYgetstr(buffer,
  141.                VISIBLE, (sizeof(buffer)/2), recall)) < 0 ||
  142.         *buffer == '\0' || ch == UPARROW || ch == DNARROW) {
  143.         if (recall && ch == UPARROW) {
  144.         if (FirstRecall) {
  145.             FirstRecall = FALSE;
  146.             /*
  147.              *    Use the last Fname in the list. - FM
  148.              */
  149.             FnameNum = 0;
  150.         } else {
  151.             /*
  152.              *    Go back to the previous Fname in the list. - FM
  153.              */
  154.             FnameNum++;
  155.         }
  156.         if (FnameNum >= FnameTotal) {
  157.             /*
  158.              *    Reset the FirstRecall flag,
  159.              *    and use sug_file or a blank. - FM
  160.              */
  161.             FirstRecall = TRUE;
  162.             FnameNum = FnameTotal;
  163.             _statusline(FILENAME_PROMPT);
  164.             goto retry;
  165.         } else if ((cp = (char *)HTList_objectAt(
  166.                         sug_filenames,
  167.                         FnameNum)) != NULL) {
  168.             strcpy(buffer, cp);
  169.             if (FnameTotal == 1) {
  170.             _statusline(EDIT_THE_PREV_FILENAME);
  171.             } else {
  172.             _statusline(EDIT_A_PREV_FILENAME);
  173.             }
  174.             goto check_recall;
  175.         }
  176.         } else if (recall && ch == DNARROW) {
  177.         if (FirstRecall) {
  178.             FirstRecall = FALSE;
  179.             /*
  180.              *    Use the first Fname in the list. - FM
  181.              */
  182.             FnameNum = FnameTotal - 1;
  183.         } else {
  184.             /*
  185.              *    Advance to the next Fname in the list. - FM
  186.              */
  187.             FnameNum--;
  188.         }
  189.         if (FnameNum < 0) {
  190.             /*
  191.              *    Set the FirstRecall flag,
  192.              *    and use sug_file or a blank. - FM
  193.              */
  194.             FirstRecall = TRUE;
  195.             FnameNum = FnameTotal;
  196.             _statusline(FILENAME_PROMPT);
  197.             goto retry;
  198.         } else if ((cp = (char *)HTList_objectAt(
  199.                         sug_filenames,
  200.                         FnameNum)) != NULL) {
  201.             strcpy(buffer, cp);
  202.             if (FnameTotal == 1) {
  203.             _statusline(EDIT_THE_PREV_FILENAME);
  204.             } else {
  205.             _statusline(EDIT_A_PREV_FILENAME);
  206.             }
  207.             goto check_recall;
  208.         }
  209.         }
  210.  
  211.         /*
  212.          *    Save cancelled.
  213.          */
  214.         goto cancelled;
  215.     }
  216.  
  217.     if (no_dotfiles || !show_dotfiles) {
  218.       if (*buffer == '.' ||
  219. #ifdef VMS
  220.           ((cp = strrchr(buffer, ':')) && *(cp+1) == '.') ||
  221.           ((cp = strrchr(buffer, ']')) && *(cp+1) == '.') ||
  222. #endif /* VMS */
  223.           ((cp = strrchr(buffer, '/')) && *(cp+1) == '.')) {
  224.         HTAlert(FILENAME_CANNOT_BE_DOT);
  225.         _statusline(NEW_FILENAME_PROMPT);
  226.         FirstRecall = TRUE;
  227.         FnameNum = FnameTotal;
  228.         goto retry;
  229.       }
  230.     }
  231.     /*
  232.      *  Cancel if the user entered "/dev/null" on Unix,
  233.      *  or an "nl:" path (case-insensitive) on VMS. - FM
  234.      */
  235. #ifdef VMS
  236.     if (!strncasecomp(buffer, "nl:", 3) ||
  237.         !strncasecomp(buffer, "/nl/", 4))
  238. #else
  239.     if (!strcmp(buffer, "/dev/null"))
  240. #endif /* VMS */
  241.     {
  242.         goto cancelled;
  243.     }
  244.     if ((cp = strchr(buffer, '~'))) {
  245.         *(cp++) = '\0';
  246.         strcpy(command, buffer);
  247.         if ((len = strlen(command)) > 0 && command[len-1] == '/')
  248.         command[len-1] = '\0';
  249. #ifdef DOSPATH
  250.         strcat(command, HTDOS_wwwName((char *)Home_Dir()));
  251. #else
  252. #ifdef VMS
  253.         strcat(command, HTVMS_wwwName((char *)Home_Dir()));
  254. #else
  255.         strcat(command, Home_Dir());
  256. #endif /* VMS */
  257. #endif /* DOSPATH */
  258.         strcat(command, cp);
  259.         strcpy(buffer, command);
  260.     }
  261. #ifdef VMS
  262.     if (strchr(buffer, '/') != NULL) {
  263.         strcpy(command, HTVMS_name("", buffer));
  264.         strcpy(buffer, command);
  265.     }
  266.     if (buffer[0] != '/' && strchr(buffer, ':') == NULL) {
  267.         strcpy(command, "sys$disk:");
  268.         if (strchr(buffer, ']') == NULL)
  269.         strcat(command, "[]");
  270.         strcat(command, buffer);
  271.         strcpy(buffer, command);
  272.     }
  273. #else
  274. #ifndef __EMX__
  275.     if (*buffer != '/')
  276.         cp = getenv("PWD");
  277.     else
  278. #endif /* __EMX__*/
  279.         cp = NULL;
  280.     if (cp) {
  281.         sprintf(command, "%s/%s", cp, buffer);
  282. #ifdef DOSPATH
  283.         strcpy(buffer, HTDOS_name(command));
  284. #else
  285.         strcpy(buffer, command);
  286. #endif
  287.     }
  288. #endif /* VMS */
  289.  
  290.     /*
  291.      *  See if it already exists.
  292.      */
  293.     if ((fp = fopen(buffer, "r")) != NULL) {
  294.         fclose(fp);
  295.  
  296. #ifdef VMS
  297.         _statusline(FILE_EXISTS_HPROMPT);
  298. #else
  299.         _statusline(FILE_EXISTS_OPROMPT);
  300. #endif /* VMS */
  301.         c = 0;
  302.         while(TOUPPER(c)!='Y' && TOUPPER(c)!='N' && c != 7 && c != 3)
  303.         c = LYgetch();
  304. #ifdef VMS
  305.         if (HadVMSInterrupt) {
  306.         HadVMSInterrupt = FALSE;
  307.         FREE(Line);
  308.         return;
  309.         }
  310. #endif /* VMS */
  311.  
  312.         if (c == 7 || c == 3) { /* Control-G or Control-C */
  313.         goto cancelled;
  314.         }
  315.  
  316.         if (TOUPPER(c) == 'N') {
  317.         _statusline(NEW_FILENAME_PROMPT);
  318.         FirstRecall = TRUE;
  319.         FnameNum = FnameTotal;
  320.         goto retry;
  321.         }
  322.     }
  323.  
  324.     /*
  325.      *  See if we can write to it.
  326.      */
  327.     CTRACE(tfp, "LYDownload: filename is %s", buffer);
  328.  
  329.     if ((fp = fopen(buffer, "w")) != NULL) {
  330.         fclose(fp);
  331.         remove(buffer);
  332.     } else {
  333.         HTAlert(CANNOT_WRITE_TO_FILE);
  334.         _statusline(NEW_FILENAME_PROMPT);
  335.         FirstRecall = TRUE;
  336.         FnameNum = FnameTotal;
  337.         goto retry;
  338.     }
  339.     SecondS = TRUE;
  340.  
  341.     _statusline(SAVING);
  342.     sleep(InfoSecs);
  343. #ifdef VMS
  344.     /*
  345.      *  Try rename() first. - FM
  346.      */
  347.     CTRACE(tfp, "command: rename(%s, %s)\n", file, buffer);
  348.     if (rename(file, buffer)) {
  349.         /*
  350.          *    Failed.  Use spawned COPY_COMMAND. - FM
  351.          */
  352.         CTRACE(tfp, "         FAILED!\n");
  353.         sprintf(command, COPY_COMMAND, file, buffer);
  354.         CTRACE(tfp, "command: %s\n", command);
  355.         fflush(stderr);
  356.         fflush(stdout);
  357.         stop_curses();
  358.         system(command);
  359.         fflush(stdout);
  360.         fflush(stderr);
  361.         start_curses();
  362.     } else {
  363.         /*
  364.          *    We don't have the temporary file (it was renamed to
  365.          *    a permanent file), so set a flag to pop out of the
  366.          *    download menu. - FM
  367.          */
  368.         LYDidRename = TRUE;
  369.     }
  370.     chmod(buffer, HIDE_CHMOD);
  371. #else /* Unix: */
  372.     /*
  373.      *  Prevent spoofing of the shell.
  374.      */
  375. #ifndef __EMX__
  376.     cp = quote_pathname(file);
  377.     cp1 = quote_pathname(buffer);
  378.     sprintf(command, "%s %s %s", COPY_PATH, cp, cp1);
  379.     FREE(cp);
  380.     FREE(cp1);
  381. #else
  382.     sprintf(command, "%s %s %s", COPY_PATH, file, buffer);
  383. #endif /* __EMX__ */
  384.     CTRACE(tfp, "command: %s\n", command);
  385.     fflush(stderr);
  386.     fflush(stdout);
  387.     stop_curses();
  388.     system(command);
  389.     fflush(stdout);
  390.     fflush(stderr);
  391.     start_curses();
  392. #if defined(UNIX)
  393.     LYRelaxFilePermissions(buffer);
  394. #endif /* defined(UNIX) */
  395. #endif /* VMS */
  396.  
  397.     } else {
  398.     /*
  399.      *  Use configured download commands.
  400.      */
  401.     buffer[0] = '\0';
  402.     for (count = 0, download_command=downloaders;
  403.          count < method_number;
  404.          count++, download_command = download_command->next)
  405.         ; /* null body */
  406.  
  407.     /*
  408.      *  Commands have the form "command %s [etc]"
  409.      *  where %s is the filename.
  410.      */
  411.     if (download_command->command != NULL) {
  412.         /*
  413.          *    Check for two '%s' and ask for the local filename if
  414.          *    there is.
  415.          */
  416.         char *first_s = strstr(download_command->command, "%s");
  417.         if (first_s && strstr(first_s+1, "%s")) {
  418.         _statusline(FILENAME_PROMPT);
  419.     again:    if (sug_file)
  420.             strcpy(buffer, sug_file);
  421.         else
  422.             *buffer = '\0';
  423.     check_again:
  424.         if ((ch = LYgetstr(buffer, VISIBLE,
  425.                    sizeof(buffer), recall)) < 0 ||
  426.             *buffer == '\0' || ch == UPARROW || ch == DNARROW) {
  427.             if (recall && ch == UPARROW) {
  428.             if (FirstRecall) {
  429.                 FirstRecall = FALSE;
  430.                 /*
  431.                  *    Use the last Fname in the list. - FM
  432.                  */
  433.                 FnameNum = 0;
  434.             } else {
  435.                 /*
  436.                  *    Go back to the previous Fname
  437.                  *    in the list. - FM
  438.                  */
  439.                 FnameNum++;
  440.             }
  441.             if (FnameNum >= FnameTotal) {
  442.                 /*
  443.                  *    Reset the FirstRecall flag,
  444.                  *    and use sug_file or a blank. - FM
  445.                  */
  446.                 FirstRecall = TRUE;
  447.                 FnameNum = FnameTotal;
  448.                 _statusline(FILENAME_PROMPT);
  449.                 goto again;
  450.             } else if ((cp = (char *)HTList_objectAt(
  451.                             sug_filenames,
  452.                             FnameNum)) != NULL) {
  453.                 strcpy(buffer, cp);
  454.                 if (FnameTotal == 1) {
  455.                 _statusline(EDIT_THE_PREV_FILENAME);
  456.                 } else {
  457.                 _statusline(EDIT_A_PREV_FILENAME);
  458.                 }
  459.                 goto check_again;
  460.             }
  461.             } else if (recall && ch == DNARROW) {
  462.             if (FirstRecall) {
  463.                 FirstRecall = FALSE;
  464.                 /*
  465.                  *    Use the first Fname in the list. - FM
  466.                  */
  467.                 FnameNum = FnameTotal - 1;
  468.             } else {
  469.                 /*
  470.                  *    Advance to the next Fname in the list. - FM
  471.                  */
  472.                 FnameNum--;
  473.             }
  474.             if (FnameNum < 0) {
  475.                 /*
  476.                  *    Set the FirstRecall flag,
  477.                  *    and use sug_file or a blank. - FM
  478.                  */
  479.                 FirstRecall = TRUE;
  480.                 FnameNum = FnameTotal;
  481.                 _statusline(FILENAME_PROMPT);
  482.                 goto again;
  483.             } else if ((cp = (char *)HTList_objectAt(
  484.                             sug_filenames,
  485.                             FnameNum)) != NULL) {
  486.                 strcpy(buffer, cp);
  487.                 if (FnameTotal == 1) {
  488.                 _statusline(EDIT_THE_PREV_FILENAME);
  489.                 } else {
  490.                 _statusline(EDIT_A_PREV_FILENAME);
  491.                 }
  492.                 goto check_again;
  493.             }
  494.             }
  495.  
  496.             /*
  497.              * Download cancelled.
  498.              */
  499.             goto cancelled;
  500.         }
  501.  
  502.         if (no_dotfiles || !show_dotfiles) {
  503.             if (*buffer == '.' ||
  504. #ifdef VMS
  505.                ((cp = strrchr(buffer, ':')) && *(cp+1) == '.') ||
  506.                ((cp = strrchr(buffer, ']')) && *(cp+1) == '.') ||
  507. #endif /* VMS */
  508.                ((cp = strrchr(buffer, '/')) && *(cp+1) == '.')) {
  509.             HTAlert(FILENAME_CANNOT_BE_DOT);
  510.             _statusline(NEW_FILENAME_PROMPT);
  511.             goto again;
  512.             }
  513.         }
  514.         /*
  515.          *  Cancel if the user entered "/dev/null" on Unix,
  516.          *  or an "nl:" path (case-insensitive) on VMS. - FM
  517.          */
  518. #ifdef VMS
  519.         if (!strncasecomp(buffer, "nl:", 3) ||
  520.             !strncasecomp(buffer, "/nl/", 4))
  521. #else
  522.         if (!strcmp(buffer, "/dev/null"))
  523. #endif /* VMS */
  524.         {
  525.             goto cancelled;
  526.         }
  527.         SecondS = TRUE;
  528.         }
  529.  
  530.         /*
  531.          *    The following is considered a bug by the community.
  532.          *    If the command only takes one argument on the command
  533.          *    line, then the suggested file name is not used.
  534.          *    It actually is not a bug at all and does as it should,
  535.          *    putting both names on the command line.
  536.          */
  537. #ifdef VMS
  538.         sprintf(command, download_command->command, file, buffer,
  539.                  "", "", "", "", "", "", "", "", "", "");
  540. #else /* Unix: */
  541.         /*
  542.          *    Prevent spoofing of the shell.
  543.          */
  544.         cp = quote_pathname(file);
  545.         cp1 = quote_pathname(buffer);
  546.         sprintf(command, download_command->command, cp, cp1,
  547.                  "", "", "", "", "", "", "", "", "", "");
  548.         FREE(cp);
  549.         FREE(cp1);
  550. #endif /* VMS */
  551.  
  552.     } else {
  553.         _statusline(MISCONF_DOWNLOAD_COMMAND);
  554.         sleep(AlertSecs);
  555.         goto failed;
  556.     }
  557.  
  558.     CTRACE(tfp, "command: %s\n", command);
  559.     stop_curses();
  560.     fflush(stderr);
  561.     fflush(stdout);
  562.     system(command);
  563.     fflush(stderr);
  564.     fflush(stdout);
  565.     start_curses();
  566.     /* don't remove(file); */
  567.     }
  568.  
  569.     if (SecondS == TRUE) {
  570. #ifdef VMS
  571.     if (0 == strncasecomp(buffer, "sys$disk:", 9)) {
  572.         if (0 == strncmp((buffer+9), "[]", 2)) {
  573.         HTAddSugFilename(buffer+11);
  574.         } else {
  575.         HTAddSugFilename(buffer+9);
  576.         }
  577.     } else {
  578.         HTAddSugFilename(buffer);
  579.     }
  580. #else
  581.     HTAddSugFilename(buffer);
  582. #endif /* VMS */
  583.     }
  584.     FREE(Line);
  585.     return;
  586.  
  587. failed:
  588.     _statusline(CANNOT_DOWNLOAD_FILE);
  589.     sleep(AlertSecs);
  590.     FREE(Line);
  591.     return;
  592.  
  593. cancelled:
  594.     _statusline(CANCELLING);
  595.     sleep(InfoSecs);
  596.     FREE(Line);
  597.     return;
  598. }
  599.  
  600. /*
  601.  *  LYdownload_options writes out the current download choices to
  602.  *  a file so that the user can select printers in the same way that
  603.  *  they select all other links.  Download links look like:
  604.  *  LYNXDOWNLOAD://Method=<#>/File=<STRING>/SugFile=<STRING>
  605.  */
  606. PUBLIC int LYdownload_options ARGS2(
  607.     char **,    newfile,
  608.     char *,     data_file)
  609. {
  610.     static char tempfile[256];
  611.     static BOOLEAN first = TRUE;
  612.     static char download_filename[256];
  613.     char *sug_filename = NULL;
  614.     FILE *fp0;
  615.     lynx_html_item_type *cur_download;
  616.     int count;
  617.  
  618.     if (first) {
  619.     tempname(tempfile, NEW_FILE);
  620.     first = FALSE;
  621. #if defined (VMS) || defined (DOSPATH) || defined (__EMX__)
  622.         sprintf(download_filename, "file://localhost/%s", tempfile);
  623. #else
  624.         sprintf(download_filename, "file://localhost%s", tempfile);
  625. #endif /* VMS */
  626. #ifdef VMS
  627.     } else {
  628.     remove(tempfile);   /* Remove duplicates on VMS. */
  629. #endif /* VMS */
  630.     }
  631.  
  632.     /*
  633.      *    Get a suggested filename.
  634.      */
  635.     StrAllocCopy(sug_filename, *newfile);
  636.     change_sug_filename(sug_filename);
  637.  
  638.     if ((fp0 = LYNewTxtFile(tempfile)) == NULL) {
  639.     HTAlert(CANNOT_OPEN_TEMP);
  640.     return(-1);
  641.     }
  642.  
  643.     LYstrncpy(LYValidDownloadFile,
  644.           data_file,
  645.           (sizeof(LYValidDownloadFile) - 1));
  646.     StrAllocCopy(*newfile, download_filename);
  647.     LYforce_no_cache = TRUE;  /* don't cache this doc */
  648.  
  649.     fprintf(fp0, "<head>\n<title>%s</title>\n</head>\n<body>\n",
  650.          DOWNLOAD_OPTIONS_TITLE);
  651.  
  652.     fprintf(fp0,"<h1>Download Options (%s Version %s)</h1><pre>\n",
  653.                        LYNX_NAME, LYNX_VERSION);
  654.  
  655.  
  656.     fprintf(fp0, "   You have the following download choices.\n");
  657.     fprintf(fp0, "   Please select one:\n\n");
  658.  
  659.     if(!no_disk_save && !child_lynx)
  660. #ifdef DIRED_SUPPORT
  661.     /*
  662.      *  Disable save to disk option for local files.
  663.      */
  664.     if (!lynx_edit_mode)
  665. #endif /* DIRED_SUPPORT */
  666.         fprintf(fp0,"   \
  667. <a href=\"LYNXDOWNLOAD://Method=-1/File=%s/SugFile=%s%s\">Save to disk</a>\n",
  668.        data_file, (lynx_save_space ? lynx_save_space : ""), sug_filename);
  669. #ifdef DIRED_SUPPORT
  670.     else {}
  671. #endif /* DIRED_SUPPORT */
  672.     else
  673.     fprintf(fp0,"   Save to disk disabled.\n");
  674.  
  675.     if (downloaders != NULL) {
  676.     for (count = 0, cur_download = downloaders; cur_download != NULL;
  677.             cur_download = cur_download->next, count++) {
  678.         if (!no_download || cur_download->always_enabled) {
  679.         fprintf(fp0,"   \
  680. <a href=\"LYNXDOWNLOAD://Method=%d/File=%s/SugFile=%s\">",
  681.                 count,data_file, sug_filename);
  682.         fprintf(fp0, (cur_download->name ?
  683.                 cur_download->name : "No Name Given"));
  684.         fprintf(fp0,"</a>\n");
  685.         }
  686.     }
  687.     } else {
  688.     fprintf(fp0, "\n\
  689. No other download methods have been defined yet.  You may define\n\
  690. an unlimited number of download methods using the lynx.cfg file.\n");
  691.     }
  692.     fprintf(fp0, "</pre>\n</body>\n");
  693.     fclose(fp0);
  694.  
  695.     /*
  696.      *    Free off temp copy.
  697.      */
  698.     FREE(sug_filename);
  699.  
  700.     return(0);
  701. }
  702.