]> sjero.net Git - wget/blobdiff - src/ftp.c
[svn] Update copyright notices.
[wget] / src / ftp.c
index e9b686097cd28c3c980c7f6c9d60cfa4de60fee8..f48f1beb583ef329143b105f75cc57d188b303d1 100644 (file)
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -1,20 +1,21 @@
 /* File Transfer Protocol support.
-   Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001
+   Free Software Foundation, Inc.
 
-This file is part of Wget.
+This file is part of GNU Wget.
 
-This program is free software; you can redistribute it and/or modify
+GNU Wget is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
+GNU Wget is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
+along with Wget; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include <config.h>
@@ -114,6 +115,7 @@ getftp (struct urlinfo *u, long *len, long restval, ccon *con)
   FILE *fp;
   char *user, *passwd, *respline;
   char *tms, *tmrate;
+  struct wget_timer *timer;
   unsigned char pasv_addr[6];
   int cmd = con->cmd;
   int passive_mode_open = 0;
@@ -132,8 +134,6 @@ getftp (struct urlinfo *u, long *len, long restval, ccon *con)
   passwd = u->passwd;
   search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
   user = user ? user : opt.ftp_acc;
-  if (!opt.ftp_pass)
-    opt.ftp_pass = ftp_getaddress ();
   passwd = passwd ? passwd : opt.ftp_pass;
   assert (user && passwd);
 
@@ -298,6 +298,29 @@ Error in server response, closing control connection.\n"));
          abort ();
          break;
        }
+      /* VMS will report something like "PUB$DEVICE:[INITIAL.FOLDER]".
+         Convert it to "/INITIAL/FOLDER" */ 
+      if (con->rs == ST_VMS)
+        {
+          char *path = strchr (con->id, '[');
+         char *pathend = path ? strchr (path + 1, ']') : NULL;
+         if (!path || !pathend)
+           DEBUGP (("Initial VMS directory not in the form [...]!\n"));
+         else
+           {
+             char *idir = con->id;
+             DEBUGP (("Preprocessing the initial VMS directory\n"));
+             DEBUGP (("  old = '%s'\n", con->id));
+             /* We do the conversion in-place by copying the stuff
+                between [ and ] to the beginning, and changing dots
+                to slashes at the same time.  */
+             *idir++ = '/';
+             for (++path; path < pathend; path++, idir++)
+               *idir = *path == '.' ? '/' : *path;
+             *idir = '\0';
+             DEBUGP (("  new = '%s'\n\n", con->id));
+           }
+       }
       if (!opt.server_response)
        logputs (LOG_VERBOSE, _("done.\n"));
 
@@ -349,56 +372,55 @@ Error in server response, closing control connection.\n"));
        logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));
       else
        {
-         /* Change working directory. If the FTP host runs VMS and
-             the path specified is absolute, we will have to convert
-             it to VMS style as VMS does not like leading slashes */
+         char *target = u->dir;
+
          DEBUGP (("changing working directory\n"));
-         if (*(u->dir) == '/')
+
+         /* Change working directory.  To change to a non-absolute
+            Unix directory, we need to prepend initial directory
+            (con->id) to it.  Absolute directories "just work".  */
+
+         if (*target != '/')
            {
-             int pwd_len = strlen (con->id);
-             char *result = (char *)alloca (strlen (u->dir) + pwd_len + 10);
-             *result = '\0';
-             switch (con->rs)
-               {
-               case ST_VMS:
-                 {
-                   char *tmp_dir, *tmpp;
-                   STRDUP_ALLOCA (tmp_dir, u->dir);
-                   for (tmpp = tmp_dir; *tmpp; tmpp++)
-                     if (*tmpp=='/')
-                       *tmpp = '.';
-                   strcpy (result, con->id);
-                   /* pwd ends with ']', we have to get rid of it */
-                   result[pwd_len - 1]= '\0';
-                   strcat (result, tmp_dir);
-                   strcat (result, "]");
-                 }
-                 break;
-               case ST_UNIX:
-               case ST_WINNT:
-               case ST_MACOS:
-                 /* pwd_len == 1 means pwd = "/", but u->dir begins with '/'
-                    already */
-                 if (pwd_len > 1)
-                   strcpy (result, con->id);
-                 strcat (result, u->dir);
-                 DEBUGP(("\npwd=\"%s\"", con->id));
-                 DEBUGP(("\nu->dir=\"%s\"", u->dir));
-                 break;
-               default:
-                 abort ();
-                 break;
-               }
-             if (!opt.server_response)
-               logprintf (LOG_VERBOSE, "==> CWD %s ... ", result);
-             err = ftp_cwd (&con->rbuf, result);
+             int idlen = strlen (con->id);
+             char *ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
+             /* idlen == 1 means con->id = "/" */
+             sprintf (ntarget, "%s%s%s", con->id, idlen == 1 ? "" : "/",
+                      target);
+              DEBUGP (("Prepended initial PWD to relative path:\n"));
+              DEBUGP (("  old: '%s'\n  new: '%s'\n", target, ntarget));
+             target = ntarget;
            }
-         else
+
+         /* If the FTP host runs VMS, we will have to convert the absolute
+             directory path in UNIX notation to absolute directory path in
+             VMS notation as VMS FTP servers do not like UNIX notation of
+             absolute paths.  "VMS notation" is [dir.subdir.subsubdir]. */
+
+         if (con->rs == ST_VMS)
            {
-             if (!opt.server_response)
-               logprintf (LOG_VERBOSE, "==> CWD %s ... ", u->dir);
-             err = ftp_cwd (&con->rbuf, u->dir);
+             char *tmpp;
+             char *ntarget = (char *)alloca (strlen (target) + 2);
+             /* We use a converted initial dir, so directories in
+                 TARGET will be separated with slashes, something like
+                 "/INITIAL/FOLDER/DIR/SUBDIR".  Convert that to
+                 "[INITIAL.FOLDER.DIR.SUBDIR]".  */
+             strcpy (ntarget, target);
+             assert (*ntarget == '/');
+             *ntarget = '[';
+             for (tmpp = ntarget + 1; *tmpp; tmpp++)
+               if (*tmpp == '/')
+                 *tmpp = '.';
+             *tmpp++ = ']';
+             *tmpp = '\0';
+              DEBUGP (("Changed file name to VMS syntax:\n"));
+              DEBUGP (("  Unix: '%s'\n  VMS: '%s'\n", target, ntarget));
+             target = ntarget;
            }
+
+         if (!opt.server_response)
+           logprintf (LOG_VERBOSE, "==> CWD %s ... ", target);
+         err = ftp_cwd (&con->rbuf, target);
          /* FTPRERR, WRITEFAILED, FTPNSFOD */
          switch (err)
            {
@@ -838,6 +860,7 @@ Error in server response, closing control connection.\n"));
       if (restval)
        logprintf (LOG_VERBOSE, _(" [%s to go]"), legible (*len - restval));
       logputs (LOG_VERBOSE, "\n");
+      expected_bytes = *len;   /* for get_contents/show_progress */
     }
   else if (expected_bytes)
     {
@@ -847,10 +870,11 @@ Error in server response, closing control connection.\n"));
                   legible (expected_bytes - restval));
       logputs (LOG_VERBOSE, _(" (unauthoritative)\n"));
     }
