--- ChangeLog.orig	Sun Sep  3 15:36:13 2006
+++ ChangeLog	Sat Nov  4 23:29:19 2006
@@ -2,6 +2,28 @@
                         Enhanced CTorrent Change Log
      _________________________________________________________________
 
+   Changes for "dnh2.2" Release
+
+   Code Fixes
+     * Fixed checking of seed ratio (-E option) to allow fractional
+       values.
+     * Fixed CTCS interaction when a limit was not specified on the
+       command line.
+     * Fixed peer reconnect determination.
+     * Fixed a request-queue handling error that could cause a crash upon
+       becoming a seeder.
+     * Fixed creation of metainfo (torrent) file with multiple
+       subdirectories.
+     * Torrent metainfo is now only printed twice if hash-checking is
+       performed.
+
+   Operational Enhancements
+     * Errors flushing the cache are now handled more gracefully. (This
+       happens when the disk is full.)
+     * Added additional seeder detection criteria.
+     * Cleaned up parts of the help screen.
+     _________________________________________________________________
+
    Changes for "dnh2.1" Release
 
    Code Fixes
--- README-DNH.TXT.orig	Sun Sep  3 15:35:15 2006
+++ README-DNH.TXT	Sat Nov  4 23:39:51 2006
@@ -38,33 +38,13 @@
      * Performance optimization and bug fixes
      * An interface for monitoring and managing multiple clients
 
-  Status Line
+  Documentation
 
-   The status line that is output by the client has changed since the
-   original and deserves some explanation.
+   For documentation that provides a little more than the help screen,
+   please see the [11]User's Guide.
 
-       / 0/33/110 [672/672/672] 0MB,1130MB | 0,20K/s | 0,0K E:0,31
-       - - -- ---  --- --- ---  --- ------   - --      - -    - --
-       A B  C  D    E   F   G    H     I     J  K      L M    N  O
-
-   A: Ticker; this character changes to indicate that the client is
-   running.
-   B: Number of seeders (complete peers) to which you are connected.
-   C: Number of leechers (incomplete peers) to which you are connected.
-   D: Total number of peers in the swarm, as last reported by the
-   tracker.
-   E: Number of pieces of the torrent that you have completed.
-   F: Total number of pieces in the torrent.
-   G: Number of pieces currently available from you and your connected
-   peers.
-   H: Total amount of data you have downloaded.
-   I: Total amount of data you have uploaded.
-   J: Your current total download rate.
-   K: Your current total upload rate.
-   L: Amount of data downloaded since the last status line update.
-   M: Amount of data uploaded since the last status line update.
-   N: Number of tracker connection errors.
-   O: Number of successful tracker connections.
+   For a list of changes in the current and previous versions, see the
+   [12]ChangeLog file.
 
   Peer ID
 
@@ -80,7 +60,7 @@
 
   CTCS
 
-   [11]CTorrent Control Server (CTCS) is an interface for monitoring and
+   [13]CTorrent Control Server (CTCS) is an interface for monitoring and
    managing Enhanced CTorrent clients. It can manage allocation of
    bandwidth, provide status information, and allow changes to the
    running configuration of each client. Support for this interface was
@@ -89,47 +69,55 @@
 
    News
 
+   2006-11-05
+          Version dnh2.2 is [14]released, mostly for bug fixes. Thanks to
+          those who have reported them and helped with debugging!
+          A simple [15]user's guide is also available.
+
    2006-09-03
-          Version dnh2.1 is [12]released, along with [13]CTCS 1.1. Both
+          Version dnh2.1 is [16]released, along with [17]CTCS 1.1. Both
           updates fix issues when using CTCS on Linux, among other
           things.
 
    2006-04-26
-          The [14]CTCS protocol is finally documented.
+          The [18]CTCS protocol is finally documented.
 
    2006-04-25
-          A [15]patch is available to fix a bug in my solution for the
+          A [19]patch is available to fix a bug in my solution for the
           vfat filesystem issue. This bug can cause the client to crash
           when creating a file on any filesystem type; the patch is
           recommended for all users.
 
    2006-01-15
           Version dnh2 is released! This version includes a number of
-          significant [16]changes, including large file support, piece
+          significant [20]changes, including large file support, piece
           selection, tuned request queue depth, and support for
-          [17]CTorrent Control Server.
+          [21]CTorrent Control Server.
      _________________________________________________________________
 
-   Changes
+   Download
 
-   For a list of changes in the current and previous versions, see the
-   [18]ChangeLog file.
-     _________________________________________________________________
+   Release dnh2.2
 
-   Download
+   [22]dnh2.1 to dnh2.2 patch file
+   A patch file of changes to release dnh2.1 to bring it up to dnh2.2.
+
+   [23]Source distribution
+   A complete source distribution for all platforms.
+                    ___________________________________
 
    Release dnh2.1
 
-   [19]dnh2 to dnh2.1 patch file
+   [24]dnh2 to dnh2.1 patch file
    A patch file of changes to release dnh2 to bring it up to dnh2.1.
 
-   [20]Source distribution
+   [25]Source distribution
    A complete source distribution for all platforms.
                     ___________________________________
 
    Patch for vfat bug
 
-   [21]btfiles patch
+   [26]btfiles patch
    This fixes a coding bug in my solution for the vfat filesystem issue.
    This bug can cause the client to crash when creating a file on any
    filesystem type; the patch is recommended for all users of release
@@ -147,94 +135,42 @@
    previous releases. It will be faster and easier to just download the
    patched source distribution below.
 
-   [22]dnh1.2 to dnh2 patch file
+   [27]dnh1.2 to dnh2 patch file
    A patch file of changes to release dnh1.2 to bring it up to dnh2.
 
-   [23]Patch file
+   [28]Patch file
    A patch file of changes to the CTorrent 1.3.4 base.
 
-   [24]Patched source
+   [29]Patched source
    A complete source distribution for all platforms.
                     ___________________________________
 
-   Release dnh1.2
-   Note: If you get a message about needing to install OpenSSL, you might
-   want to try the FreeBSD patch/version even if you are not using
-   FreeBSD.
-
-   [25]dnh1.1 to dnh1.2 patch file
-   A patch file of changes to release dnh1.1 to bring it up to dnh1.2.
-
-   [26]FreeBSD patch file
-   A patch file of changes to the CTorrent 1.3.4 base, including the
-   patches from the FreeBSD ports tree.
-
-   [27]Patch file
-   A patch file of changes to the CTorrent 1.3.4 base.
-
-   [28]FreeBSD patched source
-   This includes the patches from the FreeBSD ports tree.
-
-   [29]Linux/Windows/Other patched source
-   Please [30]let me know if you encounter any portability issues, as I
-   don't have a test environment set up for these platforms.
-                    ___________________________________
-
-   Bitfield::Invert patch
-
-   [31]Bitfield::Invert patch
-   See notes in the change log; this is needed if you are using dnh1.1,
-   dnh1, or ctorrent-1.3.4.
-                    ___________________________________
-
-   Release dnh1.1
-
-   [32]dnh1 to dnh1.1 patch file
-   A patch file of changes to release dnh1 to bring it up to dnh1.1.
-                    ___________________________________
-
-   Release dnh1
-
-   [33]FreeBSD patch file
-   A patch file of changes to the CTorrent 1.3.4 base, including the
-   patches from the FreeBSD ports tree.
-   Note: Thanks to Florent Thoumie, as of 29 Jul 2005 this patchset is
-   included in the FreeBSD port. If you update your ports tree (or at
-   least net/ctorrent) and install from there, you will have these
-   updates without downloading the file and patching manually.
-
-   [34]Patch file
-   A patch file of changes to the CTorrent 1.3.4 base.
-
-   [35]FreeBSD patched source
-   This includes the patches from the FreeBSD ports tree.
-
-   [36]Linux/Windows/Other patched source
-   Please [37]let me know if you encounter any portability issues, as I
-   don't have a test environment set up for these platforms.
+   Older Versions
+   Please see the [30]Old Versions page for previous releases and
+   patches.
      _________________________________________________________________
 
    Resources
 
-   [38]CTorrent Home Page 
+   [31]CTorrent Home Page 
    Outdated, but you may find some useful info (particularly the FAQ).
 
-   [39]CTorrent SourceForge Project 
+   [32]CTorrent SourceForge Project 
    Hosts the original CTorrent codebase, bug reports, patches, and forum.
 
-   [40]Custom CTorrent 
+   [33]Custom CTorrent 
    A page by the author of the "get1file" patch and other fixes. It
    contains a custom version and a GUI for CTorrent.
 
-   [41]BitTorrent 
+   [34]BitTorrent 
    The official BitTorrent home page.
 
-   [42]BitTorrent wiki 
+   [35]BitTorrent wiki 
    Various documentation.
 
-   [43]BitTorrent protocol specification (official version)
+   [36]BitTorrent protocol specification (official version)
 
