1
2
3
4
5
6
7
8
9
10 """Provide support to OBEX protocol"""
11
12
13 import time
14 import struct
15 import xml.dom.minidom
16
17
18 import bptime
19
20 module_debug=False
21
22
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
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
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
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
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
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
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
246
247
248
255
259
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
277 """Handle an OBEX Header object"""
279 self.code=header_code
280 if self.code is None and data:
281 self.decode(data)
282 else:
283 self.data=data
284
286 """Return the length of this header"""
287 return len(self.encode())
291 if string_key:
292 return { self.get_name(): self.data }
293 return { self.code: self.data }
294
295
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
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
310 return struct.pack('BB', self.code, self.data and self.data&0xff or 0)
311
313 return struct.pack('!BI', self.code, self.data or 0)
314
315 encode_list=(_encode_unicode, _encode_bytes, _encode_1, _encode_4)
322
323
334 decode_list=(_decode_unicode, _decode_bytes, _decode_1, _decode_4)
343
344
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
360 - def append(self, header_code, data=None):
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
372 global Valid_Packet_Code
373 if self.code not in Valid_Packet_Code:
374 raise OBEXBadPacketCode(self.code)
375 _packet_len=3
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
418
438
439
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
455
456 - def _log(self, str):
459 print desc,pos,'out of',max
460
467
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
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
554
565
574
590
597
603
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
632
639
646
658
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