--- src/networks/donkey/donkeyClient.ml	2006-12-21 23:36:03.000000000 +0100
+++ src/networks/donkey/donkeyClient.ml	2006-12-22 03:55:52.196777232 +0100
@@ -415,17 +415,45 @@
     end
         
   
-let new_chunk up begin_pos end_pos =
-  if begin_pos <> end_pos then
-    let pair = (begin_pos, end_pos) in
+let new_chunks up chunks =
+  if (not up.up_finish) || (not !!upload_complete_chunks) then
+  List.iter (fun ((begin_pos, end_pos) as chunk) ->
+    begin
+    let req_size = end_pos -- begin_pos in
+    let req_location = (begin_pos ++ end_pos) // (2L ** block_size) in
+    if !verbose_upload then
+      lprintf_nl "new block: (%Ld,%Ld) size %Ld chunk #%Ld" begin_pos end_pos req_size req_location;
+    if (req_size < Int64.zero) || (req_size > zone_size) || ((up.up_current <> req_location) && (req_size <> Int64.zero)) then
+      up.up_finish <- true;
+    if ((not up.up_finish) || (not !!upload_complete_chunks)) && (req_size > Int64.zero) && (req_size <= zone_size) then
+    if (not (List.mem chunk up.up_chunks_served)) ||
+      ((not (List.mem (begin_pos -- zone_size, begin_pos) chunks)) && (not (List.mem (end_pos, end_pos ++ zone_size) chunks))) then
     (match up.up_chunks with
         [] ->
           up.up_pos <- begin_pos;
           up.up_end_chunk <- end_pos;
-          up.up_chunks <- [pair];
+          up.up_chunks <- [chunk];
       | chunks ->
-          if not (List.mem pair chunks) then
-            up.up_chunks <- chunks @ [pair])
+          if not (List.mem chunk chunks) then
+            begin
+              List.iter (fun (b_e, e_e) ->
+                if !verbose && (((begin_pos >= b_e) && (begin_pos < e_e)) || ((end_pos > b_e) && (end_pos <= e_e))) then
+                  lprintf_nl "REREQUEST for file %s block: (%Ld,%Ld) matching served block: (%Ld,%Ld)"
+                    (file_best_name up.up_file) begin_pos end_pos b_e e_e;
+              ) up.up_chunks_served;
+              (match
+                try 
+                  List.find (fun (b_e, e_e) -> ((begin_pos >= b_e) && (begin_pos < e_e)) || ((end_pos > b_e) && (end_pos <= e_e))) chunks
+                with | Not_found -> (Int64.zero,Int64.zero)
+              with
+                (begin_exist, end_exist) ->
+                if begin_exist <> end_exist then
+                  lprintf_nl "blockreq exists, requested block: (%Ld,%Ld) existing block: (%Ld,%Ld)"
+                    begin_pos end_pos begin_exist end_exist);
+              up.up_chunks <- chunks @ [chunk];
+            end;)
+    end
+  ) chunks
   
 let identify_client_brand c =
   if c.client_brand = Brand_unknown then
@@ -2002,15 +2006,8 @@
 
       let prio = (file_priority file) in
       let client_upload_lifetime = ref ((max 0 !!upload_lifetime) * 60) in
-      let client_received_enough c =
-        if !!upload_full_chunks then
-          c.client_session_uploaded > (block_size ++ 20L ** 1024L)
-        else
-          last_time() > c.client_connect_time + !client_upload_lifetime + 5 * prio
-      in
-      begin
         
-        if !!dynamic_upload_lifetime
+      if !!dynamic_upload_lifetime && not !!upload_complete_chunks
             && c.client_session_uploaded > c.client_session_downloaded
             && c.client_session_uploaded > Int64.of_int !!dynamic_upload_threshold ** zone_size
         then
@@ -2018,6 +2015,15 @@
           Int64.to_int 
             (Int64.of_int !client_upload_lifetime 
               ** c.client_session_downloaded // c.client_session_uploaded);
+
+      let client_received_enough c =
+        if !!upload_full_chunks && not !!upload_complete_chunks then
+          c.client_session_uploaded > (block_size ++ 20L ** 1024L)
+        else
+          last_time() > c.client_connect_time + !client_upload_lifetime + 5 * prio
+      in
+
+      begin
         if client_received_enough c then
           begin
             DonkeyOneFile.remove_client_slot c;
@@ -2035,6 +2041,9 @@
                 up_pos = Int64.zero;
                 up_end_chunk = Int64.zero;
                 up_chunks = [];
+                up_chunks_served = [];
+                up_current = Int64.zero;
+                up_finish = true;
                 up_waiting = old_up.up_waiting;
               }, old_up.up_waiting
           | _ ->