-   [44]BitTorrent protocol specification (wiki version)
+   [37]BitTorrent protocol specification (wiki version)
 
 References
 
@@ -248,37 +184,30 @@
    8. http://ctorrent.sourceforge.net/
    9. http://www.bittorrent.com/
   10. http://sourceforge.net/projects/ctorrent/
-  11. http://www.rahul.net/dholmes/ctorrent/ctcs.html
-  12. http://www.rahul.net/dholmes/ctorrent/index.html#download
+  11. http://www.rahul.net/dholmes/ctorrent/userguide.html
+  12. http://www.rahul.net/dholmes/ctorrent/changelog.html
   13. http://www.rahul.net/dholmes/ctorrent/ctcs.html
-  14. http://www.rahul.net/dholmes/ctorrent/ctcs-protocol.html
-  15. http://www.rahul.net/dholmes/ctorrent/index.html#download
-  16. http://www.rahul.net/dholmes/ctorrent/changelog.html
+  14. http://www.rahul.net/dholmes/ctorrent/index.html#download
+  15. http://www.rahul.net/dholmes/ctorrent/userguide.html
+  16. http://www.rahul.net/dholmes/ctorrent/index.html#download
   17. http://www.rahul.net/dholmes/ctorrent/ctcs.html
-  18. http://www.rahul.net/dholmes/ctorrent/changelog.html
-  19. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-dnh2-dnh2.1.diff
-  20. http://www.rahul.net/dholmes/ctorrent/ctorrent-1.3.4-dnh2.1.tar.gz
-  21. http://www.rahul.net/dholmes/ctorrent/patch-btfiles.cpp.diff
-  22. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-dnh1.2-dnh2.diff
-  23. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-1.3.4-dnh2.diff
-  24. http://www.rahul.net/dholmes/ctorrent/ctorrent-1.3.4-dnh2.tar.gz
-  25. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-dnh1.1-dnh1.2.diff
-  26. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-1.3.4-dnh1.2-fbsd.diff
-  27. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-1.3.4-dnh1.2.diff
-  28. http://www.rahul.net/dholmes/ctorrent/ctorrent-1.3.4-dnh1.2-fbsd.tar.gz
-  29. http://www.rahul.net/dholmes/ctorrent/ctorrent-1.3.4-dnh1.2.tar.gz
-  30. mailto:dholmes@ct.boxmail.com
-  31. http://www.rahul.net/dholmes/ctorrent/patch-invert.diff
-  32. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-dnh1-dnh1.1.diff
-  33. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-1.3.4-dnh1-fbsd.diff
-  34. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-1.3.4-dnh1.diff
-  35. http://www.rahul.net/dholmes/ctorrent/ctorrent-1.3.4-dnh1-fbsd.tar.gz
-  36. http://www.rahul.net/dholmes/ctorrent/ctorrent-1.3.4-dnh1.tar.gz
-  37. mailto:dholmes@ct.boxmail.com
-  38. http://ctorrent.sourceforge.net/
-  39. http://sourceforge.net/projects/ctorrent/
-  40. http://customctorrent.ifreepages.com/
-  41. http://bittorrent.com/
-  42. http://wiki.theory.org/CategoryBitTorrent
-  43. http://www.bittorrent.com/protocol.html
-  44. http://wiki.theory.org/BitTorrentSpecification
+  18. http://www.rahul.net/dholmes/ctorrent/ctcs-protocol.html
+  19. http://www.rahul.net/dholmes/ctorrent/index.html#download
+  20. http://www.rahul.net/dholmes/ctorrent/changelog.html
+  21. http://www.rahul.net/dholmes/ctorrent/ctcs.html
+  22. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-dnh2.1-dnh2.2.diff
+  23. http://www.rahul.net/dholmes/ctorrent/ctorrent-1.3.4-dnh2.2.tar.gz
+  24. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-dnh2-dnh2.1.diff
+  25. http://www.rahul.net/dholmes/ctorrent/ctorrent-1.3.4-dnh2.1.tar.gz
+  26. http://www.rahul.net/dholmes/ctorrent/patch-btfiles.cpp.diff
+  27. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-dnh1.2-dnh2.diff
+  28. http://www.rahul.net/dholmes/ctorrent/patchset-ctorrent-1.3.4-dnh2.diff
+  29. http://www.rahul.net/dholmes/ctorrent/ctorrent-1.3.4-dnh2.tar.gz
+  30. http://www.rahul.net/dholmes/ctorrent/oldversion.html
+  31. http://ctorrent.sourceforge.net/
+  32. http://sourceforge.net/projects/ctorrent/
+  33. http://customctorrent.ifreepages.com/
+  34. http://bittorrent.com/
+  35. http://wiki.theory.org/CategoryBitTorrent
+  36. http://www.bittorrent.com/protocol.html
+  37. http://wiki.theory.org/BitTorrentSpecification
--- UserGuide.orig	Sat Nov  4 23:28:40 2006
+++ UserGuide	Sat Nov  4 23:35:21 2006
@@ -0,0 +1,290 @@
+
+                       Enhanced CTorrent User's Guide
+
+   This guide is presented to offer additional information related to
+   using [1]Enhanced CTorrent.
+
+   This document is not an introduction to BitTorrent--for that, try
+   [2]this, [3]this, or an Internet search.
+
+  Contents
+
+     * Options
+          + [4]General
+          + [5]Downloading
+          + [6]Create Torrent
+     * [7]Examples
+     * Usage Notes
+          + [8]Startup
+          + [9]Status Line
+          + [10]Stopping CTorrent
+     _________________________________________________________________
+
+   Options
+
+  General Options
+
+-x          Decode metainfo (torrent) file only, don't download.
+
+          Displays the torrent information and contents from the metainfo
+          (.torrent) file. No piece checking or downloading is performed.
+          This option is normally used alone.
+
+-c          Check pieces only, don't download.
+
+          Hash-checks all pieces of the torrent to verify completion
+          status and exits. Use this when you want to verify that you've
+          successfully downloaded the complete torrent, or to make sure
+          the files are intact after a system crash. This option is
+          normally used alone.
+
+-v          Verbose output (for debugging).
+
+          Generates [a lot of] extra output while CTorrrent is running.
+
+  Downloading Options
+
+-e int      Exit while seed  hours later. (default 72 hours)
+
+          Indicate how long (in hours) you want to "seed" (continue
+          uploading) after download has completed. It is considered
+          polite and fair (and required by some tracker sites) to seed
+          for some time after downloading.
+
+-E num      Exit after seeding to  ratio (UL:DL).
+
+          Specify a desired "seed ratio". After downloading completes,
+          the client will continue seeding (uploading) until your total
+          upload volume divided by your download volume equals this
+          number. Fractional values (such as 1.5) are allowed. It is
+          considered polite and fair (and required by some tracker sites)
+          to seed until your ratio is at least 1:1.
+
+-i ip       Listen for connections on ip. (default all IP's)
+
+          Specify the IP address on which you want to listen for incoming
+          connections. This is only useful if your system has multiple
+          network interfaces and you want to restrict access or run
+          multiple clients on different interfaces.
+
+-p port     Listen port. (default 2706 -> 2106)
+
+          Specify the TCP port number on which to listen for incoming
+          connections. By default, CTorrent starts at 2706 and searches
+          for an available port in decreasing order until it finds one or
+          exhausts all ports down through 2106.
+
+-s filename     Download ("save as") to a different file or directory.
+
+          Download to a different filename or top-level directory name
+          than what is given in the metainfo file.
+
+-C cache_size   Cache size, unit MB. (default 16MB)
+
+          Specify the amount of memory to use for caching downloaded
+          slices. You will probably need to use this option if running on
+          a memory-constrained system such as a router or SAN device. If
+          you use a value of 0, no memory cache will be used but the
+          process will be more disk-intensive. If cache is used, the size
+          will be set to a minimum of the size of 4 pieces.
+
+-f              Force seed mode (skip hash check at startup).
+
+          Perform a fast startup for seeding by skipping the initial hash
+          verification of the files. Use this option only if you have
+          completed downloading the entire torrent and are absolutely
+          certain that the files are intact.
+
+-b filename     Bitfield filename. (use it carefully)
+
+          Save piece completion status to a file on exit, and read this
+          file on startup. This can be used as a "fast restart" option,
+          but note that no validation of the initial status is performed.
+          Use this option only if you are absolutely certain that the
+          files have not been changed or corrupted since the bitfield
+          file was written.
+
+-M max_peers    Max peers count. (default 100)
+
+          Set the maximum allowable number of peer connections. If this
+          number is reached, no new connections will be initiated or
+          accepted. If memory or upload bandwidth are constrained, you
+          may want to use this option to specify a lower value.
+
+-m min_peers    Min peers count. (default 1)
+
+          Set the desired minimum number of peer connections. If the
+          number falls below this value, the client will contact the
+          tracker to request more peers.
+
+-z slice_size   Download slice/block size, unit KB. (default 16, max 128).
+
+          Sets the size of the basic unit of download. For greatest
+          compatibility with other peer clients, use the default. This
+          value can also affect the precision with which bandwidth is
+          managed.
+
+-n file_number  Specify file to download.
+
+          Specify a file in the torrent to download as a priority; the
+          file numbers can be seen with the -n option. Only pieces that
+          are part of this file will be downloaded until the file is
+          complete. At that point, the next file will be targeted. When
+          the last (highest-numbered) file in the torrent is completed,
+          this option is deactivated and the remaining pieces of the
+          torrent will be downloaded.
+
+-D rate         Max bandwidth down (unit KB/s)
+
+          Specify a download bandwidth limit for this torrent. The client
+          will maintain its short-term average download rate at or below
+          this value.
+
+-U rate         Max bandwidth up (unit KB/s)
+
+          Specify an upload bandwidth limit for this torrent. The client
+          will maintain its short-term average upload rate at or below
+          this value.
+
+-P peer_id      Set Peer ID prefix. (default "-CD0202-")
+
+          Specify an alternate peer ID prefix. This can be useful if a
+          tracker is set up to only allow client programs that it
+          recognizes. (The admin may not even realize it, so you may want
+          to try contacting them to request that they change their
+          configuration or add Enhanced CTorrent to the list.) If you
+          receive a tracker warning message that your client is out of
+          date, try using this option with the prefix of another
+          well-known client program (such as "-AZ2304-").
+
+-S host:port    Use CTCS server at host:port.
+
+          Maintain a connection to CTCS for status reporting, bandwidth
+          control, and client management. Using a colon at the end of the
+          parameter (as in "-S localhost:2780:") will cause the client to
+          prompt for a password to send to CTCS when connecting.
+
+  Options for Creating a New Torrent
+
+-t              Create a new torrent file.
+
+          Indicates that you want to create a new torrent.
+
+-s filename     Specify metainfo file name.
+
+          (Required) Give the name of the file to be created.
+
+-u url          Tracker's url.
+
+          (Required) Specify the tracker's announce URL. This usually
+          looks similar to "http://tracker.example.com:port/announce".
+
+-l piece_len    Piece length. (default 262144)
+
+          Specify the piece size for your torrent. This will also
+          determine the number of pieces in the torrent.
+     _________________________________________________________________
+
+   Examples
+
+   List the contents of a torrent:
+
+      ctorrent -x example.torrent
+
+   Verify download completion status (takes a little time):
+
+      ctorrent -c example.torrent
+
+   Download or seed a torrent using default options:
+
+      ctorrent example.torrent
+
+   Download with a limit of 100KB/s, upload limit of 10KB/s, and seed
+   until a ratio of 1.5:1 is achieved:
+
+      ctorrent -D 100 -U 10 -E 1.5 example.torrent
+
+   Create a torrent:
+
+      ctorrent -t -u "http://tracker.example.com:6969/announce"
+         -s example.torrent file_or_dir_to_upload
+     _________________________________________________________________
+
+   Usage Notes
+
+  Startup
+
+   If you have previously started the torrent, CTorrent will perform a
+   hash-check of all pieces at startup. This does not mean that it is
+   starting over--quite the opposite! This is how the client determines
+   which pieces it already has so that they will not be downloaded again
+   (and can be offered for uploading). This process confirms the pieces
+   that you have even if the files have been altered or recovered after a
+   system crash.
+
+  Status Line
+
+   The status line that is output by the client has changed since the
+   original and deserves some explanation.
+
+    / 0/33/110 [672/672/672] 0MB,1130MB | 0,20K/s | 0,0K E:0,31 P:4/10
+    - - -- ---  --- --- ---  --- ------   - --      - -    - --   ----
+    A B  C  D    E   F   G    H     I     J  K      L M    N  O     P
+
+   A: Ticker; this character changes to indicate that the client is
+   running.
+   B: Number of seeders (complete peers) to which you are connected.
+   C: Number of leechers (incomplete peers) to which you are connected.
+   D: Total number of peers in the swarm, as last reported by the
+   tracker.
+   E: Number of pieces of the torrent that you have completed.
+   F: Total number of pieces in the torrent.
+   G: Number of pieces currently available from you and your connected
+   peers.
+   H: Total amount of data you have downloaded.
+   I: Total amount of data you have uploaded.
+   J: Your current total download rate.
+   K: Your current total upload rate.
+   L: Amount of data downloaded since the last status line update.
+   M: Amount of data uploaded since the last status line update.
+   N: Number of tracker connection errors.
+   O: Number of successful tracker connections.
+   P: Completion ratio of current file (when -n is used).
+
+   Additional information such as tracker connection status may be
+   displayed at the end of the status line when appropriate.
+
+  Stopping CTorrent
+
+   CTorrent can be stopped before completing download or seeding by
+   pressing Ctrl-C or sending the TERM signal ("kill pid"). This will
+   tell the client to contact the tracker to send its final statistics
+   and advise that it is leaving the torrent. Note that this could take a
+   couple of minutes if the tracker is down or very busy. (Only one
+   attempt is made, so the client will exit even if the connection
+   fails.)
+
+   If Ctrl-C or kill is used a second time, the client closes all peer
+   connections and exits without waiting for the tracker connection. This
+   means that other peers may still attempt to contact you for a while,
+   and the tracker may not accept you back into the torrent until your
+   original session expires. (This could take up to a couple of hours,
+   depending on the tracker.)
+
+   In either case, this is a clean shutdown of CTorrent. All downloaded
+   data is written to disk before exiting. (Only complete pieces really
+   count though, as there is no way to know which blocks are missing from
+   partial pieces.)
+
+References
+
+   1. http://www.rahul.net/dholmes/ctorrent/
+   2. http://en.wikipedia.org/wiki/BitTorrent
+   3. http://btfaq.com/
+   4. http://www.rahul.net/dholmes/ctorrent/userguide.html#opt_general
+   5. http://www.rahul.net/dholmes/ctorrent/userguide.html#opt_download
+   6. http://www.rahul.net/dholmes/ctorrent/userguide.html#opt_create
+   7. http://www.rahul.net/dholmes/ctorrent/userguide.html#examples
+   8. http://www.rahul.net/dholmes/ctorrent/userguide.html#startup
+   9. http://www.rahul.net/dholmes/ctorrent/userguide.html#status
+  10. http://www.rahul.net/dholmes/ctorrent/userguide.html#stopping
--- btconfig.cpp.orig	Sun Jan  1 18:39:06 2006
+++ btconfig.cpp	Sat Oct 21 17:29:59 2006
@@ -13,8 +13,8 @@
 int cfg_max_listen_port = 2706;
 int cfg_min_listen_port = 2106;
 
-int cfg_max_bandwidth_down = -1;
-int cfg_max_bandwidth_up = -1;
+int cfg_max_bandwidth_down = 0;
+int cfg_max_bandwidth_up = 0;
 
 time_t cfg_seed_hours = 72;
 double cfg_seed_ratio = 0;
--- btconfig.h.orig	Sun Sep  3 13:48:55 2006
+++ btconfig.h	Sat Nov  4 22:34:58 2006
@@ -12,7 +12,7 @@
 extern size_t cfg_req_queue_length;
 #define MAX_PF_LEN 8
 #define PEER_ID_LEN 20
-#define PEER_PFX "-CD0201-"
+#define PEER_PFX "-CD0202-"
 
 extern size_t cfg_cache_size;
 
--- btcontent.cpp.orig	Sun Jan  1 18:40:49 2006
+++ btcontent.cpp	Sat Nov  4 11:38:38 2006
@@ -23,11 +23,14 @@
 #include <fcntl.h>
 #include <errno.h>
 
+#include "ctorrent.h"
 #include "btconfig.h"
 #include "bencode.h"
 #include "peer.h"
 #include "httpencode.h"
 #include "tracker.h"
+#include "peerlist.h"
+#include "ctcs.h"
 
 #if defined(USE_STANDALONE_SHA1)
 #include "sha1.h"
@@ -74,6 +77,7 @@
   time(&m_start_timestamp);
   m_cache = (BTCACHE*) 0;
   m_cache_size = m_cache_used = 0;
+  m_flush_failed = (time_t) 0;
 }
 
 int btContent::CreateMetainfoFile(const char *mifn)
