diff -r 38a0105c05ea src/exits.c
--- a/src/exits.c	Sat Oct 24 16:06:44 2009 -0700
+++ b/src/exits.c	Wed Dec 02 04:05:25 2009 +0800
@@ -76,7 +76,7 @@
     case CONTNOTSUPPORTED: case RANGEERR: case RETRBADPATTERN:
     case PROXERR:
       return WGET_EXIT_SERVER_ERROR;
-    case URLERROR: case QUOTEXC: case SSLINITFAILED:
+    case URLERROR: case QUOTEXC: case SSLINITFAILED: case HARDQUOTAEXCEEDED:
     default:
       return WGET_EXIT_UNKNOWN;
     }
diff -r 38a0105c05ea src/ftp.c
--- a/src/ftp.c	Sat Oct 24 16:06:44 2009 -0700
+++ b/src/ftp.c	Wed Dec 02 04:05:25 2009 +0800
@@ -968,6 +968,7 @@
           con->csock = -1;
           fd_close (dtsock);
           fd_close (local_sock);
+          if (res == HARDQUOTAEXCEEDED) return HARDQUOTAEXCEEDED;
           return RETRFINISHED;
         }
 
@@ -1233,8 +1234,17 @@
   if (!output_stream || con->cmd & DO_LIST)
     fclose (fp);
 
+  if (res == -3)
+    {
+      logprintf (LOG_NOTQUIET, _("Hard quota exceeded: %s, closing control connection.\n"),
+                 con->target);
+      fd_close (csock);
+      con->csock = -1;
+      fd_close (dtsock);
+      return HARDQUOTAEXCEEDED;
+    }
   /* If fd_read_body couldn't write to fp, bail out.  */
-  if (res == -2)
+  else if (res == -2)
     {
       logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"),
                  con->target, strerror (errno));
@@ -1468,6 +1478,7 @@
         {
         case HOSTERR: case CONIMPOSSIBLE: case FWRITEERR: case FOPENERR:
         case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
+        case HARDQUOTAEXCEEDED:
           /* Fatal errors, give up.  */
           return err;
         case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
@@ -1693,6 +1704,11 @@
           --depth;
           return QUOTEXC;
         }
+      if (opt.hard_quota && total_downloaded_bytes > opt.hard_quota)
+        {
+          --depth;
+          return HARDQUOTAEXCEEDED;
+        }
       old_target = con->target;
 
       ofile = xstrdup (u->file);
@@ -1868,7 +1884,7 @@
       xfree (ofile);
 
       /* Break on fatals.  */
-      if (err == QUOTEXC || err == HOSTERR || err == FWRITEERR)
+      if (err == HARDQUOTAEXCEEDED || err == QUOTEXC || err == HOSTERR || err == FWRITEERR)
         break;
       con->cmd &= ~ (DO_CWD | DO_LOGIN);
       f = f->next;
@@ -1902,6 +1918,8 @@
 
       if (opt.quota && total_downloaded_bytes > opt.quota)
         break;
+      if (opt.hard_quota && total_downloaded_bytes > opt.hard_quota)
+        break;
       if (f->type != FT_DIRECTORY)
         continue;
 
@@ -1940,17 +1958,21 @@
       odir = xstrdup (u->dir);  /* because url_set_dir will free
                                    u->dir. */
       url_set_dir (u, newdir);
-      ftp_retrieve_glob (u, con, GLOB_GETALL);
+      uerr_t res=ftp_retrieve_glob (u, con, GLOB_GETALL);
       url_set_dir (u, odir);
       xfree (odir);
 
       /* Set the time-stamp?  */
+
+      //fatal, bail out.
+      if(res == HARDQUOTAEXCEEDED)return HARDQUOTAEXCEEDED;
     }
 
   if (opt.quota && total_downloaded_bytes > opt.quota)
     return QUOTEXC;
-  else
-    return RETROK;
+  if (opt.hard_quota && total_downloaded_bytes > opt.hard_quota)
+    return HARDQUOTAEXCEEDED;
+  return RETROK;
 }
 
 /* Return true if S has a leading '/'  or contains '../' */
