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