changeset 14:83090328581e

* More largefile support. Hopefully all that is left is the configure stuff * Sanity checking on the fdopen() calls. Also make sure that all of them have a + in their open mode. Doesn't affect UNIX, but it does affect Windows * HTTP fixes when running under Solaris. Read from request->sockfd and write to request->sockfd_write (Solaris doesn't like it when you read/write to the same FILE structure) * Display major/minor properly for a device when connected with the local protocol
author masneyb
date Wed, 04 Sep 2002 11:45:56 +0000
parents cd2e26a69461
children 82fabd6ef1c4
files lib/gftp.h lib/local.c lib/misc.c lib/protocols.c lib/rfc2068.c lib/rfc959.c lib/ssh.c lib/sshv2.c src/gtk/gftp-gtk.c src/gtk/gftp-gtk.h src/gtk/menu-items.c src/gtk/misc-gtk.c src/gtk/transfer.c src/gtk/view_dialog.c
diffstat 14 files changed, 304 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/lib/gftp.h	Fri Aug 30 19:46:27 2002 +0000
+++ b/lib/gftp.h	Wed Sep 04 11:45:56 2002 +0000
@@ -123,8 +123,8 @@
        *destfile;		/* Full pathname to the destination for the 
                                    file transfer */
   time_t datetime;		/* File date and time */
-  unsigned long size,		/* Size of the file */
-                startsize;	/* Size to start the transfer at */
+  off_t size,			/* Size of the file */
+        startsize;		/* Size to start the transfer at */
   unsigned int isdir : 1,	/* File type */
                isexe : 1,
                islink : 1,
@@ -293,9 +293,7 @@
                show : 1,
                stalled : 1,
                next_file : 1,
-               skip_file : 1,
-               current_file_number, 
-               current_file_retries;
+               skip_file : 1;
 
   struct timeval starttime,
                  lasttime;
@@ -306,8 +304,10 @@
         * curfle,
         * updfle;
 
-  long numfiles,
-       numdirs;
+  unsigned long numfiles,
+                numdirs,
+                current_file_number,
+                current_file_retries;
 
   off_t curtrans,		/* Current transfered bytes for this file */
         curresumed,		/* Resumed bytes for this file */
@@ -481,7 +481,7 @@
 void print_bookmarks 			( gftp_bookmarks * bookmarks );
 
 /* misc.c */
-char *insert_commas 			( unsigned long number, 
+char *insert_commas 			( off_t number, 
 					  char *dest_str, 
 					  size_t dest_len );
 
--- a/lib/local.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/lib/local.c	Wed Sep 04 11:45:56 2002 +0000
@@ -150,6 +150,7 @@
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
 
+  /* Just to simulate that we are actually connected */
   request->sockfd = (void *) 1;
 
   if (request->directory)
@@ -223,7 +224,7 @@
           return (-2);
         }
 
