<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>.gitignore</filename>
    </added>
    <added>
      <filename>doc/rfc2349.txt</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -34,6 +34,11 @@ def main():
                       action='store_true',
                       default=False,
                       help=&quot;downgrade logging from info to warning&quot;)
+    parser.add_option('-t',
+                      '--tsize',
+                      action='store_true',
+                      default=False,
+                      help=&quot;ask client to send tsize option in download&quot;)
     options, args = parser.parse_args()
     if not options.host or not options.filename:
         sys.stderr.write(&quot;Both the --host and --filename options &quot;
@@ -55,8 +60,11 @@ def main():
             self.progress = 0
             self.out = out
         def progresshook(self, pkt):
-            self.progress += len(pkt.data)
-            self.out(&quot;Downloaded %d bytes&quot; % self.progress)
+            if isinstance(pkt, tftpy.TftpPacketDAT):
+                self.progress += len(pkt.data)
+                self.out(&quot;Downloaded %d bytes&quot; % self.progress)
+            elif isinstance(pkt, tftpy.TftpPacketOACK):
+                self.out(&quot;Received OACK, options are: %s&quot; % pkt.options)
         
     if options.debug:
         tftpy.setLogLevel(logging.DEBUG)
@@ -70,6 +78,8 @@ def main():
     tftp_options = {}
     if options.blocksize:
         tftp_options['blksize'] = int(options.blocksize)
+    if options.tsize:
+        tftp_options['tsize'] = 1
 
     tclient = tftpy.TftpClient(options.host,
                                int(options.port),</diff>
      <filename>bin/tftpy_client.py</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
 from distutils.core import setup
 
 setup(name='tftpy',
-      version='0.4.5',
+      version='0.4.6',
       description='Python TFTP library',
       author='Michael P. Soulier',
       author_email='msoulier@digitaltorque.ca',</diff>
      <filename>setup.py</filename>
    </modified>
    <modified>
      <diff>@@ -97,6 +97,13 @@ class TftpClient(TftpSession):
                             % (raddress, rport,
                             self.host, self.port))
                 continue
+
+            # If there is a packethook defined, call it. We unconditionally
+            # pass all packets, it's up to the client to screen out different
+            # kinds of packets. This way, the client is privy to things like
+            # negotiated options.
+            if packethook:
+                packethook(recvpkt)
             
             if not self.port and self.state.state == 'rrq':
                 self.port = rport
@@ -126,11 +133,8 @@ class TftpClient(TftpSession):
                                 % len(recvpkt.data))
                     outputfile.write(recvpkt.data)
                     bytes += len(recvpkt.data)
-                    # If there is a packethook defined, call it.
-                    if packethook:
-                        packethook(recvpkt)
                     # Check for end-of-file, any less than full data packet.
-                    if len(recvpkt.data) &lt; self.options['blksize']:
+                    if len(recvpkt.data) &lt; int(self.options['blksize']):
                         logger.info(&quot;end of file detected&quot;)
                         break
 
@@ -165,6 +169,8 @@ class TftpClient(TftpSession):
                 if recvpkt.options.keys() &gt; 0:
                     if recvpkt.match_options(self.options):
                         logger.info(&quot;Successful negotiation of options&quot;)
+                        # Set options to OACK options
+                        self.options = recvpkt.options
                         for key in self.options:
                             logger.info(&quot;    %s = %s&quot; % (key, self.options[key]))
                         logger.debug(&quot;sending ACK to OACK&quot;)</diff>
      <filename>tftpy/TftpClient.py</filename>
    </modified>
    <modified>
      <diff>@@ -28,7 +28,7 @@ class TftpPacketWithOptions(object):
     goal is just to share code here, and not cause diamond inheritance.&quot;&quot;&quot;
 
     def __init__(self):
-        self.options = None
+        self.options = []
 
     def setoptions(self, options):
         logger.debug(&quot;in TftpPacketWithOptions.setoptions&quot;)
@@ -41,11 +41,11 @@ class TftpPacketWithOptions(object):
                          % (newkey, myoptions[newkey]))
 
         logger.debug(&quot;setting options hash to: &quot; + str(myoptions))
-        self.__options = myoptions
+        self._options = myoptions
 
     def getoptions(self):
         logger.debug(&quot;in TftpPacketWithOptions.getoptions&quot;)
-        return self.__options
+        return self._options
 
     # Set up getter and setter on options to ensure that they are the proper
     # type. They should always be strings, but we don't need to force the
@@ -123,6 +123,7 @@ class TftpPacketInitial(TftpPacket, TftpPacketWithOptions):
     they share quite a bit of code.&quot;&quot;&quot;
     def __init__(self):
         TftpPacket.__init__(self)
+        TftpPacketWithOptions.__init__(self)
         self.filename = None
         self.mode = None
         
@@ -151,11 +152,14 @@ class TftpPacketInitial(TftpPacket, TftpPacketWithOptions):
             logger.debug(&quot;there are options to encode&quot;)
             for key in self.options:
                 format += &quot;%dsx&quot; % len(key)
-                format += &quot;%dsx&quot; % len(str(self.options[key]))
                 options_list.append(key)
-                options_list.append(str(self.options[key]))
+                # Not all options have values.
+                if key != 'tsize':
+                    format += &quot;%dsx&quot; % len(str(self.options[key]))
+                    options_list.append(str(self.options[key]))
 
         logger.debug(&quot;format is %s&quot; % format)