-  reset_timer ();
+  timer = wtimer_new ();
   /* Get the contents of the document.  */
   res = get_contents (dtsock, fp, len, restval, expected_bytes, &con->rbuf, 0);
-  con->dltime = elapsed_time ();
+  con->dltime = wtimer_elapsed (timer);
+  wtimer_delete (timer);
   tms = time_str (NULL);
   tmrate = rate (*len - restval, con->dltime, 0);
   /* Close data connection socket.  */
@@ -966,7 +990,7 @@ Error in server response, closing control connection.\n"));
 static uerr_t
 ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
 {
-  int count, orig_lp, no_truncate;
+  int count, orig_lp;
   long restval, len;
   char *tms, *tmrate, *locf;
   uerr_t err;
@@ -997,13 +1021,6 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
 
   orig_lp = con->cmd & LEAVE_PENDING ? 1 : 0;
 
-  /* In `-c' is used, check whether the file we're writing to exists
-     before we've done anything.  If so, we'll refuse to truncate it
-     if the server doesn't support continued downloads.  */
-  no_truncate = 0;
-  if (opt.always_rest)
-    no_truncate = file_exists_p (locf);
-
   /* THE loop.  */
   do
     {
@@ -1030,8 +1047,7 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
          else
            con->cmd |= DO_CWD;
        }
-      if (no_truncate)
-       con->cmd |= NO_TRUNCATE;
+
       /* Assume no restarting.  */
       restval = 0L;
       if ((count > 1 || opt.always_rest)
@@ -1039,6 +1055,14 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
          && file_exists_p (locf))
        if (stat (locf, &st) == 0 && S_ISREG (st.st_mode))
          restval = st.st_size;
+
+      /* In `-c' is used, check whether the file we're writing to
+        exists and is of non-zero length.  If so, we'll refuse to
+        truncate it if the server doesn't support continued
+        downloads.  */
+      if (opt.always_rest && restval > 0)
+       con->cmd |= NO_TRUNCATE;
+
       /* Get the current time string.  */
       tms = time_str (NULL);
       /* Print fetch message, if opt.verbose.  */
@@ -1465,14 +1489,24 @@ ftp_retrieve_dirs (struct urlinfo *u, struct fileinfo *f, ccon *con)
       if (f->type != FT_DIRECTORY)
        continue;
       odir = u->dir;
-      len = 1 + strlen (u->dir) + 1 + strlen (f->name) + 1;
+      len = strlen (u->dir) + 1 + strlen (f->name) + 1;
       /* Allocate u->dir off stack, but reallocate only if a larger
          string is needed.  */
       if (len > current_length)
        current_container = (char *)alloca (len);
       u->dir = current_container;
-      sprintf (u->dir, "/%s%s%s", odir + (*odir == '/'),
-             (!*odir || (*odir == '/' && !* (odir + 1))) ? "" : "/", f->name);
+      if (*odir == '\0'
+         || (*odir == '/' && *(odir + 1) == '\0'))
+       /* If ODIR is empty or just "/", simply append f->name to
+          ODIR.  (In the former case, to preserve u->dir being
+          relative; in the latter case, to avoid double slash.)  */
+       sprintf (u->dir, "%s%s", odir, f->name);
+      else
+       /* Else, use a separator. */
+       sprintf (u->dir, "%s/%s", odir, f->name);
+      DEBUGP (("Composing new CWD relative to the initial directory.\n"));
+      DEBUGP (("  odir = '%s'\n  f->name = '%s'\n  u->dir = '%s'\n\n",
+              odir, f->name, u->dir));
       if (!accdir (u->dir, ALLABS))
        {
          logprintf (LOG_VERBOSE, _("\