-      if ((request->datafd = fdopen (sock, "rb")) == NULL)
+      if ((request->datafd = fdopen (sock, "rb+")) == NULL)
         {
           request->logging_function (gftp_logging_error, request->user_data,
                                      _("Cannot fdopen() socket for %s: %s\n"),
@@ -293,7 +294,7 @@
           return (-2);
         }
 
-      if ((request->datafd = fdopen (sock, "ab")) == NULL)
+      if ((request->datafd = fdopen (sock, "ab+")) == NULL)
         {
           request->logging_function (gftp_logging_error, request->user_data,
                                      _("Cannot fdopen() socket for %s: %s\n"),
@@ -432,9 +433,21 @@
       g_hash_table_insert (lpd->grouphash, GUINT_TO_POINTER (st.st_gid), group);
     }
 
-  fle->size = st.st_size;
+  fle->attribs = make_text_mode (fle, st.st_mode);
   fle->datetime = st.st_mtime;
-  fle->attribs = make_text_mode (fle, st.st_mode);
+
+  if ((fle->attribs[0] == 'b' || fle->attribs[0] == 'u' ||
+       fle->attribs[0] == 'c'))
+    {
+      /* FIXME find out if sys/sysmacros.h is portable, and if 
+         #define {major,minor} is portable. If so, use that instead. If not,
+         I will have to add a configure flag to find out the size of the
+         major numbers */
+      fle->size = ((((int) st.st_rdev) >> 8) & 0xFF) << 16;
+      fle->size |= st.st_rdev & 0xFF;
+    }
+  else
+    fle->size = st.st_size;
 
   if (*fle->attribs == 'd')
     fle->isdir = 1;
--- a/lib/misc.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/lib/misc.c	Wed Sep 04 11:45:56 2002 +0000
@@ -21,7 +21,7 @@
 #include "options.h"
 
 char *
-insert_commas (unsigned long number, char *dest_str, size_t dest_len)
+insert_commas (off_t number, char *dest_str, size_t dest_len)
 {
   char *frompos, *topos, src[50], *dest;
   int len, num, rem, i;
@@ -54,7 +54,11 @@
   else
     dest = dest_str;
 
+#if defined (_LARGEFILE_SOURCE)
+  g_snprintf (src, sizeof (src), "%lld", number);
+#else
   g_snprintf (src, sizeof (src), "%ld", number);
+#endif
 
   num = strlen (src) / 3 - 1;
   rem = strlen (src) % 3;
--- a/lib/protocols.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/lib/protocols.c	Wed Sep 04 11:45:56 2002 +0000
@@ -1038,8 +1038,7 @@
 parse_time (char **str)
 {
   const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
-    "Aug", "Sep", "Oct", "Nov", "Dec"
-  };
+    "Aug", "Sep", "Oct", "Nov", "Dec" };
   char *startpos, *endpos, *datepos;
   struct tm curtime, tt;
   time_t t;
@@ -1245,7 +1244,7 @@
   /* See if this is a block or character device. We will store the major number
      in the high word and the minor number in the low word.  */
   if ((fle->attribs[0] == 'b' || fle->attribs[0] == 'u' || 
-       fle->attribs[0] == 'c') && 
+       fle->attribs[0] == 'c') &&
       ((endpos = strchr (startpos, ',')) != NULL))
     {
       fle->size = strtol (startpos, NULL, 10) << 16;
@@ -1257,7 +1256,7 @@
       /* Get the minor number */
       if ((endpos = strchr (startpos, ' ')) == NULL)
 	return (-2);
-      fle->size |= strtol (startpos, NULL, 10);
+      fle->size |= strtol (startpos, NULL, 10) & 0xFF;
     }
   else
     {
@@ -1920,7 +1919,12 @@
   for (templist = list; ; templist = templist->next)
     {
       tempfle = templist->data;
-      printf ("%s:%s:%ld:%ld:%s:%s:%s\n", tempfle->file, tempfle->destfile,
+#if defined (_LARGEFILE_SOURCE)
+      printf ("%s:%s:%lld:%lld:%s:%s:%s\n", 
+#else
+      printf ("%s:%s:%ld:%ld:%s:%s:%s\n", 
+#endif
+              tempfle->file, tempfle->destfile,
               tempfle->size, tempfle->startsize, tempfle->user, tempfle->group,
               tempfle->attribs);
       if (templist->next == NULL)
@@ -1931,7 +1935,12 @@
   for (; ; templist = templist->prev)
     {
       tempfle = templist->data;
-      printf ("%s:%s:%ld:%ld:%s:%s:%s\n", tempfle->file, tempfle->destfile,
+#if defined (_LARGEFILE_SOURCE)
+      printf ("%s:%s:%lld:%lld:%s:%s:%s\n", 
+#else
+      printf ("%s:%s:%ld:%ld:%s:%s:%s\n", 
+#endif
+              tempfle->file, tempfle->destfile,
               tempfle->size, tempfle->startsize, tempfle->user, tempfle->group,
               tempfle->attribs);
       if (templist == list)
--- a/lib/rfc2068.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/lib/rfc2068.c	Wed Sep 04 11:45:56 2002 +0000
@@ -101,10 +101,11 @@
   g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2);
   g_return_val_if_fail (request->hostname != NULL, -2);
 
-  if (request->datafd != NULL)
+  if (request->sockfd != NULL)
     return (0);
 
-  service = request->use_proxy && request->proxy_config != NULL && *request->proxy_config != '\0' ? request->proxy_config : "http";
+  service = request->use_proxy && request->proxy_config != NULL && 
+            *request->proxy_config != '\0' ? request->proxy_config : "http";
   if ((sock = gftp_connect_server (request, service)) < 0)
     return (-1);
 
@@ -120,7 +121,24 @@
       strcpy (request->directory, "/");
     }
 
-  request->sockfd = request->datafd = fdopen (sock, "rb+");
+  if ((request->sockfd = fdopen (sock, "rb+")) == NULL)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Cannot fdopen() socket: %s\n"),
+                                 g_strerror (errno));
+      close (sock);
+      return (-2);
+    }
+
+  if ((request->sockfd_write = fdopen (sock, "wb+")) == NULL)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Cannot fdopen() socket: %s\n"),
+                                 g_strerror (errno));
+      gftp_disconnect (request);
+      return (-2);
+    }
+
   return (0);
 }
 
@@ -131,15 +149,20 @@
   g_return_if_fail (request != NULL);
   g_return_if_fail (request->protonum == GFTP_HTTP_NUM);
 
-  if (request->datafd != NULL)
+  if (request->sockfd != NULL)
     {
       request->logging_function (gftp_logging_misc, request->user_data,
 				 _("Disconnecting from site %s\n"),
 				 request->hostname);
-      fclose (request->datafd);
-      request->datafd = NULL;
+      fclose (request->sockfd);
+      request->sockfd = NULL;
     }
-  request->sockfd = NULL;
+
+  if (request->sockfd_write != NULL)
+    {
+      fclose (request->sockfd_write);
+      request->sockfd_write = NULL;
+    }
 }
 
 