+        logger.debug(&quot;options_list is %s&quot; % options_list)
         logger.debug(&quot;size of struct is %d&quot; % struct.calcsize(format))
 
         self.buffer = struct.pack(format,
@@ -212,23 +216,37 @@ class TftpPacketRRQ(TftpPacketInitial):
         2 bytes    string   1 byte     string   1 byte
         -----------------------------------------------
 RRQ/  | 01/02 |  Filename  |   0  |    Mode    |   0  |
-WRQ    -----------------------------------------------
+WRQ     -----------------------------------------------
     &quot;&quot;&quot;
     def __init__(self):
         TftpPacketInitial.__init__(self)
         self.opcode = 1
 
+    def __str__(self):
+        s = 'RRQ packet: filename = %s' % self.filename
+        s += ' mode = %s' % self.mode
+        if self.options:
+            s += '\n    options = %s' % self.options
+        return s
+
 class TftpPacketWRQ(TftpPacketInitial):
     &quot;&quot;&quot;
         2 bytes    string   1 byte     string   1 byte
         -----------------------------------------------
 RRQ/  | 01/02 |  Filename  |   0  |    Mode    |   0  |
-WRQ    -----------------------------------------------
+WRQ     -----------------------------------------------
     &quot;&quot;&quot;
     def __init__(self):
         TftpPacketInitial.__init__(self)
         self.opcode = 2
 
+    def __str__(self):
+        s = 'WRQ packet: filename = %s' % self.filename
+        s += ' mode = %s' % self.mode
+        if self.options:
+            s += '\n    options = %s' % self.options
+        return s
+
 class TftpPacketDAT(TftpPacket):
     &quot;&quot;&quot;
         2 bytes    2 bytes       n bytes
@@ -242,6 +260,12 @@ DATA  | 03    |   Block #  |    Data    |
         self.blocknumber = 0
         self.data = None
 
+    def __str__(self):
+        s = 'DAT packet: block %s' % self.blocknumber
+        if self.data:
+            s += '\n    data: %d bytes' % len(self.data)
+        return s
+
     def encode(self):
         &quot;&quot;&quot;Encode the DAT packet. This method populates self.buffer, and
         returns self for easy method chaining.&quot;&quot;&quot;
@@ -281,6 +305,9 @@ ACK   | 04    |   Block #  |
         self.opcode = 4
         self.blocknumber = 0
 
+    def __str__(self):
+        return 'ACK packet: block %d' % self.blocknumber
+
     def encode(self):
         logger.debug(&quot;encoding ACK: opcode = %d, block = %d&quot; 
                      % (self.opcode, self.blocknumber))
@@ -330,6 +357,9 @@ ERROR | 05    |  ErrorCode |   ErrMsg   |   0  |
             8: &quot;Failed to negotiate options&quot;
             }
 
+    def __str__(self):
+        return 'ERR packet: errorcode = %d' % self.errorcode
+
     def encode(self):
         &quot;&quot;&quot;Encode the DAT packet based on instance variables, populating
         self.buffer, returning self.&quot;&quot;&quot;
@@ -362,7 +392,11 @@ class TftpPacketOACK(TftpPacket, TftpPacketWithOptions):
     &quot;&quot;&quot;
     def __init__(self):
         TftpPacket.__init__(self)
+        TftpPacketWithOptions.__init__(self)
         self.opcode = 6
+
+    def __str__(self):
+        return 'OACK packet:\n    options = %s' % self.options
         
     def encode(self):
         format = &quot;!H&quot; # opcode</diff>
      <filename>tftpy/TftpPacketTypes.py</filename>
    </modified>
    <modified>
      <diff>@@ -320,7 +320,7 @@ class TftpServerHandler(TftpSession):
                                            % (self.key, blksize))
                             self.options['blksize'] = DEF_BLKSIZE
                     if recvpkt.options.has_key('tsize'):
-                        logger.debug('RRQ includes received tsize')
+                        logger.debug('RRQ includes tsize option')
                         self.options['tsize'] = os.stat(self.filename).st_size
                     self.send_oack()
 </diff>
      <filename>tftpy/TftpServer.py</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>8a0162b31739bc05bcec1b846834de33f5830b37</id>
    </parent>
  </parents>
  <author>
    <name>Michael P. Soulier</name>
    <email>msoulier@digitaltorque.ca</email>
  </author>
  <url>http://github.com/msoulier/tftpy/commit/07416bf84823f06a29c87c0ab90db6aa8ffef078</url>
  <id>07416bf84823f06a29c87c0ab90db6aa8ffef078</id>
  <committed-date>2008-10-04T17:42:27-07:00</committed-date>
  <authored-date>2008-10-04T17:42:27-07:00</authored-date>
  <message>Rebased tsize branch and added a --tsize option to the client.
Now sending all packets to the progresshook, not just DAT packets,
so that the client can see the OACK. Not yet making use of the returned
tsize. Need to test this on a server that supports tsize.</message>
  <tree>8e7b889b395dbca9e8f8ba6ecf5f326d06f3ce18</tree>
  <committer>
    <name>Michael P. Soulier</name>
    <email>msoulier@digitaltorque.ca</email>
  </committer>
</commit>