@@ -258,17 +262,15 @@
   if( !pBF ) ERR_RETURN();
 #endif
 
-    //create the file filter
-    pBFilter = new BitField(m_npieces);
+  //create the file filter
+  pBFilter = new BitField(m_npieces);
 #ifndef WINDOWS
-     if( !pBFilter ) ERR_RETURN();
+   if( !pBFilter ) ERR_RETURN();
 #endif
   if(arg_file_to_download>0){
     m_btfiles.SetFilter(arg_file_to_download,pBFilter,m_piece_length);
   }
 
-
-
   m_left_bytes = m_btfiles.GetTotalLength() / m_piece_length;
   if( m_btfiles.GetTotalLength() % m_piece_length ) m_left_bytes++;
   if( m_left_bytes != m_npieces ) ERR_RETURN();
@@ -283,12 +285,11 @@
         r = 0;
         for( idx = 0; idx < m_npieces; idx++ )
           if( pBF->IsSet(idx) ) m_left_bytes -= GetPieceLength(idx);
-      }
-      else{
-        fprintf(stderr,"warn, couldn't set bit field refer file %s.\n",arg_bitfield_file);
+      }else{
+        fprintf(stderr,"warn, couldn't set bit field refer file %s.\n",
+          arg_bitfield_file);
       }
     }
