]> sjero.net Git - wget/blobdiff - src/ftp.c
[svn] Removed ftpparse dependencies. New parser for VMS listings. MacOS
[wget] / src / ftp.c
index aa283cf8fbbc554799f39185b164a54c38b6d327..80573a4ff40633f08776100e447b4df51d323160 100644 (file)
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -33,6 +33,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/types.h>
 #include <assert.h>
 #include <errno.h>
+#ifndef WINDOWS
+# include <netdb.h>            /* for h_errno */
+#endif
 
 #include "wget.h"
 #include "utils.h"
@@ -49,7 +52,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 extern int errno;
 #endif
 #ifndef h_errno
+# ifndef __CYGWIN__
 extern int h_errno;
+# endif
 #endif
 
 /* File where the "ls -al" listing will be saved.  */
@@ -103,7 +108,7 @@ ftp_expected_bytes (const char *s)
    connection to the server.  It always closes the data connection,
    and closes the control connection in case of error.  */
 static uerr_t
-getftp (const struct urlinfo *u, long *len, long restval, ccon *con)
+getftp (struct urlinfo *u, long *len, long restval, ccon *con)
 {
   int csock, dtsock, res;
   uerr_t err;
@@ -129,7 +134,7 @@ getftp (const struct urlinfo *u, long *len, long restval, ccon *con)
   search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
   user = user ? user : opt.ftp_acc;
   if (!opt.ftp_pass)
-    opt.ftp_pass = xstrdup (ftp_getaddress ());
+    opt.ftp_pass = ftp_getaddress ();
   passwd = passwd ? passwd : opt.ftp_pass;
   assert (user && passwd);
 
@@ -240,7 +245,63 @@ Error in server response, closing control connection.\n"));
          exit (1);
          break;
        }
-      /* Third: Set type to Image (binary).  */
+      /* Third: Get the system type */
+      if (!opt.server_response)
+       logprintf (LOG_VERBOSE, "==> SYST ... ");
+      err = ftp_syst (&con->rbuf, &con->rs);
+      /* FTPRERR */
+      switch (err)
+       {
+       case FTPRERR:
+         logputs (LOG_VERBOSE, "\n");
+         logputs (LOG_NOTQUIET, _("\
+Error in server response, closing control connection.\n"));
+         CLOSE (csock);
+         rbuf_uninitialize (&con->rbuf);
+         return err;
+         break;
+       case FTPSRVERR:
+         logputs (LOG_VERBOSE, "\n");
+         logputs (LOG_NOTQUIET,
+                  _("Server error, can't determine system type.\n"));
+         break;
+       case FTPOK:
+         /* Everything is OK.  */
+         break;
+       default:
+         abort ();
+         break;
+       }
+      if (!opt.server_response)
+       logputs (LOG_VERBOSE, _("done.    "));
+
+      /* Fourth: Find the initial ftp directory */
+
+      if (!opt.server_response)
+       logprintf (LOG_VERBOSE, "==> PWD ... ");
+      err = ftp_pwd(&con->rbuf, &con->id);
+      /* FTPRERR */
+      switch (err)
+      {
+       case FTPRERR || FTPSRVERR :
+         logputs (LOG_VERBOSE, "\n");
+         logputs (LOG_NOTQUIET, _("\
+Error in server response, closing control connection.\n"));
+         CLOSE (csock);
+         rbuf_uninitialize (&con->rbuf);
+         return err;
+         break;
+       case FTPOK:
+         /* Everything is OK.  */
+         break;
+       default:
+         abort ();
+         break;
+      }
+      if (!opt.server_response)
+       logputs (LOG_VERBOSE, _("done.\n"));
+
+      /* Fifth: Set the FTP type.  */
       if (!opt.server_response)
        logprintf (LOG_VERBOSE, "==> TYPE %c ... ", TOUPPER (u->ftp_type));
       err = ftp_type (&con->rbuf, TOUPPER (u->ftp_type));
