PyXR

c:\projects\bitpim\src \ bp_obex.py



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2006 Joe Pham <djpham@bitpim.org>
0004 ###
0005 ### This program is free software; you can redistribute it and/or modify
0006 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0007 ###
0008 ### $Id: bp_obex.py 3460 2006-07-08 23:55:09Z djpham $
0009 
0010 """Provide support to OBEX protocol"""
0011 
0012 # System Modules
0013 import time
0014 import struct
0015 import xml.dom.minidom
0016 
0017 # BitPim modules
0018 import bptime
0019 
0020 module_debug=False
0021 
0022 # Header Codes
0023 Header_Count=0xC
0024 Header_Name=0x01
0025 Header_Type=0x42
0026 Header_Length=0xC3
0027 Header_Time=0x44
0028 Header_Description=0x05
0029 Header_Target=0x46
0030 Header_HTTP=0x47
0031 Header_Body=0x48
0032 Header_BodyEnd=0x49
0033 Header_Who=0x4A
0034 Header_ConnectionID=0xCB
0035 Header_AppParameters=0x4C
0036 Header_AuthChallenge=0x4D
0037 Header_AuthResponse=0x4E
0038 Header_ObjectClass=0x4F
0039 # Header String
0040 Header_Count_Str='Count'
0041 Header_Name_Str='Name'
0042 Header_Type_Str='Type'
0043 Header_Length_Str='Length'
0044 Header_Time_Str='Time'
0045 Header_Description_Str='Description'
0046 Header_Target_Str='Target'
0047 Header_HTTP_Str='HTTP'
0048 Header_Body_Str='Body'
0049 Header_BodyEnd_Str='BodyEnd'
0050 Header_Who_Str='Who'
0051 Header_ConnectionID_Str='ConnectionID'
0052 Header_AppParameters_Str='AppParameters'
0053 Header_AuthChallenge_Str='AuthChallenge'
0054 Header_AuthResponse_Str='AuthResponse'
0055 Header_ObjectClass_Str='ObjectClass'
0056 # Code-to-name dict
0057 Header_Name_Dict={
0058     Header_Count: Header_Count_Str,
0059     Header_Name: Header_Name_Str,
0060     Header_Type: Header_Type_Str,
0061     Header_Length: Header_Length_Str,
0062     Header_Time: Header_Time_Str,
0063     Header_Description: Header_Description_Str,
0064     Header_Target: Header_Target_Str,
0065     Header_HTTP: Header_HTTP_Str,
0066     Header_Body: Header_Body_Str,
0067     Header_BodyEnd: Header_BodyEnd_Str,
0068     Header_Who: Header_Who_Str,
0069     Header_ConnectionID: Header_ConnectionID_Str,
0070     Header_AppParameters: Header_AppParameters_Str,
0071     Header_AuthChallenge: Header_AuthChallenge_Str,
0072     Header_AuthResponse: Header_AuthResponse_Str,
0073     Header_ObjectClass: Header_ObjectClass_Str,
0074     }
0075 Valid_Header_Codes=Header_Name_Dict.keys()
0076 
0077 # Packet code constants
0078 Packet_Connect=0x80
0079 Packet_Disconnect=0x81
0080 Packet_Put=0x02
0081 Packet_PutEnd=0x82
0082 Packet_Get=0x03
0083 Packet_GetEnd=0x83
0084 Packet_SetPath=0x85
0085 Packet_Abort=0xFF
0086 Packet_Resp_Continue=0x90
0087 Packet_Resp_OK=0xA0
0088 Packet_Resp_Created=0xA1
0089 Packet_Resp_Accepted=0xA2
0090 Packet_Resp_NonAuthoritativeInfo=0xA3
0091 Packet_Resp_NoContent=0xA4
0092 Packet_Resp_ResetContent=0xA5
0093 Packet_Resp_PartialContent=0xA6
0094 Packet_Resp_MultipleChoices=0xB0
0095 Packet_Resp_MovedPermanently=0xB1
0096 Packet_Resp_MovedTemporarily=0xB2
0097 Packet_Resp_SeeOther=0xB3
0098 Packet_Resp_NotModified=0xB4
0099 Packet_Resp_UseProxy=0xB5
0100 Packet_Resp_BadRequest=0xC0
0101 Packet_Resp_Unauthorized=0xC1
0102 Packet_Resp_PaymentRequired=0xC2
0103 Packet_Resp_Forbidden=0xC3
0104 Packet_Resp_NotFound=0xC4
0105 Packet_Resp_MethodNotAllowed=0xC5
0106 Packet_Resp_NotAcceptable=0xC6
0107 Packet_Resp_ProxyAuthenticationRequired=0xC7
0108 Packet_Resp_RequestTimeOut=0xC8
0109 Packet_Resp_Conflict=0xC9
0110 Packet_Resp_Gone=0xCA
0111 Packet_Resp_LengthRequired=0xCB
0112 Packet_Resp_PreconditionFailed=0xCC
0113 Packet_Resp_RequestedEntityTooLarge=0xCD
0114 Packet_Resp_RequestURLTooLarge=0xCE
0115 Packet_Resp_UnsupportedMediaType=0xCF
0116 Packet_Resp_InternalServerError=0xD0
0117 Packet_Resp_NotImplemented=0xD1
0118 Packet_Resp_BadGateway=0xD2
0119 Packet_Resp_ServiceUnavailable=0xD3
0120 Packet_Resp_GatewayTimeout=0xD4
0121 Packet_Resp_HTTPVersionNotSupported=0xD5
0122 Packet_Resp_DatabaseFull=0xE0
0123 Packet_Resp_DatabaseLocked=0xE1
0124 # Packet code name
0125 Packet_Connect_Str='Connect'
0126 Packet_Disconnect_Str='Disconnect'
0127 Packet_Put_Str='Put'
0128 Packet_PutEnd_Str='PutEnd'
0129 Packet_Get_Str='Get'
0130 Packet_GetEnd_Str='GetEnd'
0131 Packet_SetPath_Str='SetPath'
0132 Packet_Abort_Str='Abort'
0133 Packet_Resp_Continue_Str='Continue'
0134 Packet_Resp_OK_Str='OK'
0135 Packet_Resp_Created_Str='Created'
0136 Packet_Resp_Accepted_Str='Accepted'
0137 Packet_Resp_NonAuthoritativeInfo_Str='NonAuthoritative Information'
0138 Packet_Resp_NoContent_Str='No Content'
0139 Packet_Resp_ResetContent_Str='Reset Content'
0140 Packet_Resp_PartialContent_Str='Partial Content'
0141 Packet_Resp_MultipleChoices_Str='Multiple Choices'
0142 Packet_Resp_MovedPermanently_Str='Moved Permanently'
0143 Packet_Resp_MovedTemporarily_Str='Moved Temporarily'
0144 Packet_Resp_SeeOther_Str='See Other'
0145 Packet_Resp_NotModified_Str='Not Modified'
0146 Packet_Resp_UseProxy_Str='Use Proxy'
0147 Packet_Resp_BadRequest_Str='Bad Request'
0148 Packet_Resp_Unauthorized_Str='Unauthorized'
0149 Packet_Resp_PaymentRequired_Str='Payment Required'
0150 Packet_Resp_Forbidden_Str='Forbidden'
0151 Packet_Resp_NotFound_Str='Not Found'
0152 Packet_Resp_MethodNotAllowed_Str='Method Not Allowed'
0153 Packet_Resp_NotAcceptable_Str='NotAcceptable'
0154 Packet_Resp_ProxyAuthenticationRequired_Str='Proxy Authentication Required'
0155 Packet_Resp_RequestTimeOut_Str='Request Time Out'
0156 Packet_Resp_Conflict_Str='Conflict'
0157 Packet_Resp_Gone_Str='Gone'
0158 Packet_Resp_LengthRequired_Str='Length Required'
0159 Packet_Resp_PreconditionFailed_Str='Precondition Failed'
0160 Packet_Resp_RequestedEntityTooLarge_Str='Requested Entity Too Large'
0161 Packet_Resp_RequestURLTooLarge_Str='Request URL Too Large'
0162 Packet_Resp_UnsupportedMediaType_Str='Unsupported Media Type'
0163 Packet_Resp_InternalServerError_Str='Internal Server Error'
0164 Packet_Resp_NotImplemented_Str='Not Implemented'
0165 Packet_Resp_BadGateway_Str='Bad Gateway'
0166 Packet_Resp_ServiceUnavailable_Str='Service Unavailable'
0167 Packet_Resp_GatewayTimeout_Str='Gateway Timeout'
0168 Packet_Resp_HTTPVersionNotSupported_Str='HTTP Version Not Supported'
0169 Packet_Resp_DatabaseFull_Str='Database Full'
0170 Packet_Resp_DatabaseLocked_Str='Database Locked'
0171 # Code-to-name dict
0172 Packet_Name_Dict={
0173     Packet_Connect: Packet_Connect_Str,
0174     Packet_Disconnect: Packet_Disconnect_Str,
0175     Packet_Put: Packet_Put_Str,
0176     Packet_PutEnd: Packet_PutEnd_Str,
0177     Packet_Get: Packet_Get_Str,
0178     Packet_GetEnd: Packet_GetEnd_Str,
0179     Packet_SetPath: Packet_SetPath_Str,
0180     Packet_Abort: Packet_Abort_Str,
0181     Packet_Resp_Continue: Packet_Resp_Continue_Str,
0182     Packet_Resp_OK: Packet_Resp_OK_Str,
0183     Packet_Resp_Created: Packet_Resp_Created_Str,
0184     Packet_Resp_Accepted: Packet_Resp_Accepted_Str,
0185     Packet_Resp_NonAuthoritativeInfo: Packet_Resp_NonAuthoritativeInfo_Str,
0186     Packet_Resp_NoContent: Packet_Resp_NoContent_Str,
0187     Packet_Resp_ResetContent: Packet_Resp_ResetContent_Str,
0188     Packet_Resp_PartialContent: Packet_Resp_PartialContent_Str,
0189     Packet_Resp_MultipleChoices: Packet_Resp_MultipleChoices_Str,
0190     Packet_Resp_MovedPermanently: Packet_Resp_MovedPermanently_Str,
0191     Packet_Resp_MovedTemporarily: Packet_Resp_MovedTemporarily_Str,
0192     Packet_Resp_SeeOther: Packet_Resp_SeeOther_Str,
0193     Packet_Resp_NotModified: Packet_Resp_NotModified_Str,
0194     Packet_Resp_UseProxy: Packet_Resp_UseProxy_Str,
0195     Packet_Resp_BadRequest: Packet_Resp_BadRequest_Str,
0196     Packet_Resp_Unauthorized: Packet_Resp_Unauthorized_Str,
0197     Packet_Resp_PaymentRequired: Packet_Resp_PaymentRequired_Str,
0198     Packet_Resp_Forbidden: Packet_Resp_Forbidden_Str,
0199     Packet_Resp_NotFound: Packet_Resp_NotFound_Str,
0200     Packet_Resp_MethodNotAllowed: Packet_Resp_MethodNotAllowed_Str,
0201     Packet_Resp_NotAcceptable: Packet_Resp_NotAcceptable_Str,
0202     Packet_Resp_ProxyAuthenticationRequired: Packet_Resp_ProxyAuthenticationRequired_Str,
0203     Packet_Resp_RequestTimeOut: Packet_Resp_RequestTimeOut_Str,
0204     Packet_Resp_Conflict: Packet_Resp_Conflict_Str,
0205     Packet_Resp_Gone: Packet_Resp_Gone_Str,
0206     Packet_Resp_LengthRequired: Packet_Resp_LengthRequired_Str,
0207     Packet_Resp_PreconditionFailed: Packet_Resp_PreconditionFailed_Str,
0208     Packet_Resp_RequestedEntityTooLarge: Packet_Resp_RequestedEntityTooLarge_Str,
0209     Packet_Resp_RequestURLTooLarge: Packet_Resp_RequestURLTooLarge_Str,
0210     Packet_Resp_UnsupportedMediaType: Packet_Resp_UnsupportedMediaType_Str,
0211     Packet_Resp_InternalServerError: Packet_Resp_InternalServerError_Str,
0212     Packet_Resp_NotImplemented: Packet_Resp_NotImplemented_Str,
0213     Packet_Resp_BadGateway: Packet_Resp_BadGateway_Str,
0214     Packet_Resp_ServiceUnavailable: Packet_Resp_ServiceUnavailable_Str,
0215     Packet_Resp_GatewayTimeout: Packet_Resp_GatewayTimeout_Str,
0216     Packet_Resp_HTTPVersionNotSupported: Packet_Resp_HTTPVersionNotSupported_Str,
0217     Packet_Resp_DatabaseFull: Packet_Resp_DatabaseFull_Str,
0218     Packet_Resp_DatabaseLocked: Packet_Resp_DatabaseLocked_Str,
0219     }
0220 Valid_Packet_Code=Packet_Name_Dict.keys()
0221 FolderBrowsingServiceID='\xF9\xEC\x7B\xC4\x95\x3C\x11\xD2\x98\x4E\x52\x54\x00\xDC\x9E\x09'
0222 FolderListingType='x-obex/folder-listing'
0223 
0224 # OBEX Exceptions
0225 class OBEXBadHeaderCode(Exception):
0226     def __init__(self, code):
0227         Exception.__init__(self, 'Bad Header Code: 0x%02X'%code)
0228         self.bad_code=code
0229 class OBEXBadPacketCode(Exception):
0230     def __init__(self, code):
0231         Exception.__init__(self, 'Bad Packet Code: 0x%02X'%code)
0232         self.bad_code=code
0233 class OBEXBadPacketLength(Exception):
0234     def __init__(self, expected_length, bad_length):
0235         Exception.__init__(self, 'Bad Packet Length: %d instead of %d'%(bad_length,
0236                                                                         expected_length))
0237         self.expected_length=expected_length
0238         self.bad_length=bad_length
0239 class OBEXBadResponse(Exception):
0240     def __init__(self, code):
0241         Exception.__init__(self, 'Bad response code: %d (%s)'%(code, Packet_Name_Dict.get(code, 'Unknown code')))
0242         self.bad_code=code
0243 class OBEXNoResponse(Exception):
0244     def __init__(self):
0245         Exception.__init__(self, 'No response received from device')
0246 
0247 
0248 # OBEX FolderListingObject
0249 class OBEXFolderListingObject(object):
0250     def __init__(self, data=None):
0251         if data:
0252             self.decode(data)
0253         else:
0254             self.data=None
0255 
0256     def _decode_date(self, dt_str):
0257         _date=bptime.BPTime(dt_str).mktime()
0258         return _date, time.strftime("%x %X", time.gmtime(_date))
0259 
0260     def decode(self, data):
0261         dom=xml.dom.minidom.parseString(data)
0262         _folder_listing=dom.getElementsByTagName('folder-listing')[0]
0263         self.data={}
0264         for _f in _folder_listing.getElementsByTagName('file'):
0265             _file_dict={ 'name': _f.getAttribute('name'),
0266                          'size': int(_f.getAttribute('size')),
0267                          'type': 'file',
0268                          'date':  self._decode_date(_f.getAttribute('modified')) }
0269             self.data[_file_dict['name']]=_file_dict
0270         for _f in _folder_listing.getElementsByTagName('folder'):
0271             _file_dict={ 'name': _f.getAttribute('name'),
0272                          'type': 'directory' }
0273             self.data[_file_dict['name']]=_file_dict
0274                          
0275 # OBEXHeader--------------------------------------------------------------------
0276 class OBEXHeader(object):
0277     """Handle an OBEX Header object"""
0278     def __init__(self, header_code, data=None):
0279         self.code=header_code
0280         if self.code is None and data:
0281             self.decode(data)
0282         else:
0283             self.data=data
0284 
0285     def len(self):
0286         """Return the length of this header"""
0287         return len(self.encode())
0288     def get_name(self):
0289         return Header_Name_Dict.get(self.code, 'Unknown Header Code')
0290     def get(self, string_key=False):
0291         if string_key:
0292             return { self.get_name(): self.data }
0293         return { self.code: self.data }
0294 
0295     # encoding routines---------------------------------------------------------
0296     def _encode_unicode(self):
0297         if self.data is not None:
0298             _s=(self.data+'\x00').encode('utf_16be')
0299             return struct.pack('B', self.code)+struct.pack('!H', len(_s)+3)+_s
0300         return struct.pack('B', self.code)+'\x00\x03'
0301 
0302     def _encode_bytes(self):
0303         if self.data:
0304             return struct.pack('B', self.code)+\
0305                    struct.pack('!H', len(self.data)+3)+\
0306                    self.data
0307         return struct.pack('B', self.code)+'\x00\x03'
0308 
0309     def _encode_1(self):
0310         return struct.pack('BB', self.code, self.data and self.data&0xff or 0)
0311 
0312     def _encode_4(self):
0313         return struct.pack('!BI', self.code, self.data or 0)
0314 
0315     encode_list=(_encode_unicode, _encode_bytes, _encode_1, _encode_4)
0316     def encode(self):
0317         """Return an encoded string of this header"""
0318         if self.code not in Valid_Header_Codes:
0319             raise OBEXBadHeaderCode(self.code)
0320         _encode_type=(self.code & 0xC0)>>6
0321         return self.encode_list[_encode_type](self)
0322 
0323     # decoding routines---------------------------------------------------------
0324     def _decode_unicode(self, data):
0325         _len=struct.unpack('!H', data[1:3])[0]
0326         self.data=data[3:_len].decode('utf_16be')[:-1]
0327     def _decode_bytes(self, data):
0328         _len=struct.unpack('!H', data[1:3])[0]
0329         self.data=data[3:_len]
0330     def _decode_1(self, data):
0331         self.data=struct.unpack('B', data[1])[0]
0332     def _decode_4(self, data):
0333         self.data=struct.unpack('!I', data[1:5])[0]
0334     decode_list=(_decode_unicode, _decode_bytes, _decode_1, _decode_4)
0335     def decode(self, data):
0336         global Valid_Header_Codes
0337         """decode the raw data received from a device"""
0338         self.code=struct.unpack('B', data[0])[0]
0339         if self.code not in Valid_Header_Codes:
0340             raise OBEXBadHeaderCode(self.code)
0341         _decode_type=(self.code&0xC0)>>6
0342         self.decode_list[_decode_type](self, data)
0343 
0344 # Packet Class------------------------------------------------------------------
0345 class OBEXPacket(object):
0346     def __init__(self, code, data=None):
0347         self.version_number=None
0348         self.flags=None
0349         self.max_packet_length=None
0350         self.constants=None
0351         self._headers=[]
0352         self.code=code
0353         if code is None and data:
0354             self.decode(data)
0355             
0356     def len(self):
0357         return len(self.encode())
0358     def get_name(self):
0359         return Packet_Name_Dict.get(self.code, 'Unknown Packet Code')
0360     def append(self, header_code, data=None):
0361         self._headers.append(OBEXHeader(header_code, data))
0362     def clear(self):
0363         self._headers=[]
0364     def get(self, string_key=False):
0365         _res={}
0366         for _h in self._headers:
0367             _res.update(_h.get(string_key))
0368         return _res
0369 
0370     # encoding stuff
0371     def encode(self):
0372         global Valid_Packet_Code
0373         if self.code not in Valid_Packet_Code:
0374             raise OBEXBadPacketCode(self.code)
0375         _packet_len=3   # code+len
0376         _packet_str=[struct.pack('B', self.code), '']
0377         if self.version_number is not None:
0378             _packet_len+=1
0379             _packet_str.append(struct.pack('B', self.version_number))
0380         if self.flags is not None:
0381             _packet_len+=1
0382             _packet_str.append(struct.pack('B', self.flags))
0383         if self.max_packet_length is not None:
0384             _packet_len+=2
0385             _packet_str.append(struct.pack('!H', self.max_packet_length))
0386         elif self.constants is not None:
0387             _packet_len+=1
0388             _packet_str.append(struct.pack('B', self.constants))
0389         for _h in self._headers:
0390             _s=_h.encode()
0391             _packet_len+=len(_s)
0392             _packet_str.append(_s)
0393         _packet_str[1]=struct.pack('!H', _packet_len)
0394         return ''.join(_packet_str)
0395 
0396     # decoding stuff
0397     def decode(self, data):
0398         global Valid_Packet_Code
0399         self.code=struct.unpack('B', data[0])[0]
0400         if self.code not in Valid_Packet_Code:
0401             raise OBEXBadPacketCode(self.code)
0402         _packet_len=struct.unpack('!H', data[1:3])[0]
0403         if _packet_len!=len(data):
0404             raise OBEXBadPacketLength(_packet_len, len(data))
0405         if self.code==Packet_Connect:
0406             self.version_number, self.flags, self.max_packet_length=struct.unpack('!BBH',
0407                                                                                   data[3:7])
0408             _idx=7
0409         elif self.code==Packet_SetPath:
0410             self.flags, self.constants=struct.unpack('BB', data[3:5])
0411             _idx=5
0412         else:
0413             _idx=3
0414         while _idx<_packet_len:
0415             _h=OBEXHeader(None, data[_idx:])
0416             _idx+=_h.len()
0417             self._headers.append(_h)
0418 
0419 class OBEXPacketConnectResp(OBEXPacket):
0420     # Special response packet to a Connect request
0421     # This one has a slightly different format than the standard response
0422     # Should ONLY be used for decoding incoming response to a Connect request
0423     def decode(self, data):
0424         global Valid_Packet_Code
0425         self.code=struct.unpack('B', data[0])[0]
0426         if self.code not in Valid_Packet_Code:
0427             raise OBEXBadPacketCode(self.code)
0428         _packet_len=struct.unpack('!H', data[1:3])[0]
0429         if _packet_len!=len(data):
0430             raise OBEXBadPacketLength(_packet_len, len(data))
0431         self.version_number, self.flags, self.max_packet_length=struct.unpack('!BBH',
0432                                                                               data[3:7])
0433         _idx=7
0434         while _idx<_packet_len:
0435             _h=OBEXHeader(None, data[_idx:])
0436             _idx+=_h.len()
0437             self._headers.append(_h)
0438 
0439 # Class FolderBrowsingService---------------------------------------------------
0440 class FolderBrowsingService(object):
0441     def __init__(self, logtarget, commport):
0442         self.log=self._log
0443         self.progress=self._progress
0444         if logtarget:
0445             if hasattr(logtarget, 'log'):
0446                 self.log=logtarget.log
0447             if hasattr(logtarget, 'progress'):
0448                 self.progress=logtarget.progress
0449         self.comm=commport
0450         self.connection_id=0
0451         self.max_packet_length=0x2000
0452         self.server_max_packet_length=255
0453         self.version_number=0x10
0454         self.data_block_length=0x07E0   # default length of a data block
0455 
0456     def _log(self, str):
0457         print str
0458     def _progress(self, pos, max, desc):
0459         print desc,pos,'out of',max
0460 
0461     def _send_packet(self, packet):
0462         global module_debug
0463         _s=packet.encode()
0464         if module_debug:
0465             self.log('Sending Packet: '+' '.join(['0x%02X'%ord(x) for x in _s]))
0466         self.comm.write(_s)
0467 
0468     def _get_response(self):
0469         global module_debug
0470         _code=self.comm.read(1)
0471         if not _code:
0472             raise OBEXNoResponse()
0473         _len_str=self.comm.read(2)
0474         _len=struct.unpack('!H', _len_str)[0]
0475         if _len>3:
0476             _data=self.comm.read(_len-3)
0477         else:
0478             _data=''
0479         _s=_code+_len_str+_data
0480         if module_debug:
0481             self.log('Receiving Packet: '+' '.join(['0x%02X'%ord(x) for x in _s]))
0482         return _s
0483 
0484     def _send_and_check_return(self, packet, expected_code=[Packet_Resp_OK]):
0485         self._send_packet(packet)
0486         _resp=OBEXPacket(None, self._get_response())
0487         if _resp.code not in expected_code:
0488             raise OBEXBadResponse(_resp.code)
0489         return _resp
0490 
0491     def _get_body(self, packet, totallen=None, filename=None):
0492         _resp=self._send_and_check_return(packet,
0493                                           [Packet_Resp_OK, Packet_Resp_Continue])
0494         _s=''
0495         _pkt=OBEXPacket(Packet_GetEnd)
0496         while _resp.code==Packet_Resp_Continue:
0497             _dict=_resp.get()
0498             if _dict.has_key(Header_Body):
0499                 if _dict[Header_Body]:
0500                     _s+=_dict[Header_Body]
0501             elif _dict.has_key(Header_BodyEnd):
0502                 if _dict[Header_BodyEnd]:
0503                     _s+=_dict[Header_BodyEnd]
0504             _resp=self._send_and_check_return(_pkt,
0505                                               [Packet_Resp_OK,
0506                                                Packet_Resp_Continue])
0507             if totallen and filename:
0508                 self.progress(len(_s), totallen, 'Reading file: '+filename)
0509         if _resp.code==Packet_Resp_OK:
0510             _dict=_resp.get()
0511             if _dict.get(Header_BodyEnd, None):
0512                 _s+=_dict[Header_BodyEnd]
0513         return _s
0514 
0515     def _send_body(self, packet, data, filename=None):
0516         _resp=self._send_and_check_return(packet, [Packet_Resp_Continue])
0517         _len_data=len(data)
0518         _pkt=OBEXPacket(Packet_Put)
0519         for _block in range(0, _len_data, self.data_block_length):
0520             _start_idx=_block
0521             _end_idx=min(_start_idx+self.data_block_length, _len_data)
0522             _pkt.clear()
0523             _pkt.append(Header_Body, data[_start_idx:_end_idx])
0524             self._send_and_check_return(_pkt, [Packet_Resp_Continue])
0525             if filename:
0526                 self.progress(_end_idx, _len_data, 'Writing file: '+filename)
0527         _pkt=OBEXPacket(Packet_PutEnd)
0528         _pkt.append(Header_BodyEnd)
0529         self._send_and_check_return(_pkt, [Packet_Resp_OK])
0530                                           
0531     def connect(self):
0532         # connect to a phone
0533         try:
0534             _pkt=OBEXPacket(Packet_Connect)
0535             _pkt.version_number=self.version_number
0536             _pkt.flags=0
0537             _pkt.max_packet_length=self.max_packet_length
0538             _pkt.append(Header_Target, FolderBrowsingServiceID)
0539             self._send_packet(_pkt)
0540             _s=self._get_response()
0541             _resp=OBEXPacketConnectResp(None, _s)
0542             if _resp.code!=Packet_Resp_OK:
0543                 return False
0544             self.server_max_packet_length=_resp.max_packet_length
0545             _pkt_dict=_resp.get()
0546             if _pkt_dict.has_key(Header_ConnectionID):
0547                 self.connection_id=_pkt_dict[Header_ConnectionID]
0548             return True
0549         except Exception, e:
0550             if __debug__:
0551                 raise
0552             self.log('Exception raise: '+str(e))
0553             return False
0554 
0555     def disconnect(self):
0556         try:
0557             _pkt=OBEXPacket(Packet_Disconnect)
0558             _pkt.append(Header_ConnectionID, self.connection_id)
0559             self._send_packet(_pkt)
0560             self._get_response()
0561         except Exception, e:
0562             if __debug__:
0563                 raise
0564             self.log('Exception raise: '+str(e))
0565 
0566     def _setpath(self, dirname=''):
0567         # go to the root first
0568         _pkt=OBEXPacket(Packet_SetPath)
0569         _pkt.flags=2
0570         _pkt.constants=0
0571         _pkt.append(Header_ConnectionID, self.connection_id)
0572         _pkt.append(Header_Name, dirname)
0573         self._send_and_check_return(_pkt)
0574 
0575     def _set_path_root(self):
0576         # go back to root
0577         # The V710 OBEX firmware SetPath to root has a bug
0578         # this is a work-around for it but also works with other device too.
0579         _pkt=OBEXPacket(Packet_SetPath)
0580         _pkt.flags=3    # go up one, don't create
0581         _pkt.constants=0
0582         _pkt.append(Header_ConnectionID, self.connection_id)
0583         _pkt.append(Header_Name)
0584         while True:
0585             # keep going one dir up until no further
0586             try:
0587                 self._send_and_check_return(_pkt)
0588             except OBEXBadResponse:
0589                 break
0590 
0591     def _list_current_folder(self):
0592         _pkt=OBEXPacket(Packet_GetEnd)
0593         _pkt.append(Header_ConnectionID, self.connection_id)
0594         _pkt.append(Header_Name, '')
0595         _pkt.append(Header_Type, FolderListingType+'\x00')
0596         return OBEXFolderListingObject(self._get_body(_pkt)).data
0597 
0598     def setpath(self, dir=''):
0599         self._set_path_root()
0600         for _path in dir.split('/'):
0601             if _path:
0602                 self._setpath(_path)
0603 
0604     def _update_filesystem_dict(self, fs_dict, dir):
0605         _res={}
0606         for _,_entry in fs_dict.items():
0607             if dir:
0608                 _name=dir+'/'+_entry['name']
0609             else:
0610                 _name=_entry['name']
0611             _res[_name]=_entry
0612             _res[_name]['name']=_name
0613         return _res
0614 
0615     def getfilesystem(self, dir='', recurse=0):
0616         self.log('Listing OBEX dir '+dir)
0617         try:
0618             self.setpath(dir)
0619             _res=self._update_filesystem_dict(self._list_current_folder(),
0620                                               dir)
0621             if recurse:
0622                 _subdir_list=[_key for _key,_entry in _res.items() \
0623                               if _entry.get('type', None)=='directory']
0624                 for _subdir in _subdir_list:
0625                     _res.update(self.getfilesystem(_subdir, recurse-1))
0626             return _res
0627         except Exception, e:
0628             if __debug__:
0629                 raise
0630             self.log('Exception raised: '+str(e))
0631             return {}
0632 
0633     def listfiles(self, dir=''):
0634         _res={}
0635         for _key,_entry in self.getfilesystem(dir).items():
0636             if _entry['type']=='file':
0637                 _res[_key]=_entry
0638         return _res
0639 
0640     def listsubdirs(self, dir='', recurse=0):
0641         _res={}
0642         for _key,_entry in self.getfilesystem(dir, recurse).items():
0643             if _entry['type']=='directory':
0644                 _res[_key]=_entry
0645         return _res
0646 
0647     def writefile(self, name, data):
0648         self.log('Writing OBEX file: '+name)
0649         _name_list=name.split('/')
0650         _dir_name='/'.join(_name_list[:-1])
0651         _file_name=_name_list[-1]
0652         self.setpath('/'.join(name.split('/')[:-1]))
0653         _pkt=OBEXPacket(Packet_Put)
0654         _pkt.append(Header_ConnectionID, self.connection_id)
0655         _pkt.append(Header_Length, len(data))
0656         _pkt.append(Header_Name, _file_name)
0657         self._send_body(_pkt, data, _file_name)
0658 
0659     def rmfile(self, name):
0660         self.log('Deleting OBEX file: '+name)
0661         _name_list=name.split('/')
0662         _dir_name='/'.join(_name_list[:-1])
0663         _file_name=_name_list[-1]
0664         self.setpath('/'.join(name.split('/')[:-1]))
0665         _pkt=OBEXPacket(Packet_PutEnd)
0666         _pkt.append(Header_ConnectionID, self.connection_id)
0667         _pkt.append(Header_Name, _file_name)
0668         self._send_and_check_return(_pkt)
0669 
0670     def getfilecontents(self, name, size=None):
0671         self.log('Reading OBEX file: '+name)
0672         _name_list=name.split('/')
0673         _dir_name='/'.join(_name_list[:-1])
0674         _file_name=_name_list[-1]
0675         if size:
0676             self.setpath('/'.join(name.split('/')[:-1]))
0677             _totallen=size
0678         else:
0679             _file_list=self.listfiles(_dir_name)
0680             _totallen=_file_list.get(name, {}).get('size', None)
0681         _pkt=OBEXPacket(Packet_GetEnd)
0682         _pkt.append(Header_ConnectionID, self.connection_id)
0683         _pkt.append(Header_Name, _file_name)
0684         return self._get_body(_pkt, _totallen, _file_name)
0685 

Generated by PyXR 0.9.4