@@ -2043,18 +2051,31 @@
                 up_pos = Int64.zero;
                 up_end_chunk = Int64.zero;
                 up_chunks = [];
+                up_chunks_served = [];
+                up_current = ((t.Q.start_pos1 ++ t.Q.end_pos1) // (2L ** block_size));
+                up_finish = false;
                 up_waiting = false;
               }, false
         in
-        new_chunk up t.Q.start_pos1 t.Q.end_pos1;
-        new_chunk up t.Q.start_pos2 t.Q.end_pos2;
-        new_chunk up t.Q.start_pos3 t.Q.end_pos3;
+        new_chunks up [(t.Q.start_pos1, t.Q.end_pos1);
+		       (t.Q.start_pos2, t.Q.end_pos2);
+		       (t.Q.start_pos3, t.Q.end_pos3)];
+        (match up.up_chunks with
+          [] ->
+(* it should never happen here, that a client with up.up_finish = false
+   has an empty block queue *)
+            if up.up_finish && !!upload_complete_chunks then
+              begin
+                DonkeyOneFile.remove_client_slot c;
+                raise Not_found
+              end;
+          | chunks ->
         c.client_upload <- Some up;
         set_client_upload (as_client c) (as_file file);
         if not waiting && !CommonUploads.has_upload = 0 then begin
             CommonUploads.ready_for_upload (as_client c);
             up.up_waiting <- true
-          end
+            end)
       end;
       if !verbose_upload then lprintf_nl "QueryBloc treated"
       
--- src/networks/donkey/donkeyFiles.ml	2006-12-21 22:29:19.000000000 +0100
+++ src/networks/donkey/donkeyFiles.ml	2006-12-22 03:31:43.855958504 +0100
@@ -241,10 +241,12 @@
                 up.up_chunks <- chunks;
+                up.up_chunks_served <- up.up_chunks_served @ [(begin_offset,end_offset)];
                 let per_client = per_client - max_len in
                 match chunks with
                   [] -> 
                     if !verbose_upload then
                         lprintf_nl "NO CHUNKS";
-                    c.client_upload <- None;
+                    if up.up_finish && !!upload_complete_chunks then
+                      DonkeyOneFile.remove_client_slot c;
                 | (begin_pos, end_pos) :: _ ->
                     up.up_pos <- begin_pos;
                     up.up_end_chunk <- end_pos;
--- src/networks/donkey/donkeyOptions.ml	2006-12-21 22:29:19.000000000 +0100
+++ src/networks/donkey/donkeyOptions.ml	2006-12-22 03:22:05.032952976 +0100
@@ -178,6 +178,12 @@
   "If true, each client is allowed to receive one chunk, this setting overrides upload_lifetime"
     bool_option false
 
+let upload_complete_chunks = define_expert_option donkey_section ["upload_complete_chunks"]
+  "If true, each client is allowed to complete only one chunk, independent, if it is empty or
+   partial. this setting overrides upload_full_chunks and dynamic_upload_lifetime,
+   but is, as a failsafe, limited by upload_lifetime (should be set reasonable high)"
+    bool_option false
+
 let dynamic_upload_lifetime = define_expert_option donkey_section ["dynamic_upload_lifetime"]
   "Each client upload lifetime depends on download-upload ratio"
     bool_option false
--- src/networks/donkey/donkeyTypes.ml	2006-12-21 22:29:19.000000000 +0100
+++ src/networks/donkey/donkeyTypes.ml	2006-12-22 02:10:44.952624088 +0100
@@ -618,6 +618,9 @@
     mutable up_pos : int64;
     mutable up_end_chunk : int64;
     mutable up_chunks : (int64 * int64) list;
+    mutable up_chunks_served : (int64 * int64) list;
+    mutable up_current : int64;
+    mutable up_finish : bool;
     mutable up_waiting : bool;
   }
 
