diff lib/protocols.c @ 122:76e2b58a9440

2003-4-5 Brian Masney <masneyb@gftp.org> * lib/config_file.c lib/options.h lib/gftp.h lib/rfc959.c lib/rfc2068.c lib/ssh.c - added new internal configuration interface. Rather than having a global variable for each option, I have a global hash table (gftp_global_options_htable) that I can look up option names by name using gftp_lookup_global_option(). I also an options hash associated with a request structure, so I will be able to call gftp_lookup_request_option(). I will be able to override options with bookmarks or while transfers are in progress very easily now. Also, all options no longer have to appear in config_file.c, the per protocol options can appear inside their own file * lib/gftp.h lib/bookmarks.c lib/local.c lib/rfc959.c lib/rfc2068.c - remove set_data_type and protocol name from struct gftp_request * lib/rfc959.c - renamed all firewall_* variables to ftp_proxy_* in the config file * lib/gftp.h lib/protocols.c lib/rfc959.c - renamed all GFTP_TYPE_* vars to GFTP_DIRTYPE_* * lib/gftp.h - removed ascii field and renamed the node pointer to user_data in struct gftp_file. In gftp_request, removed any setting that is now stored in the global/local hash tables. Added register_module() pointer that will be called whenever the protocol is first loaded into gftp * lib/rfc959.c src/text/gftp-text.c - moved the ascii/binary translation to rfc959.c. Also, moved any instance of automatically setting the data type to rfc959.c as well. * lib/misc.c lib/sshv2.c - moved all ssh functions from misc.c to sshv2.c. I had these origionally in misc.c because I used to have 2 different SSH protocols * lib/protocols.c src/text/gftp-text.c - added gftp_calc_kbs() to protocols.c. This no longer needs to be in the different ports * src/text/gftp-text.c - read/write options based on new configuration interface * Use new configuration interface in all source files * Updated copyright dates on all source files * Note: GTK+ port is completely broken at the moment. I'll upload those changes whenever I get them done
author masneyb
date Sat, 05 Apr 2003 16:30:45 +0000
parents 982e3890e7fe
children 65048c959029
line wrap: on
line diff
--- a/lib/protocols.c	Sat Apr 05 02:25:42 2003 +0000
+++ b/lib/protocols.c	Sat Apr 05 16:30:45 2003 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************/
 /*  protocols.c - Skeleton functions for the protocols gftp supports         */
-/*  Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org>                  */
+/*  Copyright (C) 1998-2003 Brian Masney <masneyb@gftp.org>                  */
 /*                                                                           */
 /*  This program is free software; you can redistribute it and/or modify     */
 /*  it under the terms of the GNU General Public License as published by     */
@@ -20,6 +20,7 @@
 #include "gftp.h"
 static const char cvsid[] = "$Id$";
 
+/* {{{ gftp_request_new */
 gftp_request *
 gftp_request_new (void)
 {
@@ -29,11 +30,10 @@
   request->sockfd = -1;
   request->datafd = -1;
   request->cachefd = -1;
-  request->data_type = GFTP_TYPE_BINARY;
-  request->server_type = GFTP_TYPE_OTHER;
+  request->server_type = GFTP_DIRTYPE_OTHER;
   return (request);
 }
-
+/* }}} */
 
 void
 gftp_request_destroy (gftp_request * request, int free_request)
@@ -61,22 +61,10 @@
     }
   if (request->directory)
     g_free (request->directory);
-  if (request->proxy_config)
-    g_free (request->proxy_config);
-  if (request->proxy_hostname)
-    g_free (request->proxy_hostname);
-  if (request->proxy_username)
-    g_free (request->proxy_username);
-  if (request->proxy_password)
-    g_free (request->proxy_password);
-  if (request->proxy_account)
-    g_free (request->proxy_account);
   if (request->last_ftp_response)
     g_free (request->last_ftp_response);
   if (request->protocol_data)
     g_free (request->protocol_data);
-  if (request->sftpserv_path)
-    g_free (request->sftpserv_path);
 
   memset (request, 0, sizeof (*request));
 