-    
     if( r ) CheckExist();
     
   }else if( arg_flg_force_seed_mode ){
@@ -298,7 +299,8 @@
     CheckExist();
   }
   
-  PrintOut();
+  if( r && !arg_flg_force_seed_mode )
+    m_btfiles.PrintOut();  // show file completion
   printf("Already/Total: %u/%u (%d%%)\n",pBF->Count(),m_npieces,
     100 * pBF->Count() / m_npieces);
   
@@ -340,7 +342,6 @@
 {
   //changed
   u_int64_t offset = (u_int64_t)idx * (u_int64_t)m_piece_length + (u_int64_t)off;
-
   if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 0);
   else{
     size_t len2;
@@ -388,6 +389,9 @@
 void btContent::CacheClean()
 {
   BTCACHE *p, *pp, *prm, *prmp;
+  int f_flushed = 0;
+
+  if( m_flush_failed ) FlushCache();  // try again
 
  again:
   pp = prm = prmp = (BTCACHE*) 0;
@@ -399,7 +403,7 @@
   }
   
   if( !prm ){
-    if( m_cache_used ) { FlushCache(); goto again; }
+    if( m_cache_used && !f_flushed ){ FlushCache(); f_flushed = 1; goto again; }
     else return;
   }
 
@@ -425,12 +429,39 @@
 void btContent::FlushCache()
 {
   BTCACHE *p = m_cache;
-  for( ; p; p = p->bc_next)
+  for( ; p; p = p->bc_next ){
     if( p->bc_f_flush ){
-      p->bc_f_flush = 0;
-      if(m_btfiles.IO(p->bc_buf, p->bc_off, p->bc_len, 1) < 0)
-        fprintf(stderr,"warn, write file failed while flush cache.\n");
+      if(m_btfiles.IO(p->bc_buf, p->bc_off, p->bc_len, 1) < 0){
+        if( time((time_t *)0) >= m_flush_failed + 300 ){
+          char wmsg[256]; int t;
+          warning(1, "warn, write file failed while flushing cache.");
+          snprintf(wmsg,256,
+            "You need to have at least %llu bytes free on this filesystem!",
+            m_left_bytes + m_cache_used);
+          warning(1, wmsg);
+          warning(1, "This can also be caused by a disk error.");
+          snprintf(wmsg,256, "Temporarily"); t=11;
+          if( !m_flush_failed && m_cache_size - m_cache_used < m_piece_length ){
+            snprintf(wmsg+t,256-t, " increasing cache size and"); t+=26;
+            m_cache_size += m_piece_length;
+          }
+          snprintf(wmsg+t,256-t, " suspending download...");
+          warning(1, wmsg);
+          time(&m_flush_failed);
+          WORLD.SeedOnly(1);
+        }
+        return;
+      }else{
+        p->bc_f_flush = 0;
+        if(m_flush_failed){
+          warning(3, "Flushing cache succeeded, resuming download");
+          m_flush_failed = 0;
+          CacheConfigure();
+          WORLD.SeedOnly(0);
+        }
+      }
     }
+  }
 }
 
 ssize_t btContent::WriteSlice(char *buf,size_t idx,size_t off,size_t len)
@@ -606,7 +637,9 @@
   if( GetHashValue(idx, md) < 0 ) return -1;
 
   if( memcmp(md,(m_hash_table + idx * 20), 20) != 0){
-    fprintf(stderr,"warn,piece %d hash check failed.\n",idx);
+    char wmsg[256];
+    sprintf(wmsg,"warn,piece %d hash check failed.",idx);
+    warning(0, wmsg);
     return 0;
   }
   pBF->Set(idx);
@@ -643,7 +676,7 @@
         (cfg_seed_hours > 0 &&
           (*pnow - m_seed_timestamp) >= (cfg_seed_hours * 60 * 60)) ||
         (cfg_seed_ratio > 0 &&
-          cfg_seed_ratio <= Self.TotalUL() / dl) ) return 1;
+          cfg_seed_ratio <= (double) Self.TotalUL() / dl) ) return 1;
   }
   return 0;
 }
--- btcontent.h.orig	Sun Nov 27 21:58:31 2005
+++ btcontent.h	Sat Nov  4 11:35:30 2006
@@ -37,6 +37,8 @@
   u_int64_t m_left_bytes;
   btFiles m_btfiles;
 
+  time_t m_flush_failed;
+
   BTCACHE *m_cache;
   size_t m_cache_size, m_cache_used;
   
--- btfiles.cpp.orig	Sun Mar 19 19:54:53 2006
+++ btfiles.cpp	Wed Oct 25 19:58:00 2006
@@ -180,7 +180,7 @@
 #endif
 }
 
