• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1""" Copyright (C) 2010-2011 ST-Ericsson SA """
2
3""" Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson. """
4
5""" This program is free software; you can redistribute it and/or modify """
6""" it under the terms of the GNU General Public License as published by """
7""" the Free Software Foundation; either version 2 of the License, or """
8""" (at your option) any later version. """
9
10""" This program is distributed in the hope that it will be useful, """
11""" but WITHOUT ANY WARRANTY; without even the implied warranty of """
12""" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the """
13""" GNU General Public License for more details. """
14
15""" You should have received a copy of the GNU General Public License """
16""" along with this program; if not, write to the Free Software """
17""" Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """
18
19from array import array
20from bluetooth import *
21import time
22import re
23
24class SAPParam:
25    """ SAP Parameter Class """
26
27    MaxMsgSize = 0x00
28    ConnectionStatus = 0x01
29    ResultCode = 0x02
30    DisconnectionType = 0x03
31    CommandAPDU = 0x04
32    ResponseAPDU = 0x05
33    ATR = 0x06
34    CardReaderStatus = 0x07
35    StatusChange = 0x08
36    TransportProtocol = 0x09
37    CommandAPDU7816 = 0x10
38
39    def __init__(self, name, id, value = None):
40        self.name = name
41        self.id = id
42        self.value = value
43
44    def _padding(self,  buf):
45        pad = array('B')
46        while ( (len(buf) + len(pad)) % 4 ) != 0:
47            pad.append(0)
48        return pad
49
50    def _basicCheck(self,  buf):
51        if len(buf) < 4 or (len(buf) % 4) != 0 or buf[1] != 0:
52                return (-1,  -1)
53        if buf[0] != self.id:
54            return (-1,  -1)
55        plen = buf[2] * 256 + buf[3] + 4
56        if plen > len(buf):
57            return (-1,  -1)
58        pad = plen
59        while (pad % 4) != 0:
60            if buf[pad] != 0:
61                return (-1,  -1)
62            pad+=1
63        return (plen,  pad)
64
65    def getID(self):
66        return self.id
67
68    def getValue(self):
69        return self.value
70
71    def getContent(self):
72        return "%s(id=0x%.2X), value=%s \n" %  (self.name,  self.id, self.value)
73
74    def serialize(self):
75        a = array('B', '\00\00\00\00')
76        a[0] = self.id
77        a[1] = 0	# reserved
78        a[2] = 0	# length
79        a[3] = 1	# length
80        a.append(self.value)
81        a.extend(self._padding(a))
82        return a
83
84    def deserialize(self,  buf):
85        p = self._basicCheck(buf)
86        if p[0] == -1:
87            return -1
88        self.id = buf[0]
89        self.value = buf[4]
90        return p[1]
91
92
93class SAPParam_MaxMsgSize(SAPParam):
94    """MaxMsgSize Param """
95
96    def __init__(self,  value = None):
97        SAPParam.__init__(self,"MaxMsgSize",  SAPParam.MaxMsgSize, value)
98        self.__validate()
99
100    def __validate(self):
101        if self.value > 0xFFFF:
102             self.value = 0xFFFF
103
104    def serialize(self):
105        a = array('B', '\00\00\00\00')
106        a[0] = self.id
107        a[3] = 2
108        a.append(self.value / 256)
109        a.append(self.value % 256)
110        a.extend(self._padding(a))
111        return a
112
113    def deserialize(self,  buf):
114        p = self._basicCheck(buf)
115        if p[0] == -1 :
116            return -1
117        self.value = buf[4] * 256 + buf[5]
118        return p[1]
119
120class SAPParam_CommandAPDU(SAPParam):
121    def __init__(self,  value = None):
122        if value is None:
123            SAPParam.__init__(self, "CommandAPDU",  SAPParam.CommandAPDU, array('B'))
124        else:
125            SAPParam.__init__(self, "CommandAPDU",  SAPParam.CommandAPDU, array('B', value))
126
127    def serialize(self):
128        a = array('B', '\00\00\00\00')
129        a[0] = self.id
130        plen = len(self.value)
131        a[2] = plen / 256
132        a[3] = plen % 256
133        a.extend(self.value)
134        a.extend(self._padding(a))
135        return a
136
137    def deserialize(self,  buf):
138        p = self._basicCheck(buf)
139        if p[0] == -1:
140            return -1
141        self.value = buf[4:p[0]]
142        return p[1]
143
144class SAPParam_ResponseAPDU(SAPParam_CommandAPDU):
145    """ResponseAPDU Param """
146
147    def __init__(self,  value = None):
148        if value is None:
149            SAPParam.__init__(self, "ResponseAPDU",  SAPParam.ResponseAPDU, array('B'))
150        else:
151            SAPParam.__init__(self, "ResponseAPDU",  SAPParam.ResponseAPDU, array('B', value))
152
153class SAPParam_ATR(SAPParam_CommandAPDU):
154    """ATR Param """
155
156    def __init__(self,  value = None):
157        if value is None:
158            SAPParam.__init__(self, "ATR",  SAPParam.ATR, array('B'))
159        else:
160            SAPParam.__init__(self, "ATR",  SAPParam.ATR, array('B', value))
161
162class SAPParam_CommandAPDU7816(SAPParam_CommandAPDU):
163    """Command APDU7816 Param."""
164
165    def __init__(self,  value = None):
166        if value is None:
167            SAPParam.__init__(self, "CommandAPDU7816",  SAPParam.CommandAPDU7816, array('B'))
168        else:
169            SAPParam.__init__(self, "CommandAPDU7816",  SAPParam.CommandAPDU7816, array('B', value))
170
171
172class SAPParam_ConnectionStatus(SAPParam):
173    """Connection status Param."""
174
175    def __init__(self,  value = None):
176        SAPParam.__init__(self,"ConnectionStatus",  SAPParam.ConnectionStatus, value)
177        self.__validate()
178
179    def __validate(self):
180        if self.value is not None and self.value not in (0x00,  0x01,  0x02,  0x03,  0x04):
181            print "Warning. ConnectionStatus value in reserved range (0x%x)" % self.value
182
183    def deserialize(self,  buf):
184        ret = SAPParam.deserialize(self, buf)
185        if ret == -1:
186            return -1
187        self.__validate()
188        return ret
189
190class SAPParam_ResultCode(SAPParam):
191    """ Result Code Param """
192
193    def __init__(self,  value = None):
194        SAPParam.__init__(self,"ResultCode",  SAPParam.ResultCode, value)
195        self.__validate()
196
197    def __validate(self):
198        if self.value is not None and self.value not in (0x00,  0x01,  0x02,  0x03,  0x04,  0x05,  0x06,  0x07):
199            print "Warning. ResultCode value in reserved range (0x%x)" % self.value
200
201    def deserialize(self,  buf):
202        ret = SAPParam.deserialize(self, buf)
203        if ret == -1:
204            return -1
205        self.__validate()
206        return ret
207
208class SAPParam_DisconnectionType(SAPParam):
209    """Disconnection Type Param."""
210
211    def __init__(self,  value = None):
212        SAPParam.__init__(self,"DisconnectionType",  SAPParam.DisconnectionType, value)
213        self.__validate()
214
215    def __validate(self):
216        if self.value is not None and self.value not in (0x00,  0x01):
217            print "Warning. DisconnectionType value in reserved range (0x%x)" % self.value
218
219    def deserialize(self,  buf):
220        ret = SAPParam.deserialize(self, buf)
221        if ret == -1:
222            return -1
223        self.__validate()
224        return ret
225
226class SAPParam_CardReaderStatus(SAPParam_CommandAPDU):
227    """Card reader Status Param."""
228
229    def __init__(self,  value = None):
230        if value is None:
231            SAPParam.__init__(self, "CardReaderStatus",  SAPParam.CardReaderStatus, array('B'))
232        else:
233            SAPParam.__init__(self, "CardReaderStatus",  SAPParam.CardReaderStatus, array('B', value))
234
235class SAPParam_StatusChange(SAPParam):
236    """Status Change Param """
237
238    def __init__(self,  value = None):
239        SAPParam.__init__(self,"StatusChange",  SAPParam.StatusChange, value)
240
241    def __validate(self):
242        if self.value is not None and self.value not in (0x00,  0x01,  0x02,  0x03,  0x04,  0x05):
243            print "Warning. StatusChange value in reserved range (0x%x)" % self.value
244
245    def deserialize(self,  buf):
246        ret = SAPParam.deserialize(self, buf)
247        if ret == -1:
248            return -1
249        self.__validate()
250        return ret
251
252class SAPParam_TransportProtocol(SAPParam):
253    """Transport Protocol Param """
254
255    def __init__(self,  value = None):
256        SAPParam.__init__(self,"TransportProtocol",  SAPParam.TransportProtocol, value)
257        self.__validate()
258
259    def __validate(self):
260        if self.value is not None and self.value not in (0x00,  0x01):
261            print "Warning. TransportProtoco value in reserved range (0x%x)" % self.value
262
263    def deserialize(self,  buf):
264        ret = SAPParam.deserialize(self, buf)
265        if ret == -1:
266            return -1
267        self.__validate()
268        return ret
269
270class SAPMessage:
271
272    CONNECT_REQ = 0x00
273    CONNECT_RESP = 0x01
274    DISCONNECT_REQ = 0x02
275    DISCONNECT_RESP =0x03
276    DISCONNECT_IND = 0x04
277    TRANSFER_APDU_REQ = 0x05
278    TRANSFER_APDU_RESP = 0x06
279    TRANSFER_ATR_REQ = 0x07
280    TRANSFER_ATR_RESP = 0x08
281    POWER_SIM_OFF_REQ = 0x09
282    POWER_SIM_OFF_RESP = 0x0A
283    POWER_SIM_ON_REQ = 0x0B
284    POWER_SIM_ON_RESP = 0x0C
285    RESET_SIM_REQ = 0x0D
286    RESET_SIM_RESP = 0x0E
287    TRANSFER_CARD_READER_STATUS_REQ = 0x0F
288    TRANSFER_CARD_READER_STATUS_RESP = 0x10
289    STATUS_IND = 0x11
290    ERROR_RESP = 0x12
291    SET_TRANSPORT_PROTOCOL_REQ = 0x13
292    SET_TRANSPORT_PROTOCOL_RESP = 0x14
293
294    def __init__(self,  name,  id):
295        self.name = name
296        self.id = id
297        self.params = []
298        self.buf = array('B')
299
300    def _basicCheck(self,  buf):
301        if len(buf) < 4 or (len(buf) % 4) != 0 :
302            return False
303
304        if buf[0] != self.id:
305            return False
306
307        return True
308
309    def getID(self):
310        return self.id
311
312    def getContent(self):
313        s = "%s(id=0x%.2X) " % (self.name,  self.id)
314        if len( self.buf): s = s + "[%s]" % re.sub("(.{2})", "0x\\1 " , self.buf.tostring().encode("hex").upper(), re.DOTALL)
315        s = s + "\n\t"
316        for p in self.params:
317            s = s + "\t" + p.getContent()
318        return s
319
320    def getParams(self):
321        return self.params
322
323    def addParam(self,  param):
324        self.params.append(param)
325
326    def serialize(self):
327        ret = array('B', '\00\00\00\00')
328        ret[0] = self.id
329        ret[1] = len(self.params)
330        ret[2] = 0	# reserved
331        ret[3] = 0	# reserved
332        for p in self.params:
333            ret.extend(p.serialize())
334
335        self.buf = ret
336        return ret
337
338    def deserialize(self,  buf):
339        self.buf = buf
340        return len(buf) == 4 and buf[1] == 0 and self._basicCheck(buf)
341
342
343class SAPMessage_CONNECT_REQ(SAPMessage):
344    def __init__(self,  MaxMsgSize = None):
345        SAPMessage.__init__(self,"CONNECT_REQ",  SAPMessage.CONNECT_REQ)
346        if MaxMsgSize is not None:
347            self.addParam(SAPParam_MaxMsgSize(MaxMsgSize))
348
349    def _validate(self):
350        if len(self.params) == 1:
351            if self.params[0].getID() == SAPParam.MaxMsgSize:
352                return True
353        return False
354
355    def deserialize(self,  buf):
356        self.buf = buf
357        self.params[:] = []
358        if SAPMessage._basicCheck(self,  buf):
359            p = SAPParam_MaxMsgSize()
360            if p.deserialize(buf[4:]) == len(buf[4:]):
361                self.addParam(p)
362                return self._validate()
363
364        return False
365
366class SAPMessage_CONNECT_RESP(SAPMessage):
367    def __init__(self,  ConnectionStatus = None,  MaxMsgSize = None):
368        SAPMessage.__init__(self,"CONNECT_RESP",  SAPMessage.CONNECT_RESP)
369        if ConnectionStatus is not None:
370            self.addParam(SAPParam_ConnectionStatus(ConnectionStatus))
371            if MaxMsgSize is not None:
372                self.addParam(SAPParam_MaxMsgSize(MaxMsgSize))
373
374    def _validate(self):
375        if len(self.params) > 0:
376            if self.params[0] .getID() == SAPParam.ConnectionStatus:
377                if self.params[0].getValue() ==  0x02:
378                    if len(self.params) == 2:
379                        return True
380                else:
381                    if len(self.params) == 1:
382                        return True
383        return False
384
385    def deserialize(self,  buf):
386        self.buf = buf
387        self.params[:] = []
388
389        if SAPMessage._basicCheck(self,  buf):
390            p = SAPParam_ConnectionStatus()
391            r = p.deserialize(buf[4:])
392            if  r != -1:
393                self.addParam(p)
394                if buf[1] == 2:
395                    p = SAPParam_MaxMsgSize()
396                    r = p.deserialize(buf[4+r:])
397                    if r != -1:
398                        self.addParam(p)
399
400                return self._validate()
401
402        return False
403
404class SAPMessage_DISCONNECT_REQ(SAPMessage):
405    def __init__(self):
406        SAPMessage.__init__(self,"DISCONNECT_REQ",  SAPMessage.DISCONNECT_REQ)
407
408class SAPMessage_DISCONNECT_RESP(SAPMessage):
409    def __init__(self):
410        SAPMessage.__init__(self,"DISCONNECT_RESP",  SAPMessage.DISCONNECT_RESP)
411
412class SAPMessage_DISCONNECT_IND(SAPMessage):
413    def __init__(self,  Type = None):
414        SAPMessage.__init__(self,"DISCONNECT_IND",  SAPMessage.DISCONNECT_IND)
415        if Type is not None:
416            self.addParam(SAPParam_DisconnectionType(Type))
417
418    def _validate(self):
419        if len(self.params) == 1:
420            if self.params[0].getID() == SAPParam.DisconnectionType:
421                return True
422        return False
423
424    def deserialize(self,  buf):
425        self.buf = buf
426        self.params[:] = []
427        if SAPMessage._basicCheck(self,  buf):
428            p = SAPParam_DisconnectionType()
429            if p.deserialize(buf[4:]) == len(buf[4:]):
430                self.addParam(p)
431                return self._validate()
432
433        return False
434
435
436class SAPMessage_TRANSFER_APDU_REQ(SAPMessage):
437    def __init__(self,  APDU = None,  T = False):
438        SAPMessage.__init__(self,"TRANSFER_APDU_REQ",  SAPMessage.TRANSFER_APDU_REQ)
439        if APDU is not None:
440            if T :
441                self.addParam(SAPParam_CommandAPDU(APDU))
442            else:
443                self.addParam(SAPParam_CommandAPDU7816(APDU))
444
445    def _validate(self):
446        if len(self.params) == 1:
447            if self.params[0].getID() == SAPParam.CommandAPDU or self.params[0].getID() == SAPParam.CommandAPDU7816:
448                return True
449        return False
450
451    def deserialize(self,  buf):
452        self.buf = buf
453        self.params[:] = []
454        if SAPMessage._basicCheck(self,  buf):
455
456            p = SAPParam_CommandAPDU()
457            p2 = SAPParam_CommandAPDU7816()
458            if p.deserialize(buf[4:]) == len(buf[4:]):
459                self.addParam(p)
460                return self._validate()
461            elif p2.deserialize(buf[4:]) == len(buf[4:]):
462                self.addParam(p2)
463                return self._validate()
464
465        return False
466
467class SAPMessage_TRANSFER_APDU_RESP(SAPMessage):
468    def __init__(self,  ResultCode = None,  Response = None):
469        SAPMessage.__init__(self,"TRANSFER_APDU_RESP",  SAPMessage.TRANSFER_APDU_RESP)
470        if ResultCode is not None:
471            self.addParam(SAPParam_ResultCode(ResultCode))
472            if Response is not None:
473                self.addParam(SAPParam_ResponseAPDU(Response))
474
475    def _validate(self):
476        if len(self.params) > 0:
477            if self.params[0] .getID() == SAPParam.ResultCode:
478                if self.params[0].getValue() == 0x00:
479                    if len(self.params) == 2:
480                        return True
481                else:
482                    if len(self.params) == 1:
483                        return True
484        return False
485
486    def deserialize(self,  buf):
487        self.buf = buf
488        self.params[:] = []
489
490        if SAPMessage._basicCheck(self,  buf):
491            p = SAPParam_ResultCode()
492            r = p.deserialize(buf[4:])
493            if  r != -1:
494                self.addParam(p)
495                if buf[1] == 2:
496                    p = SAPParam_ResponseAPDU()
497                    r = p.deserialize(buf[4+r:])
498                    if r != -1:
499                        self.addParam(p)
500
501                return self._validate()
502
503        return False
504
505class SAPMessage_TRANSFER_ATR_REQ(SAPMessage):
506    def __init__(self):
507        SAPMessage.__init__(self,"TRANSFER_ATR_REQ",  SAPMessage.TRANSFER_ATR_REQ)
508
509class SAPMessage_TRANSFER_ATR_RESP(SAPMessage):
510    def __init__(self,  ResultCode = None,  ATR = None):
511        SAPMessage.__init__(self,"TRANSFER_ATR_RESP",  SAPMessage.TRANSFER_ATR_RESP)
512        if ResultCode is not None:
513            self.addParam(SAPParam_ResultCode(ResultCode))
514            if ATR is not None:
515                self.addParam(SAPParam_ATR(ATR))
516
517    def _validate(self):
518        if len(self.params) > 0:
519            if self.params[0] .getID() == SAPParam.ResultCode:
520                if self.params[0].getValue() == 0x00:
521                    if len(self.params) == 2:
522                        return True
523                else:
524                    if len(self.params) == 1:
525                        return True
526        return False
527
528    def deserialize(self,  buf):
529        self.buf = buf
530        self.params[:] = []
531
532        if SAPMessage._basicCheck(self,  buf):
533
534            p = SAPParam_ResultCode()
535            r = p.deserialize(buf[4:])
536
537            if  r != -1:
538
539                self.addParam(p)
540                if buf[1] == 2:
541
542                    p = SAPParam_ATR()
543                    r = p.deserialize(buf[4+r:])
544                    if r != -1:
545                        self.addParam(p)
546
547                return self._validate()
548
549        return False
550
551class SAPMessage_POWER_SIM_OFF_REQ(SAPMessage):
552    def __init__(self):
553        SAPMessage.__init__(self,"POWER_SIM_OFF_REQ",  SAPMessage.POWER_SIM_OFF_REQ)
554
555class SAPMessage_POWER_SIM_OFF_RESP(SAPMessage):
556    def __init__(self,  ResultCode = None):
557        SAPMessage.__init__(self,"POWER_SIM_OFF_RESP",  SAPMessage.POWER_SIM_OFF_RESP)
558        if ResultCode is not None:
559            self.addParam(SAPParam_ResultCode(ResultCode))
560
561    def _validate(self):
562        if len(self.params) == 1:
563            if self.params[0].getID() == SAPParam.ResultCode:
564                return True
565        return False
566
567    def deserialize(self,  buf):
568        self.buf = buf
569        self.params[:] = []
570        if SAPMessage._basicCheck(self,  buf):
571            p = SAPParam_ResultCode()
572            if p.deserialize(buf[4:]) == len(buf[4:]):
573                self.addParam(p)
574                return self._validate()
575
576        return False
577
578class SAPMessage_POWER_SIM_ON_REQ(SAPMessage):
579    def __init__(self):
580        SAPMessage.__init__(self,"POWER_SIM_ON_REQ",  SAPMessage.POWER_SIM_ON_REQ)
581
582class SAPMessage_POWER_SIM_ON_RESP(SAPMessage_POWER_SIM_OFF_RESP):
583    def __init__(self,  ResultCode = None):
584        SAPMessage.__init__(self,"POWER_SIM_ON_RESP",  SAPMessage.POWER_SIM_ON_RESP)
585        if ResultCode is not None:
586            self.addParam(SAPParam_ResultCode(ResultCode))
587
588class SAPMessage_RESET_SIM_REQ(SAPMessage):
589    def __init__(self):
590        SAPMessage.__init__(self,"RESET_SIM_REQ",  SAPMessage.RESET_SIM_REQ)
591
592class SAPMessage_RESET_SIM_RESP(SAPMessage_POWER_SIM_OFF_RESP):
593    def __init__(self,  ResultCode = None):
594        SAPMessage.__init__(self,"RESET_SIM_RESP",  SAPMessage.RESET_SIM_RESP)
595        if ResultCode is not None:
596            self.addParam(SAPParam_ResultCode(ResultCode))
597
598class SAPMessage_STATUS_IND(SAPMessage):
599    def __init__(self,  StatusChange = None):
600        SAPMessage.__init__(self,"STATUS_IND",  SAPMessage.STATUS_IND)
601        if StatusChange is not None:
602            self.addParam(SAPParam_StatusChange(StatusChange))
603
604    def _validate(self):
605        if len(self.params) == 1:
606            if self.params[0].getID() == SAPParam.StatusChange:
607                return True
608        return False
609
610    def deserialize(self,  buf):
611        self.buf = buf
612        self.params[:] = []
613        if SAPMessage._basicCheck(self,  buf):
614            p = SAPParam_StatusChange()
615            if p.deserialize(buf[4:]) == len(buf[4:]):
616                self.addParam(p)
617                return self._validate()
618
619        return False
620
621class SAPMessage_TRANSFER_CARD_READER_STATUS_REQ(SAPMessage):
622    def __init__(self):
623        SAPMessage.__init__(self,"TRANSFER_CARD_READER_STATUS_REQ",  SAPMessage.TRANSFER_CARD_READER_STATUS_REQ)
624
625class SAPMessage_TRANSFER_CARD_READER_STATUS_RESP(SAPMessage):
626    def __init__(self,  ResultCode = None,  Status = None):
627        SAPMessage.__init__(self,"TRANSFER_CARD_READER_STATUS_RESP",  SAPMessage.TRANSFER_CARD_READER_STATUS_RESP)
628        if ResultCode is not None:
629            self.addParam(SAPParam_ResultCode(ResultCode))
630            if Status is not None:
631                self.addParam(SAPParam_CardReaderStatus(Status))
632
633    def _validate(self):
634        if len(self.params) > 0:
635            if self.params[0] .getID() == SAPParam.ResultCode:
636                if self.params[0].getValue() == 0x00:
637                    if len(self.params) == 2:
638                        return True
639                else:
640                    if len(self.params) == 1:
641                        return True
642        return False
643
644    def deserialize(self,  buf):
645        self.buf = buf
646        self.params[:] = []
647
648        if SAPMessage._basicCheck(self,  buf):
649            p = SAPParam_ResultCode()
650            r = p.deserialize(buf[4:])
651            if  r != -1:
652                self.addParam(p)
653                if buf[1] == 2:
654                    p = SAPParam_CardReaderStatus()
655                    r = p.deserialize(buf[4+r:])
656                    if r != -1:
657                        self.addParam(p)
658
659                return self._validate()
660
661        return False
662
663class SAPMessage_ERROR_RESP(SAPMessage):
664    def __init__(self):
665        SAPMessage.__init__(self,"ERROR_RESP",  SAPMessage.ERROR_RESP)
666
667
668class SAPMessage_SET_TRANSPORT_PROTOCOL_REQ(SAPMessage):
669    def __init__(self,  protocol = None):
670        SAPMessage.__init__(self,"SET_TRANSPORT_PROTOCOL_REQ",  SAPMessage.SET_TRANSPORT_PROTOCOL_REQ)
671        if protocol is not None:
672            self.addParam(SAPParam_TransportProtocol(protocol))
673
674    def _validate(self):
675        if len(self.params) == 1:
676            if self.params[0].getID() == SAPParam.TransportProtocol:
677                return True
678        return False
679
680    def deserialize(self,  buf):
681        self.buf = buf
682        self.params[:] = []
683        if SAPMessage._basicCheck(self,  buf):
684            p = SAPParam_TransportProtocol()
685            if p.deserialize(buf[4:]) == len(buf[4:]):
686                self.addParam(p)
687                return self._validate()
688
689        return False
690
691class SAPMessage_SET_TRANSPORT_PROTOCOL_RESP(SAPMessage_POWER_SIM_OFF_RESP):
692    def __init__(self,  ResultCode = None):
693        SAPMessage.__init__(self,"SET_TRANSPORT_PROTOCOL_RESP",  SAPMessage.SET_TRANSPORT_PROTOCOL_RESP)
694        if ResultCode is not None:
695            self.addParam(SAPParam_ResultCode(ResultCode))
696
697
698class SAPClient:
699
700    CONNECTED = 1
701    DISCONNECTED = 0
702
703    uuid = "0000112D-0000-1000-8000-00805F9B34FB"
704    bufsize = 1024
705    timeout = 20
706    state = DISCONNECTED
707
708    def __init__(self,  host = None,  port = None):
709        self.sock = None
710
711        if host is None or is_valid_address(host):
712            self.host = host
713        else:
714            raise BluetoothError ("%s is not a valid BT address." % host)
715            self.host = None
716            return
717
718        if port is None:
719            self.__discover()
720        else:
721            self.port = port
722
723        self.__connectRFCOMM()
724
725    def __del__(self):
726        self.__disconnectRFCOMM()
727
728    def __disconnectRFCOMM(self):
729        if self.sock is not None:
730            self.sock.close()
731            self.state = self.DISCONNECTED
732
733    def __discover(self):
734        service_matches = find_service(self.uuid, self.host)
735
736        if len(service_matches) == 0:
737            raise BluetoothError ("No SAP service found")
738            return
739
740        first_match = service_matches[0]
741        self.port = first_match["port"]
742        self.host = first_match["host"]
743
744        print "SAP Service found on %s(%s)" % first_match["name"] % self.host
745
746    def __connectRFCOMM(self):
747        self.sock=BluetoothSocket( RFCOMM )
748        self.sock.connect((self.host, self.port))
749        self.sock.settimeout(self.timeout)
750        self.state = self.CONNECTED
751
752    def __sendMsg(self, msg):
753        if isinstance(msg,  SAPMessage):
754            s = msg.serialize()
755            print "\tTX: " + msg.getContent()
756            return self.sock.send(s.tostring())
757
758    def __rcvMsg(self,  msg):
759        if isinstance(msg,  SAPMessage):
760            print "\tRX Wait: %s(id = 0x%.2x)" % (msg.name, msg.id)
761            data = self.sock.recv(self.bufsize)
762            if data:
763                if msg.deserialize(array('B',data)):
764                    print "\tRX: len(%d) %s" % (len(data), msg.getContent())
765                    return msg
766                else:
767                    print "msg: %s" % array('B',data)
768                    raise BluetoothError ("Message deserialization failed.")
769            else:
770                raise BluetoothError ("Timeout. No data received.")
771
772    def connect(self):
773        self.__connectRFCOMM()
774
775    def disconnect(self):
776        self.__disconnectRFCOMM()
777
778    def isConnected(self):
779        return self.state
780
781    def proc_connect(self):
782        try:
783            self.__sendMsg(SAPMessage_CONNECT_REQ(self.bufsize))
784            params = self.__rcvMsg(SAPMessage_CONNECT_RESP()).getParams()
785
786            if params[0].getValue() in (0x00,  0x04):
787                pass
788            elif params[0].getValue() == 0x02:
789                self.bufsize = params[1].getValue()
790
791                self.__sendMsg(SAPMessage_CONNECT_REQ(self.bufsize))
792                params = self.__rcvMsg(SAPMessage_CONNECT_RESP()).getParams()
793
794                if params[0].getValue() not in (0x00,  0x04):
795                    return False
796            else:
797                return False
798
799            params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
800            if params[0].getValue() == 0x00:
801                return False
802            elif params[0].getValue() == 0x01:
803                """OK, Card reset"""
804                return self.proc_transferATR()
805            elif params[0].getValue() == 0x02:
806                """T0 not supported"""
807                if self.proc_transferATR():
808                    return self.proc_setTransportProtocol(1)
809                else:
810                    return False
811            else:
812                return False
813        except BluetoothError , e:
814            print "Error. " +str(e)
815            return False
816
817    def proc_disconnectByClient(self, timeout=0):
818        try:
819            self.__sendMsg(SAPMessage_DISCONNECT_REQ())
820            self.__rcvMsg(SAPMessage_DISCONNECT_RESP())
821            time.sleep(timeout) # let srv to close rfcomm
822            self.__disconnectRFCOMM()
823            return True
824        except BluetoothError , e:
825            print "Error. " +str(e)
826            return False
827
828    def proc_disconnectByServer(self, timeout=0):
829        try:
830            params = self.__rcvMsg(SAPMessage_DISCONNECT_IND()).getParams()
831
832            """gracefull"""
833            if params[0].getValue() == 0x00:
834                if not self.proc_transferAPDU():
835                    return False
836
837            return self.proc_disconnectByClient(timeout)
838
839        except BluetoothError , e:
840            print "Error. " +str(e)
841            return False
842
843    def proc_transferAPDU(self,  apdu = "Sample APDU command"):
844        try:
845            self.__sendMsg(SAPMessage_TRANSFER_APDU_REQ(apdu))
846            params = self.__rcvMsg(SAPMessage_TRANSFER_APDU_RESP()).getParams()
847            return True
848        except BluetoothError , e:
849            print "Error. " +str(e)
850            return False
851
852    def proc_transferATR(self):
853        try:
854            self.__sendMsg(SAPMessage_TRANSFER_ATR_REQ())
855            params = self.__rcvMsg(SAPMessage_TRANSFER_ATR_RESP()).getParams()
856            return True
857        except BluetoothError , e:
858            print "Error. " +str(e)
859            return False
860
861    def proc_powerSimOff(self):
862        try:
863            self.__sendMsg(SAPMessage_POWER_SIM_OFF_REQ())
864            params = self.__rcvMsg(SAPMessage_POWER_SIM_OFF_RESP()).getParams()
865            return True
866        except BluetoothError , e:
867            print "Error. " +str(e)
868            return False
869
870    def proc_powerSimOn(self):
871        try:
872            self.__sendMsg(SAPMessage_POWER_SIM_ON_REQ())
873            params = self.__rcvMsg(SAPMessage_POWER_SIM_ON_RESP()).getParams()
874            if params[0].getValue() == 0x00:
875                return self.proc_transferATR()
876
877            return True
878        except BluetoothError , e:
879            print "Error. " +str(e)
880            return False
881
882    def proc_resetSim(self):
883        try:
884            self.__sendMsg(SAPMessage_RESET_SIM_REQ())
885            params = self.__rcvMsg(SAPMessage_RESET_SIM_RESP()).getParams()
886            if params[0].getValue() == 0x00:
887                return self.proc_transferATR()
888
889            return True
890        except BluetoothError , e:
891            print "Error. " +str(e)
892            return False
893
894    def proc_reportStatus(self):
895        try:
896            params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
897        except BluetoothError , e:
898            print "Error. " +str(e)
899            return False
900
901    def proc_transferCardReaderStatus(self):
902        try:
903            self.__sendMsg(SAPMessage_TRANSFER_CARD_READER_STATUS_REQ())
904            params = self.__rcvMsg(SAPMessage_TRANSFER_CARD_READER_STATUS_RESP()).getParams()
905        except BluetoothError , e:
906            print "Error. " +str(e)
907            return False
908
909    def proc_errorResponse(self):
910        try:
911            """ send malformed message, no mandatory maxmsgsize parameter"""
912            self.__sendMsg(SAPMessage_CONNECT_REQ())
913
914            params = self.__rcvMsg(SAPMessage_ERROR_RESP()).getParams()
915        except BluetoothError , e:
916            print "Error. " +str(e)
917            return False
918
919    def proc_setTransportProtocol(self,  protocol = 0):
920        try:
921            self.__sendMsg(SAPMessage_SET_TRANSPORT_PROTOCOL_REQ(protocol))
922            params = self.__rcvMsg(SAPMessage_SET_TRANSPORT_PROTOCOL_RESP()).getParams()
923
924            if params[0].getValue() == 0x00:
925                params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
926                if params[0].getValue() in (0x01,  0x02):
927                    return self.proc_transferATR()
928                else:
929                    return True
930                    """return False ???"""
931            elif params[0].getValue == 0x07:
932                """not supported"""
933                return True
934                """return False ???"""
935            else:
936                return False
937
938        except BluetoothError , e:
939            print "Error. " +str(e)
940            return False
941
942if __name__ == "__main__":
943    pass
944