@@ -288,10 +349,56 @@ Error in server response, closing control connection.\n"));
        logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));
       else
        {
-         /* Change working directory.  */
-         if (!opt.server_response)
-           logprintf (LOG_VERBOSE, "==> CWD %s ... ", u->dir);
-         err = ftp_cwd (&con->rbuf, u->dir);
+         /* 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 */
+         DEBUGP (("changing working directory\n"));
+         if (*(u->dir) == '/')
+           {
+             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);
+           }
+         else
+           {
+             if (!opt.server_response)
+               logprintf (LOG_VERBOSE, "==> CWD %s ... ", u->dir);
+             err = ftp_cwd (&con->rbuf, u->dir);
+           }
          /* FTPRERR, WRITEFAILED, FTPNSFOD */
          switch (err)
            {
@@ -724,7 +831,7 @@ Error in server response, closing control connection.\n"));
   res = get_contents (dtsock, fp, len, restval, expected_bytes, &con->rbuf, 0);
   con->dltime = elapsed_time ();
   tms = time_str (NULL);
-  tmrate = rate (*len - restval, con->dltime);
+  tmrate = rate (*len - restval, con->dltime, 0);
   /* Close data connection socket.  */
   closeport (dtsock);
   /* Close the local file.  */
@@ -763,7 +870,7 @@ Error in server response, closing control connection.\n"));
   rbuf_discard (&con->rbuf);
   if (err != FTPOK)
     {
-      free (respline);
+      xfree (respline);
       /* The control connection is decidedly closed.  Print the time
         only if it hasn't already been printed.  */
       if (res != -1)
@@ -783,13 +890,13 @@ Error in server response, closing control connection.\n"));
      become apparent later.  */
   if (*respline != '2')
     {
-      free (respline);
+      xfree (respline);
       if (res != -1)
        logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
       logputs (LOG_NOTQUIET, _("Data transfer aborted.\n"));
       return FTPRETRINT;
     }
-  free (respline);
+  xfree (respline);
 
   if (res == -1)
     {
@@ -821,7 +928,7 @@ Error in server response, closing control connection.\n"));
          while ((line = read_whole_line (fp)))
            {
              logprintf (LOG_ALWAYS, "%s\n", line);
-             free (line);
+             xfree (line);
            }
          fclose (fp);
        }
@@ -838,8 +945,6 @@ Error in server response, closing control connection.\n"));
 static uerr_t
 ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
 {
-  static int first_retrieval = 1;
-
   int count, orig_lp;
   long restval, len;
   char *tms, *tmrate, *locf;
@@ -876,23 +981,7 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
     {
       /* Increment the pass counter.  */
       ++count;
-      /* Wait before the retrieval (unless this is the very first
-        retrieval).
-        Check if we are retrying or not, wait accordingly - HEH */
-      if (!first_retrieval && (opt.wait || (count && opt.waitretry)))
-       {
-         if (count)
-           {
-             if (count<opt.waitretry)
-               sleep(count);
-             else
-               sleep(opt.waitretry);
-           }
-         else
-           sleep (opt.wait);
-       }
-      if (first_retrieval)
-       first_retrieval = 0;
+      sleep_between_retrievals (count);
       if (con->st & ON_YOUR_OWN)
        {
          con->cmd = 0;
@@ -935,7 +1024,7 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
 #ifdef WINDOWS
          ws_changetitle (hurl, 1);
 #endif
-         free (hurl);
+         xfree (hurl);
        }
       /* Send getftp the proper length, if fileinfo was provided.  */
       if (f)
@@ -945,7 +1034,7 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
       err = getftp (u, &len, restval, con);
       /* Time?  */
       tms = time_str (NULL);
-      tmrate = rate (len - restval, con->dltime);
+      tmrate = rate (len - restval, con->dltime, 0);
 
       if (!rbuf_initialized_p (&con->rbuf))
        con->st &= ~DONE_CWD;
@@ -1003,7 +1092,7 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
          char *hurl = str_url (u->proxy ? u->proxy : u, 1);
          logprintf (LOG_NONVERBOSE, "%s URL: %s [%ld] -> \"%s\" [%d]\n",
                     tms, hurl, len, locf, count);
-         free (hurl);
+         xfree (hurl);
        }
 
       if ((con->cmd & DO_LIST))
@@ -1080,7 +1169,7 @@ ftp_get_listing (struct urlinfo *u, ccon *con)
   err = ftp_loop_internal (u, NULL, con);
   u->local = olocal;
   if (err == RETROK)
-    f = ftp_parse_ls (list_filename);
+    f = ftp_parse_ls (list_filename, con->rs);
   else
     f = NULL;
   if (opt.remove_listing)
@@ -1090,7 +1179,7 @@ ftp_get_listing (struct urlinfo *u, ccon *con)
       else
        logprintf (LOG_VERBOSE, _("Removed `%s'.\n"), list_filename);
     }
-  free (list_filename);
+  xfree (list_filename);
   con->cmd &= ~DO_LIST;
   return f;
 }
@@ -1162,7 +1251,7 @@ ftp_retrieve_list (struct urlinfo *u, struct fileinfo *f, ccon *con)
 
       dlthis = 1;
       if (opt.timestamping && f->type == FT_PLAINFILE)
-       {
+        {
          struct stat st;
          /* If conversion of HTML files retrieved via FTP is ever implemented,
             we'll need to stat() <file>.orig here when -K has been specified.
@@ -1171,21 +1260,38 @@ ftp_retrieve_list (struct urlinfo *u, struct fileinfo *f, ccon *con)
             .orig suffix. */
          if (!stat (u->local, &st))
            {
+              int eq_size;
+              int cor_val;
              /* Else, get it from the file.  */
              local_size = st.st_size;
              tml = st.st_mtime;
-             if (local_size == f->size && tml >= f->tstamp)
+              /* Compare file sizes only for servers that tell us correct
+                 values. Assumme sizes being equal for servers that lie
+                 about file size.  */
+              cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT);
+              eq_size = cor_val ? (local_size == f->size) : 1 ;
+             if (f->tstamp <= tml && eq_size)
                {
-                 logprintf (LOG_VERBOSE, _("\
-Server file no newer than local file `%s' -- not retrieving.\n\n"), u->local);
+                 /* Remote file is older, file sizes can be compared and
+                     are both equal. */
+                  logprintf (LOG_VERBOSE, _("\
+Remote file no newer than local file `%s' -- not retrieving.\n"), u->local);
                  dlthis = 0;
                }
-             else if (local_size != f->size)
-               {
-                 logprintf (LOG_VERBOSE, _("\
-The sizes do not match (local %ld) -- retrieving.\n"), local_size);
-               }
-           }
+             else if (eq_size)
+                {
+                  /* Remote file is newer or sizes cannot be matched */
+                  logprintf (LOG_VERBOSE, _("\
+Remote file is newer than local file `%s' -- retrieving.\n\n"),
+                             u->local);
+                }
+              else
+                {
+                  /* Sizes do not match */
+                  logprintf (LOG_VERBOSE, _("\
+The sizes do not match (local %ld) -- retrieving.\n\n"), local_size);
+                }
+            }
        }       /* opt.timestamping && f->type == FT_PLAINFILE */
       switch (f->type)
        {
@@ -1264,13 +1370,23 @@ Already have correct symlink %s -> %s\n\n"),
       /* Set the time-stamp information to the local file.  Symlinks
         are not to be stamped because it sets the stamp on the
         original.  :( */
-      if (!opt.dfp
-         && !(f->type == FT_SYMLINK && !opt.retr_symlinks)
+      if (!(f->type == FT_SYMLINK && !opt.retr_symlinks)
          && f->tstamp != -1
           && dlthis
          && file_exists_p (u->local))
        {
-         touch (u->local, f->tstamp);
+         /* #### This code repeats in http.c and ftp.c.  Move it to a
+             function!  */
+         const char *fl = NULL;
+         if (opt.output_document)
+           {
+             if (opt.od_known_regular)
+               fl = opt.output_document;
+           }
+         else
+           fl = u->local;
+         if (fl)
+           touch (fl, f->tstamp);
        }
       else if (f->tstamp == -1)
        logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), u->local);