@@ -156,9 +179,9 @@
   g_return_val_if_fail (filename != NULL, -2);
 
   if (fd != NULL)
-    request->datafd = fd;
+    request->sockfd = fd;
 
-  if (request->datafd == NULL && rfc2068_connect (request) != 0)
+  if (request->sockfd == NULL && rfc2068_connect (request) != 0)
     return (-2);
 
   if (request->proxy_config != NULL && *request->proxy_config != '\0')
@@ -184,25 +207,32 @@
     extrahdr = NULL;
   else
     {
+#if defined (_LARGEFILE_SOURCE)
+      extrahdr = g_strdup_printf ("Range: bytes=%lld-\n", startsize);
+      request->logging_function (gftp_logging_misc, request->user_data,
+                              _("Starting the file transfer at offset %lld\n"),
+                              startsize);
+#else
       extrahdr = g_strdup_printf ("Range: bytes=%ld-\n", startsize);
       request->logging_function (gftp_logging_misc, request->user_data,
 			       _("Starting the file transfer at offset %ld\n"), 
                                startsize);
+#endif
     }
 
   size = rfc2068_send_command (request, tempstr, extrahdr);
   g_free (tempstr);
   if (extrahdr)
     g_free (extrahdr);
-  if (request->datafd == NULL)
+  if (request->sockfd == NULL)
     return (-2);
 
   restarted = 0;
   if (strlen (request->last_ftp_response) > 9 
       && strncmp (request->last_ftp_response + 9, "206", 3) == 0)
     restarted = 1;
-  else if (strlen (request->last_ftp_response) < 9 
-           || strncmp (request->last_ftp_response + 9, "200", 3) != 0)
+  else if (strlen (request->last_ftp_response) < 9 ||
+           strncmp (request->last_ftp_response + 9, "200", 3) != 0)
     {
       request->logging_function (gftp_logging_misc, request->user_data,
 			         _("Cannot retrieve file %s\n"), filename);
@@ -225,14 +255,14 @@
   g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2);
 
   params = request->protocol_data;
-  if (params->max_bytes == params->read_bytes || feof (request->datafd))
+  if (params->max_bytes == params->read_bytes || feof (request->sockfd))
     return (0);
 
   FD_ZERO (&fset);
-  FD_SET (fileno (request->datafd), &fset);
+  FD_SET (fileno (request->sockfd), &fset);
   tv.tv_sec = request->network_timeout;
   tv.tv_usec = 0;
