Module bp_obex
[hide private]
[frames] | no frames]

Source Code for Module bp_obex

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2006 Joe Pham <djpham@bitpim.org> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: bp_obex.py 3460 2006-07-08 23:55:09Z djpham $ 
  9   
 10  """Provide support to OBEX protocol""" 
 11   
 12  # System Modules 
 13  import time 
 14  import struct 
 15  import xml.dom.minidom 
 16   
 17  # BitPim modules 
 18  import bptime 
 19   
 20  module_debug=False 
 21   
 22  # Header Codes 
 23  Header_Count=0xC 
 24  Header_Name=0x01 
 25  Header_Type=0x42 
 26  Header_Length=0xC3 
 27  Header_Time=0x44 
 28  Header_Description=0x05 
 29  Header_Target=0x46 
 30  Header_HTTP=0x47 
 31  Header_Body=0x48 
 32  Header_BodyEnd=0x49 
 33  Header_Who=0x4A 
 34  Header_ConnectionID=0xCB 
 35  Header_AppParameters=0x4C 
 36  Header_AuthChallenge=0x4D 
 37  Header_AuthResponse=0x4E 
 38  Header_ObjectClass=0x4F 
 39  # Header String 
 40  Header_Count_Str='Count' 
 41  Header_Name_Str='Name' 
 42  Header_Type_Str='Type' 
 43  Header_Length_Str='Length' 
 44  Header_Time_Str='Time' 
 45  Header_Description_Str='Description' 
 46  Header_Target_Str='Target' 
 47  Header_HTTP_Str='HTTP' 
 48  Header_Body_Str='Body' 
 49  Header_BodyEnd_Str='BodyEnd' 
 50  Header_Who_Str='Who' 
 51  Header_ConnectionID_Str='ConnectionID' 
 52  Header_AppParameters_Str='AppParameters' 
 53  Header_AuthChallenge_Str='AuthChallenge' 
 54  Header_AuthResponse_Str='AuthResponse' 
 55  Header_ObjectClass_Str='ObjectClass' 
 56  # Code-to-name dict 
 57  Header_Name_Dict={ 
 58      Header_Count: Header_Count_Str, 
 59      Header_Name: Header_Name_Str, 
 60      Header_Type: Header_Type_Str, 
 61      Header_Length: Header_Length_Str, 
 62      Header_Time: Header_Time_Str, 
 63      Header_Description: Header_Description_Str, 
 64      Header_Target: Header_Target_Str, 
 65      Header_HTTP: Header_HTTP_Str, 
 66      Header_Body: Header_Body_Str, 
 67      Header_BodyEnd: Header_BodyEnd_Str, 
 68      Header_Who: Header_Who_Str, 
 69      Header_ConnectionID: Header_ConnectionID_Str, 
 70      Header_AppParameters: Header_AppParameters_Str, 
 71      Header_AuthChallenge: Header_AuthChallenge_Str, 
 72      Header_AuthResponse: Header_AuthResponse_Str, 
 73      Header_ObjectClass: Header_ObjectClass_Str, 
 74      } 
 75  Valid_Header_Codes=Header_Name_Dict.keys() 
 76   
 77  # Packet code constants 
 78  Packet_Connect=0x80 
 79  Packet_Disconnect=0x81 
 80  Packet_Put=0x02 
 81  Packet_PutEnd=0x82 
 82  Packet_Get=0x03 
 83  Packet_GetEnd=0x83 
 84  Packet_SetPath=0x85 
 85  Packet_Abort=0xFF 
 86  Packet_Resp_Continue=0x90 
 87  Packet_Resp_OK=0xA0 
 88  Packet_Resp_Created=0xA1 
 89  Packet_Resp_Accepted=0xA2 
 90  Packet_Resp_NonAuthoritativeInfo=0xA3 
 91  Packet_Resp_NoContent=0xA4 
 92  Packet_Resp_ResetContent=0xA5 
 93  Packet_Resp_PartialContent=0xA6 
 94  Packet_Resp_MultipleChoices=0xB0 
 95  Packet_Resp_MovedPermanently=0xB1 
 96  Packet_Resp_MovedTemporarily=0xB2 
 97  Packet_Resp_SeeOther=0xB3 
 98  Packet_Resp_NotModified=0xB4 
 99  Packet_Resp_UseProxy=0xB5 
