From 02964335538e48aabdb1ab2ca89b9e619aec240c Mon Sep 17 00:00:00 2001
From: hniksic <devnull@localhost>
Date: Tue, 20 Nov 2001 13:01:27 -0800
Subject: [PATCH] [svn] Support the SIZE command. Originally by Dave Turner. 
 Modified by Ian Abbott and published in <3BFAA33C.6236.6D42F6@localhost>.

---
 src/ChangeLog   |  8 +++++++
 src/ftp-basic.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/ftp.c       | 32 +++++++++++++++++++++++++++
 src/ftp.h       |  1 +
 4 files changed, 100 insertions(+)

diff --git a/src/ChangeLog b/src/ChangeLog
index 24b22777..9e766719 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,11 @@
+2001-08-21  Dave Turner <dct25@hermes.cam.ac.uk>
+
+	* ftp-basic.c (ftp_size): New function to send non-standard SIZE
+	  command to server to request file size.
+	* ftp.h (ftp_size): Export it.
+	* ftp.c (getftp): Use new ftp_size function if restoring
+	  transfer of a file with unknown size.
+
 2001-11-20  Hrvoje Niksic  <hniksic@arsdigita.com>
 
 	* url.c (parseurl): Don't depend on the now-obsolete TYPE.
diff --git a/src/ftp-basic.c b/src/ftp-basic.c
index cb2621ae..ee176690 100644
--- a/src/ftp-basic.c
+++ b/src/ftp-basic.c
@@ -21,6 +21,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
+
 #ifdef HAVE_STRING_H
 # include <string.h>
 #else
@@ -631,3 +633,60 @@ ftp_pwd (struct rbuf *rbuf, char **pwd)
   /* All OK.  */
   return FTPOK;
 }
+/* Sends the SIZE command to the server, and returns the value in 'size'.
+ * If an error occurs, size is set to zero. */
+uerr_t
+ftp_size (struct rbuf *rbuf, const char *file, long int *size)
+{
+  char *request, *respline;
+  int nwritten;
+  uerr_t err;
+
+  /* Send PWD request.  */
+  request = ftp_request ("SIZE", file);
+  nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
+  if (nwritten < 0)
+    {
+      xfree (request);
+      *size = 0;
+      return WRITEFAILED;
+    }
+  xfree (request);
+  /* Get appropriate response.  */
+  err = ftp_response (rbuf, &respline);
+  if (err != FTPOK)
+    {
+      xfree (respline);
+      *size = 0;
+      return err;
+    }
+  if (*respline == '5')
+    {
+      /* 
+       * Probably means SIZE isn't supported on this server.
+       * Error is nonfatal since SIZE isn't in RFC 959 
+       */
+      xfree (respline);
+      *size = 0;
+      return FTPOK;
+    }
+
+  errno = 0;
+  *size = strtol (respline + 4, NULL, 0);
+  if (errno) 
+    {
+      /* 
+       * Couldn't parse the response for some reason.  On the (few)
+       * tests I've done, the response is 213 <SIZE> with nothing else -
+       * maybe something a bit more resilient is necessary.  It's not a
+       * fatal error, however.
+       */
+      xfree (respline);
+      *size = 0;
+      return FTPOK;
+    }
+
+  xfree (respline);
+  /* All OK.  */
+  return FTPOK;
+}
diff --git a/src/ftp.c b/src/ftp.c
index 7bcca7ab..7427d9e8 100644
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -462,6 +462,38 @@ Error in server response, closing control connection.\n"));
   else /* do not CWD */
     logputs (LOG_VERBOSE, _("==> CWD not required.\n"));
 
+  if ((cmd & DO_RETR) && restval && *len == 0)
+    {
+      if (opt.verbose)
+	{
+          if (!opt.server_response)
+	    logprintf (LOG_VERBOSE, "==> SIZE %s ... ", u->file);
+	}
+
+      err = ftp_size(&con->rbuf, u->file, len);
+      /* FTPRERR */
+      switch (err)
+	{
+	case FTPRERR:
+	case 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"));
+    }
+
   /* If anything is to be retrieved, PORT (or PASV) must be sent.  */
   if (cmd & (DO_LIST | DO_RETR))
     {
diff --git a/src/ftp.h b/src/ftp.h
index 718106ce..e0ad7ccb 100644
--- a/src/ftp.h
+++ b/src/ftp.h
@@ -44,6 +44,7 @@ uerr_t ftp_rest PARAMS ((struct rbuf *, long));
 uerr_t ftp_list PARAMS ((struct rbuf *, const char *));
 uerr_t ftp_syst PARAMS ((struct rbuf *, enum stype *));
 uerr_t ftp_pwd PARAMS ((struct rbuf *, char **));
+uerr_t ftp_size PARAMS ((struct rbuf *, const char *, long int *));
 
 struct urlinfo;