-int btFiles::_btf_recurses_directory(const char *cur_path, BTFILE* lastnode)
+int btFiles::_btf_recurses_directory(const char *cur_path, BTFILE* *plastnode)
 {
   char full_cur[MAXPATHLEN];
   char fn[MAXPATHLEN];
@@ -236,12 +236,12 @@
       pbf->bf_length = sb.st_size;
       m_total_files_length += sb.st_size;
 
-      if( lastnode ) lastnode->bf_next = pbf; else m_btfhead = pbf;
-      
-      lastnode = pbf;
+      if( *plastnode ) (*plastnode)->bf_next = pbf; else m_btfhead = pbf;
+
+      *plastnode = pbf;
 
     }else if( S_IFDIR & sb.st_mode ){
-      if(_btf_recurses_directory(fn, lastnode) < 0){closedir(dp); return -1;}
+      if(_btf_recurses_directory(fn, plastnode) < 0){closedir(dp); return -1;}
     }else{
       fprintf(stderr,"error, %s is not a directory or regular file.\n",fn);
       closedir(dp);
@@ -293,6 +293,7 @@
 {
   struct stat sb;
   BTFILE *pbf = (BTFILE*) 0;
+  BTFILE *lastnode = (BTFILE*) 0;
 
   if( stat(pathname, &sb) < 0 ){
     fprintf(stderr,"error, stat file %s failed, %s\n",pathname,strerror(errno));
@@ -325,7 +326,7 @@
       return -1;
     }
 
-    if(_btf_recurses_directory((const char*)0, (BTFILE*) 0) < 0) return -1;
+    if(_btf_recurses_directory((const char*)0, &lastnode) < 0) return -1;
     if( chdir(wd) < 0) return -1;
   }else{
     fprintf(stderr,"error, %s is not a directory or regular file.\n",pathname);
--- btfiles.h.orig	Sun Jan  1 18:41:33 2006
+++ btfiles.h	Wed Oct 25 19:58:00 2006
@@ -43,7 +43,7 @@
   int _btf_ftruncate(int fd,int64_t length);
   int _btf_creat_by_path(const char *pathname, int64_t file_length);
   int _btf_destroy();
-  int _btf_recurses_directory(const char *cur_path, BTFILE *lastnode);
+  int _btf_recurses_directory(const char *cur_path, BTFILE **plastnode);
 
  public:
   int CreateFiles();
--- btrequest.cpp.orig	Sun Jan  1 18:46:17 2006
+++ btrequest.cpp	Tue Oct 24 20:41:00 2006
@@ -405,9 +405,11 @@
   return 0;
 }
 
+// Sending an empty queue to this function WILL cause a crash.  This exposure
+// is left open in order to help track down bugs that cause this condition.
 int PendingQueue::Pending(RequestQueue *prq)
 {
-   int i = 0, j = 0;
+   int i = 0, j = -1;
   PSLICE n, u = (PSLICE) 0;
   size_t idx, off, len;
   RequestQueue tmprq;
@@ -426,9 +428,10 @@
 
   for( ; i < PENDING_QUEUE_SIZE; i++){
     if(pending_array[i] == (PSLICE) 0){
-      // Don't add a piece to Pending more than once.
-      if(!j) j = i;
+      // Find an empty slot in case we need it.
+      if(j<0) j = i;
     }else if(prq->GetRequestIdx() == pending_array[i]->index){
+      // Don't add a piece to Pending more than once.
       while( !prq->IsEmpty() &&
           prq->GetRequestIdx() == pending_array[i]->index )
         prq->Pop(&idx,&off,&len);
@@ -436,13 +439,12 @@
       i = 0;
     }
   }
-  i = j;
-  pending_array[i] = prq->GetHead();
+  pending_array[j] = prq->GetHead();
   prq->Release();
   pq_count++;
 
   // If multiple pieces are queued, break up the queue separately.
-  n = pending_array[i];
+  n = pending_array[j];
   idx = n->index;
   for( ; n ; u = n, n = u->next)
     if( n->index != idx ) break;
--- ctcs.cpp.orig	Tue Aug 15 21:06:00 2006
+++ ctcs.cpp	Thu Oct 26 20:27:00 2006
@@ -381,11 +381,11 @@
 }
 
 
-int Ctcs::Send_Info(const char *info)
+int Ctcs::Send_Info(int sev, const char *info)
 {
   char message[CTCS_BUFSIZE];
 
-  snprintf(message, CTCS_BUFSIZE, "CTINFO %s", info);
+  snprintf(message, CTCS_BUFSIZE, "CTINFO %d %s", sev, info);
   return SendMessage(message);
 }
 
--- ctcs.h.orig	Mon Nov 14 20:40:00 2005
+++ ctcs.h	Wed Oct 25 22:14:00 2006
@@ -65,7 +65,7 @@
   int Set_Config(char *msgbuf);
   int Send_Detail();
   int Send_Peers();
-  int Send_Info(const char *info);
+  int Send_Info(int sev, const char *info);
   int IntervalCheck(const time_t *pnow, fd_set *rfdp, fd_set *wfdp);
   int SocketReady(fd_set *rfdp, fd_set *wfdp, int *nfds);
   void RestartTracker();
--- ctorrent.cpp.orig	Sat Dec 24 19:03:58 2005
+++ ctorrent.cpp	Tue Oct 31 20:26:00 2006
@@ -14,6 +14,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "ctorrent.h"
 #include "btconfig.h"
 #include "btcontent.h"
 #include "downloader.h"
@@ -253,36 +254,67 @@
 {
   fprintf(stderr,"%s	Original code Copyright: YuHong(992126018601033)",PACKAGE_STRING);
   fprintf(stderr,"\nWARNING: THERE IS NO WARRANTY FOR CTorrent. USE AT YOUR OWN RISK!!!\n");
-  fprintf(stderr,"\nGeneric Options:\n");
-  fprintf(stderr,"-h/-H\t\tShow this message.\n");
-  fprintf(stderr,"-x\t\tDecode metainfo(torrent) file only, don't download.\n");
-  fprintf(stderr,"-c\t\tCheck exist only. don't download.\n");
-  fprintf(stderr,"-v\t\tVerbose output (for debugging).\n");
+  fprintf(stderr,"\nGeneral Options:\n");
+  fprintf(stderr, "%-15s %s\n", "-h/-H", "Show this message.");
+  fprintf(stderr, "%-15s %s\n", "-x",
+    "Decode metainfo (torrent) file only, don't download.");
+  fprintf(stderr, "%-15s %s\n", "-c", "Check pieces only, don't download.");
+  fprintf(stderr, "%-15s %s\n", "-v", "Verbose output (for debugging).");
+
   fprintf(stderr,"\nDownload Options:\n");
-  fprintf(stderr,"-e int\t\tExit while seed <int> hours later. (default 72 hours)\n");
-  fprintf(stderr,"-E num\t\tExit after seeding to <num> ratio (UL:DL).\n");
-  fprintf(stderr,"-i ip\t\tListen for connection on ip. (default all ip's)\n");
-  fprintf(stderr,"-p port\t\tListen port. (default 2706 -> 2106)\n");
-  fprintf(stderr,"-s save_as\tSave file/directory/metainfo as... \n");
-  fprintf(stderr,"-C cache_size\tCache size,unit MB. (default 16MB)\n");
-  fprintf(stderr,"-f\t\tForce seed mode. skip hash check at startup.\n");
-  fprintf(stderr,"-b bf_filename\tBit field filename. (use it carefully)\n");
-  fprintf(stderr,"-M max_peers\tMax peers count.\n");
-  fprintf(stderr,"-m min_peers\tMin peers count.\n");
-  fprintf(stderr,"-z slice_size\tDownload slice/block size, unit KB. (default 16, max 128).\n");
-  fprintf(stderr,"-n file_number\tWhich file download.\n");
-  fprintf(stderr,"-D rate\t\tMax bandwidth down (unit KB/s)\n");
-  fprintf(stderr,"-U rate\t\tMax bandwidth up (unit KB/s)\n");
-  fprintf(stderr,"-P peer_id\tSet Peer ID ["PEER_PFX"]\n");
-  fprintf(stderr,"-S host:port\tUse CTCS server\n");
-  fprintf(stderr,"\nMake metainfo(torrent) file Options:\n");
-  fprintf(stderr,"-t\t\tWith make torrent. must specify this option.\n");
-  fprintf(stderr,"-u url\t\tTracker's url.\n");
-  fprintf(stderr,"-l piece_len\tPiece length.(default 262144)\n");
-  fprintf(stderr,"\neg.\n");
-  fprintf(stderr,"hong> ctorrent -s new_filename -e 12 -C 32 -p 6881 eg.torrent\n\n");
-  fprintf(stderr,"home page: http://ctorrent.sourceforge.net/\n");
+  fprintf(stderr, "%-15s %s\n", "-e int",
+    "Exit while seed <int> hours later. (default 72 hours)");
+  fprintf(stderr, "%-15s %s\n", "-E num",
+    "Exit after seeding to <num> ratio (UL:DL).");
+  fprintf(stderr, "%-15s %s\n", "-i ip",
+    "Listen for connections on ip. (default all IP's)");
+  fprintf(stderr, "%-15s %s\n", "-p port",
+    "Listen port. (default 2706 -> 2106)");
+  fprintf(stderr, "%-15s %s\n", "-s filename",
+    "Download (\"save as\") to a different file or directory.");
+  fprintf(stderr, "%-15s %s\n", "-C cache_size",
+    "Cache size, unit MB. (default 16MB)");
+  fprintf(stderr, "%-15s %s\n", "-f",
+    "Force seed mode (skip hash check at startup).");
+  fprintf(stderr, "%-15s %s\n", "-b filename",
+    "Bitfield filename. (use it carefully)");
+  fprintf(stderr, "%-15s %s\n", "-M max_peers",
+    "Max peers count. (default 100)");
+  fprintf(stderr, "%-15s %s\n", "-m min_peers", "Min peers count. (default 1)");
+  fprintf(stderr, "%-15s %s\n", "-z slice_size",
+    "Download slice/block size, unit KB. (default 16, max 128).");
+  fprintf(stderr, "%-15s %s\n", "-n file_number", "Specify file to download.");
+  fprintf(stderr, "%-15s %s\n", "-D rate", "Max bandwidth down (unit KB/s)");
+  fprintf(stderr, "%-15s %s\n", "-U rate", "Max bandwidth up (unit KB/s)");
+  fprintf(stderr, "%-15s %s%s\")\n", "-P peer_id",
+    "Set Peer ID prefix. (default \"", PEER_PFX);
+  fprintf(stderr, "%-15s %s\n", "-S host:port",
+    "Use CTCS server at host:port.");
+
+  fprintf(stderr,"\nMake metainfo (torrent) file options:\n");
+  fprintf(stderr, "%-15s %s\n", "-t", "Create a new torrent file.");
+  fprintf(stderr, "%-15s %s\n", "-u url", "Tracker's url.");
+  fprintf(stderr, "%-15s %s\n", "-l piece_len",
+    "Piece length. (default 262144)");
+  fprintf(stderr, "%-15s %s\n", "-s filename", "Specify metainfo file name.");
+
+  fprintf(stderr,"\nExample:\n");
+  fprintf(stderr,"ctorrent -s new_filename -e 12 -C 32 -p 6881 example.torrent\n");
+  fprintf(stderr,"\nhome page: http://ctorrent.sourceforge.net/\n");
   fprintf(stderr,"see also: http://www.rahul.net/dholmes/ctorrent/\n");
   fprintf(stderr,"bug report: %s\n",PACKAGE_BUGREPORT);
   fprintf(stderr,"original author: bsdi@sina.com\n\n");
 }
+
+/* "sev" indicates the severity of the message.
+   0: will be printed but not sent to CTCS
+   1: extremely urgent/important
+   2: less important
+   3: no problem
+*/
+void warning (int sev, const char *message)
+{
+  fprintf(stderr, "%s\n", message);
+  if(sev && arg_ctcs) CTCS.Send_Info(sev, message);
+}
+
--- ctorrent.h.orig	Wed Oct 25 21:19:00 2006
+++ ctorrent.h	Wed Oct 25 21:29:00 2006
@@ -0,0 +1,2 @@
+void warning (int sev, const char *message);
+
--- peer.cpp.orig	Tue Aug 15 22:02:00 2006
+++ peer.cpp	Sat Nov  4 11:39:24 2006
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <ctype.h>
 
+#include "ctorrent.h"
 #include "btstream.h"
 #include "./btcontent.h"
 #include "./msgencode.h"
@@ -135,6 +136,7 @@
   m_health_time = m_receive_time = m_choketime = m_last_timestamp;
   m_bad_health = 0;
   m_want_again = m_connect = 0;
+  m_connect_seed = 0;
 }
 
 int btPeer::SetLocal(unsigned char s)