-  if (select (fileno (request->datafd) + 1, &fset, NULL, NULL, &tv) <= 0)
+  if (select (fileno (request->sockfd) + 1, &fset, NULL, NULL, &tv) <= 0)
     {
       request->logging_function (gftp_logging_error, request->user_data,
                                  _("Connection to %s timed out\n"),
@@ -244,8 +274,8 @@
   if (params->max_bytes > 0 && size + params->read_bytes > params->max_bytes)
     size = params->max_bytes - params->read_bytes;
 
-  len = fread (buf, 1, size, request->datafd);
-  if (ferror (request->datafd))
+  len = fread (buf, 1, size, request->sockfd);
+  if (ferror (request->sockfd))
     {
       request->logging_function (gftp_logging_error, request->user_data,
                                  _("Error reading from host %s: %s\n"),
@@ -267,15 +297,19 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
+  g_return_val_if_fail (request->sockfd != NULL, -2);
 
-  if (request->datafd == NULL)
+  if (request->sockfd == NULL)
     return (-2);
 
+  fclose (request->sockfd);
+  request->sockfd = NULL;
+  fclose (request->sockfd_write);
+  request->sockfd_write = NULL;
+
   params = request->protocol_data;
-  fclose (request->datafd);
-  request->datafd = NULL;
   params->max_bytes = 0;
+
   request->logging_function (gftp_logging_misc, request->user_data,
                              _("Finished retrieving data\n"));
   return (0);
@@ -292,7 +326,7 @@
   g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2);
 
   params = request->protocol_data;
-  if (request->datafd == NULL && rfc2068_connect (request) != 0)
+  if (request->sockfd == NULL && rfc2068_connect (request) != 0)
     return (-2);
 
   if (request->proxy_config != NULL && *request->proxy_config != '\0')
@@ -316,7 +350,7 @@
 
   rfc2068_send_command (request, tempstr, NULL);
   g_free (tempstr);
-  if (request->datafd == NULL)
+  if (request->sockfd == NULL)
     return (-2);
 
   params->read_bytes = 0;
@@ -342,7 +376,7 @@
   g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2);
   g_return_val_if_fail (filename != NULL, -2);
 
-  if (request->datafd == NULL && rfc2068_connect (request) != 0)
+  if (request->sockfd == NULL && rfc2068_connect (request) != 0)
     return (-2);
 
   if (request->proxy_config != NULL && *request->proxy_config != '\0')
@@ -365,7 +399,7 @@
 
   size = rfc2068_send_command (request, tempstr, NULL);
   g_free (tempstr);
-  if (request->datafd == NULL)
+  if (request->sockfd == NULL)
     return (-2);
 
   return (size);
@@ -470,16 +504,16 @@
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2);
   g_return_val_if_fail (command != NULL, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
+  g_return_val_if_fail (request->sockfd_write != NULL, -2);
 
   request->logging_function (gftp_logging_send, request->user_data, "%s",
                              command);
 
   request->logging_function (gftp_logging_send, request->user_data,
                              "User-Agent: %s\n", version);
-  fprintf (request->datafd, "%sUser-Agent: %s\nHost: %s\n", command, version,
-           request->hostname);
-  if (ferror (request->datafd) != 0)
+  fprintf (request->sockfd_write, "%sUser-Agent: %s\nHost: %s\n", command, 
+           version, request->hostname);
+  if (ferror (request->sockfd_write) != 0)
     {
       gftp_disconnect (request);
       return (-2);
@@ -495,9 +529,9 @@
 
       request->logging_function (gftp_logging_send, request->user_data,
                                  "Proxy-authorization: Basic xxxx:xxxx\n");
-      fprintf (request->datafd, "Proxy-authorization: Basic %s\n", str);
+      fprintf (request->sockfd_write, "Proxy-authorization: Basic %s\n", str);
       g_free (str);
-      if (ferror (request->datafd) != 0)
+      if (ferror (request->sockfd_write) != 0)
         {
           gftp_disconnect (request);
 	  return (-2);
@@ -512,9 +546,9 @@
 
       request->logging_function (gftp_logging_send, request->user_data,
                                  "Authorization: Basic xxxx\n");
-      fprintf (request->datafd, "Authorization: Basic %s\n", str);
+      fprintf (request->sockfd_write, "Authorization: Basic %s\n", str);
       g_free (str);
-      if (ferror (request->datafd) != 0)
+      if (ferror (request->sockfd_write) != 0)
         {
           gftp_disconnect (request);
 	  return (-2);
@@ -527,11 +561,16 @@
                                  "%s", extrahdr);
       request->logging_function (gftp_logging_send, request->user_data, "%s",
                                  extrahdr);
-      fprintf (request->datafd, "%s", extrahdr);
+      fprintf (request->sockfd_write, "%s", extrahdr);
+      if (ferror (request->sockfd_write) != 0)
+        {
+          gftp_disconnect (request);
+          return (-2);
+        }
     }
 
-  fprintf (request->datafd, "\n");
-  if (ferror (request->datafd) != 0)
+  fprintf (request->sockfd_write, "\n");
+  if (ferror (request->sockfd_write) != 0)
     {
       gftp_disconnect (request);
       return (-2);
@@ -551,7 +590,7 @@
   /* I don't run select() here because select could return 
      successfully saying there is data, but the fgets call could block if 
      there is no carriage return */
-  if (!fgets (tempstr, sizeof (tempstr), request->datafd))
+  if (!fgets (tempstr, sizeof (tempstr), request->sockfd))
     {
       gftp_disconnect (request);
       return (0);
@@ -571,7 +610,7 @@
          successfully saying there is data, but the fgets call could block if 
          there is no carriage return */
       /* Read rest of proxy header */
-      if (!fgets (tempstr, sizeof (tempstr), request->datafd))
+      if (!fgets (tempstr, sizeof (tempstr), request->sockfd))
         {
           gftp_disconnect (request);
 	  return (0);
--- a/lib/rfc959.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/lib/rfc959.c	Wed Sep 04 11:45:56 2002 +0000
@@ -131,7 +131,7 @@
   if ((sock = gftp_connect_server (request, "ftp")) < 0)
     return (-1);
 
-  if ((request->sockfd = fdopen (sock, "rb")) == NULL)
+  if ((request->sockfd = fdopen (sock, "rb+")) == NULL)
     {
       request->logging_function (gftp_logging_error, request->user_data,
                                  _("Cannot fdopen() socket: %s\n"),
@@ -140,7 +140,7 @@
       return (-2);
     }
 
-  if ((request->sockfd_write = fdopen (dup (sock), "wb")) == NULL)
+  if ((request->sockfd_write = fdopen (dup (sock), "wb+")) == NULL)
     {
       request->logging_function (gftp_logging_error, request->user_data,
                                  _("Cannot fdopen() socket: %s\n"),
@@ -314,7 +314,11 @@
 
   if (startsize > 0)
     {
+#if defined (_LARGEFILE_SOURCE)
+      command = g_strdup_printf ("REST %lld\r\n", startsize); 
+#else
       command = g_strdup_printf ("REST %ld\r\n", startsize); 
+#endif
       resp = rfc959_send_command (request, command);
       g_free (command);
 
@@ -383,7 +387,11 @@
 
   if (startsize > 0)
     {
-      command = g_strdup_printf ("REST %ld\r\n", startsize);  
+#if defined (_LARGEFILE_SOURCE)
+      command = g_strdup_printf ("REST %lld\r\n", startsize); 
+#else
+      command = g_strdup_printf ("REST %ld\r\n", startsize); 
+#endif
       resp = rfc959_send_command (request, command);
       g_free (command);
       if (resp != '3')
--- a/lib/ssh.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/lib/ssh.c	Wed Sep 04 11:45:56 2002 +0000
@@ -298,8 +298,23 @@
       g_free (exepath);
       g_free (tempstr);
 
-      request->sockfd = request->datafd = fdopen (fdm, "rb");
-      request->sockfd_write = fdopen (fdm, "wb");
+      if ((request->sockfd = fdopen (fdm, "rb+")) == NULL)
+        {
+          request->logging_function (gftp_logging_error, request->user_data,
+                                     _("Cannot fdopen() socket: %s\n"),
+                                     g_strerror (errno));
+          close (fdm);
+          return (-2);
+        }
+
+      if ((request->sockfd_write = fdopen (fdm, "wb+")) == NULL)
+        {
+          request->logging_function (gftp_logging_error, request->user_data,
+                                     _("Cannot fdopen() socket: %s\n"),
+                                     g_strerror (errno));
+          gftp_disconnect (request);
+          return (-2);
+        }
 
       params->channel = 0;
       version = htonl (7 << 4);
@@ -359,7 +374,7 @@
 			         _("Disconnecting from site %s\n"),
                                  request->hostname);
       fclose (request->sockfd);
-      request->sockfd = request->datafd = request->sockfd_write = NULL;
+      request->sockfd = request->sockfd_write = NULL;
     }
 }
 
@@ -470,8 +485,10 @@
   if (startsize > 0)
     {
       startsize = htonl (startsize);
-      /* FIXME - warning on IRIX - pointer from integer of different size */
-      if (ssh_send_command (request, SKIPBYTES, GUINT_TO_POINTER (startsize), 4) < 0)
+      /* This protocol only supports files up to 2 gig in size. I truncate
+         the file size here just to suppress compiler warnings  */
+      if (ssh_send_command (request, SKIPBYTES, 
+                            GINT_TO_POINTER ((gint32) startsize), 4) < 0)
         return (-1);
     }
 
@@ -536,7 +553,6 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
 
   params = request->protocol_data;
   if (params->buffer)
--- a/lib/sshv2.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/lib/sshv2.c	Wed Sep 04 11:45:56 2002 +0000
@@ -356,8 +356,23 @@
       g_free (args);
       g_free (exepath);
 
-      request->sockfd = request->datafd = fdopen (fdm, "rb");
-      request->sockfd_write = fdopen (fdm, "wb");
+      if ((request->sockfd = fdopen (fdm, "rb+")) == NULL)
+        {
+          request->logging_function (gftp_logging_error, request->user_data,
+                                     _("Cannot fdopen() socket: %s\n"),
+                                     g_strerror (errno));
+          close (fdm);
+          return (-2);
+        }
+
+      if ((request->sockfd_write = fdopen (fdm, "wb+")) == NULL)
+        {
+          request->logging_function (gftp_logging_error, request->user_data,
+                                     _("Cannot fdopen() socket: %s\n"),
+                                     g_strerror (errno));
+          gftp_disconnect (request);
+          return (-2);
+        }
 
       version = htonl (SSH_MY_VERSION);
       if (sshv2_send_command (request, SSH_FXP_INIT, (char *) &version, 4) < 0)
@@ -411,7 +426,7 @@
 			         _("Disconnecting from site %s\n"),
                                  request->hostname);
       fclose (request->sockfd);
-      request->sockfd = request->datafd = request->sockfd_write = NULL;
+      request->sockfd = request->sockfd_write = NULL;
     }
 
   if (params->message.buffer != NULL)
@@ -780,7 +795,6 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
 
   params = request->protocol_data;
   if (params->message.buffer != NULL)
@@ -1087,7 +1101,6 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
 
   params = request->protocol_data;
   if (request->directory != directory)
@@ -1157,7 +1170,6 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
 
   if (request->directory == NULL || *request->directory == '\0')
     dir = ".";
@@ -1219,7 +1231,6 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
   g_return_val_if_fail (directory != NULL, -2);
 
   params = request->protocol_data;
@@ -1277,7 +1288,6 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
   g_return_val_if_fail (file != NULL, -2);
 
   params = request->protocol_data;
@@ -1335,7 +1345,6 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
   g_return_val_if_fail (file != NULL, -2);
 
   params = request->protocol_data;
@@ -1400,7 +1409,6 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
   g_return_val_if_fail (newdir != NULL, -2);
 
   params = request->protocol_data;
@@ -1459,7 +1467,6 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
   g_return_val_if_fail (oldname != NULL, -2);
   g_return_val_if_fail (newname != NULL, -2);
 
@@ -1531,7 +1538,6 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
   g_return_val_if_fail (file != NULL, -2);
 
   params = request->protocol_data;
@@ -1599,7 +1605,6 @@
 
   g_return_val_if_fail (request != NULL, -2);
   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
-  g_return_val_if_fail (request->datafd != NULL, -2);
   g_return_val_if_fail (file != NULL, -2);
 
   params = request->protocol_data;
--- a/src/gtk/gftp-gtk.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/src/gtk/gftp-gtk.c	Wed Sep 04 11:45:56 2002 +0000
@@ -370,6 +370,7 @@
     {N_("/Local/Select All Files"), NULL, selectallfiles, 0, MN_(NULL)},
     {N_("/Local/Deselect All"), NULL, deselectall, 0, MN_(NULL)},
     {N_("/Local/sep"), NULL, 0, 0, MN_("<Separator>")},
+    {N_("/Local/Save Directory Listing..."), NULL, save_directory_listing, 0, MN_(NULL)},
     {N_("/Local/Send SITE Command..."), NULL, site_dialog, 0, MN_(NULL)},
     {N_("/Local/Change Directory"), NULL, chfunc, 0, MN_(NULL)},
     {N_("/Local/Chmod..."), NULL, chmod_dialog, 0, MN_(NULL)},
@@ -392,6 +393,7 @@
     {N_("/Remote/Select All Files"), NULL, selectallfiles, 0, MN_(NULL)},
     {N_("/Remote/Deselect All"), NULL, deselectall, 0, MN_(NULL)},
     {N_("/Remote/sep"), NULL, 0, 0, MN_("<Separator>")},
+    {N_("/Remote/Save Directory Listing..."), NULL, save_directory_listing, 0, MN_(NULL)},
     {N_("/Remote/Send SITE Command..."), NULL, site_dialog, 0, MN_(NULL)},
     {N_("/Remote/Change Directory"), NULL, chfunc, 0, MN_(NULL)},
     {N_("/Remote/Chmod..."), NULL, chmod_dialog, 0, MN_(NULL)},
@@ -450,13 +452,13 @@
   i += len;
   /* Local Menu */
   local_start = i;
-  local_len = 20;
+  local_len = 21;
   create_item_factory (factory, local_len, menu_items + i, &window1);
 
   i += local_len;
   /* Remote Menu */
   remote_start = i;
-  remote_len = 20;
+  remote_len = 21;
   create_item_factory (factory, remote_len, menu_items + i, &window2);
 
   i += remote_len;
--- a/src/gtk/gftp-gtk.h	Fri Aug 30 19:46:27 2002 +0000
+++ b/src/gtk/gftp-gtk.h	Wed Sep 04 11:45:56 2002 +0000
@@ -98,6 +98,13 @@
 } gftp_curtrans_data;
 
 
+typedef struct gftp_save_dir_struct_tag
+{
+  GtkWidget * filew;
+  gftp_window_data * wdata;
+} gftp_save_dir_struct;
+
+
 extern gftp_window_data window1, window2, * other_wdata, * current_wdata;
 extern GtkWidget * stop_btn, * hostedit, * useredit, * passedit,
                  * portedit, * logwdw, * dlwdw, * protocol_menu, * optionmenu;
@@ -176,6 +183,8 @@
 
 void change_filespec 				( gpointer data );
 
+void save_directory_listing 			( gpointer data );
+
 void show_selected				( gpointer data );
 
 void selectall 					( gpointer data );
--- a/src/gtk/menu-items.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/src/gtk/menu-items.c	Wed Sep 04 11:45:56 2002 +0000
@@ -23,6 +23,9 @@
 						  gftp_dialog_data * data );
 static void dochange_filespec 			( GtkWidget * widget, 
 						  gftp_dialog_data * data );
+static void dosave_directory_listing 		( GtkWidget * widget, 
+						  gftp_save_dir_struct * str );
+static void destroy_save_directory_listing 	( gftp_save_dir_struct * str );
 static void dosite 				( GtkWidget * widget, 
 						  gftp_dialog_data * data );
 static int do_change_dir			( gftp_window_data * wdata,
@@ -217,6 +220,100 @@
 }
 
 
+void 
+save_directory_listing (gpointer data)
+{
+  gftp_save_dir_struct * str;
+  GtkWidget *filew;
+
+  filew = gtk_file_selection_new (_("Save Directory Listing"));
+
+  str = g_malloc (sizeof (*str));
+  str->filew = filew;
+  str->wdata = data;
+
+  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
+                      "clicked", GTK_SIGNAL_FUNC (dosave_directory_listing), 
+                      str);
+  gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
+                             "clicked", 
+                             GTK_SIGNAL_FUNC (destroy_save_directory_listing),
+                             GTK_OBJECT (str));
+  gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button), "clicked", GTK_SIGNAL_FUNC (destroy_save_directory_listing), GTK_OBJECT (str));
+
+  gtk_window_set_wmclass (GTK_WINDOW(filew), "Save Directory Listing", "gFTP");
+  gtk_widget_show (filew);
+}
+
+
+static void
+destroy_save_directory_listing (gftp_save_dir_struct * str)
+{
+  gtk_widget_destroy (str->filew);
+  g_free (str);
+}
+
+
+static void
+dosave_directory_listing (GtkWidget * widget, gftp_save_dir_struct * str)
+{
+  const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
+    "Aug", "Sep", "Oct", "Nov", "Dec" };
+  const char *filename;
+  struct tm *lt;
+  gftp_file * tempfle;
+  GList * templist;
+  FILE * fd;
+  time_t t;
+
+  filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (str->filew));
+  if ((fd = fopen (filename, "w")) == NULL)
+    {
+      ftp_log (gftp_logging_misc, NULL, 
+               _("Error: Cannot open %s for writing: %s\n"), filename, 
+               g_strerror (errno));
+      return;
+    }
+
+  time (&t);
+
+  for (templist = str->wdata->files; 
+       templist->next != NULL;
+       templist = templist->next)
+    {
+      tempfle = templist->data;
+      fprintf (fd, "%10s %8s %8s ", tempfle->attribs, tempfle->user, 
+               tempfle->group);
+      if (tempfle->attribs && (*tempfle->attribs == 'b' || 
+                               *tempfle->attribs == 'c'))
+        fprintf (fd, "%5d, %4d", (((unsigned int) tempfle->size) >> 16) & 0xFF,
+                                 ((unsigned int) tempfle->size) & 0xFF);
+      else
+        {
+#if defined (_LARGEFILE_SOURCE)
+          fprintf (fd, "%11lld", tempfle->size);
+#else
+          fprintf (fd, "%11ld", tempfle->size);
+#endif
+        }
+
+      lt = localtime (&tempfle->datetime);
+
+      if (tempfle->datetime > t ||
+          t - 3600*24*90 > tempfle->datetime)
+        fprintf (fd, " %s %2d  %4d", months[lt->tm_mon], lt->tm_mday, 
+                 lt->tm_year + 1900);
+      else
+        fprintf (fd, " %s %2d %02d:%02d", months[lt->tm_mon], lt->tm_mday, 
+                 lt->tm_hour, lt->tm_min);
+
+      fprintf (fd, " %s\n", tempfle->file);
+    }
+
+  fclose (fd);
+}
+
+
 void
 show_selected (gpointer data)
 {
@@ -552,8 +649,9 @@
   tempstr = g_strconcat (tmp_directory, "/gftp-view.XXXXXXXXXX", NULL);
   if ((fd = mkstemp (tempstr)) < 0)
     {
-      ftp_log (gftp_logging_misc, NULL, _("Error: Cannot open %s: %s\n"),
-	       tempstr, g_strerror (errno));
+      ftp_log (gftp_logging_misc, NULL, 
+               _("Error: Cannot open %s for writing: %s\n"), tempstr, 
+               g_strerror (errno));
       g_free (tempstr); 
       return;
     }
@@ -627,8 +725,9 @@
   filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs));
   if ((fd = fopen (filename, "w")) == NULL)
     {
-      ftp_log (gftp_logging_misc, NULL, _("Error: Cannot open %s: %s\n"),
-               filename, g_strerror (errno));
+      ftp_log (gftp_logging_misc, NULL, 
+               _("Error: Cannot open %s for writing: %s\n"), filename, 
+               g_strerror (errno));
       return;
     }
 
