summaryrefslogtreecommitdiffstats
path: root/src/LYDownload.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/LYDownload.c')
-rw-r--r--src/LYDownload.c591
1 files changed, 591 insertions, 0 deletions
diff --git a/src/LYDownload.c b/src/LYDownload.c
new file mode 100644
index 0000000..afd6638
--- /dev/null
+++ b/src/LYDownload.c
@@ -0,0 +1,591 @@
+/* $LynxId: LYDownload.c,v 1.72 2021/07/29 20:30:00 tom Exp $ */
+#include <HTUtils.h>
+#include <HTParse.h>
+#include <HTList.h>
+#include <HTAlert.h>
+#include <LYCurses.h>
+#include <LYUtils.h>
+#include <LYGlobalDefs.h>
+#include <LYStrings.h>
+#include <LYDownload.h>
+
+#include <LYLeaks.h>
+
+/*
+ * LYDownload takes a URL and downloads it using a user selected download
+ * program
+ *
+ * It parses an incoming link that looks like
+ *
+ * LYNXDOWNLOAD://Method=<#>/File=<STRING>/SugFile=<STRING>
+ */
+#ifdef VMS
+BOOLEAN LYDidRename = FALSE;
+#endif /* VMS */
+
+static char LYValidDownloadFile[LY_MAXPATH] = "\0";
+
+void LYDownload(char *line)
+{
+ char *Line = NULL, *method, *file, *sug_file = NULL;
+ int method_number;
+ int count;
+ char *the_command = 0;
+ bstring *buffer = NULL;
+ bstring *command = NULL;
+ char *cp;
+ lynx_list_item_type *download_command = 0;
+ int ch;
+ RecallType recall;
+ int FnameTotal;
+ int FnameNum;
+ BOOLEAN FirstRecall = TRUE;
+ BOOLEAN SecondS = FALSE;
+
+#ifdef VMS
+ LYDidRename = FALSE;
+#endif /* VMS */
+
+ /*
+ * Make sure we have a valid download file comparison string loaded via the
+ * download options menu. - FM
+ */
+ if (LYValidDownloadFile[0] == '\0') {
+ goto failed;
+ }
+
+ /*
+ * Make a copy of the LYNXDOWNLOAD internal URL for parsing. - FM
+ */
+ if (StrAllocCopy(Line, line) == 0)
+ goto failed;
+
+ /*
+ * Parse out the File, sug_file, and the Method.
+ */
+ if ((file = LYstrstr(Line, "/File=")) == NULL)
+ goto failed;
+ *file = '\0';
+ /*
+ * Go past "File=".
+ */
+ file += 6;
+
+ if ((sug_file = LYstrstr(file + 1, "/SugFile=")) != NULL) {
+ *sug_file = '\0';
+ /*
+ * Go past "SugFile=".
+ */
+ sug_file += 9;
+ HTUnEscape(sug_file);
+ }
+
+ /*
+ * Make sure that the file string is the one from the last displayed
+ * download options menu. - FM
+ */
+ if (strcmp(file, LYValidDownloadFile)) {
+ goto failed;
+ }
+#if defined(DIRED_SUPPORT)
+ /* FIXME: use HTLocalName */
+ if (!StrNCmp(file, "file://localhost", 16)) {
+#ifdef __DJGPP__
+ if (!StrNCmp(file + 16, "/dev/", 5))
+ file += 16;
+ else {
+ file += 17;
+ file = HTDOS_name(file);
+ }
+#else
+ file += 16;
+#endif /* __DJGPP__ */
+ } else if (isFILE_URL(file))
+ file += LEN_FILE_URL;
+ HTUnEscape(file);
+#else
+#if defined(_WINDOWS) /* 1997/10/15 (Wed) 16:27:38 */
+ if (!StrNCmp(file, "file://localhost/", 17))
+ file += 17;
+ else if (!StrNCmp(file, "file:/", 6))
+ file += 6;
+ HTUnEscape(file);
+#endif /* _WINDOWS */
+#endif /* DIRED_SUPPORT */
+
+ if ((method = LYstrstr(Line, "Method=")) == NULL)
+ goto failed;
+ /*
+ * Go past "Method=".
+ */
+ method += 7;
+ method_number = atoi(method);
+
+ /*
+ * Set up the sug_filenames recall buffer.
+ */
+ FnameTotal = (sug_filenames ? HTList_count(sug_filenames) : 0);
+ recall = ((FnameTotal >= 1) ? RECALL_URL : NORECALL);
+ FnameNum = FnameTotal;
+
+ if (method_number < 0) {
+ /*
+ * Write to local file.
+ */
+ _statusline(FILENAME_PROMPT);
+ retry:
+ if (sug_file) {
+ BStrCopy0(buffer, sug_file);
+ } else {
+ BStrCopy0(buffer, "");
+ }
+
+ check_recall:
+ if ((ch = LYgetBString(&buffer, FALSE, 0, recall)) < 0 ||
+ isBEmpty(buffer) ||
+ ch == UPARROW_KEY ||
+ ch == DNARROW_KEY) {
+
+ if (recall && ch == UPARROW_KEY) {
+ if (FirstRecall) {
+ FirstRecall = FALSE;
+ /*
+ * Use the last Fname in the list. - FM
+ */
+ FnameNum = 0;
+ } else {
+ /*
+ * Go back to the previous Fname in the list. - FM
+ */
+ FnameNum++;
+ }
+ if (FnameNum >= FnameTotal) {
+ /*
+ * Reset the FirstRecall flag, and use sug_file or a blank.
+ * - FM
+ */
+ FirstRecall = TRUE;
+ FnameNum = FnameTotal;
+ _statusline(FILENAME_PROMPT);
+ goto retry;
+ } else if ((cp = (char *) HTList_objectAt(sug_filenames,
+ FnameNum)) != NULL) {
+ BStrCopy0(buffer, cp);
+ if (FnameTotal == 1) {
+ _statusline(EDIT_THE_PREV_FILENAME);
+ } else {
+ _statusline(EDIT_A_PREV_FILENAME);
+ }
+ goto check_recall;
+ }
+ } else if (recall && ch == DNARROW_KEY) {
+ if (FirstRecall) {
+ FirstRecall = FALSE;
+ /*
+ * Use the first Fname in the list. - FM
+ */
+ FnameNum = FnameTotal - 1;
+ } else {
+ /*
+ * Advance to the next Fname in the list. - FM
+ */
+ FnameNum--;
+ }
+ if (FnameNum < 0) {
+ /*
+ * Set the FirstRecall flag, and use sug_file or a blank.
+ * - FM
+ */
+ FirstRecall = TRUE;
+ FnameNum = FnameTotal;
+ _statusline(FILENAME_PROMPT);
+ goto retry;
+ } else if ((cp = (char *) HTList_objectAt(sug_filenames,
+ FnameNum)) != NULL) {
+ BStrCopy0(buffer, cp);
+ if (FnameTotal == 1) {
+ _statusline(EDIT_THE_PREV_FILENAME);
+ } else {
+ _statusline(EDIT_A_PREV_FILENAME);
+ }
+ goto check_recall;
+ }
+ }
+
+ /*
+ * Save cancelled.
+ */
+ goto cancelled;
+ }
+
+ BStrCopy(command, buffer);
+ if (!LYValidateFilename(&buffer, &command))
+ goto cancelled;
+#ifdef HAVE_POPEN
+ else if (LYIsPipeCommand(buffer->str)) {
+ /* I don't know how to download to a pipe */
+ HTAlert(CANNOT_WRITE_TO_FILE);
+ _statusline(NEW_FILENAME_PROMPT);
+ FirstRecall = TRUE;
+ FnameNum = FnameTotal;
+ goto retry;
+ }
+#endif
+
+ /*
+ * See if it already exists.
+ */
+ switch (LYValidateOutput(buffer->str)) {
+ case 'Y':
+ break;
+ case 'N':
+ _statusline(NEW_FILENAME_PROMPT);
+ FirstRecall = TRUE;
+ FnameNum = FnameTotal;
+ goto retry;
+ default:
+ goto cleanup;
+ }
+
+ /*
+ * See if we can write to it.
+ */
+ CTRACE((tfp, "LYDownload: filename is %s\n", buffer->str));
+
+ SecondS = TRUE;
+
+ HTInfoMsg(SAVING);
+#ifdef VMS
+ /*
+ * Try rename() first. - FM
+ */
+ CTRACE((tfp, "command: rename(%s, %s)\n", file, buffer->str));
+ if (rename(file, buffer->str)) {
+ /*
+ * Failed. Use spawned COPY_COMMAND. - FM
+ */
+ CTRACE((tfp, " FAILED!\n"));
+ LYCopyFile(file, buffer->str);
+ } else {
+ /*
+ * We don't have the temporary file (it was renamed to a permanent
+ * file), so set a flag to pop out of the download menu. - FM
+ */
+ LYDidRename = TRUE;
+ }
+ chmod(buffer->str, HIDE_CHMOD);
+#else /* Unix: */
+
+ LYCopyFile(file, buffer->str);
+ LYRelaxFilePermissions(buffer->str);
+#endif /* VMS */
+
+ } else {
+ /*
+ * Use configured download commands.
+ */
+ BStrCopy0(buffer, "");
+ for (count = 0, download_command = downloaders;
+ count < method_number;
+ count++, download_command = download_command->next) ; /* null body */
+
+ /*
+ * Commands have the form "command %s [etc]" where %s is the filename.
+ */
+ if (download_command->command != NULL) {
+ /*
+ * Check for two '%s' and ask for the local filename if there is.
+ */
+ if (HTCountCommandArgs(download_command->command) >= 2) {
+ _statusline(FILENAME_PROMPT);
+
+ again:
+ if (sug_file) {
+ BStrCopy0(buffer, sug_file);
+ } else {
+ BStrCopy0(buffer, "");
+ }
+
+ check_again:
+ if ((ch = LYgetBString(&buffer, FALSE, 0, recall)) < 0 ||
+ isBEmpty(buffer) ||
+ ch == UPARROW_KEY ||
+ ch == DNARROW_KEY) {
+
+ if (recall && ch == UPARROW_KEY) {
+ if (FirstRecall) {
+ FirstRecall = FALSE;
+ /*
+ * Use the last Fname in the list. - FM
+ */
+ FnameNum = 0;
+ } else {
+ /*
+ * Go back to the previous Fname in the list. - FM
+ */
+ FnameNum++;
+ }
+ if (FnameNum >= FnameTotal) {
+ /*
+ * Reset the FirstRecall flag, and use sug_file or
+ * a blank. - FM
+ */
+ FirstRecall = TRUE;
+ FnameNum = FnameTotal;
+ _statusline(FILENAME_PROMPT);
+ goto again;
+ } else if ((cp = (char *) HTList_objectAt(sug_filenames,
+ FnameNum))
+ != NULL) {
+ BStrCopy0(buffer, cp);
+ if (FnameTotal == 1) {
+ _statusline(EDIT_THE_PREV_FILENAME);
+ } else {
+ _statusline(EDIT_A_PREV_FILENAME);
+ }
+ goto check_again;
+ }
+ } else if (recall && ch == DNARROW_KEY) {
+ if (FirstRecall) {
+ FirstRecall = FALSE;
+ /*
+ * Use the first Fname in the list. - FM
+ */
+ FnameNum = FnameTotal - 1;
+ } else {
+ /*
+ * Advance to the next Fname in the list. - FM
+ */
+ FnameNum--;
+ }
+ if (FnameNum < 0) {
+ /*
+ * Set the FirstRecall flag, and use sug_file or a
+ * blank. - FM
+ */
+ FirstRecall = TRUE;
+ FnameNum = FnameTotal;
+ _statusline(FILENAME_PROMPT);
+ goto again;
+ } else if ((cp = (char *) HTList_objectAt(sug_filenames,
+ FnameNum))
+ != NULL) {
+ BStrCopy0(buffer, cp);
+ if (FnameTotal == 1) {
+ _statusline(EDIT_THE_PREV_FILENAME);
+ } else {
+ _statusline(EDIT_A_PREV_FILENAME);
+ }
+ goto check_again;
+ }
+ }
+
+ /*
+ * Download cancelled.
+ */
+ goto cancelled;
+ }
+
+ if (no_dotfiles || !show_dotfiles) {
+ if (*LYPathLeaf(buffer->str) == '.') {
+ HTAlert(FILENAME_CANNOT_BE_DOT);
+ _statusline(NEW_FILENAME_PROMPT);
+ goto again;
+ }
+ }
+ /*
+ * Cancel if the user entered "/dev/null" on Unix, or an "nl:"
+ * path on VMS. - FM
+ */
+ if (LYIsNullDevice(buffer->str)) {
+ goto cancelled;
+ }
+ SecondS = TRUE;
+ }
+
+ /*
+ * The following is considered a bug by the community. If the
+ * command only takes one argument on the command line, then the
+ * suggested file name is not used. It actually is not a bug at
+ * all and does as it should, putting both names on the command
+ * line.
+ */
+ count = 1;
+ HTAddParam(&the_command, download_command->command, count, file);
+ if (HTCountCommandArgs(download_command->command) > 1)
+ HTAddParam(&the_command, download_command->command, ++count, buffer->str);
+ HTEndParam(&the_command, download_command->command, count);
+
+ } else {
+ HTAlert(MISCONF_DOWNLOAD_COMMAND);
+ goto failed;
+ }
+
+ CTRACE((tfp, "command: %s\n", the_command));
+ stop_curses();
+ LYSystem(the_command);
+ FREE(the_command);
+ start_curses();
+ /* don't remove(file); */
+ }
+
+ if (SecondS == TRUE) {
+#ifdef VMS
+ if (0 == strncasecomp(buffer->str, "sys$disk:", 9)) {
+ if (0 == StrNCmp((buffer->str + 9), "[]", 2)) {
+ HTAddSugFilename(buffer->str + 11);
+ } else {
+ HTAddSugFilename(buffer->str + 9);
+ }
+ } else {
+ HTAddSugFilename(buffer->str);
+ }
+#else
+ HTAddSugFilename(buffer->str);
+#endif /* VMS */
+ }
+ goto cleanup;
+
+ failed:
+ HTAlert(CANNOT_DOWNLOAD_FILE);
+ goto cleanup;
+
+ cancelled:
+ HTInfoMsg(CANCELLING);
+
+ cleanup:
+ FREE(Line);
+ BStrFree(buffer);
+ BStrFree(command);
+ return;
+}
+
+/*
+ * Compare a filename with a given suffix, which we have set to give a rough
+ * idea of its content.
+ */
+static int SuffixIs(char *filename, const char *suffix)
+{
+ size_t have = strlen(filename);
+ size_t need = strlen(suffix);
+
+ return have > need && !strcmp(filename + have - need, suffix);
+}
+
+/*
+ * LYdownload_options writes out the current download choices to a file so that
+ * the user can select downloaders in the same way that they select all other
+ * links. Download links look like:
+ * LYNXDOWNLOAD://Method=<#>/File=<STRING>/SugFile=<STRING>
+ */
+int LYdownload_options(char **newfile, char *data_file)
+{
+ static char tempfile[LY_MAXPATH] = "\0";
+ char *downloaded_url = NULL;
+ char *sug_filename = NULL;
+ FILE *fp0;
+ lynx_list_item_type *cur_download;
+ int count;
+
+ /*
+ * Get a suggested filename.
+ */
+ StrAllocCopy(sug_filename, *newfile);
+ change_sug_filename(sug_filename);
+
+ if ((fp0 = InternalPageFP(tempfile, TRUE)) == 0)
+ return (-1);
+
+ StrAllocCopy(downloaded_url, *newfile);
+ LYLocalFileToURL(newfile, tempfile);
+
+ LYStrNCpy(LYValidDownloadFile,
+ data_file,
+ (sizeof(LYValidDownloadFile) - 1));
+ LYforce_no_cache = TRUE; /* don't cache this doc */
+
+ BeginInternalPage(fp0, DOWNLOAD_OPTIONS_TITLE, DOWNLOAD_OPTIONS_HELP);
+
+ fprintf(fp0, "<pre>\n");
+ fprintf(fp0, "<em>%s</em> %s\n",
+ gettext("Downloaded link:"),
+ downloaded_url);
+ FREE(downloaded_url);
+
+ fprintf(fp0, "<em>%s</em> %s\n",
+ gettext("Suggested file name:"),
+ sug_filename);
+
+ fprintf(fp0, "\n%s\n",
+ (user_mode == NOVICE_MODE)
+ ? gettext("Standard download options:")
+ : gettext("Download options:"));
+
+ if (!no_disk_save) {
+#if defined(DIRED_SUPPORT)
+ /*
+ * Disable save to disk option for local files.
+ */
+ if (!lynx_edit_mode)
+#endif /* DIRED_SUPPORT */
+ {
+ fprintf(fp0,
+ " <a href=\"%s//Method=-1/File=%s/SugFile=%s%s\">%s</a>\n",
+ STR_LYNXDOWNLOAD,
+ data_file,
+ NonNull(lynx_save_space),
+ sug_filename,
+ gettext("Save to disk"));
+ /*
+ * If it is not a binary file, offer the opportunity to view the
+ * downloaded temporary file (see HTSaveToFile).
+ */
+ if (SuffixIs(data_file, HTML_SUFFIX)
+ || SuffixIs(data_file, TEXT_SUFFIX)) {
+ char *target = NULL;
+ char *source = LYAddPathToSave(data_file);
+
+ LYLocalFileToURL(&target, source);
+ fprintf(fp0,
+ " <a href=\"%s\">%s</a>\n",
+ target,
+ gettext("View temporary file"));
+
+ FREE(source);
+ FREE(target);
+ }
+ }
+ } else {
+ fprintf(fp0, " <em>%s</em>\n", gettext("Save to disk disabled."));
+ }
+
+ if (user_mode == NOVICE_MODE)
+ fprintf(fp0, "\n%s\n", gettext("Local additions:"));
+
+ if (downloaders != NULL) {
+ for (count = 0, cur_download = downloaders; cur_download != NULL;
+ cur_download = cur_download->next, count++) {
+ if (!no_download || cur_download->always_enabled) {
+ fprintf(fp0,
+ " <a href=\"%s//Method=%d/File=%s/SugFile=%s\">",
+ STR_LYNXDOWNLOAD, count, data_file, sug_filename);
+ fprintf(fp0, "%s", (cur_download->name
+ ? cur_download->name
+ : gettext("No Name Given")));
+ fprintf(fp0, "</a>\n");
+ }
+ }
+ }
+
+ fprintf(fp0, "</pre>\n");
+ EndInternalPage(fp0);
+ LYCloseTempFP(fp0);
+ LYRegisterUIPage(*newfile, UIP_DOWNLOAD_OPTIONS);
+
+ /*
+ * Free off temp copy.
+ */
+ FREE(sug_filename);
+
+ return (0);
+}