def handleApdu(self, cardData, apdu):
        card = cardData[0]
        sendData = cardData[1]

        if card == None:
            raise Exception("card not initialized")

        ins = types.insName(apdu)

        if card != self.getMainCard(0):
            origApdu = apdu
            if ( self.aidCommon(card) and
                 card.routingAttr.aidToSelect and
                 self.getMainCard(0).routingAttr.aidToSelect == hextools.bytes2hex(apdu) and #origin apdu is AID
                 int(card.routingAttr.aidToSelect[0:2], 16) == apdu[0]): #check the same class
                apdu = hextools.hex2bytes(card.routingAttr.aidToSelect)
                card.routingAttr.aidToSelect = None
            elif ( self.aidCommon(card) and
                   card.routingAttr.getFileSelected(apdu[0]) == 'EF_DIR' and
                   ins == 'READ_RECORD' and
                   card.routingAttr.recordEfDirLength):
                apdu[4] = card.routingAttr.recordEfDirLength

            if origApdu != apdu:
                self.loggingApdu.info("")
                self.loggingApdu.info("*C-APDU%d: %s" %(self.getSimId(card), hextools.bytes2hex(apdu)))

        if self.simType == types.TYPE_SIM and (apdu[0] & 0xF0) != 0xA0:
            #force 2G on USIM cards
            sw = types_g.sw.CLASS_NOT_SUPPORTED
            sw1 = sw>>8
            sw2 = sw & 0x00FF
            responseApdu = [sw1, sw2]
        elif ins == 'GET_RESPONSE' and card.routingAttr.getResponse:
            responseApdu = card.routingAttr.getResponse
            card.routingAttr.getResponse = None
        else:
            responseApdu = card.apdu(apdu)

        if card != self.getMainCard(0):
            if (self.aidCommon(card) and
                    card.routingAttr.getFileSelected(apdu[0]) == 'EF_DIR' and
                    ins == 'GET_RESPONSE' and
                    types.swNoError(responseApdu) and
                    len(responseApdu) > 7):
                card.routingAttr.recordEfDirLength = responseApdu[7]

        if (TRY_ANOTHER_CARD_ON_AUTH_FAILURE and
                self.getNbrOfCards() > 1 and
                card.routingAttr.getFileSelected(apdu[0]) == 'AUTH' and
                types.sw(responseApdu) == types_g.sw.AUTHENTICATION_ERROR_APPLICATION_SPECIFIC):
            sw1Name, swName = types.swName(types.sw(responseApdu) >> 8, types.sw(responseApdu) & 0x00FF)
            self.logging.warning("Response not expected. SW1: %s, SW: %s" %(sw1Name, swName))
            self.logging.warning("Change card to process AUTHENTICATION")
            if card == self.getMainCard(0):
                cardTmp = self.getMainCard(1)
            else:
                cardTmp = self.getMainCard(0)
            responseApdu = cardTmp.apdu(apdu)
            cardTmp.routingAttr.setFileSelected('AUTH', apdu[0])
            card.routingAttr.setFileSelected(None, apdu[0])
            # TODO: check if exist
            cardTmp.routingAttr.insReplaced.append('INTERNAL_AUTHENTICATE')
            if types.sw1(responseApdu) in [types_g.sw1.RESPONSE_DATA_AVAILABLE_2G, types_g.sw1.RESPONSE_DATA_AVAILABLE_3G]:
                # cache 'GET_RESPONSE'
                getResponseLength = types.sw2(responseApdu)
                cla = apdu[0]
                apduTmp = "%02XC00000%02X" %(cla, getResponseLength)
                self.loggingApdu.info("**C-APDU%d: %s" %(self.getSimId(cardTmp), apduTmp))
                cardTmp.routingAttr.getResponse = cardTmp.apdu(apduTmp)

        if card.routingAttr.getFileSelected(apdu[0]) == 'EF_IMSI' and types.swNoError(responseApdu):
            #cache imsi
            responseData = types.responseData(responseApdu)
            if ins == 'READ_BINARY' and types.p1(apdu) == 0 and types.p2(apdu) == 0:
                #When P1=8X then SFI is used to select the file.
                #Remove the check when SFI checking is implemented
                imsi = hextools.decode_BCD(responseData)[3:]
                #TODO: remove length check when name for the file comes from
                #the whole path and not fid. 6f07 is also in ADF_ISIM
                if len(imsi) > 10:
                    card.imsi = imsi
                    #update associated interface
                    if self.isCardCtrl(card):
                        self.getRelatedMainCard(card).imsi = imsi
                    else:
                        self.getRelatedCtrlCard(card).imsi = imsi
            elif ins == 'UPDATE_BINARY':
                card.imsi = None

        responseApduHex = hextools.bytes2hex(responseApdu)
        #example of APDU modification
        if responseApduHex == "02542D4D6F62696C652E706CFFFFFFFFFF9000":
            #change SPN name 'T-mobile.pl' for 'Tmobile-SPN'
            responseApdu = hextools.hex2bytes("02546D6F62696C652D53504EFFFFFFFFFF9000")

        if sendData:
            if ((types.sw(responseApdu) == types_g.sw.NO_ERROR or
                 types.sw1(responseApdu) == types_g.sw1.NO_ERROR_PROACTIVE_DATA) and
                 self.getNbrOfCards() > 1):
                # Check for pending SAT command
                for cardDict in self.cardsDict:
                    cardTmp = cardDict[MAIN_INTERFACE]
                    if card == cardTmp:
                        continue
                    if set(sim_card.SAT_INS) <= set(cardTmp.routingAttr.insReplaced):
                        swNoError = cardTmp.swNoError
                        if types.unpackSw(swNoError)[0] == types_g.sw1.NO_ERROR_PROACTIVE_DATA:
                            #update r-apdu with proactive data information
                            responseApdu[-2] = swNoError >> 8
                            responseApdu[-1] = swNoError & 0x00FF
                        break
            self.sendResponseApdu(responseApdu)
        if card == self.getMainCard(0) or sendData:
            self.pretty_apdu(apdu)
        responseApduHex = hextools.bytes2hex(responseApdu)
        self.loggingApdu.info("R-APDU%d: %s" %(self.getSimId(card), responseApduHex))
        # gsmtap.log(apdu,responseApdu) # Uncomment for wireshark
        return responseApdu