home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 October / maximum-cd-2011-10.iso / DiscContents / digsby_setup.exe / lib / oscar / rendezvous / filetransfer.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2011-06-22  |  21.0 KB  |  536 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. from __future__ import with_statement
  5. __metaclass__ = type
  6. from oscar.rendezvous.peer import OscarPeer
  7. from oscar.rendezvous.rendezvous import oscarcookie, map_intarg, rendezvous_tlvs
  8. import oscar.capabilities as capabilities
  9. from util import Storage, strlist, NoneFileChunker, to_hex
  10. from util.packable import Packable
  11. import util
  12. import oscar.snac as oscar
  13. import oscar.OscarUtil as oscar
  14. import common
  15. import hooks
  16. from path import path
  17. import os.path as os
  18. import traceback
  19. import struct
  20. from logging import getLogger
  21. log = getLogger('oscar.rdv.ft')
  22. info = log.info
  23.  
  24. def prettyoft(oft):
  25.     return '\n'.join((lambda .0: for line in .0:
  26. '%20s: %r' % line)(list(iter(oft))))
  27.  
  28. rz = rendezvous_tlvs
  29. tlv = oscar.OscarUtil.tlv
  30. tlv_list = oscar.OscarUtil.tlv_list
  31.  
  32. def send(oscar, screenname, filestorage):
  33.     cookie = oscarcookie()
  34.     oscar.rdv_sessions[cookie] = transfer = OutgoingOscarFileTransfer(oscar, screenname, cookie, filestorage)
  35.     transfer.request()
  36.     return transfer
  37.  
  38.  
  39. class OFTHeader(Packable):
  40.     fmt = strlist('\n        protocol_version 4s  # Always \'OFT2\'\n        length           H   # includes all data, including version and length\n        type             H   # one of "types" below\n    ')
  41.     invars = [
  42.         (lambda self: self.protocol_version == 'OFT2'),
  43.         (lambda self: self.type in self.types.values())]
  44.     types = Storage(prompt = 257, ack = 514, done = 516, receiver_resume = 517, sender_resume = 262, rcv_resume_ack = 519)
  45.  
  46.  
  47. class OFTBody(Packable):
  48.     fmt = strlist("\n    cookie              Q\n    encryption          H\n    compression         H\n    num_files           H\n    files_left          H\n    num_parts           H\n    parts_left          H\n    total_size          I\n    file_size           I\n\n    modification_time   I   # since unix epoch\n    checksum            I   # see OscarFileTransferChecksum\n    recv_fork_checksum  I\n    fork_size           I\n    creation_time       I\n    fork_checksum       I\n    bytes_received      I\n    recv_checksum       I\n    id_string           32s # 32 byte right padded string: usually 'CoolFileXfer'\n\n    flags               B   # Flags: 0x20 - Negotiation (not complete), 0x01 - Done\n    list_name_offset    B   # always 0x1c\n    list_size_offset    B   # always 0x11\n\n    dummy_block         69s # Dummy Block - large null block for future expansion of OFT\n\n    mac_file_info       16s # Mac File Info\n\n    charset             H   # charset\n    subset              H   # subset: 0 for ASCII, 2 for UTF-16BE, 3 for ISO-8859-1\n    ")
  49.     default_checksum = 0xFFFF0000L
  50.     
  51.     def padfilename(filename):
  52.         if len(filename) < 64:
  53.             filename += '\x00' * (64 - len(filename))
  54.         
  55.         return filename
  56.  
  57.     padfilename = staticmethod(padfilename)
  58.  
  59. OFTId = 'Cool FileXfer'
  60. OFTId = OFTId + '\x00' * (32 - len(OFTId))
  61.  
  62. class OscarFileTransfer(OscarPeer):
  63.     
  64.     def __init__(self, protocol, screenname, cookie):
  65.         OscarPeer.__init__(self, protocol, screenname, cookie, capabilities.by_name['file_xfer'])
  66.         common.FileTransfer.__init__(self)
  67.         self.cancelled = False
  68.         self.resuming = False
  69.         self.on_get_buddy(self.buddy)
  70.  
  71.     
  72.     def ch2cancel(self, data):
  73.         log.info('%r cancelled by buddy', self)
  74.         self.cancelled = True
  75.         self.cancel_by_buddy()
  76.         if data:
  77.             log.info('data in a ch2 cancel: %s', to_hex(data))
  78.         
  79.  
  80.     
  81.     def cancel_by_buddy(self):
  82.         log.info('cancel_by_buddy')
  83.         if self.state != self.states.CANCELLED_BY_YOU:
  84.             self.state = self.states.CANCELLED_BY_BUDDY
  85.         
  86.         
  87.         try:
  88.             self.fileobj.close()
  89.         except Exception:
  90.             traceback.print_exc()
  91.  
  92.  
  93.     
  94.     def on_close(self):
  95.         log.info('%r on_close', self)
  96.         
  97.         try:
  98.             self.fileobj.close()
  99.         except AttributeError:
  100.             pass
  101.  
  102.         if self.state == self.states.TRANSFERRING:
  103.             self.state = self.states.CONN_FAIL_XFER
  104.             self.on_error()
  105.         
  106.  
  107.     
  108.     def close(self):
  109.         log.info('close')
  110.         
  111.         try:
  112.             self.socket.close()
  113.             del self.socket
  114.         except Exception:
  115.             pass
  116.  
  117.         self.done = True
  118.         
  119.         try:
  120.             self.fileobj.close()
  121.         except AttributeError:
  122.             pass
  123.  
  124.  
  125.     
  126.     def cancel(self, msg = '', state = None):
  127.         if hasattr(self, 'socket') and self.socket:
  128.             
  129.             try:
  130.                 self.socket.cancel_timeout()
  131.             except Exception:
  132.                 traceback.print_exc()
  133.             except:
  134.                 None<EXCEPTION MATCH>Exception
  135.             
  136.  
  137.         None<EXCEPTION MATCH>Exception
  138.         
  139.         try:
  140.             self.filechunker.cancelled = True
  141.         except Exception:
  142.             traceback.print_exc()
  143.             info('$$$ sending cancel')
  144.             self.send_rdv('cancel')
  145.  
  146.         self.close()
  147.         self.setnotifyif('cancelled', True)
  148.         info('%r cancelled. %s', self, msg)
  149.         if state is None:
  150.             state = self.states.CANCELLED_BY_YOU
  151.         
  152.         self.state = state
  153.  
  154.     
  155.     def ch2accept(self, data):
  156.         if data:
  157.             log.error('got data in a channel 2 accept: data = %r', data)
  158.             self.cancel()
  159.         else:
  160.             log.info('ch2accept data = %r', data)
  161.  
  162.     
  163.     def decline_transfer(self, reason = None):
  164.         log.info('decline_transfer: reason = %r', reason)
  165.         self.cancel()
  166.  
  167.     
  168.     def send_oft(self, type, setvalues = True):
  169.         oft = self.oft
  170.         if not oft:
  171.             return None
  172.         info('sending oft %s for %s', type, self.filename)
  173.         info(prettyoft(oft) + '\n  filename: %s', self.filename)
  174.         self.socket.push(oftpacket(type, oft, self.filename))
  175.  
  176.  
  177.  
  178. class OutgoingOscarFileTransfer(OscarFileTransfer, common.OutgoingFileTransfer):
  179.     
  180.     def __init__(self, o, screenname, cookie, fileinfo):
  181.         OscarFileTransfer.__init__(self, o, screenname, cookie)
  182.         [ setattr(self, a, fileinfo[a]) for a in 'name files size numfiles'.split() ]
  183.         self.filepath = path(fileinfo.path)
  184.         self.fileobj = None
  185.         self.oft = self.next_file()
  186.         self.accepted = False
  187.         self.connected = False
  188.         self.completed = 0
  189.         self.state = self.states.WAITING_FOR_BUDDY
  190.  
  191.     
  192.     def next_file(self):
  193.         if self.files:
  194.             self.file = self.files.pop(0)
  195.             if hasattr(self, 'rootpath'):
  196.                 p = self.rootpath.relpathto(self.file)
  197.                 self.filename = p.normpath().replace('\\', '/').replace('/', chr(1))
  198.             else:
  199.                 self.filename = self.file.name
  200.             return self.oft_for_file(self.file)
  201.         self.file = None
  202.         return False
  203.  
  204.     
  205.     def __repr__(self):
  206.         if not getattr(self.file, 'name', None):
  207.             pass
  208.         return '<OutgoingOscarFileTransfer to %s (%r)>' % (self.screenname, '')
  209.  
  210.     
  211.     def request(self, message = '<html>'):
  212.         xdata = xdata_block(self.name, self.size, self.numfiles)
  213.         self.establish_out_dc(message = message, extratlvs = [
  214.             (rz.extended_data, xdata),
  215.             (rz.filename_encoding, 'utf-8')])
  216.  
  217.     
  218.     def on_odc_connection(self):
  219.         info('%r connected!', self)
  220.         self.connected = True
  221.         self.maybe_start()
  222.  
  223.     
  224.     def received_oft_header(self, data):
  225.         (header, data) = OFTHeader.unpack(data)
  226.         log.debug('received OFT header: oft=%(protocol_version)s length=0x%(length)x type=0x%(type)x', dict(header))
  227.         bytes_left = header.length - OFTHeader._struct.size
  228.         if header.type in (OFTHeader.types.ack, OFTHeader.types.rcv_resume_ack):
  229.             self.open_file()
  230.         elif header.type == OFTHeader.types.done:
  231.             
  232.             try:
  233.                 self.fileobj.close()
  234.             except AttributeError:
  235.                 pass
  236.  
  237.             self.fileobj = None
  238.             self.oft = self.next_file()
  239.             if not self.oft:
  240.                 if self.completed:
  241.                     self.state = self.states.FINISHED
  242.                     self._ondone()
  243.                 else:
  244.                     self.cancel_by_buddy()
  245.                 self.close()
  246.             
  247.             return None
  248.         if header.type == OFTHeader.types.receiver_resume:
  249.             log.info('Going to resume file %s' % self.file)
  250.             self.resuming = True
  251.         else:
  252.             log.warning('Error! OFT type %r', header.type)
  253.         self.socket.receive_next(bytes_left, self.received_oft_body)
  254.  
  255.     
  256.     def open_file(self):
  257.         
  258.         try:
  259.             self.fileobj = self.file.open('rb')
  260.             return True
  261.         except IOError:
  262.             self.cancel('Could not open file %s' % self.file)
  263.             return False
  264.  
  265.  
  266.     
  267.     def received_oft_body(self, data):
  268.         (oft, data) = OFTBody.unpack(data)
  269.         (filename, data) = read_cstring(data)
  270.         info(prettyoft(oft) + '\n  filename: %s', filename)
  271.         self.oft = oft
  272.         self.socket.receive_next(OFTHeader, self.received_oft_header)
  273.         if self.fileobj:
  274.             if self.resuming:
  275.                 self.fileobj.seek(oft.bytes_received)
  276.                 self._setcompleted(self.fileobj.tell())
  277.             
  278.             self.filechunker = NoneFileChunker(self.fileobj, close_when_done = True, progress_cb = self._setcompleted)
  279.             log.info('Pushing FileChunker onto socket')
  280.             self.socket.push_with_producer(self.filechunker)
  281.         elif self.oft:
  282.             if self.resuming:
  283.                 self.send_oft('sender_resume', False)
  284.             else:
  285.                 self.send_oft('prompt')
  286.         else:
  287.             info('DONE!')
  288.             self.state = self.states.FINISHED
  289.             self.close()
  290.  
  291.     
  292.     def ch2accept(self, data):
  293.         info('received CH2 accept')
  294.         self.accepted = True
  295.         self.maybe_start()
  296.  
  297.     
  298.     def maybe_start(self):
  299.         if not (self.accepted) or not (self.connected):
  300.             if not self.accepted:
  301.                 info('no RDV accept yet')
  302.             
  303.             if not self.connected:
  304.                 info('no connection yet')
  305.             
  306.             return None
  307.         self.state = self.states.TRANSFERRING
  308.         if not getattr(self, 'sent_first', False):
  309.             info('sending first oft prompt')
  310.             self.sent_first = True
  311.             self.send_oft('prompt')
  312.         
  313.         self.socket.receive_next(OFTHeader, self.received_oft_header)
  314.  
  315.     
  316.     def oft_for_file(self, file):
  317.         return OFTBody(cookie = self.cookie, num_files = self.numfiles, files_left = 1 + len(self.files), num_parts = 1, parts_left = 1, total_size = self.size, file_size = file.size, modification_time = int(file.mtime), creation_time = int(file.ctime), checksum = OFTBody.default_checksum, recv_fork_checksum = OFTBody.default_checksum, fork_checksum = OFTBody.default_checksum, recv_checksum = OFTBody.default_checksum, id_string = OFTId, dummy_block = '\x00' * 69, mac_file_info = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', charset = 0, subset = 0)
  318.  
  319.  
  320.  
  321. class IncomingOscarFileTransfer(OscarFileTransfer, common.IncomingFileTransfer):
  322.     direction = 'incoming'
  323.     
  324.     def __init__(self, o, screenname, cookie):
  325.         OscarFileTransfer.__init__(self, o, screenname, cookie)
  326.         self.completed = 0
  327.  
  328.     
  329.     def handle_request(self, rendtlvs):
  330.         (info, data) = unpack_extended_data(rendtlvs.extended_data)
  331.         self.__dict__.update(info)
  332.         self._onrequest()
  333.  
  334.     
  335.     def accept(self, file_obj):
  336.         if self.cancelled:
  337.             e = OscarFileTransferError('The sender has already cancelled this file request.')
  338.             self.protocol.hub.on_error(e)
  339.         elif isinstance(file_obj, file) or self.numfiles == 1:
  340.             self.filepath = path(file_obj.name)
  341.             self.rootpath = self.filepath.parent
  342.             file_obj.close()
  343.         else:
  344.             self.rootpath = os.path.join(file_obj, self.name)
  345.             if not os.path.exists(self.rootpath):
  346.                 os.makedirs(self.rootpath)
  347.             
  348.             self.filepath = path(self.rootpath)
  349.         info('self.rootpath = %r', self.rootpath)
  350.         None(info, 'accepting incoming file transfer, saving %s to %s' if self.numfiles == 1 else 'files', self.rootpath)
  351.         self.state = self.states.CONNECTING
  352.         self.establish_dc()
  353.  
  354.     
  355.     def decline(self):
  356.         self.state = self.states.CANCELLED_BY_YOU
  357.         self.send_rdv('cancel')
  358.         common.IncomingFileTransfer.decline(self)
  359.  
  360.     
  361.     def on_odc_connection(self):
  362.         self.state = self.states.TRANSFERRING
  363.         self.socket.receive_next(OFTHeader, self.received_oft_header)
  364.  
  365.     
  366.     def received_oft_header(self, data):
  367.         (header, data) = OFTHeader.unpack(data)
  368.         log.debug('received OFT header: %r', dict(header))
  369.         if header.type == OFTHeader.types.prompt:
  370.             bytes_left = header.length - OFTHeader._struct.size
  371.             log.debug('receiving %d more OFT body bytes', bytes_left)
  372.             self.socket.receive_next(bytes_left, self.received_oft_body)
  373.         else:
  374.             self.fail('Error! OFT type ' + str(header.type))
  375.  
  376.     
  377.     def received_oft_body(self, data):
  378.         (oft, data) = OFTBody.unpack(data)
  379.         self.oft = oft
  380.         info('incoming oft body...\n' + prettyoft(oft))
  381.         nullindex = data.find('\x00')
  382.         if nullindex == -1 and len(data) >= 64:
  383.             self.filename = filename = data
  384.         elif nullindex == -1:
  385.             raise AssertionError("couldn't find a null byte in the padded filename")
  386.         else:
  387.             self.filename = filename = data[:nullindex]
  388.         self.fileobj = openpath(self.rootpath, self.filepath.name)
  389.         info('incoming file: %s (%d bytes), %d left', filename, oft.file_size, oft.files_left)
  390.         self.send_oft('ack')
  391.         self.socket.push_collector(self.collect_file_bytes)
  392.         if oft.file_size > 0:
  393.             self.socket.receive_next(oft.file_size, self.received_file)
  394.         else:
  395.             self.received_file()
  396.  
  397.     
  398.     def collect_file_bytes(self, data):
  399.         
  400.         try:
  401.             self.fileobj.write(data)
  402.         except IOError:
  403.             traceback.print_exc()
  404.             return None
  405.         else:
  406.             completed = self.fileobj.tell()
  407.             self.oft.bytes_received = completed
  408.             self._setcompleted(completed)
  409.         finally:
  410.             self.data = ''
  411.  
  412.  
  413.     
  414.     def received_file(self, *data):
  415.         self.socket.pop_collector()
  416.         info('received file %s', self.fileobj.name)
  417.         self.fileobj.close()
  418.         self.send_oft('done')
  419.         if self.oft.files_left == 1:
  420.             info('done!')
  421.             self._ondone()
  422.             self.socket.close()
  423.         else:
  424.             self.socket.receive_next(OFTHeader, self.received_oft_header)
  425.  
  426.     
  427.     def fail(self, msg):
  428.         log.error(msg)
  429.         self.close()
  430.  
  431.     
  432.     def __repr__(self):
  433.         return '<IncomingOFT from %s>' % self.screenname
  434.  
  435.  
  436.  
  437. def oftpacket(type, body, filename):
  438.     if isinstance(filename, unicode):
  439.         filename = filename.encode('utf8')
  440.     else:
  441.         filename = str(filename)
  442.     padded = OFTBody.padfilename(filename)
  443.     return ''.join([
  444.         OFTHeader('OFT2', length = 192 + len(padded), type = map_intarg(type, OFTHeader.types)).pack(),
  445.         body.pack(),
  446.         padded])
  447.  
  448.  
  449. def oft_filename(fn):
  450.     fn += chr(0)
  451.     if len(fn) < 64:
  452.         fn += (64 - len(fn)) * chr(0)
  453.     
  454.     return fn
  455.  
  456.  
  457. def read_cstring(data):
  458.     i = data.find(chr(0))
  459.     if i == -1:
  460.         raise ValueError('not a null terminated string')
  461.     i == -1
  462.     return (data[:i], data[i + 1:])
  463.  
  464.  
  465. def unpack_extended_data(data):
  466.     (multiple, filecount, totalbytes) = struct.unpack('!HHI', data[:8])
  467.     data = data[8:]
  468.     (filename, data) = read_cstring(data)
  469.     return (util.Storage(numfiles = filecount, multiple = multiple == 2, size = totalbytes, name = filename), data)
  470.  
  471.  
  472. def xdata_block(filename, filesize, filecount = 1):
  473.     return None(struct.pack, '!HHI' if filecount == 1 else 2, filecount, filesize) + filename.encode('utf-8') + '\x00'
  474.  
  475.  
  476. def openpath(rootpath, filename):
  477.     PATHSEP = chr(1)
  478.     needdirs = filename.find(PATHSEP) != -1
  479.     path = filename.split(PATHSEP)
  480.     filename = path.pop(-1)
  481.     path = [
  482.         rootpath] + path
  483.     if needdirs:
  484.         pathstr = os.path.join(*path)
  485.         if not os.path.exists(pathstr):
  486.             info('calling makedirs(%s)', pathstr)
  487.             os.makedirs(pathstr)
  488.         
  489.     
  490.     filepath = path + [
  491.         filename]
  492.     return open(os.path.join(*filepath), 'wb')
  493.  
  494.  
  495. class OscarFileTransferError(Exception):
  496.     pass
  497.  
  498.  
  499. class OFTChecksum(object):
  500.     starting_value = 0xFFFF0000L
  501.     
  502.     def __init__(self, data = None):
  503.         self.checksum = self.starting_value
  504.         if data is not None:
  505.             self.update(data)
  506.         
  507.  
  508.     
  509.     def update(self, data, offset = 0):
  510.         check = self.checksum >> 16 & 0xFFFFL
  511.         for i in xrange(len(data)):
  512.             oldcheck = check
  513.             byteval = ord(data[offset + i]) & 255
  514.             None -= check if i & 1 != 0 else byteval << 8
  515.             if check > oldcheck:
  516.                 check -= 1
  517.                 continue
  518.         
  519.         check = (check & 65535) + (check >> 16)
  520.         check = (check & 65535) + (check >> 16)
  521.         checksum = check << 16 & 0xFFFFFFFFL
  522.  
  523.  
  524.  
  525. def initialize():
  526.     log.info('\tloading rendezvous handler: file transfer')
  527.     import oscar.rendezvous.peer as peer
  528.     peer.register_rdv_factory('file_xfer', IncomingOscarFileTransfer)
  529.  
  530. hooks.Hook('oscar.rdv.load').register(initialize)
  531. if __name__ == '__main__':
  532.     p = 'c:\\users\\kevin\\desktop\\apple_evolution.jpg'
  533.     bytes = open(p, 'rb').read()
  534.     print OFTChecksum(bytes).checksum
  535.  
  536.