@@ -160,6 +162,7 @@
     m_state.local_choked = 0;
     break;
   case M_INTERESTED: 
+    if( WORLD.SeedOnly() ) return 0;
     m_standby = 0;
     if( m_state.local_interested ) return 0;
     if(arg_verbose) fprintf(stderr, "Interested in %p\n", this);
@@ -366,6 +369,10 @@
 
       /* remove peer's reponse queue */
       if( !reponse_q.IsEmpty()) reponse_q.Empty();
+
+      /* if I've been seed for a while, nobody should be uninterested */
+      if( BTCONTENT.pBF->IsFull() && BTCONTENT.GetSeedTime() - now >= 300 )
+         return -2;
       break;
 
     case M_HAVE:
@@ -660,6 +667,7 @@
 
   t = request_q.GetReqTime(idx,off,len);
 
+  // Verify whether this was actually requested (for queue management only).
   PSLICE ps = request_q.GetHead();
   if( request_q.NextSend() )
     for( ; ps; ps = ps->next){
@@ -670,15 +678,18 @@
       if( idx==ps->index && off==ps->offset && len==ps->length ) break;
     }
 
-  if( request_q.Remove(idx,off,len) < 0 ){
-    m_err_count++;
-    if(arg_verbose) fprintf(stderr, "err: %p (%d) Bad remove\n",
-      this, m_err_count);
+  // If I can't keep it, leave it in the queue--I'll need to request it again.
+  if(BTCONTENT.WriteSlice((char*)(msgbuf + 13),idx,off,len) < 0){
+    warning(2, "warn, WriteSlice failed; is filesystem full?");
     return 0;
   }
 
-  if(BTCONTENT.WriteSlice((char*)(msgbuf + 13),idx,off,len) < 0){
-    fprintf(stderr, "warn, WriteSlice failed; is filesystem full?\n");
+  // request_q should only be empty here if cache flush failed (so no error).
+  // in that case, slice will be removed from pending queue later.
+  if( !request_q.IsEmpty() && request_q.Remove(idx,off,len) < 0 ){
+    m_err_count++;
+    if(arg_verbose) fprintf(stderr, "err: %p (%d) Bad remove\n",
+      this, m_err_count);
     return 0;
   }
 
@@ -730,8 +741,15 @@
   if( requested ) m_req_out--;
 
   /* if piece download complete. */
-  return ( request_q.IsEmpty() || !request_q.HasIdx(idx) ) ?
-    ReportComplete(idx) : RequestCheck();
+  if( request_q.IsEmpty() || !request_q.HasIdx(idx) ){
+    // If flushing cache failed, we may not really have a complete piece.
+    // This is an interim method until we have a "master map" of recv'd slices.
+    if( WORLD.SeedOnly() && PENDINGQUEUE.Exist(idx) ){
+      PENDINGQUEUE.DeleteSlice(idx, off, len);
+      if( PENDINGQUEUE.Exist(idx) ) return RequestCheck();
+      else return ReportComplete(idx);
+    }else return ReportComplete(idx);
+  }else return RequestCheck();
 }
 
 int btPeer::RequestCheck()
@@ -741,7 +759,7 @@
     return SetLocal(M_NOT_INTERESTED);
   }
 
-  if( Need_Remote_Data() ){
+  if( Need_Remote_Data() && !WORLD.SeedOnly() ){
     if(!m_state.local_interested && SetLocal(M_INTERESTED) < 0) return -1;
     if( !m_state.remote_choked ){
       if( m_req_out > cfg_req_queue_length ){
@@ -869,8 +887,10 @@
     m_status = P_SUCCESS;
     m_want_again = 1;
     // When seeding, new peer starts at the end of the line.
-    if( BTCONTENT.pBF->IsFull() )	// i am seed
+    if( BTCONTENT.pBF->IsFull() ){	// i am seed
       m_unchoke_timestamp = now;
+      m_connect_seed = 1;
+    }
   }
   return r;
 }
@@ -889,6 +909,7 @@
 
 int btPeer::BandWidthLimitDown()
 {
+  if( WORLD.SeedOnly() ) return 1;
   if( cfg_max_bandwidth_down <= 0 ) return 0;
   return ((Self.RateDL()) >= cfg_max_bandwidth_down) ?
     1:0;
@@ -969,15 +990,17 @@
 
       if( r < 0 && r != -2 )
         return -1;
-      else if ( r == -2 ){ // seed<->seed
+      else if ( r == -2 )  // remote closed
         f_peer_closed = 1;
-        m_want_again = 0;
-      }
   
       r = stream.HaveMessage();
       for( ; r;){
         if( r < 0 ) return -1;
-        if(MsgDeliver() < 0 || stream.PickMessage() < 0) return -1;
+        if( (r = MsgDeliver()) == -2 ){
+          if(arg_verbose) fprintf(stderr, "%p seed<->seed detected\n", this);
+          m_want_again = 0;
+        }
+        if( r < 0 || stream.PickMessage() < 0 ) return -1;
         r = stream.HaveMessage();
       }
     }else{
@@ -1044,8 +1067,7 @@
       m_bad_health = 1;
       if(arg_verbose)
         fprintf(stderr, "%p unresponsive; resetting request queue\n", this);
-      PSLICE ps = request_q.GetHead();
-      int retval = CancelRequest(ps);
+      int retval = CancelRequest(request_q.GetHead());
       PENDINGQUEUE.Pending(&request_q);
       return (retval < 0) ? -1 : RequestCheck();
     } else m_bad_health = 0;
@@ -1060,6 +1082,17 @@
 {
   return ( bitfield.IsEmpty() && TotalUL() < BTCONTENT.GetPieceLength()*2 ) ?
     1:0;
+}
+
+int btPeer::PutPending()
+{
+  int retval = 0;
+
+  if( !request_q.IsEmpty() ){
+    retval = CancelRequest(request_q.GetHead());
+    PENDINGQUEUE.Pending(&request_q);
+  }
+  return retval;
 }
 
 void btPeer::dump()
--- peer.h.orig	Sat Jan 28 19:52:31 2006
+++ peer.h	Thu Oct 26 20:22:00 2006
@@ -96,7 +96,8 @@
   unsigned char m_want_again:1;  // attempt reconnect if lost
 
   unsigned char m_connect:1;     // we initiated the connection
-  unsigned char m_reserved:7;
+  unsigned char m_connect_seed:1; // connected while I am seed
+  unsigned char m_reserved:6;
 
   BTSTATUS m_state;
 
@@ -165,6 +166,7 @@
   void DontWantAgain() { m_want_again = 0; }
   void SetConnect() { m_connect = 1; }
 
+  int ConnectedWhileSeed() { return m_connect_seed; }
   
   int AreYouOK();
   int Send_ShakeInfo();
@@ -172,6 +174,8 @@
 
   int Need_Remote_Data();
   int Need_Local_Data();
+
+  int PutPending();
 
   void dump();
 };
--- peerlist.cpp.orig	Fri Aug 18 23:03:43 2006
+++ peerlist.cpp	Thu Oct 26 20:19:00 2006
@@ -49,6 +49,7 @@
   m_listen_sock = INVALID_SOCKET;
   m_peers_count = m_seeds_count = 0;
   m_live_idx = 0;
+  m_seed_only = 0;
 }
 
 PeerList::~PeerList()
@@ -225,6 +226,11 @@
            Self.RateDL(), Self.RateUL(),
            Self.TotalDL(), Self.TotalUL(),
            cfg_max_bandwidth_down, cfg_max_bandwidth_up);