@@ -2079,7 +2101,7 @@
   if (start)
     {
       /* Just get everything.  */
-      ftp_retrieve_list (u, start, con);
+      res = ftp_retrieve_list (u, start, con);
     }
   else
     {
@@ -2105,11 +2127,12 @@
       */
     }
   freefileinfo (start);
+  if (res == HARDQUOTAEXCEEDED)
+    return HARDQUOTAEXCEEDED;
   if (opt.quota && total_downloaded_bytes > opt.quota)
     return QUOTEXC;
-  else
-    /* #### Should we return `res' here?  */
-    return RETROK;
+  /* #### Should we return `res' here?  */
+  return RETROK;
 }
 
 /* The wrapper that calls an appropriate routine according to contents
diff -r 38a0105c05ea src/http.c
--- a/src/http.c	Sat Oct 24 16:06:44 2009 -0700
+++ b/src/http.c	Wed Dec 02 04:05:25 2009 +0800
@@ -2396,7 +2396,12 @@
   else
     {
       if (hs->res < 0)
-        hs->rderrmsg = xstrdup (fd_errstr (sock));
+        {
+    	  if (hs->res == -3)
+    	    hs->rderrmsg = xstrdup (_("Hard quota exceeded"));
+    	  else
+            hs->rderrmsg = xstrdup (fd_errstr (sock));
+        }
       CLOSE_INVALIDATE (sock);
     }
 
@@ -2404,6 +2409,11 @@
     fclose (fp);
   if (hs->res == -2)
     return FWRITEERR;
+  if (hs->res == -3)
+    {
+      logprintf (LOG_NOTQUIET, "%s\n", hs->rderrmsg);
+      return HARDQUOTAEXCEEDED;
+    }
   return RETRFINISHED;
 }
 
@@ -2603,7 +2613,7 @@
           logprintf (LOG_NOTQUIET, _("Cannot write to %s (%s).\n"),
                      quote (hstat.local_file), strerror (errno));
         case HOSTERR: case CONIMPOSSIBLE: case PROXERR: case AUTHFAILED:
-        case SSLINITFAILED: case CONTNOTSUPPORTED: case VERIFCERTERR:
+        case SSLINITFAILED: case CONTNOTSUPPORTED: case VERIFCERTERR: case HARDQUOTAEXCEEDED:
           /* Fatal errors just return from the function.  */
           ret = err;
           goto exit;
@@ -2914,8 +2924,34 @@
               goto exit;
             }
         }
