home *** CD-ROM | disk | FTP | other *** search
Wrap
# Source Generated with Decompyle++ # File: in.pyo (Python 2.5) from __future__ import with_statement __metaclass__ = type import struct import socket import time from struct import unpack, pack from pprint import pformat, pprint from util import Storage, enum, strlist, autoassign, lookup_table, removedupes, myip, FileChunker, to_hex from util.packable import Packable from path import path import util import oscar import oscar.snac as oscar import oscar.OscarUtil as oscar from oscar.rendezvous.peer import OscarPeer, ipstr from oscar.rendezvous.rendezvous import oscarcookie, map_intarg, rendezvous_tlvs import oscar.capabilities as capabilities import os import os.path as os import traceback import common from logging import getLogger log = getLogger('oscar.rz.ft') info = log.info def prettyoft(oft): return '\n'.join((lambda .0: for line in .0: '%20s: %r' % line)(list(iter(oft)))) rz = rendezvous_tlvs tlv = oscar.OscarUtil.tlv tlv_list = oscar.OscarUtil.tlv_list def send(oscar, screenname, filestorage): cookie = oscarcookie() oscar.rdv_sessions[cookie] = transfer = OutgoingOscarFileTransfer(oscar, screenname, cookie, filestorage) transfer.request() return transfer class OFTHeader(Packable): 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 ') invars = [ (lambda self: self.protocol_version == 'OFT2'), (lambda self: self.type in self.types.values())] types = Storage(prompt = 257, ack = 514, done = 516, receiver_resume = 517, sender_resume = 262, rcv_resume_ack = 519) class OFTBody(Packable): 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 ") default_checksum = 0xFFFF0000L def padfilename(filename): if len(filename) < 64: filename += '\x00' * (64 - len(filename)) return filename padfilename = staticmethod(padfilename) OFTId = 'Cool FileXfer' OFTId = OFTId + '\x00' * (32 - len(OFTId)) class OscarFileTransfer(OscarPeer): def __init__(self, protocol, screenname, cookie): OscarPeer.__init__(self, protocol, screenname, cookie, capabilities.by_name['file_xfer']) common.FileTransfer.__init__(self) self.cancelled = False self.resuming = False self.on_get_buddy(self.buddy) def ch2cancel(self, data): log.info('%r cancelled by buddy', self) self.cancelled = True self.cancel_by_buddy() if data: log.info('data in a ch2 cancel: %s', to_hex(data)) def cancel_by_buddy(self): log.info('cancel_by_buddy') if self.state != self.states.CANCELLED_BY_YOU: self.state = self.states.CANCELLED_BY_BUDDY try: self.fileobj.close() except Exception: import traceback traceback.print_exc() def on_close(self): log.info('%r on_close', self) try: self.fileobj.close() except AttributeError: pass if self.state == self.states.TRANSFERRING: self.state = self.states.CONN_FAIL_XFER self.on_error() def close(self): log.info('close') try: self.socket.close() del self.socket except Exception: pass self.done = True try: self.fileobj.close() except AttributeError: pass def cancel(self, msg = '', state = None): if hasattr(self, 'socket') and self.socket: try: self.socket.cancel_timeout() except Exception: traceback.print_exc() except: None<EXCEPTION MATCH>Exception None<EXCEPTION MATCH>Exception try: self.filechunker.cancelled = True except Exception: traceback.print_exc() info('$$$ sending cancel') self.send_rdv('cancel') self.close() self.setnotifyif('cancelled', True) info('%r cancelled. %s', self, msg) if state is None: state = self.states.CANCELLED_BY_YOU self.state = state def ch2accept(self, data): if data: log.error('got data in a channel 2 accept: data = %r', data) self.cancel() else: log.info('ch2accept data = %r', data) def decline_transfer(self, reason = None): log.info('decline_transfer: reason = %r', reason) self.cancel() def send_oft(self, type, setvalues = True): oft = self.oft if not oft: return None if setvalues: oft.id_string = OFTId oft.cookie = self.cookie oft.list_name_offset = 28 oft.list_size_offset = 17 oft.flags = None if 'type' == 'done' else 32 oft.checksum = OFTBody.default_checksum info('sending oft %s for %s', type, self.filename) info(prettyoft(oft) + '\n filename: %s', self.filename) self.socket.push(oftpacket(type, oft, self.filename)) class OutgoingOscarFileTransfer(OscarFileTransfer, common.OutgoingFileTransfer): def __init__(self, o, screenname, cookie, fileinfo): OscarFileTransfer.__init__(self, o, screenname, cookie) [ setattr(self, a, fileinfo[a]) for a in 'name files size numfiles'.split() ] self.filepath = path(fileinfo.path) self.fileobj = None self.oft = self.next_file() self.accepted = False self.connected = False self.completed = 0 self.state = self.states.WAITING_FOR_BUDDY def next_file(self): if self.files: self.file = self.files.pop(0) if hasattr(self, 'rootpath'): p = self.rootpath.relpathto(self.file) self.filename = p.normpath().replace('\\', '/').replace('/', chr(1)) else: self.filename = self.file.name return self.oft_for_file(self.file) else: self.file = None return False def __repr__(self): if not getattr(self.file, 'name', None): pass return '<OutgoingOscarFileTransfer to %s (%r)>' % (self.screenname, '') def request(self, message = '<html>'): xdata = xdata_block(self.name, self.size, self.numfiles) self.establish_out_dc(message = message, extratlvs = [ (rz.extended_data, xdata), (rz.filename_encoding, 'utf-8')]) def on_odc_connection(self): info('%r connected!', self) self.connected = True self.maybe_start() def received_oft_header(self, data): (header, data) = OFTHeader.unpack(data) log.debug('received OFT header: oft=%(protocol_version)s length=0x%(length)x type=0x%(type)x', dict(header)) bytes_left = header.length - OFTHeader._struct.size if header.type in (OFTHeader.types.ack, OFTHeader.types.rcv_resume_ack): self.open_file() elif header.type == OFTHeader.types.done: try: self.fileobj.close() except AttributeError: pass self.fileobj = None self.oft = self.next_file() if not self.oft: if self.completed: self.state = self.states.FINISHED self._ondone() else: self.cancel_by_buddy() self.close() return None elif header.type == OFTHeader.types.receiver_resume: log.info('Going to resume file %s' % self.file) self.resuming = True else: log.warning('Error! OFT type %r', header.type) self.socket.receive_next(bytes_left, self.received_oft_body) def open_file(self): try: self.fileobj = self.file.open('rb') return True except IOError: self.cancel('Could not open file %s' % self.file) return False def received_oft_body(self, data): (oft, data) = OFTBody.unpack(data) (filename, data) = read_cstring(data) info(prettyoft(oft) + '\n filename: %s', filename) self.oft = oft self.socket.receive_next(OFTHeader, self.received_oft_header) if self.fileobj: if self.resuming: self.fileobj.seek(oft.bytes_received) self._setcompleted(self.fileobj.tell()) self.filechunker = FileChunker(self.fileobj, close_when_done = True, progress_cb = self._setcompleted) log.info('Pushing FileChunker onto socket') self.socket.push_with_producer(self.filechunker) elif self.oft: if self.resuming: self.send_oft('sender_resume', False) else: self.send_oft('prompt') else: info('DONE!') self.state = self.states.FINISHED self.close() def ch2accept(self, data): info('received CH2 accept') self.accepted = True self.maybe_start() def maybe_start(self): if not (self.accepted) or not (self.connected): if not self.accepted: info('no RDV accept yet') if not self.connected: info('no connection yet') return None self.state = self.states.TRANSFERRING if not getattr(self, 'sent_first', False): info('sending first oft prompt') self.sent_first = True self.send_oft('prompt') self.socket.receive_next(OFTHeader, self.received_oft_header) def oft_for_file(self, file): 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) class IncomingOscarFileTransfer(OscarFileTransfer, common.IncomingFileTransfer): direction = 'incoming' def __init__(self, o, screenname, cookie): OscarFileTransfer.__init__(self, o, screenname, cookie) self.completed = 0 def handle_request(self, rendtlvs): (info, data) = unpack_extended_data(rendtlvs.extended_data) self.__dict__.update(info) self._onrequest() def accept(self, file_obj): if self.cancelled: e = OscarFileTransferError('The sender has already cancelled this file request.') self.protocol.hub.on_error(e) elif isinstance(file_obj, file) or self.numfiles == 1: self.filepath = path(file_obj.name) self.rootpath = self.filepath.parent file_obj.close() else: self.rootpath = os.path.join(file_obj, self.name) if not os.path.exists(self.rootpath): os.makedirs(self.rootpath) self.filepath = path(self.rootpath) info('self.rootpath = %r', self.rootpath) None(info, 'accepting incoming file transfer, saving %s to %s' if self.numfiles == 1 else 'files', self.rootpath) self.state = self.states.CONNECTING self.establish_dc() def decline(self): self.state = self.states.CANCELLED_BY_YOU self.send_rdv('cancel') common.IncomingFileTransfer.decline(self) def on_odc_connection(self): self.state = self.states.TRANSFERRING self.socket.receive_next(OFTHeader, self.received_oft_header) def received_oft_header(self, data): (header, data) = OFTHeader.unpack(data) log.debug('received OFT header: %r', dict(header)) if header.type == OFTHeader.types.prompt: bytes_left = header.length - OFTHeader._struct.size log.debug('receiving %d more OFT body bytes', bytes_left) self.socket.receive_next(bytes_left, self.received_oft_body) else: self.fail('Error! OFT type ' + str(header.type)) def received_oft_body(self, data): (oft, data) = OFTBody.unpack(data) self.oft = oft info('incoming oft body...\n' + prettyoft(oft)) nullindex = data.find('\x00') if nullindex == -1: raise AssertionError("couldn't find a null byte in the padded filename") self.filename = filename = data[:nullindex] self.fileobj = openpath(self.rootpath, self.filepath.name) info('incoming file: %s (%d bytes), %d left', filename, oft.file_size, oft.files_left) self.send_oft('ack') self.socket.push_collector(self.collect_file_bytes) if oft.file_size > 0: self.socket.receive_next(oft.file_size, self.received_file) else: self.received_file() def collect_file_bytes(self, data): try: self.fileobj.write(data) except IOError: import traceback traceback.print_exc() return None else: self._setcompleted(self.fileobj.tell()) finally: self.data = '' def received_file(self, *data): self.socket.pop_collector() info('received file %s', self.fileobj.name) self.fileobj.close() self.send_oft('done') if self.oft.files_left == 1: info('done!') self.socket.close() self._ondone() else: self.socket.receive_next(OFTHeader, self.received_oft_header) def fail(self, msg): log.error(msg) self.close() def __repr__(self): return '<IncomingOFT from %s>' % self.screenname def oftpacket(type, body, filename): if isinstance(filename, unicode): filename = filename.encode('utf8') else: filename = str(filename) padded = OFTBody.padfilename(filename) return ''.join([ OFTHeader('OFT2', length = 192 + len(padded), type = map_intarg(type, OFTHeader.types)).pack(), body.pack(), padded]) def oft_filename(fn): fn += chr(0) if len(fn) < 64: fn += (64 - len(fn)) * chr(0) return fn def read_cstring(data): i = data.find(chr(0)) if i == -1: raise ValueError('not a null terminated string') return (data[:i], data[i + 1:]) def unpack_extended_data(data): (multiple, filecount, totalbytes) = struct.unpack('!HHI', data[:8]) data = data[8:] (filename, data) = read_cstring(data) return (util.Storage(numfiles = filecount, multiple = multiple == 2, size = totalbytes, name = filename), data) def xdata_block(filename, filesize, filecount = 1): return None(struct.pack, '!HHI' if filecount == 1 else 2, filecount, filesize) + filename.encode('utf-8') + '\x00' def openpath(rootpath, filename): PATHSEP = chr(1) needdirs = filename.find(PATHSEP) != -1 path = filename.split(PATHSEP) filename = path.pop(-1) path = [ rootpath] + path if needdirs: pathstr = os.path.join(*path) if not os.path.exists(pathstr): info('calling makedirs(%s)', pathstr) os.makedirs(pathstr) filepath = path + [ filename] return open(os.path.join(*filepath), 'wb') class OscarFileTransferError(Exception): pass class OFTChecksum(object): starting_value = 0xFFFF0000L def __init__(self, data = None): self.checksum = self.starting_value if data is not None: self.update(data) def update(self, data, offset = 0): check = self.checksum >> 16 & 0xFFFFL for i in xrange(len(data)): oldcheck = check byteval = ord(data[offset + i]) & 255 None -= check if i & 1 != 0 else byteval << 8 if check > oldcheck: check -= 1 continue check = (check & 65535) + (check >> 16) check = (check & 65535) + (check >> 16) checksum = check << 16 & 0xFFFFFFFFL if __name__ == '__main__': p = 'c:\\users\\kevin\\desktop\\apple_evolution.jpg' bytes = open(p, 'rb').read() print OFTChecksum(bytes).checksum