--- a/src/gtk/misc-gtk.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/src/gtk/misc-gtk.c	Wed Sep 04 11:45:56 2002 +0000
@@ -294,24 +294,25 @@
   set_menu_sensitive (wdata, menus[start + 7].path, connected);
   set_menu_sensitive (wdata, menus[start + 8].path, connected);
   set_menu_sensitive (wdata, menus[start + 9].path, connected);
-  set_menu_sensitive (wdata, menus[start + 11].path, connected &&
-                      wdata->request->site != NULL);
+  set_menu_sensitive (wdata, menus[start + 11].path, connected);
   set_menu_sensitive (wdata, menus[start + 12].path, connected &&
+                      wdata->request->site != NULL);
+  set_menu_sensitive (wdata, menus[start + 13].path, connected &&
                       wdata->request->chdir!= NULL);
-  set_menu_sensitive (wdata, menus[start + 13].path, connected &&
+  set_menu_sensitive (wdata, menus[start + 14].path, connected &&
                       wdata->request->chmod != NULL);
-  set_menu_sensitive (wdata, menus[start + 14].path, connected &&
+  set_menu_sensitive (wdata, menus[start + 15].path, connected &&
                       wdata->request->mkdir != NULL);
-  set_menu_sensitive (wdata, menus[start + 15].path, connected &&
+  set_menu_sensitive (wdata, menus[start + 16].path, connected &&
                       wdata->request->rename != NULL);
-  set_menu_sensitive (wdata, menus[start + 16].path, connected &&
+  set_menu_sensitive (wdata, menus[start + 17].path, connected &&
                       wdata->request->rmdir != NULL &&
                       wdata->request->rmfile != NULL);
-  set_menu_sensitive (wdata, menus[start + 17].path, connected &&
-                      wdata->request->get_file != NULL);
   set_menu_sensitive (wdata, menus[start + 18].path, connected &&
                       wdata->request->get_file != NULL);
-  set_menu_sensitive (wdata, menus[start + 19].path, connected);
+  set_menu_sensitive (wdata, menus[start + 19].path, connected &&
+                      wdata->request->get_file != NULL);
+  set_menu_sensitive (wdata, menus[start + 20].path, connected);
   fix_display ();
 }  
 
--- a/src/gtk/transfer.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/src/gtk/transfer.c	Wed Sep 04 11:45:56 2002 +0000
@@ -1242,7 +1242,7 @@
     pcent = 0;
 
   g_snprintf (totstr, sizeof (totstr),
-	_("%d%% complete, %02d:%02d:%02d est. time remaining. (File %d of %ld)"),
+	_("%d%% complete, %02d:%02d:%02d est. time remaining. (File %ld of %ld)"),
 	pcent, hours, mins, secs, tdata->current_file_number,
 	tdata->numdirs + tdata->numfiles);
 
--- a/src/gtk/view_dialog.c	Fri Aug 30 19:46:27 2002 +0000
+++ b/src/gtk/view_dialog.c	Wed Sep 04 11:45:56 2002 +0000
@@ -66,7 +66,8 @@
       new_fle->destfile = g_strconcat (tmp_directory, "/gftp-view.XXXXXX", NULL);
       if ((fd = mkstemp (new_fle->destfile)) < 0)
         {
-          ftp_log (gftp_logging_misc, NULL, _("Error: Cannot open %s: %s\n"),
+          ftp_log (gftp_logging_misc, NULL, 
+                   _("Error: Cannot open %s for writing: %s\n"),  
                    new_fle->destfile, g_strerror (errno));
           free_fdata (new_fle);
           return;
@@ -135,7 +136,8 @@
                                        NULL);
       if ((fd = mkstemp (new_fle->destfile)) < 0)
         {
-          ftp_log (gftp_logging_misc, NULL, _("Error: Cannot open %s: %s\n"),
+          ftp_log (gftp_logging_misc, NULL, 
+                   _("Error: Cannot open %s for writing: %s\n"),
                    new_fle->destfile, g_strerror (errno));
           free_fdata (new_fle);
           return;