-      else /* from now on hstat.res can only be -1 */
+      else /* from now on hstat.res can only be -1 or -3 */
         {
+    	  //start of -3 handling
+    	  if (hstat.res == -3)
+			{
+              if (hstat.contlen == -1)
+	            {
+                  logprintf (LOG_VERBOSE,
+                             _("%s (%s) - Interrupting at byte %s (%s).\n"),
+                             tms, tmrate, number_to_static_string (hstat.len),
+                             hstat.rderrmsg);
+                  ret = HARDQUOTAEXCEEDED;
+                  break;
+                }
+              else /* hstat.res == -3 and contlen is given */
+                {
+                  logprintf (LOG_VERBOSE,
+                             _("%s (%s) - Interrupting at byte %s/%s (%s).\n"),
+                             tms, tmrate,
+                             number_to_static_string (hstat.len),
+                             number_to_static_string (hstat.contlen),
+                             hstat.rderrmsg);
+                  ret = HARDQUOTAEXCEEDED;
+                  break;
+                }
+		    }
+    	  //end of -3 handling
+
           if (hstat.contlen == -1)
             {
               logprintf (LOG_VERBOSE,
@@ -2942,7 +2978,7 @@
   while (!opt.ntry || (count < opt.ntry));
 
 exit:
-  if (ret == RETROK)
+  if (ret == RETROK || ret == HARDQUOTAEXCEEDED)
     *local_file = xstrdup (hstat.local_file);
   free_hstat (&hstat);
 
diff -r 38a0105c05ea src/init.c
--- a/src/init.c	Sat Oct 24 16:06:44 2009 -0700
+++ b/src/init.c	Wed Dec 02 04:05:25 2009 +0800
@@ -163,6 +163,7 @@
 #endif /* def __VMS */
   { "ftpuser",          &opt.ftp_user,          cmd_string },
   { "glob",             &opt.ftp_glob,          cmd_boolean },
+  { "hardquota",        &opt.hard_quota,        cmd_bytes_sum },
   { "header",           NULL,                   cmd_spec_header },
   { "htmlextension",    &opt.adjust_extension,  cmd_boolean }, /* deprecated */
   { "htmlify",          NULL,                   cmd_spec_htmlify },
diff -r 38a0105c05ea src/main.c
--- a/src/main.c	Sat Oct 24 16:06:44 2009 -0700
+++ b/src/main.c	Wed Dec 02 04:05:25 2009 +0800
@@ -244,6 +244,7 @@
     { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
     { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
     { "quota", 'Q', OPT_VALUE, "quota", -1 },
+    { "hard-quota", 0, OPT_VALUE, "hardquota", -1 },
     { "random-file", 0, OPT_VALUE, "randomfile", -1 },
     { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
     { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
@@ -477,7 +478,9 @@
     N_("\
        --no-proxy                explicitly turn off proxy.\n"),
     N_("\
-  -Q,  --quota=NUMBER            set retrieval quota to NUMBER.\n"),
+  -Q,  --quota=NUMBER            set retrieval soft quota to NUMBER.\n"),
+    N_("\
+       --hard-quota=NUMBER       set retrieval hard quota to NUMBER.\n"),
     N_("\
        --bind-address=ADDRESS    bind to ADDRESS (hostname or IP) on local host.\n"),
     N_("\
@@ -1301,10 +1304,11 @@
           url_free (url_parsed);
         }
       iri_free (iri);
+      if(status == HARDQUOTAEXCEEDED)break;
     }
 
   /* And then from the input file, if any.  */
-  if (opt.input_filename)
+  if (status != HARDQUOTAEXCEEDED && opt.input_filename)
     {
       int count;
       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
@@ -1340,6 +1344,11 @@
                    human_readable (opt.quota));
     }
 
+  if (opt.hard_quota && total_downloaded_bytes > opt.hard_quota)
+    logprintf (LOG_NOTQUIET,
+                   _("Download hard quota of %s EXCEEDED!\n"),
+                   human_readable (opt.hard_quota));
+
   if (opt.cookies_output)
     save_cookies ();
 
diff -r 38a0105c05ea src/options.h
--- a/src/options.h	Sat Oct 24 16:06:44 2009 -0700
+++ b/src/options.h	Wed Dec 02 04:05:25 2009 +0800
@@ -123,6 +123,7 @@
 				   many bps. */
   SUM_SIZE_INT quota;		/* Maximum file size to download and
 				   store. */
+  SUM_SIZE_INT hard_quota;		/* Maximum traffic (bytes) to download. */
 
   bool server_response;		/* Do we print server response? */
   bool save_headers;		/* Do we save headers together with
diff -r 38a0105c05ea src/recur.c
--- a/src/recur.c	Sat Oct 24 16:06:44 2009 -0700
+++ b/src/recur.c	Wed Dec 02 04:05:25 2009 +0800
@@ -235,7 +235,9 @@
 
       if (opt.quota && total_downloaded_bytes > opt.quota)
         break;
-      if (status == FWRITEERR)
+      if (opt.hard_quota && total_downloaded_bytes > opt.hard_quota)
+        break;
+      if (status == FWRITEERR || status == HARDQUOTAEXCEEDED)
         break;
 
       /* Get the next URL from the queue... */
@@ -284,6 +286,7 @@
 
           status = retrieve_url (url_parsed, url, &file, &redirected, referer,
                                  &dt, false, i, true);
+          if(status == HARDQUOTAEXCEEDED)break;
 
           if (html_allowed && file && status == RETROK
               && (dt & RETROKF) && (dt & TEXTHTML))
@@ -471,10 +474,13 @@
 
   if (opt.quota && total_downloaded_bytes > opt.quota)
     return QUOTEXC;
-  else if (status == FWRITEERR)
+  if (status == HARDQUOTAEXCEEDED)
+    return HARDQUOTAEXCEEDED;
+  if (opt.hard_quota && total_downloaded_bytes > opt.hard_quota)
+    return HARDQUOTAEXCEEDED;
+  if (status == FWRITEERR)
     return FWRITEERR;
-  else
-    return RETROK;
+  return RETROK;
 }
 
 /* Based on the context provided by retrieve_tree, decide whether a
diff -r 38a0105c05ea src/retr.c
--- a/src/retr.c	Sat Oct 24 16:06:44 2009 -0700
+++ b/src/retr.c	Wed Dec 02 04:05:25 2009 +0800
@@ -185,9 +185,9 @@
 }
 
 /* Read the contents of file descriptor FD until it the connection
-   terminates or a read error occurs.  The data is read in portions of
-   up to 16K and written to OUT as it arrives.  If opt.verbose is set,
-   the progress is shown.
+   terminates, a read error occurs, or traffic hard quota is exceeded.
+   The data is read in portions of up to 16K and written to OUT as it
+   arrives.  If opt.verbose is set, the progress is shown.
 
    TOREAD is the amount of data expected to arrive, normally only used
    by the progress gauge.
@@ -201,7 +201,8 @@
 
    The function exits and returns the amount of data read.  In case of
    error while reading data, -1 is returned.  In case of error while
-   writing data, -2 is returned.  */
+   writing data, -2 is returned.  In case of traffic hard quota exceeded,
+   -3 is returned. */
 
 int
 fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
@@ -236,6 +237,13 @@
 
   if (opt.verbose)
     {
+	  if (opt.hard_quota)
+		{
+	      logprintf(LOG_VERBOSE, _("Hard quota: %s (%s).\n"),
+			  number_to_static_string(opt.hard_quota),
+			  human_readable (opt.hard_quota));
+
+        }
       /* If we're skipping STARTPOS bytes, pass 0 as the INITIAL
          argument to progress_create because the indicator doesn't
          (yet) know about "skipping" data.  */
@@ -263,13 +271,22 @@
   if (opt.limit_rate && opt.limit_rate < dlbufsize)
     dlbufsize = opt.limit_rate;
 
-  /* Read from FD while there is data to read.  Normally toread==0
+  SUM_SIZE_INT total_downloaded_bytes_tmp=total_downloaded_bytes;
+
+/* Read from FD while there is data to read.  Normally toread==0
      means that it is unknown how much data is to arrive.  However, if
      EXACT is set, then toread==0 means what it says: that no data
      should be read.  */
   while (!exact || (sum_read < toread))
     {
       int rdsize = exact ? MIN (toread - sum_read, dlbufsize) : dlbufsize;
+      if (opt.hard_quota)
+        {
+    	  rdsize = MIN (rdsize, opt.hard_quota - total_downloaded_bytes_tmp);
+    	  if (rdsize < 0) rdsize = 0;
+    	  if (rdsize == 0) { ret = -3; goto out; }
+        }
+
       double tmout = opt.read_timeout;
       if (progress_interactive)
         {
@@ -311,6 +328,7 @@
       if (ret > 0)
         {
           sum_read += ret;
+          total_downloaded_bytes_tmp += ret;
           if (!write_data (out, dlbuf, ret, &skip, &sum_written))
             {
               ret = -2;
diff -r 38a0105c05ea src/wget.h
--- a/src/wget.h	Sat Oct 24 16:06:44 2009 -0700
+++ b/src/wget.h	Wed Dec 02 04:05:25 2009 +0800
@@ -351,7 +351,7 @@
   RETRBADPATTERN, RETNOTSUP /* ! */, ROBOTSOK /* ! */, NOROBOTS /* ! */,
   PROXERR,
   /* 50  */
-  AUTHFAILED, QUOTEXC, WRITEFAILED, SSLINITFAILED, VERIFCERTERR
+  AUTHFAILED, QUOTEXC, WRITEFAILED, SSLINITFAILED, VERIFCERTERR, HARDQUOTAEXCEEDED
 } uerr_t;
 
 /* 2005-02-19 SMS.