100  Packet_Resp_BadRequest=0xC0 
101  Packet_Resp_Unauthorized=0xC1 
102  Packet_Resp_PaymentRequired=0xC2 
103  Packet_Resp_Forbidden=0xC3 
104  Packet_Resp_NotFound=0xC4 
105  Packet_Resp_MethodNotAllowed=0xC5 
106  Packet_Resp_NotAcceptable=0xC6 
107  Packet_Resp_ProxyAuthenticationRequired=0xC7 
108  Packet_Resp_RequestTimeOut=0xC8 
109  Packet_Resp_Conflict=0xC9 
110  Packet_Resp_Gone=0xCA 
111  Packet_Resp_LengthRequired=0xCB 
112  Packet_Resp_PreconditionFailed=0xCC 
113  Packet_Resp_RequestedEntityTooLarge=0xCD 
114  Packet_Resp_RequestURLTooLarge=0xCE 
115  Packet_Resp_UnsupportedMediaType=0xCF 
116  Packet_Resp_InternalServerError=0xD0 
117  Packet_Resp_NotImplemented=0xD1 
118  Packet_Resp_BadGateway=0xD2 
119  Packet_Resp_ServiceUnavailable=0xD3 
120  Packet_Resp_GatewayTimeout=0xD4 
121  Packet_Resp_HTTPVersionNotSupported=0xD5 
122  Packet_Resp_DatabaseFull=0xE0 
123  Packet_Resp_DatabaseLocked=0xE1 
124  # Packet code name 
125  Packet_Connect_Str='Connect' 
126  Packet_Disconnect_Str='Disconnect' 
127  Packet_Put_Str='Put' 
128  Packet_PutEnd_Str='PutEnd' 
129  Packet_Get_Str='Get' 
130  Packet_GetEnd_Str='GetEnd' 
131  Packet_SetPath_Str='SetPath' 
132  Packet_Abort_Str='Abort' 
133  Packet_Resp_Continue_Str='Continue' 
134  Packet_Resp_OK_Str='OK' 
135  Packet_Resp_Created_Str='Created' 
136  Packet_Resp_Accepted_Str='Accepted' 
137  Packet_Resp_NonAuthoritativeInfo_Str='NonAuthoritative Information' 
138  Packet_Resp_NoContent_Str='No Content' 
139  Packet_Resp_ResetContent_Str='Reset Content' 
140  Packet_Resp_PartialContent_Str='Partial Content' 
141  Packet_Resp_MultipleChoices_Str='Multiple Choices' 
142  Packet_Resp_MovedPermanently_Str='Moved Permanently' 
143  Packet_Resp_MovedTemporarily_Str='Moved Temporarily' 
144  Packet_Resp_SeeOther_Str='See Other' 
145  Packet_Resp_NotModified_Str='Not Modified' 
146  Packet_Resp_UseProxy_Str='Use Proxy' 
147  Packet_Resp_BadRequest_Str='Bad Request' 
148  Packet_Resp_Unauthorized_Str='Unauthorized' 
149  Packet_Resp_PaymentRequired_Str='Payment Required' 
150  Packet_Resp_Forbidden_Str='Forbidden' 
151  Packet_Resp_NotFound_Str='Not Found' 
152  Packet_Resp_MethodNotAllowed_Str='Method Not Allowed' 
153  Packet_Resp_NotAcceptable_Str='NotAcceptable' 
154  Packet_Resp_ProxyAuthenticationRequired_Str='Proxy Authentication Required' 
155  Packet_Resp_RequestTimeOut_Str='Request Time Out' 
156  Packet_Resp_Conflict_Str='Conflict' 
157  Packet_Resp_Gone_Str='Gone' 
158  Packet_Resp_LengthRequired_Str='Length Required' 
159  Packet_Resp_PreconditionFailed_Str='Precondition Failed' 
160  Packet_Resp_RequestedEntityTooLarge_Str='Requested Entity Too Large' 
161  Packet_Resp_RequestURLTooLarge_Str='Request URL Too Large' 
162  Packet_Resp_UnsupportedMediaType_Str='Unsupported Media Type' 
163  Packet_Resp_InternalServerError_Str='Internal Server Error' 
164  Packet_Resp_NotImplemented_Str='Not Implemented' 
165  Packet_Resp_BadGateway_Str='Bad Gateway' 
166  Packet_Resp_ServiceUnavailable_Str='Service Unavailable' 
167  Packet_Resp_GatewayTimeout_Str='Gateway Timeout' 
168  Packet_Resp_HTTPVersionNotSupported_Str='HTTP Version Not Supported' 
169  Packet_Resp_DatabaseFull_Str='Database Full' 
170  Packet_Resp_DatabaseLocked_Str='Database Locked' 
171  # Code-to-name dict 
172  Packet_Name_Dict={ 
173      Packet_Connect: Packet_Connect_Str, 
174      Packet_Disconnect: Packet_Disconnect_Str, 
175      Packet_Put: Packet_Put_Str, 
176      Packet_PutEnd: Packet_PutEnd_Str, 
177      Packet_Get: Packet_Get_Str, 
178      Packet_GetEnd: Packet_GetEnd_Str, 
179      Packet_SetPath: Packet_SetPath_Str, 
180      Packet_Abort: Packet_Abort_Str, 
181      Packet_Resp_Continue: Packet_Resp_Continue_Str, 
182      Packet_Resp_OK: Packet_Resp_OK_Str, 
183      Packet_Resp_Created: Packet_Resp_Created_Str, 
184      Packet_Resp_Accepted: Packet_Resp_Accepted_Str, 
185      Packet_Resp_NonAuthoritativeInfo: Packet_Resp_NonAuthoritativeInfo_Str, 
186      Packet_Resp_NoContent: Packet_Resp_NoContent_Str, 
187      Packet_Resp_ResetContent: Packet_Resp_ResetContent_Str, 
188      Packet_Resp_PartialContent: Packet_Resp_PartialContent_Str, 
189      Packet_Resp_MultipleChoices: Packet_Resp_MultipleChoices_Str, 
190      Packet_Resp_MovedPermanently: Packet_Resp_MovedPermanently_Str, 
191      Packet_Resp_MovedTemporarily: Packet_Resp_MovedTemporarily_Str, 
192      Packet_Resp_SeeOther: Packet_Resp_SeeOther_Str, 
193      Packet_Resp_NotModified: Packet_Resp_NotModified_Str, 
194      Packet_Resp_UseProxy: Packet_Resp_UseProxy_Str, 
195      Packet_Resp_BadRequest: Packet_Resp_BadRequest_Str, 
196      Packet_Resp_Unauthorized: Packet_Resp_Unauthorized_Str, 
197      Packet_Resp_PaymentRequired: Packet_Resp_PaymentRequired_Str, 
198      Packet_Resp_Forbidden: Packet_Resp_Forbidden_Str, 
199      Packet_Resp_NotFound: Packet_Resp_NotFound_Str, 
200      Packet_Resp_MethodNotAllowed: Packet_Resp_MethodNotAllowed_Str, 
201      Packet_Resp_NotAcceptable: Packet_Resp_NotAcceptable_Str, 
202      Packet_Resp_ProxyAuthenticationRequired: Packet_Resp_ProxyAuthenticationRequired_Str, 
203      Packet_Resp_RequestTimeOut: Packet_Resp_RequestTimeOut_Str, 
204      Packet_Resp_Conflict: Packet_Resp_Conflict_Str, 
205      Packet_Resp_Gone: Packet_Resp_Gone_Str, 
206      Packet_Resp_LengthRequired: Packet_Resp_LengthRequired_Str, 
207      Packet_Resp_PreconditionFailed: Packet_Resp_PreconditionFailed_Str, 
208      Packet_Resp_RequestedEntityTooLarge: Packet_Resp_RequestedEntityTooLarge_Str, 
209      Packet_Resp_RequestURLTooLarge: Packet_Resp_RequestURLTooLarge_Str, 
210      Packet_Resp_UnsupportedMediaType: Packet_Resp_UnsupportedMediaType_Str, 
211      Packet_Resp_InternalServerError: Packet_Resp_InternalServerError_Str, 
212      Packet_Resp_NotImplemented: Packet_Resp_NotImplemented_Str, 
213      Packet_Resp_BadGateway: Packet_Resp_BadGateway_Str, 
214      Packet_Resp_ServiceUnavailable: Packet_Resp_ServiceUnavailable_Str, 
215      Packet_Resp_GatewayTimeout: Packet_Resp_GatewayTimeout_Str, 
216      Packet_Resp_HTTPVersionNotSupported: Packet_Resp_HTTPVersionNotSupported_Str, 
217      Packet_Resp_DatabaseFull: Packet_Resp_DatabaseFull_Str, 
218      Packet_Resp_DatabaseLocked: Packet_Resp_DatabaseLocked_Str, 
219      } 
220  Valid_Packet_Code=Packet_Name_Dict.keys() 
221  FolderBrowsingServiceID='\xF9\xEC\x7B\xC4\x95\x3C\x11\xD2\x98\x4E\x52\x54\x00\xDC\x9E\x09' 
222  FolderListingType='x-obex/folder-listing' 
223   
224  # OBEX Exceptions 
225 -class OBEXBadHeaderCode(Exception):
226 - def __init__(self, code):
227 Exception.__init__(self, 'Bad Header Code: 0x%02X'%code) 228 self.bad_code=code
229 -class OBEXBadPacketCode(Exception):
230 - def __init__(self, code):
231 Exception.__init__(self, 'Bad Packet Code: 0x%02X'%code) 232 self.bad_code=code
233 -class OBEXBadPacketLength(Exception):
234 - def __init__(self, expected_length, bad_length):
235 Exception.__init__(self, 'Bad Packet Length: %d instead of %d'%(bad_length, 236 expected_length)) 237 self.expected_length=expected_length 238 self.bad_length=bad_length
239 -class OBEXBadResponse(Exception):
240 - def __init__(self, code):
241 Exception.__init__(self, 'Bad response code: %d (%s)'%(code, Packet_Name_Dict.get(code, 'Unknown code'))) 242 self.bad_code=code
243 -class OBEXNoResponse(Exception):
244 - def __init__(self):
245 Exception.__init__(self, 'No response received from device')
246 247 248 # OBEX FolderListingObject
249 -class OBEXFolderListingObject(object):
250 - def __init__(self, data=None):
251 if data: 252 self.decode(data) 253 else: 254 self.data=None
255
256 - def _decode_date(self, dt_str):
257 _date=bptime.BPTime(dt_str).mktime() 258 return _date, time.strftime("%x %X", time.gmtime(_date))
259
260 - def decode(self, data):
261 dom=xml.dom.minidom.parseString(data) 262 _folder_listing=dom.getElementsByTagName('folder-listing')[0] 263 self.data={} 264 for _f in _folder_listing.getElementsByTagName('file'): 265 _file_dict={ 'name': _f.getAttribute('name'), 266 'size': int(_f.getAttribute('size')), 267 'type': 'file', 268 'date': self._decode_date(_f.getAttribute('modified')) } 269 self.data[_file_dict['name']]=_file_dict 270 for _f in _folder_listing.getElementsByTagName('folder'): 271 _file_dict={ 'name': _f.getAttribute('name'), 272 'type': 'directory' } 273 self.data[_file_dict['name']]=_file_dict
274 275 # OBEXHeader--------------------------------------------------------------------
276 -class OBEXHeader(object):
277 """Handle an OBEX Header object"""
278 - def __init__(self, header_code, data=None):
279 self.code=header_code 280 if self.code is None and data: 281 self.decode(data) 282 else: 283 self.data=data
284
285 - def len(self):
286 """Return the length of this header""" 287 return len(self.encode())
288 - def get_name(self):
289 return Header_Name_Dict.get(self.code, 'Unknown Header Code')
290 - def get(self, string_key=False):
291 if string_key: 292 return { self.get_name(): self.data } 293 return { self.code: self.data }
294 295 # encoding routines---------------------------------------------------------
296 - def _encode_unicode(self):
297 if self.data is not None: 298 _s=(self.data+'\x00').encode('utf_16be') 299 return struct.pack('B', self.code)+struct.pack('!H', len(_s)+3)+_s 300 return struct.pack('B', self.code)+'\x00\x03'
301
302 - def _encode_bytes(self):
303 if self.data: 304 return struct.pack('B', self.code)+\ 305 struct.pack('!H', len(self.data)+3)+\ 306 self.data 307 return struct.pack('B', self.code)+'\x00\x03'
308
309 - def _encode_1(self):
310 return struct.pack('BB', self.code, self.data and self.data&0xff or 0)
311
312 - def _encode_4(self):
313 return struct.pack('!BI', self.code, self.data or 0)
314 315 encode_list=(_encode_unicode, _encode_bytes, _encode_1, _encode_4)
316 - def encode(self):
317 """Return an encoded string of this header""" 318 if self.code not in Valid_Header_Codes: 319 raise OBEXBadHeaderCode(self.code) 320 _encode_type=(self.code & 0xC0)>>6 321 return self.encode_list[_encode_type](self)
322 323 # decoding routines---------------------------------------------------------
324 - def _decode_unicode(self, data):
325 _len=struct.unpack('!H', data[1:3])[0] 326 self.data=data[3:_len].decode('utf_16be')[:-1]
327 - def _decode_bytes(self, data):
328 _len=struct.unpack('!H', data[1:3])[0] 329 self.data=data[3:_len]
330 - def _decode_1(self, data):
331 self.data=struct.unpack('B', data[1])[0]
332 - def _decode_4(self, data):
333 self.data=struct.unpack('!I', data[1:5])[0]
334 decode_list=(_decode_unicode, _decode_bytes, _decode_1, _decode_4)
335 - def decode(self, data):
336 global Valid_Header_Codes 337 """decode the raw data received from a device""" 338 self.code=struct.unpack('B', data[0])[0] 339 if self.code not in Valid_Header_Codes: 340 raise OBEXBadHeaderCode(self.code) 341 _decode_type=(self.code&0xC0)>>6 342 self.decode_list[_decode_type](self, data)
343 344 # Packet Class------------------------------------------------------------------
345 -class OBEXPacket(object):
346 - def __init__(self, code, data=None):
347 self.version_number=None 348 self.flags=None 349 self.max_packet_length=None 350 self.constants=None 351 self._headers=[] 352 self.code=code 353 if code is None and data: 354 self.decode(data)
355
356 - def len(self):
357 return len(self.encode())
358 - def get_name(self):
359 return Packet_Name_Dict.get(self.code, 'Unknown Packet Code')
360 - def append(self, header_code, data=None):
361 self._headers.append(OBEXHeader(header_code, data))
362 - def clear(self):
363 self._headers=[]
364 - def get(self, string_key=False):
365 _res={} 366 for _h in self._headers: 367 _res.update(_h.get(string_key)) 368 return _res
369 370 # encoding stuff
371 - def encode(self):
372 global Valid_Packet_Code 373 if self.code not in Valid_Packet_Code: 374 raise OBEXBadPacketCode(self.code) 375 _packet_len=3 # code+len 376 _packet_str=[struct.pack('B', self.code), ''] 377 if self.version_number is not None: 378 _packet_len+=1 379 _packet_str.append(struct.pack('B', self.version_number)) 380 if self.flags is not None: 381 _packet_len+=1 382 _packet_str.append(struct.pack('B', self.flags)) 383 if self.max_packet_length is not None: 384 _packet_len+=2 385 _packet_str.append(struct.pack('!H', self.max_packet_length)) 386 elif self.constants is not None: 387 _packet_len+=1 388 _packet_str.append(struct.pack('B', self.constants)) 389 for _h in self._headers: 390 _s=_h.encode() 391 _packet_len+=len(_s) 392 _packet_str.append(_s) 393 _packet_str[1]=struct.pack('!H', _packet_len) 394 return ''.join(_packet_str)
395 396 # decoding stuff
397 - def decode(self, data):
398 global Valid_Packet_Code 399 self.code=struct.unpack('B', data[0])[0] 400 if self.code not in Valid_Packet_Code: 401 raise OBEXBadPacketCode(self.code) 402 _packet_len=struct.unpack('!H', data[1:3])[0] 403 if _packet_len!=len(data): 404 raise OBEXBadPacketLength(_packet_len, len(data)) 405 if self.code==Packet_Connect: 406 self.version_number, self.flags, self.max_packet_length=struct.unpack('!BBH', 407 data[3:7]) 408 _idx=7 409 elif self.code==Packet_SetPath: 410 self.flags, self.constants=struct.unpack('BB', data[3:5]) 411 _idx=5 412 else: 413 _idx=3 414 while _idx<_packet_len: 415 _h=OBEXHeader(None, data[_idx:]) 416 _idx+=_h.len() 417 self._headers.append(_h)
418
419 -class OBEXPacketConnectResp(OBEXPacket):
420 # Special response packet to a Connect request 421 # This one has a slightly different format than the standard response 422 # Should ONLY be used for decoding incoming response to a Connect request
423 - def decode(self, data):
424 global Valid_Packet_Code 425 self.code=struct.unpack('B', data[0])[0] 426 if self.code not in Valid_Packet_Code: 427 raise OBEXBadPacketCode(self.code) 428 _packet_len=struct.unpack('!H', data[1:3])[0] 429 if _packet_len!=len(data): 430 raise OBEXBadPacketLength(_packet_len, len(data)) 431 self.version_number, self.flags, self.max_packet_length=struct.unpack('!BBH', 432 data[3:7]) 433 _idx=7 434 while _idx<_packet_len: 435 _h=OBEXHeader(None, data[_idx:]) 436 _idx+=_h.len() 437 self._headers.append(_h)
438 439 # Class FolderBrowsingService---------------------------------------------------
440 -class FolderBrowsingService(object):
441 - def __init__(self, logtarget, commport):
442 self.log=self._log 443 self.progress=self._progress 444 if logtarget: 445 if hasattr(logtarget, 'log'): 446 self.log=logtarget.log 447 if hasattr(logtarget, 'progress'): 448 self.progress=logtarget.progress 449 self.comm=commport 450 self.connection_id=0 451 self.max_packet_length=0x2000 452 self.server_max_packet_length=255 453 self.version_number=0x10 454 self.data_block_length=0x07E0 # default length of a data block
455
456 - def _log(self, str):
457 print str
458 - def _progress(self, pos, max, desc):
459 print desc,pos,'out of',max
460
461 - def _send_packet(self, packet):
462 global module_debug 463 _s=packet.encode() 464 if module_debug: 465 self.log('Sending Packet: '+' '.join(['0x%02X'%ord(x) for x in _s])) 466 self.comm.write(_s)
467
468 - def _get_response(self):
469 global module_debug 470 _code=self.comm.read(1) 471 if not _code: 472 raise OBEXNoResponse() 473 _len_str=self.comm.read(2) 474 _len=struct.unpack('!H', _len_str)[0] 475 if _len>3: 476 _data=self.comm.read(_len-3) 477 else: 478 _data='' 479 _s=_code+_len_str+_data 480 if module_debug: 481 self.log('Receiving Packet: '+' '.join(['0x%02X'%ord(x) for x in _s])) 482 return _s
483
484 - def _send_and_check_return(self, packet, expected_code=[Packet_Resp_OK]):
485 self._send_packet(packet) 486 _resp=OBEXPacket(None, self._get_response()) 487 if _resp.code not in expected_code: 488 raise OBEXBadResponse(_resp.code) 489 return _resp
490
491 - def _get_body(self, packet, totallen=None, filename=None):
492 _resp=self._send_and_check_return(packet, 493 [Packet_Resp_OK, Packet_Resp_Continue]) 494 _s='' 495 _pkt=OBEXPacket(Packet_GetEnd) 496 while _resp.code==Packet_Resp_Continue: 497 _dict=_resp.get() 498 if _dict.has_key(Header_Body): 499 if _dict[Header_Body]: 500 _s+=_dict[Header_Body] 501 elif _dict.has_key(Header_BodyEnd): 502 if _dict[Header_BodyEnd]: 503 _s+=_dict[Header_BodyEnd] 504 _resp=self._send_and_check_return(_pkt, 505 [Packet_Resp_OK, 506 Packet_Resp_Continue]) 507 if totallen and filename: 508 self.progress(len(_s), totallen, 'Reading file: '+filename) 509 if _resp.code==Packet_Resp_OK: 510 _dict=_resp.get() 511 if _dict.get(Header_BodyEnd, None): 512 _s+=_dict[Header_BodyEnd] 513 return _s
514
515 - def _send_body(self, packet, data, filename=None):
516 _resp=self._send_and_check_return(packet, [Packet_Resp_Continue]) 517 _len_data=len(data) 518 _pkt=OBEXPacket(Packet_Put) 519 for _block in range(0, _len_data, self.data_block_length): 520 _start_idx=_block 521 _end_idx=min(_start_idx+self.data_block_length, _len_data) 522 _pkt.clear() 523 _pkt.append(Header_Body, data[_start_idx:_end_idx]) 524 self._send_and_check_return(_pkt, [Packet_Resp_Continue]) 525 if filename: 526 self.progress(_end_idx, _len_data, 'Writing file: '+filename) 527 _pkt=OBEXPacket(Packet_PutEnd) 528 _pkt.append(Header_BodyEnd) 529 self._send_and_check_return(_pkt, [Packet_Resp_OK])
530
531 - def connect(self):
532 # connect to a phone 533 try: 534 _pkt=OBEXPacket(Packet_Connect) 535 _pkt.version_number=self.version_number 536 _pkt.flags=0 537 _pkt.max_packet_length=self.max_packet_length 538 _pkt.append(Header_Target, FolderBrowsingServiceID) 539 self._send_packet(_pkt) 540 _s=self._get_response() 541 _resp=OBEXPacketConnectResp(None, _s) 542 if _resp.code!=Packet_Resp_OK: 543 return False 544 self.server_max_packet_length=_resp.max_packet_length 545 _pkt_dict=_resp.get() 546 if _pkt_dict.has_key(Header_ConnectionID): 547 self.connection_id=_pkt_dict[Header_ConnectionID] 548 return True 549 except Exception, e: 550 if __debug__: 551 raise 552 self.log('Exception raise: '+str(e)) 553 return False
554
555 - def disconnect(self):
556 try: 557 _pkt=OBEXPacket(Packet_Disconnect) 558 _pkt.append(Header_ConnectionID, self.connection_id) 559 self._send_packet(_pkt) 560 self._get_response() 561 except Exception, e: 562 if __debug__: 563 raise 564 self.log('Exception raise: '+str(e))
565
566 - def _setpath(self, dirname=''):
567 # go to the root first 568 _pkt=OBEXPacket(Packet_SetPath) 569 _pkt.flags=2 570 _pkt.constants=0 571 _pkt.append(Header_ConnectionID, self.connection_id) 572 _pkt.append(Header_Name, dirname) 573 self._send_and_check_return(_pkt)
574
575 - def _set_path_root(self):
576 # go back to root 577 # The V710 OBEX firmware SetPath to root has a bug 578 # this is a work-around for it but also works with other device too. 579 _pkt=OBEXPacket(Packet_SetPath) 580 _pkt.flags=3 # go up one, don't create 581 _pkt.constants=0 582 _pkt.append(Header_ConnectionID, self.connection_id) 583 _pkt.append(Header_Name) 584 while True: 585 # keep going one dir up until no further 586 try: 587 self._send_and_check_return(_pkt) 588 except OBEXBadResponse: 589 break
590
591 - def _list_current_folder(self):
592 _pkt=OBEXPacket(Packet_GetEnd) 593 _pkt.append(Header_ConnectionID, self.connection_id) 594 _pkt.append(Header_Name, '') 595 _pkt.append(Header_Type, FolderListingType+'\x00') 596 return OBEXFolderListingObject(self._get_body(_pkt)).data
597
598 - def setpath(self, dir=''):
599 self._set_path_root() 600 for _path in dir.split('/'): 601 if _path: 602 self._setpath(_path)
603
604 - def _update_filesystem_dict(self, fs_dict, dir):
605 _res={} 606 for _,_entry in fs_dict.items(): 607 if dir: 608 _name=dir+'/'+_entry['name'] 609 else: 610 _name=_entry['name'] 611 _res[_name]=_entry 612 _res[_name]['name']=_name 613 return _res
614
615 - def getfilesystem(self, dir='', recurse=0):
616 self.log('Listing OBEX dir '+dir) 617 try: 618 self.setpath(dir) 619 _res=self._update_filesystem_dict(self._list_current_folder(), 620 dir) 621 if recurse: 622 _subdir_list=[_key for _key,_entry in _res.items() \ 623 if _entry.get('type', None)=='directory'] 624 for _subdir in _subdir_list: 625 _res.update(self.getfilesystem(_subdir, recurse-1)) 626 return _res 627 except Exception, e: 628 if __debug__: 629 raise 630 self.log('Exception raised: '+str(e)) 631 return {}
632
633 - def listfiles(self, dir=''):
634 _res={} 635 for _key,_entry in self.getfilesystem(dir).items(): 636 if _entry['type']=='file': 637 _res[_key]=_entry 638 return _res
639
640 - def listsubdirs(self, dir='', recurse=0):
641 _res={} 642 for _key,_entry in self.getfilesystem(dir, recurse).items(): 643 if _entry['type']=='directory': 644 _res[_key]=_entry 645 return _res
646
647 - def writefile(self, name, data):
648 self.log('Writing OBEX file: '+name) 649 _name_list=name.split('/') 650 _dir_name='/'.join(_name_list[:-1]) 651 _file_name=_name_list[-1] 652 self.setpath('/'.join(name.split('/')[:-1])) 653 _pkt=OBEXPacket(Packet_Put) 654 _pkt.append(Header_ConnectionID, self.connection_id) 655 _pkt.append(Header_Length, len(data)) 656 _pkt.append(Header_Name, _file_name) 657 self._send_body(_pkt, data, _file_name)
658
659 - def rmfile(self, name):
660 self.log('Deleting OBEX file: '+name) 661 _name_list=name.split('/') 662 _dir_name='/'.join(_name_list[:-1]) 663 _file_name=_name_list[-1] 664 self.setpath('/'.join(name.split('/')[:-1])) 665 _pkt=OBEXPacket(Packet_PutEnd) 666 _pkt.append(Header_ConnectionID, self.connection_id) 667 _pkt.append(Header_Name, _file_name) 668 self._send_and_check_return(_pkt)
669
670 - def getfilecontents(self, name, size=None):
671 self.log('Reading OBEX file: '+name) 672 _name_list=name.split('/') 673 _dir_name='/'.join(_name_list[:-1]) 674 _file_name=_name_list[-1] 675 if size: 676 self.setpath('/'.join(name.split('/')[:-1])) 677 _totallen=size 678 else: 679 _file_list=self.listfiles(_dir_name) 680 _totallen=_file_list.get(name, {}).get('size', None) 681 _pkt=OBEXPacket(Packet_GetEnd) 682 _pkt.append(Header_ConnectionID, self.connection_id) 683 _pkt.append(Header_Name, _file_name) 684 return self._get_body(_pkt, _totallen, _file_name)
685