Home | History | Annotate | Download | only in test
      1 """ Copyright (C) 2010-2011 ST-Ericsson SA """
      2 
      3 """ Author: Szymon Janc <szymon.janc (a] 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 
     19 from array import array
     20 from bluetooth import *
     21 import time
     22 import re
     23 
     24 class 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 
     93 class 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 
    120 class 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 
    144 class 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 
    153 class 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 
    162 class 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 
    172 class 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 
    190 class 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 
    208 class 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 
    226 class 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 
    235 class 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 
    252 class 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 
    270 class 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 
    343 class 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 
    366 class 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 
    404 class SAPMessage_DISCONNECT_REQ(SAPMessage):
    405     def __init__(self):
    406         SAPMessage.__init__(self,"DISCONNECT_REQ",  SAPMessage.DISCONNECT_REQ)
    407 
    408 class SAPMessage_DISCONNECT_RESP(SAPMessage):
    409     def __init__(self):
    410         SAPMessage.__init__(self,"DISCONNECT_RESP",  SAPMessage.DISCONNECT_RESP)
    411 
    412 class 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 
    436 class 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 
    467 class 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 
    505 class SAPMessage_TRANSFER_ATR_REQ(SAPMessage):
    506     def __init__(self):
    507         SAPMessage.__init__(self,"TRANSFER_ATR_REQ",  SAPMessage.TRANSFER_ATR_REQ)
    508 
    509 class 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 
    551 class SAPMessage_POWER_SIM_OFF_REQ(SAPMessage):
    552     def __init__(self):
    553         SAPMessage.__init__(self,"POWER_SIM_OFF_REQ",  SAPMessage.POWER_SIM_OFF_REQ)
    554 
    555 class 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 
    578 class SAPMessage_POWER_SIM_ON_REQ(SAPMessage):
    579     def __init__(self):
    580         SAPMessage.__init__(self,"POWER_SIM_ON_REQ",  SAPMessage.POWER_SIM_ON_REQ)
    581 
    582 class 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 
    588 class SAPMessage_RESET_SIM_REQ(SAPMessage):
    589     def __init__(self):
    590         SAPMessage.__init__(self,"RESET_SIM_REQ",  SAPMessage.RESET_SIM_REQ)
    591 
    592 class 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 
    598 class 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 
    621 class 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 
    625 class 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 
    663 class SAPMessage_ERROR_RESP(SAPMessage):
    664     def __init__(self):
    665         SAPMessage.__init__(self,"ERROR_RESP",  SAPMessage.ERROR_RESP)
    666 
    667 
    668 class 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 
    691 class 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 
    698 class 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 
    942 if __name__ == "__main__":
    943     pass
    944