@@ -1280,7 +1396,7 @@ Already have correct symlink %s -> %s\n\n"),
       else
        DEBUGP (("Unrecognized permissions for %s.\n", u->local));
 
-      free (u->local);
+      xfree (u->local);
       u->local = olocal;
       u->file = ofile;
       /* Break on fatals.  */
@@ -1326,9 +1442,6 @@ ftp_retrieve_dirs (struct urlinfo *u, struct fileinfo *f, ccon *con)
       if (len > current_length)
        current_container = (char *)alloca (len);
       u->dir = current_container;
-      /* When retrieving recursively, all directories must be
-        absolute.  This restriction will (hopefully!) be lifted in
-        the future.  */
       sprintf (u->dir, "/%s%s%s", odir + (*odir == '/'),
              (!*odir || (*odir == '/' && !* (odir + 1))) ? "" : "/", f->name);
       if (!accdir (u->dir, ALLABS))
@@ -1454,8 +1567,12 @@ ftp_loop (struct urlinfo *u, int *dt)
 
   *dt = 0;
 
+  memset (&con, 0, sizeof (con));
+
   rbuf_uninitialize (&con.rbuf);
   con.st = ON_YOUR_OWN;
+  con.rs = ST_UNIX;
+  con.id = NULL;
   res = RETROK;                        /* in case it's not used */
 
   /* If the file name is empty, the user probably wants a directory
@@ -1493,7 +1610,7 @@ ftp_loop (struct urlinfo *u, int *dt)
                               _("Wrote HTML-ized index to `%s'.\n"),
                               filename);
                }
-             free (filename);
+             xfree (filename);
            }
          freefileinfo (f);
        }
@@ -1519,6 +1636,8 @@ ftp_loop (struct urlinfo *u, int *dt)
   /* If a connection was left, quench it.  */
   if (rbuf_initialized_p (&con.rbuf))
     CLOSE (RBUF_FD (&con.rbuf));
+  FREE_MAYBE (con.id);
+  con.id = NULL;
   return res;
 }
 
@@ -1531,9 +1650,9 @@ delelement (struct fileinfo *f, struct fileinfo **start)
   struct fileinfo *prev = f->prev;
   struct fileinfo *next = f->next;
 
-  free (f->name);
+  xfree (f->name);
   FREE_MAYBE (f->linkto);
-  free (f);
+  xfree (f);
 
   if (next)
     next->prev = prev;
@@ -1551,10 +1670,10 @@ freefileinfo (struct fileinfo *f)
   while (f)
     {
       struct fileinfo *next = f->next;
-      free (f->name);
+      xfree (f->name);
       if (f->linkto)
-       free (f->linkto);
-      free (f);
+       xfree (f->linkto);
+      xfree (f);
       f = next;
     }
 }