+
+    /* after seeding for a while, disconnect uninterested peers */
+    if( BTCONTENT.GetSeedTime() - now <= 301 &&
+        BTCONTENT.GetSeedTime() - now >= 300 )
+      CloseAllConnectionToSeed();
   }
     
   if(KEEPALIVE_INTERVAL <= (*pnow - m_keepalive_check_timestamp)){
@@ -248,6 +254,7 @@
   for(p = m_head; p;){
     if( PEER_IS_FAILED(p->peer)){
       if( p->peer->WantAgain() ){ // connect to this peer again
+        if(arg_verbose) fprintf(stderr, "Adding %p for reconnect\n", p->peer);
         struct sockaddr_in addr;
         p->peer->GetAddress(&addr);
         IPQUEUE.Add(&addr);
@@ -512,8 +519,8 @@
         p->peer->stream.Send_Have(idx) < 0) 
       p->peer->CloseConnection();
     
-    if( f_seed ){
-      if( !p->peer->request_q.IsEmpty() ) p->peer->request_q.Empty();
+    else if( f_seed ){
+      // request queue is emptied by setting not-interested state
       if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) {
         if(arg_verbose)
           fprintf(stderr, "close: Can't set self not interested (T_W_I_H)\n");
@@ -738,7 +745,12 @@
 {
   PEERNODE *p = m_head;
   for( ; p; p = p->next)
-    if(p->peer->bitfield.IsFull()) {
+    if( p->peer->bitfield.IsFull() ||
+        /* Drop peers who remain uninterested, but keep recent connections.
+           Peers who connected recently will resolve by bitfield exchange. */
+        (PEER_IS_SUCCESS(p->peer) && !p->peer->Is_Remote_Interested() &&
+          BTCONTENT.GetSeedTime() - now >= 300 &&
+          !p->peer->ConnectedWhileSeed()) ){
       p->peer->DontWantAgain();
       if(arg_verbose) fprintf(stderr, "close: seed<->seed\n");
       p->peer->CloseConnection();
@@ -750,7 +762,7 @@
   int i = 0;
   int cancel_idx = 0;
   btPeer *loster = (btPeer*) 0;
-  int f_seed = BTCONTENT.pBF->IsFull();
+  int f_seed = BTCONTENT.pBF->IsFull() || m_seed_only;
   int no_opt = 0;
   unsigned long rndbits;
   int r=0;
@@ -926,11 +938,29 @@
       BitField afdBitField =  *BTCONTENT.pBF;
       afdBitField.Except(*BTCONTENT.pBFilter);
       endgame = ( BTCONTENT.getFilePieces(arg_file_to_download)
-                  - afdBitField.Count() ) < WORLD.TotalPeers();
+                  - afdBitField.Count() ) < TotalPeers();
     }else
-      endgame = ( WORLD.Pieces_I_Can_Get() - BTCONTENT.pBF->Count() )
-                  < WORLD.TotalPeers();
+      endgame = ( Pieces_I_Can_Get() - BTCONTENT.pBF->Count() ) < TotalPeers();
   }
   return endgame;
+}
+
+// Note, if other seed-only reasons are added, m_seed_only will need to
+// become a multiple-bit value and this function will need to change.
+// Currently only btContent::FlushCache() sets the state.
+void PeerList::SeedOnly(int state)
+{
+  PEERNODE *p = m_head;
+
+  m_seed_only = state;
+
+  if( m_seed_only ){
+    for( ; p; p = p->next) {
+      if( p->peer->Is_Local_Interested() ) {
+        if(p->peer->PutPending() < 0 || p->peer->SetLocal(M_NOT_INTERESTED) < 0)
+          p->peer->CloseConnection();
+      }
+    }
+  }else CheckInterest();
 }
 
--- peerlist.h.orig	Sat Jan 28 18:52:48 2006
+++ peerlist.h	Mon Oct 23 20:21:00 2006
@@ -21,7 +21,8 @@
   time_t m_unchoke_check_timestamp, m_keepalive_check_timestamp, m_last_progress_timestamp, m_opt_timestamp;
 
   unsigned char m_live_idx:2;
-  unsigned char m_reserved:6;
+  unsigned char m_seed_only:1;
+  unsigned char m_reserved:5;
   
   Rate m_pre_dlrate, m_pre_ulrate;
   
@@ -59,6 +60,8 @@
   void CheckInterest();
   btPeer* GetNextPeer(btPeer *peer);
   int Endgame();
+  int SeedOnly() const { return m_seed_only ? 1 : 0; }
+  void SeedOnly(int state);
 };
 
 extern PeerList WORLD;
--- tracker.cpp.orig	Mon Aug 14 22:35:00 2006
+++ tracker.cpp	Sat Nov  4 11:41:00 2006
@@ -11,6 +11,7 @@
 #include <string.h>
 #include <errno.h>
 
+#include "ctorrent.h"
 #include "peerlist.h"
 #include "httpencode.h"
 #include "bencode.h"
@@ -112,12 +113,9 @@
       failreason[1000] = '\0';
       strcat(failreason,"...");
     }
-    fprintf(stderr,"TRACKER FAILURE REASON: %s\n",failreason);
-    if(arg_ctcs){
-      char ctcsinfo[1048];
-      snprintf(ctcsinfo,1048,"TRACKER FAILURE REASON: %s",failreason);
-      CTCS.Send_Info(ctcsinfo);
-    }
+    char wmsg[1048];
+    snprintf(wmsg,1048,"TRACKER FAILURE REASON: %s",failreason);
+    warning(1, wmsg);
     return -1;
   }
   if( decode_query(buf,bufsiz,"warning message",&ps,&i,(int64_t*) 0,QUERY_STR) ){
@@ -130,12 +128,9 @@
       warnmsg[1000] = '\0';
       strcat(warnmsg,"...");
     }
-    fprintf(stderr,"TRACKER WARNING: %s\n",warnmsg);
-    if(arg_ctcs){
-      char ctcsinfo[1048];
-      snprintf(ctcsinfo,1048,"TRACKER WARNING: %s",warnmsg);
-      CTCS.Send_Info(ctcsinfo);
-    }
+    char wmsg[1048];
+    snprintf(wmsg,1048,"TRACKER WARNING: %s",warnmsg);
+    warning(2, wmsg);
   }
 
   m_peers_count = 0;
@@ -238,13 +233,10 @@
     socklen_t n = sizeof(error);
     if(getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n) < 0 ||
        error != 0 ){
-      fprintf(stderr,"warn, received nothing from tracker! %s\n",strerror(error));
-      if(arg_ctcs){
-        char ctcsinfo[256];
-        snprintf(ctcsinfo,256,
-          "warn, received nothing from tracker! %s",strerror(error));
-        CTCS.Send_Info(ctcsinfo);
-      }
+      char wmsg[256];
+      snprintf(wmsg,256,
+        "warn, received nothing from tracker! %s",strerror(error));
+      warning(2, wmsg);
     }
     return -1;
   }
@@ -252,9 +244,7 @@
   hlen = Http_split(m_reponse_buffer.BasePointer(), q, &pdata,&dlen);
 
   if( !hlen ){
-    fprintf(stderr,"warn, tracker reponse invalid. No html header found.\n");
-    if(arg_ctcs)
-      CTCS.Send_Info("warn, tracker reponse invalid. No html header found.");
+    warning(2, "warn, tracker reponse invalid. No html header found.");
     return -1;
   }
 
@@ -266,13 +256,10 @@
         return -1;
 
       if( Http_url_analyse(redirect,m_host,&m_port,m_path) < 0){
-        fprintf(stderr,"warn, tracker redirect to an invalid url %s!\n", redirect);
-        if(arg_ctcs){
-          char ctcsinfo[256];
-          snprintf(ctcsinfo,256,
-            "warn, tracker redirect to an invalid url %s!", redirect);
-          CTCS.Send_Info(ctcsinfo);
-        }
+        char wmsg[256];
+        snprintf(wmsg,256,
+          "warn, tracker redirected to an invalid url %s", redirect);
+        warning(1, wmsg);
         return -1;
       }
 
@@ -382,8 +369,7 @@
   time(&m_last_timestamp);
 
   if(_s2sin(m_host,m_port,&m_sin) < 0) {
-    fprintf(stderr,"warn, get tracker's ip address failed.");
-    if(arg_ctcs) CTCS.Send_Info("warn, get tracker's ip address failed.");
+    warning(2, "warn, get tracker's ip address failed.");
     return -1;
   }
 
@@ -487,13 +473,10 @@
   //fprintf(stderr,"SendRequest: %s\n", REQ_BUFFER);
 
   if( 0 != m_reponse_buffer.PutFlush(m_sock,REQ_BUFFER,strlen((char*)REQ_BUFFER))){
-    fprintf(stderr,"warn, send request to tracker failed. %s\n",strerror(errno));
-    if(arg_ctcs){
-      char ctcsinfo[256];
-      snprintf(ctcsinfo,256,
-        "warn, send request to tracker failed. %s",strerror(errno));
-      CTCS.Send_Info(ctcsinfo);
-    }
+    char wmsg[256];
+    snprintf(wmsg,256,
+      "warn, send request to tracker failed. %s",strerror(errno));
+    warning(2, wmsg);
     return -1;
   }
 
@@ -545,13 +528,10 @@
     if(getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n) < 0 ||
        error != 0 ){
       if( ECONNREFUSED != error ){
-        fprintf(stderr,"warn, connect to tracker failed. %s\n",strerror(error));
-        if(arg_ctcs){
-          char ctcsinfo[256];
-          snprintf(ctcsinfo,256,
-            "warn, connect to tracker failed. %s\n",strerror(error));
-          CTCS.Send_Info(ctcsinfo);
-        }
+        char wmsg[256];
+        snprintf(wmsg,256,
+          "warn, connect to tracker failed. %s\n",strerror(error));
+        warning(2, wmsg);
       }else
         m_connect_refuse_click++;
       Reset(15);
@@ -566,13 +546,10 @@
     (*nfds)--;
     FD_CLR(m_sock, rfdp); 
     getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n);