@@ -87,8 +75,8 @@
       request->sockfd = -1;
       request->datafd = -1;
       request->cachefd = -1;
-      request->data_type = GFTP_TYPE_BINARY;
     }
+  /* FIXME - free local_options */
 }
 
 
@@ -136,12 +124,6 @@
 #endif
   request->hostp = NULL;
 
-  if (request->sftpserv_path != NULL)
-    {
-      g_free (request->sftpserv_path);
-      request->sftpserv_path = NULL;
-    }
-
   request->cached = 0;
   if (request->disconnect == NULL)
     return;
@@ -153,8 +135,18 @@
 gftp_get_file (gftp_request * request, const char *filename, int fd,
                size_t startsize)
 {
+  float maxkbs;
+
   g_return_val_if_fail (request != NULL, GFTP_EFATAL);
 
+  gftp_lookup_request_option (request, "maxkbs", &maxkbs);
+  if (maxkbs > 0)
+    {
+      request->logging_function (gftp_logging_misc, request->user_data,
+                    _("File transfer will be throttled to %.2f KB/s\n"),
+                    maxkbs);
+    }
+
   request->cached = 0;
   if (request->get_file == NULL)
     return (GFTP_EFATAL);
@@ -166,8 +158,19 @@
 gftp_put_file (gftp_request * request, const char *filename, int fd,
                size_t startsize, size_t totalsize)
 {
+  float maxkbs;
+
   g_return_val_if_fail (request != NULL, GFTP_EFATAL);
 
+  gftp_lookup_request_option (request, "maxkbs", &maxkbs);
+
+  if (maxkbs > 0)
+    {
+      request->logging_function (gftp_logging_misc, request->user_data,
+                    _("File transfer will be throttled to %.2f KB/s\n"), 
+                    maxkbs);
+    }
+
   request->cached = 0;
   if (request->put_file == NULL)
     return (GFTP_EFATAL);
@@ -377,7 +380,8 @@
 gftp_parse_bookmark (gftp_request * request, const char * bookmark)
 {
   gftp_logging_func logging_function;
-  gftp_bookmarks * tempentry;
+  gftp_bookmarks_var * tempentry;
+  char *default_protocol;
   int i;
 
   g_return_val_if_fail (request != NULL, GFTP_EFATAL);
@@ -387,7 +391,8 @@
   gftp_request_destroy (request, 0);
   request->logging_function = logging_function;
 
-  if ((tempentry = g_hash_table_lookup (bookmarks_htable, bookmark)) == NULL)
+  if ((tempentry = g_hash_table_lookup (gftp_bookmarks_htable, 
+                                        bookmark)) == NULL)
     {
       request->logging_function (gftp_logging_error, request->user_data,
                                  _("Error: Could not find bookmark %s\n"), 
@@ -405,12 +410,7 @@
     gftp_set_username (request, tempentry->user);
 
   if (tempentry->pass != NULL)
-    {
-      if (strncmp (tempentry->pass, "@EMAIL@", 7) == 0)
-        gftp_set_password (request, emailaddr);
-      else
-        gftp_set_password (request, tempentry->pass);
-    }
+    gftp_set_password (request, tempentry->pass);
 
   if (tempentry->acct != NULL)
     gftp_set_account (request, tempentry->acct);
@@ -418,7 +418,6 @@
   gftp_set_hostname (request, tempentry->hostname);
   gftp_set_directory (request, tempentry->remote_dir);
   gftp_set_port (request, tempentry->port);
-  gftp_set_sftpserv_path (request, tempentry->sftpserv_path);
 
   for (i = 0; gftp_protocols[i].name; i++)
     {
@@ -429,12 +428,18 @@
         }
     }
 
-  if (!gftp_protocols[i].name)
+  if (gftp_protocols[i].name == NULL)
     {
-      for (i = 0; gftp_protocols[i].url_prefix; i++)
+      gftp_lookup_request_option (request, "default_protocol", 
+                                  &default_protocol);
+
+      if (*default_protocol != '\0')
         {
-          if (strcmp (gftp_protocols[i].name, default_protocol) == 0)
-            break;
+          for (i = 0; gftp_protocols[i].url_prefix; i++)
+            {
+              if (strcmp (gftp_protocols[i].name, default_protocol) == 0)
+                break;
+            }
         }
 
       if (gftp_protocols[i].url_prefix == NULL)
@@ -449,7 +454,7 @@
 int
 gftp_parse_url (gftp_request * request, const char *url)
 {
-  char *pos, *endpos, *endhostpos, *str, tempchar;
+  char *pos, *endpos, *endhostpos, *str, tempchar, *default_protocol;
   gftp_logging_func logging_function;
   const char *stpos;
   int len, i;
@@ -463,6 +468,8 @@
 
   for (stpos = url; *stpos == ' '; stpos++);
 
+  i = GFTP_FTP_NUM;
+
   if ((pos = strstr (stpos, "://")) != NULL)
     {
       *pos = '\0';
@@ -479,15 +486,21 @@
     }
   else
     {
-      for (i = 0; gftp_protocols[i].url_prefix; i++)
+      gftp_lookup_request_option (request, "default_protocol", 
+                                  &default_protocol);
+
+      if (*default_protocol != '\0')
         {
-          if (strcmp (gftp_protocols[i].name, default_protocol) == 0)
-            break;
+          for (i = 0; gftp_protocols[i].url_prefix; i++)
+            {
+              if (strcmp (gftp_protocols[i].name, default_protocol) == 0)
+                break;
+            }
         }
+    }
 
-      if (gftp_protocols[i].url_prefix == NULL)
-        i = GFTP_FTP_NUM;
-    }
+  if (gftp_protocols[i].url_prefix == NULL)
+    i = GFTP_FTP_NUM;
 
   gftp_protocols[i].init (request);
 
@@ -562,17 +575,6 @@
 }
 
 
-int
-gftp_set_data_type (gftp_request * request, int data_type)
-{
-  g_return_val_if_fail (request != NULL, GFTP_EFATAL);
-
-  if (request->set_data_type == NULL)
-    return (0);
-  return (request->set_data_type (request, data_type));
-}
-
-
 void
 gftp_set_hostname (gftp_request * request, const char *hostname)
 {
@@ -658,67 +660,6 @@
 }
 
 
-void
-gftp_set_proxy_hostname (gftp_request * request, const char *hostname)
-{
-  g_return_if_fail (request != NULL);
-  g_return_if_fail (hostname != NULL);
-
-  if (request->proxy_hostname)
-    g_free (request->proxy_hostname);
-  request->proxy_hostname = g_malloc (strlen (hostname) + 1);
-  strcpy (request->proxy_hostname, hostname);
-}
-
-
-void
-gftp_set_proxy_username (gftp_request * request, const char *username)
-{
-  g_return_if_fail (request != NULL);
-  g_return_if_fail (username != NULL);
-
-  if (request->proxy_username)
-    g_free (request->proxy_username);
-  request->proxy_username = g_malloc (strlen (username) + 1);
-  strcpy (request->proxy_username, username);
-}
-
-
-void
-gftp_set_proxy_password (gftp_request * request, const char *password)
-{
-  g_return_if_fail (request != NULL);
-  g_return_if_fail (password != NULL);
-
-  if (request->proxy_password)
-    g_free (request->proxy_password);
-  request->proxy_password = g_malloc (strlen (password) + 1);
-  strcpy (request->proxy_password, password);
-}
-
-
-void
-gftp_set_proxy_account (gftp_request * request, const char *account)
-{
-  g_return_if_fail (request != NULL);
-  g_return_if_fail (account != NULL);
-
-  if (request->proxy_account)
-    g_free (request->proxy_account);
-  request->proxy_account = g_malloc (strlen (account) + 1);
-  strcpy (request->proxy_account, account);
-}
-
-
-void
-gftp_set_proxy_port (gftp_request * request, unsigned int port)
-{
-  g_return_if_fail (request != NULL);
-
-  request->proxy_port = port;
-}
-
-
 int
 gftp_remove_directory (gftp_request * request, const char *directory)
 {
@@ -797,39 +738,6 @@
 }
 
 
-void
-gftp_set_proxy_config (gftp_request * request, const char *proxy_config)
-{
-  int len;
-
-  g_return_if_fail (request != NULL);
-
-  if (request->proxy_config != NULL)
-    g_free (request->proxy_config);
-
-  if (proxy_config == NULL)
-    {
-      request->proxy_config = NULL;
-      return;
-    }
-
-  len = strlen (proxy_config);
-
-  if (len > 0 && (proxy_config[len - 1] != 'n' ||
-		  proxy_config[len - 2] != '%'))
-    len += 2;
-
-  request->proxy_config = g_malloc (len + 1);
-  strcpy (request->proxy_config, proxy_config);
-  if (len != strlen (proxy_config))
-    {
-      request->proxy_config[len - 2] = '%';
-      request->proxy_config[len - 1] = 'n';
-      request->proxy_config[len] = '\0';
-    }
-}
-
-
 off_t
 gftp_get_file_size (gftp_request * request, const char *filename)
 {
@@ -841,9 +749,11 @@
 }
 
 
-int
-gftp_need_proxy (gftp_request * request, char *service)
+static int
+gftp_need_proxy (gftp_request * request, char *service, char *proxy_hostname, 
+                 int proxy_port)
 {
+  gftp_config_list_vars * proxy_hosts;
   gftp_proxy_hosts * hostname;
   unsigned char addy[4];
   struct sockaddr *addr;
@@ -854,20 +764,24 @@
   struct addrinfo hints;
   int port, errnum;
   char serv[8];
+#endif
+
+  gftp_lookup_global_option ("ext", &proxy_hosts);
+
+  if (proxy_hostname == NULL || *proxy_hostname == '\0')
+    return (0);
+  else if (proxy_hosts->list == NULL)
+    return (proxy_hostname != NULL && 
+            *proxy_hostname != '\0');
 
   request->hostp = NULL;
-  if (proxy_hosts == NULL)
-    return (request->proxy_hostname != NULL
-	    && *request->proxy_hostname != '\0'
-	    && request->proxy_config != NULL
-	    && *request->proxy_config != '\0');
-
+#if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
   memset (&hints, 0, sizeof (hints));
   hints.ai_flags = AI_CANONNAME;
   hints.ai_family = AF_INET;
   hints.ai_socktype = SOCK_STREAM;
 
-  port = request->use_proxy ? request->proxy_port : request->port;
+  port = request->use_proxy ? proxy_port : request->port;
   if (port == 0)
     strcpy (serv, service);
   else
@@ -888,14 +802,6 @@
   addr = request->hostp->ai_addr;
 
 #else /* !HAVE_GETADDRINFO */
-
-  request->hostp = NULL;
-  if (proxy_hosts == NULL)
-    return (request->proxy_hostname != NULL
-            && *request->proxy_hostname != '\0'
-            && request->proxy_config != NULL
-            && *request->proxy_config != '\0');
-
   request->logging_function (gftp_logging_misc, request->user_data,
                              _("Looking up %s\n"), request->hostname);
 
@@ -912,7 +818,7 @@
 
 #endif /* HAVE_GETADDRINFO */
 
-  templist = proxy_hosts;
+  templist = proxy_hosts->list;
   while (templist != NULL)
     {
       hostname = templist->data;
@@ -937,48 +843,8 @@
 	}
       templist = templist->next;
     }
-  return (request->proxy_hostname != NULL && *request->proxy_hostname != '\0'
-	  && request->proxy_config != NULL && *request->proxy_config != '\0');
-}
 
-
-char *
-gftp_convert_ascii (char *buf, ssize_t *len, int direction)
-{
-  ssize_t i, j, newsize;
-  char *tempstr;
-
-  if (direction == GFTP_DIRECTION_DOWNLOAD)
-    {
-      for (i = 0, j = 0; i < *len; i++)
-        {
-          if (buf[i] != '\r')
-            buf[j++] = buf[i];
-          else
-            --*len;
-        }
-      tempstr = buf;
-    }
-  else
-    {
-      newsize = 0;
-      for (i = 0; i < *len; i++)
-        {
-          newsize++;
-          if (i > 0 && buf[i] == '\n' && buf[i - 1] != '\r')
-            newsize++;
-        }
-      tempstr = g_malloc (newsize);
-
-      for (i = 0, j = 0; i < *len; i++)
-        {
-          if (i > 0 && buf[i] == '\n' && buf[i - 1] != '\r')
-            tempstr[j++] = '\r';
-          tempstr[j++] = buf[i];
-        }
-      *len = newsize;
-    }
-  return (tempstr);
+  return (proxy_hostname != NULL && *proxy_hostname != '\0');
 }
 
 
@@ -1128,7 +994,7 @@
   fle->file = g_strdup (str);
 
   curpos = goto_next_token (curpos + 1);
-  fle->size = strtol (curpos, NULL, 10) * 512; /* FIXME - Is this correct? */
+  fle->size = strtol (curpos, NULL, 10) * 512; /* Is this correct? */
   curpos = goto_next_token (curpos);
 
   if ((fle->datetime = parse_time (curpos, &curpos)) == 0)
@@ -1264,8 +1130,8 @@
       startpos = goto_next_token (startpos);
     }
 
-  /* FIXME - make this GFTP_TYPE_CRAY */
-  if (request->server_type != GFTP_TYPE_UNIX)
+  /* FIXME - make this GFTP_DIRTYPE_CRAY */
+  if (request->server_type != GFTP_DIRTYPE_UNIX)
     {
       /* See if this is a Cray directory listing. It has the following format:
       drwx------     2 feiliu    g913     DK  common      4096 Sep 24  2001 wv */
@@ -1419,19 +1285,20 @@
 
   switch (request->server_type)
     {
-      case GFTP_TYPE_UNIX:
-	result = gftp_parse_ls_unix (request, str, fle);
+      case GFTP_DIRTYPE_CRAY:
+      case GFTP_DIRTYPE_UNIX:
+        result = gftp_parse_ls_unix (request, str, fle);
         break;
-      case GFTP_TYPE_EPLF:
+      case GFTP_DIRTYPE_EPLF:
         result = gftp_parse_ls_eplf (str, fle);
         break;
-      case GFTP_TYPE_NOVELL:
+      case GFTP_DIRTYPE_NOVELL:
         result = gftp_parse_ls_novell (str, fle);
         break;
-      case GFTP_TYPE_DOS:
+      case GFTP_DIRTYPE_DOS:
         result = gftp_parse_ls_nt (str, fle);
         break;
-      case GFTP_TYPE_VMS:
+      case GFTP_DIRTYPE_VMS:
         result = gftp_parse_ls_vms (str, fle);
         break;
       default: /* autodetect */
@@ -1673,11 +1540,7 @@
             transfer->toreq->directory = oldtodir;
         }
       else
-        {
-          curfle->ascii = gftp_get_file_transfer_mode (curfle->file, 
-                              transfer->fromreq->data_type) == GFTP_TYPE_ASCII;
-          transfer->numfiles++;
-        }
+        transfer->numfiles++;
     }
 
   if (forcecd)
@@ -1694,36 +1557,8 @@
 }
 
 
-int
-gftp_get_file_transfer_mode (char *filename, int def)
-{
-  gftp_file_extensions * tempext;
-  GList * templist;
-  int stlen, ret;
-
-  ret = def;
-  stlen = strlen (filename);
-  for (templist = registered_exts; templist != NULL; templist = templist->next)
-    {
-      tempext = templist->data;
-
-      if (stlen >= tempext->stlen &&
-          strcmp (&filename[stlen - tempext->stlen], tempext->ext) == 0)
-        {
-          if (toupper (*tempext->ascii_binary == 'A'))
-            ret = GFTP_TYPE_ASCII;
-          else if (toupper (*tempext->ascii_binary == 'B'))
-            ret = GFTP_TYPE_BINARY;
-          break;
-        }
-    }
-
-  return (ret);
-}
-
-
 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
-int
+static int
 get_port (struct addrinfo *addr)
 {
   struct sockaddr_in * saddr;
@@ -1743,7 +1578,8 @@
 
 
 int
-gftp_connect_server (gftp_request * request, char *service)
+gftp_connect_server (gftp_request * request, char *service,
+                     char *proxy_hostname, int proxy_port)
 {
   char *connect_host, *disphost;
   int port, sock;
@@ -1752,7 +1588,8 @@
   char serv[8];
   int errnum;
 
-  if ((request->use_proxy = gftp_need_proxy (request, service)) < 0)
+  if ((request->use_proxy = gftp_need_proxy (request, service,
+                                             proxy_hostname, proxy_port)) < 0)
     return (request->use_proxy);
   else if (request->use_proxy == 1)
     request->hostp = NULL;
@@ -1762,9 +1599,16 @@
   hints.ai_family = AF_INET;
   hints.ai_socktype = SOCK_STREAM;
 
-  connect_host = request->use_proxy ? request->proxy_hostname : 
-                                      request->hostname;
-  port = request->use_proxy ? request->proxy_port : request->port;
+  if (request->use_proxy)
+    {
+      connect_host = proxy_hostname;
+      port = proxy_port;
+    }
+  else
+    {
+      connect_host = request->hostname;
+      port = request->port;
+    }
 
   if (request->hostp == NULL)
     {
@@ -1831,7 +1675,8 @@
   struct servent serv_struct;
   int curhost;
 
-  if ((request->use_proxy = gftp_need_proxy (request, service)) < 0)
+  if ((request->use_proxy = gftp_need_proxy (request, service,
+                                             proxy_hostname, proxy_port)) < 0)
     return (request->use_proxy);
   else if (request->use_proxy == 1)
     request->hostp = NULL;
@@ -1847,16 +1692,26 @@
   memset (&remote_address, 0, sizeof (remote_address));
   remote_address.sin_family = AF_INET;
 
-  connect_host = request->use_proxy ? request->proxy_hostname : 
-                                      request->hostname;
-  port = htons (request->use_proxy ? request->proxy_port : request->port);
+  if (request->use_proxy)
+    {
+      connect_host = proxy_hostname;
+      port = proxy_port;
+    }
+  else
+    {
+      connect_host = request->hostname;
+      port = request->port;
+    }
 
   if (port == 0)
     {
       if (!r_getservbyname (service, "tcp", &serv_struct, NULL))
         {
-          port = htons (21);
-          request->port = 21;
+          request->logging_function (gftp_logging_error, request->user_data,
+                                     _("Cannot look up service name %s/tcp. Please check your services file\n"),
+                                     service);
+          close (sock);
+          return (GFTP_EFATAL);
         }
       else
         {
@@ -1928,35 +1783,12 @@
 void
 gftp_set_config_options (gftp_request * request)
 {
-  request->network_timeout = network_timeout;
-  request->retries = retries;
-  request->sleep_time = sleep_time;
-  request->maxkbs = maxkbs;
-
   if (request->set_config_options != NULL)
     request->set_config_options (request);
 }
 
 
 void
-gftp_set_sftpserv_path (gftp_request * request, char *path)
-{
-  g_return_if_fail (request != NULL);
-
-  if (request->sftpserv_path)
-    g_free (request->sftpserv_path);
-
-  if (path != NULL && *path != '\0')
-    {
-      request->sftpserv_path = g_malloc (strlen (path) + 1);
-      strcpy (request->sftpserv_path, path);
-    }
-  else
-    request->sftpserv_path = NULL;
-}
-
-
-void
 print_file_list (GList * list)
 {
   gftp_file * tempfle;
@@ -2096,20 +1928,20 @@
 ssize_t 
 gftp_read (gftp_request * request, void *ptr, size_t size, int fd)
 {
+  long network_timeout;
   struct timeval tv;
   fd_set fset;
   ssize_t ret;
 
+  gftp_lookup_request_option (request, "network_timeout", &network_timeout);  
+
   errno = 0;
   ret = 0;
   do
     {
       FD_ZERO (&fset);
       FD_SET (fd, &fset);
-      if (request != NULL)
-        tv.tv_sec = request->network_timeout;
-      else
-        tv.tv_sec = network_timeout;
+      tv.tv_sec = network_timeout;
       tv.tv_usec = 0;
       ret = select (fd + 1, &fset, NULL, NULL, &tv);
       if (ret == -1 && errno == EINTR)
@@ -2166,20 +1998,20 @@
 ssize_t 
 gftp_write (gftp_request * request, const char *ptr, size_t size, int fd)
 {
+  long network_timeout;
   struct timeval tv;
   size_t ret, w_ret;
   fd_set fset;
 
+  gftp_lookup_request_option (request, "network_timeout", &network_timeout);  
+
   errno = 0;
   ret = 0;
   do
     {
       FD_ZERO (&fset);
       FD_SET (fd, &fset);
-      if (request != NULL)
-        tv.tv_sec = request->network_timeout;
-      else
-        tv.tv_sec = network_timeout;
+      tv.tv_sec = network_timeout;
       tv.tv_usec = 0;
       ret = select (fd + 1, NULL, &fset, NULL, &tv);
       if (ret == -1 && errno == EINTR)
@@ -2307,3 +2139,67 @@
     dest->swap_socks (dest, source);
 }
 
+
+void
+gftp_calc_kbs (gftp_transfer * tdata, ssize_t num_read)
+{
+  unsigned long waitusecs;
+  double difftime, curkbs;
+  gftp_file * tempfle;
+  unsigned long toadd;
+  struct timeval tv;
+  float maxkbs;
+
+  gftp_lookup_request_option (tdata->fromreq, "maxkbs", &maxkbs);
+
+  gettimeofday (&tv, NULL);
+  if (g_thread_supported ())
+    g_static_mutex_lock (&tdata->statmutex);
+
+  tempfle = tdata->curfle->data;
+  tdata->trans_bytes += num_read;
+  tdata->curtrans += num_read;
+  tdata->stalled = 0;
+
+  difftime = (tv.tv_sec - tdata->starttime.tv_sec) + ((double) (tv.tv_usec - tdata->starttime.tv_usec) / 1000000.0);
+  if (difftime <= 0)
+    tdata->kbs = (double) tdata->trans_bytes / 1024.0;
+  else
+    tdata->kbs = (double) tdata->trans_bytes / 1024.0 / difftime;
+
+  difftime = (tv.tv_sec - tdata->lasttime.tv_sec) + ((double) (tv.tv_usec - tdata->lasttime.tv_usec) / 1000000.0);
+
+  if (difftime <= 0)
+    curkbs = (double) (num_read / 1024.0);
+  else
+    curkbs = (double) (num_read / 1024.0 / difftime);
+
+  if (maxkbs > 0 && curkbs > maxkbs)
+    {
+      waitusecs = (double) num_read / 1024.0 / maxkbs * 1000000.0 - difftime;
+
+      if (waitusecs > 0)
+        {
+          if (g_thread_supported ())
+            g_static_mutex_unlock (&tdata->statmutex);
+
+          difftime += ((double) waitusecs / 1000000.0);
+          usleep (waitusecs);
+
+          if (g_thread_supported ())
+            g_static_mutex_lock (&tdata->statmutex);
+        }
+    }
+
+  /* I don't call gettimeofday (&tdata->lasttime) here because this will use
+     less system resources. This will be close enough for what we need */
+  difftime += tdata->lasttime.tv_usec / 1000000.0;
+  toadd = (long) difftime;
+  difftime -= toadd;
+  tdata->lasttime.tv_sec += toadd;
+  tdata->lasttime.tv_usec = difftime * 1000000.0;
+
+  if (g_thread_supported ())
+    g_static_mutex_unlock (&tdata->statmutex);
+}
+