-    fprintf(stderr,"warn, connect to tracker failed. %s\n",strerror(error));
-    if(arg_ctcs){
-      char ctcsinfo[256];
-      snprintf(ctcsinfo,256,
-        "warn, connect to tracker failed. %s\n",strerror(error));
-      CTCS.Send_Info(ctcsinfo);
-    }
+    char wmsg[256];
+    snprintf(wmsg,256,
+      "warn, connect to tracker failed. %s\n",strerror(error));
+    warning(2, wmsg);
     Reset(15);
     return -1;
   }else if(INVALID_SOCKET != m_sock && FD_ISSET(m_sock, rfdp) ){
--- configure.ac.orig	Thu Nov 10 20:56:00 2005
+++ configure.ac	Sun Oct 22 12:38:01 2006
@@ -1,6 +1,6 @@
 # Process this file with autoconf to produce a configure script.
-AC_INIT([CTorrent], [dnh2], [dholmes@ct.boxmail.com])
-AM_INIT_AUTOMAKE(ctorrent,dnh2)
+AC_INIT([CTorrent], [dnh2.2], [dholmes@ct.boxmail.com])
+AM_INIT_AUTOMAKE(ctorrent,dnh2.2)
 AC_CONFIG_HEADER([config.h])
 
 AC_CONFIG_SRCDIR([ctorrent.cpp])
--- aclocal.m4.orig	Thu Nov 10 20:56:07 2005
+++ aclocal.m4	Sun Oct 22 12:40:01 2006
@@ -1018,3 +1018,4 @@
 AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR

+
--- Makefile.in.orig	Thu Nov 10 20:56:37 2005
+++ Makefile.in	Sun Oct 22 12:41:01 2006
@@ -582,3 +582,4 @@
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
+
--- configure.orig	Thu Nov 10 20:57:00 2005
+++ configure	Sun Oct 22 12:41:24 2006
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for CTorrent dnh2.
+# Generated by GNU Autoconf 2.59 for CTorrent dnh2.2.
 #
 # Report bugs to <dholmes@ct.boxmail.com>.
 #
@@ -269,8 +269,8 @@
 # Identity of this package.
 PACKAGE_NAME='CTorrent'
 PACKAGE_TARNAME='ctorrent'
-PACKAGE_VERSION='dnh2'
-PACKAGE_STRING='CTorrent dnh2'
+PACKAGE_VERSION='dnh2.2'
+PACKAGE_STRING='CTorrent dnh2.2'
 PACKAGE_BUGREPORT='dholmes@ct.boxmail.com'
 
 ac_unique_file="ctorrent.cpp"
@@ -788,7 +788,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures CTorrent dnh2 to adapt to many kinds of systems.
+\`configure' configures CTorrent dnh2.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -850,7 +850,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of CTorrent dnh2:";;
+     short | recursive ) echo "Configuration of CTorrent dnh2.2:";;
    esac
   cat <<\_ACEOF
 
@@ -971,7 +971,7 @@
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-CTorrent configure dnh2
+CTorrent configure dnh2.2
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -985,7 +985,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by CTorrent $as_me dnh2, which was
+It was created by CTorrent $as_me dnh2.2, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -1628,7 +1628,7 @@
 
 # Define the identity of the package.
  PACKAGE=ctorrent
- VERSION=dnh2
+ VERSION=dnh2.2
 
 
 cat >>confdefs.h <<_ACEOF
@@ -6326,7 +6326,7 @@
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by CTorrent $as_me dnh2, which was
+This file was extended by CTorrent $as_me dnh2.2, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -6389,7 +6389,7 @@
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-CTorrent config.status dnh2
+CTorrent config.status dnh2.2
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
--- config.h.in.orig	Thu Nov 10 21:00:00 2005
+++ config.h.in	Sun Oct 22 12:42:41 2006
@@ -199,3 +199,4 @@

 /* Define to `unsigned' if <sys/types.h> does not define. */
 #undef size_t
+
--- .deps/btcontent.Po.orig	Sat Jan 28 19:58:19 2006
+++ .deps/btcontent.Po	Sat Nov  4 11:42:03 2006
@@ -12,10 +12,10 @@
  /usr/include/machine/limits.h /usr/include/sha.h /usr/include/time.h \
  /usr/include/sys/stat.h /usr/include/sys/time.h /usr/include/stdlib.h \
  /usr/include/string.h /usr/include/fcntl.h /usr/include/errno.h \
- btconfig.h bencode.h peer.h /usr/include/sys/socket.h \
+ ctorrent.h btconfig.h bencode.h peer.h /usr/include/sys/socket.h \
  /usr/include/arpa/inet.h /usr/include/netinet/in.h \
  /usr/include/netinet6/in6.h btrequest.h btstream.h bufio.h rate.h \
- httpencode.h tracker.h
+ httpencode.h tracker.h peerlist.h ctcs.h
 btcontent.cpp :
 btcontent.h :
 def.h :
@@ -49,6 +49,7 @@
 /usr/include/string.h :
 /usr/include/fcntl.h :
 /usr/include/errno.h :
+ctorrent.h :
 btconfig.h :
 bencode.h :
 peer.h :
@@ -62,3 +63,5 @@
 rate.h :
 httpencode.h :
 tracker.h :
+peerlist.h :
+ctcs.h :
--- .deps/ctorrent.Po.orig	Sat Jan 28 19:58:20 2006
+++ .deps/ctorrent.Po	Sat Nov  4 11:42:04 2006
@@ -8,8 +8,8 @@
  /usr/include/machine/signal.h /usr/include/machine/trap.h \
  /usr/include/sys/ucontext.h /usr/include/machine/ucontext.h \
  /usr/include/sys/time.h /usr/include/time.h /usr/include/string.h \
- /usr/include/stdio.h /usr/include/stdlib.h btconfig.h btcontent.h \
- bitfield.h btfiles.h downloader.h peerlist.h peer.h \
+ /usr/include/stdio.h /usr/include/stdlib.h ctorrent.h btconfig.h \
+ btcontent.h bitfield.h btfiles.h downloader.h peerlist.h peer.h \
  /usr/include/sys/socket.h /usr/include/machine/param.h \
  /usr/include/arpa/inet.h /usr/include/netinet/in.h \
  /usr/include/netinet6/in6.h btrequest.h btstream.h bufio.h rate.h \
@@ -38,6 +38,7 @@
 /usr/include/string.h :
 /usr/include/stdio.h :
 /usr/include/stdlib.h :
+ctorrent.h :
 btconfig.h :
 btcontent.h :
 bitfield.h :
--- .deps/peer.Po.orig	Tue Aug 15 14:17:02 2006
+++ .deps/peer.Po	Sat Nov  4 11:42:05 2006
@@ -9,8 +9,8 @@
  /usr/include/netinet6/in6.h /usr/include/string.h /usr/include/time.h \
  btrequest.h btcontent.h /usr/include/stdio.h bitfield.h btfiles.h \
  btstream.h bufio.h rate.h btconfig.h /usr/include/stdlib.h \
- /usr/include/ctype.h /usr/include/runetype.h msgencode.h peerlist.h \
- bttime.h
+ /usr/include/ctype.h /usr/include/runetype.h ctorrent.h msgencode.h \
+ peerlist.h bttime.h
 peer.cpp :
 peer.h :
 def.h :
@@ -43,6 +43,7 @@
 /usr/include/stdlib.h :
 /usr/include/ctype.h :
 /usr/include/runetype.h :
+ctorrent.h :
 msgencode.h :
 peerlist.h :
 bttime.h :
--- .deps/tracker.Po.orig	Mon Aug 14 13:42:51 2006
+++ .deps/tracker.Po	Sat Nov  4 11:42:05 2006
@@ -13,9 +13,9 @@
  /usr/include/sys/ucontext.h /usr/include/machine/ucontext.h \
  /usr/include/machine/limits.h btconfig.h /usr/include/netdb.h \
  /usr/include/stdlib.h /usr/include/string.h /usr/include/errno.h \
- peerlist.h peer.h btrequest.h btcontent.h /usr/include/stdio.h \
- bitfield.h btfiles.h btstream.h rate.h httpencode.h bencode.h \
- setnonblock.h connect_nonb.h iplist.h ctcs.h
+ ctorrent.h peerlist.h peer.h btrequest.h btcontent.h \
+ /usr/include/stdio.h bitfield.h btfiles.h btstream.h rate.h \
+ httpencode.h bencode.h setnonblock.h connect_nonb.h iplist.h ctcs.h
 tracker.cpp :
 tracker.h :
 def.h :
@@ -50,6 +50,7 @@
 /usr/include/stdlib.h :
 /usr/include/string.h :
 /usr/include/errno.h :
+ctorrent.h :
 peerlist.h :
 peer.h :
 btrequest.h :
