Object
Represents a cardterminal. Mixes in CTAPI methods and constants.
Global lock for managment of cardterminals.
The interface this cardterminal is connected to. This is a value of PORT_COM1, PORT_COM2, PORT_COM3, PORT_COM4, PORT_LPT1, PORT_LPT2, PORT_Modem or PORT_Printer.
The slot of the card terminal where the card is inserted. This is a value in the range of ICC1, ICC2,…, ICC14. Default is ICC1.
The maximum size of the chunks of data that are read from/written to the card. Can be set by calling the chunk_size= method.
Returns the mapping of cardterminal numbers to Cardterminal instances as a hash.
# File lib/ctapi.rb, line 17 def self.cardterminals @cardterminals ||= {} end
Creates a new Cardterminal object for this interface and initializes the card terminal that is connected. If no cardterminal number is given, a number (that is not currently in use) is assigned to this object. Otherwise this object is forced to use the given card terminal number. BTW: number has to be >= 0.
# File lib/ctapi.rb, line 31 def initialize(interface, number = nil) LOCK.synchronize do @interface = interface @slot = ICC1 @chunk_size = 255 if number @number = number else @number = 0 while cardterminals.key?(@number) @number += 1 end end ct_init(@number, interface) cardterminals[@number] = true @manufacturer = get_manufacturer reset select_file # master file end end
Takes a block and yields to an initialized Cardterminal object. After the block has been called, the cardterminal is closed again.
# File lib/ctapi.rb, line 102 def self.open(interface, number = nil) cardterminal = self.new(interface, cardterminal) yield cardterminal ensure cardterminal.close if cardterminal end
Returns true if a card is inserted in the cardterminal at the moment, false if the cardterminal is empty.
# File lib/ctapi.rb, line 339 def card_inserted? cs = card_status cs == :card || cs == :card_connect ? true : false end
Returns the card status as symbol: :no_card, :card, :card_connect.
# File lib/ctapi.rb, line 325 def card_status response = request_card_status case response[0] when CTBCS_DATA_STATUS_NOCARD :no_card when CTBCS_DATA_STATUS_CARD :card when CTBCS_DATA_STATUS_CARD_CONNECT :card_connect end end
Convenience method to access Cardterminal.cardterminals.
# File lib/ctapi.rb, line 22 def cardterminals self.class.cardterminals end
The pin of this card is changed from old_pin to new_pin. They can be given as strings or arrays of characters. A true result is returned if the sending was successful.
# File lib/ctapi.rb, line 256 def change_pin(old_pin, new_pin) old_pin = old_pin.unpack("C*") if old_pin.is_a? String new_pin = new_pin.unpack("C*") if new_pin.is_a? String data = old_pin + new_pin unless data.size <= 255 raise ArgumentError.new("size of old and new pin must be <= 255") end change_pin = [ 0, 0x24, 0, 0, data.size ] + data response = data(@slot, HOST, change_pin) response.successful? or return true end
Sets the size of the chunks of data that are read from/written to the card to size: (0 < size <= 255).
# File lib/ctapi.rb, line 87 def chunk_size=(size) raise ArgumentError.new("size must be > 0") unless size > 0 raise ArgumentError.new("size must be <= 255") unless size <= 255 @chunk_size = size end
Terminates the communication with the cardterminal associated with this object and releases the assigned cardterminal number.
# File lib/ctapi.rb, line 134 def close LOCK.synchronize do ct_close(@number) cardterminals.delete @number end end
Sends a sequence of commands to the card or the cardterminal (depending on destination/dad and source address/sad) and returns the response (or responses) to the calling program. A command can be given as an array of bytes [ 0x12, 0x23 ] or as a string of the form ‘12:23:a4’ or ‘12 23 a4’ or as a Command object.
# File lib/ctapi.rb, line 114 def data(dad, sad, *commands) responses = [] commands.each do |command| command = case command when String then Command.from_string(command) when Array then Command.from_array(command) else command end $DEBUG and debug(2, command) data = ct_data(@number, dad, sad, command.data) response = Response.new(data) $DEBUG and debug(1, response) responses << response end return *responses end
Sends the eject card byte sequence to the card terminal and returns the Response object. This method is called by the Cardterminal#reset method.
# File lib/ctapi.rb, line 308 def eject_icc eject = [ 0x20, 0x15, 0x01, 0x00, 0x00 ] data(CT, HOST, eject) end
The pin is sent to the card. It can be given as a string or an array of characters. A true result is returned if the sending was successful.
# File lib/ctapi.rb, line 242 def enter_pin(pin) unless pin.size <= 255 raise ArgumentError.new("size of pin must be <= 255") end pin = pin.unpack("C*") if pin.is_a? String enter_pin = [ 0, 0x20, 0, 0, pin.size ] + pin response = data(@slot, HOST, enter_pin) response.successful? or return true end
Attempts to read data of length size starting at address. If size is nil, an attempt is made to read the whole card memory.
# File lib/ctapi.rb, line 168 def read(address = 0, size = nil) if size == nil if @card size = @card.memory_size - address else size = chunk_size end elsif @card and address + size > @card.memory_size size = @card.memory_size - address end return if size <= 0 data = '' caught = catch(:break) do while size >= chunk_size d = read_chunk(address, chunk_size) if d data << d address += chunk_size size -= chunk_size else break :break end end end if caught != :break and size > 0 d = read_chunk(address, size) and data << d end data end
Requests the card status from the cardterminal. Returns the Response object or nil if the response wasn’t successful. This method is called by the card_inserted? method to find out if a card is inserted into the terminal.
# File lib/ctapi.rb, line 273 def request_card_status get_card_status = [ CTBCS_CLA, CTBCS_INS_STATUS, CTBCS_P1_CT_KERNEL, CTBCS_P2_STATUS_ICC, 0 ] response = data(CT, HOST, get_card_status) response.successful? ? response : nil end
Sends a byte sequence to the card to get the answer to reset Response object. This method is called by the Cardterminal#reset method.
# File lib/ctapi.rb, line 283 def request_icc get_atr = [ CTBCS_CLA, CTBCS_INS_REQUEST, CTBCS_P1_INTERFACE1, CTBCS_P2_REQUEST_GET_ATR, 0 ] @card_old = @card if @card @card, atr = nil, nil begin if card_inserted? atr = data(CT, HOST, get_atr) if atr if atr.not_changed? @card = @card_old return @card.atr end @card = Card.new(atr) end end rescue CTAPIError => e STDERR.puts "Caught: #{e}." end @card.atr end
The cardterminal is reset by first calling eject_icc and then request_icc. If the reset was successful the Response object of request_icc is returned, otherwise a nontrue value is returned.
# File lib/ctapi.rb, line 317 def reset eject_icc response = request_icc or return response.successful? or return response end
Sends the select file byte sequence to the card with a default value for the master file. Returns true if the response was successful, false otherwise.
# File lib/ctapi.rb, line 144 def select_file(fid = [ 0x3f, 0 ]) select_file = [ 0, 0xa4, 0, 0, 0x02, *fid ] response = data(@slot, HOST, select_file) response.successful? end
Attempts to write the string data to the card starting at address. On success returns a true value.
# File lib/ctapi.rb, line 216 def write(data, address = 0) size = data.size if @card and address + size > @card.memory_size size = @card.memory_size - address end return if size <= 0 offset = 0 caught = catch(:break) do while size >= chunk_size write_chunk(address, data[offset, chunk_size]) or break :break address += chunk_size offset += chunk_size size -= chunk_size end end if caught == :break return false elsif size > 0 write_chunk(address, data[offset, size]) end true end
Returns true if the card has been changed in the cardterminal, false it is still the same card. If an error occured nil is returned.
# File lib/ctapi.rb, line 347 def card_changed? response = reset or return response.changed? and return true response.not_changed? and return false return end
Prints data with indication of direction to STDERR.
# File lib/ctapi.rb, line 382 def debug(direction, data) direction = case direction when 1 then '>>> ' when 2 then '<<< ' else '' end STDERR.puts direction + data.to_s end
Returns a Manufacturer object with information about the manufacturer of this cardterminal. Could return nil if the response was not successful.
# File lib/ctapi.rb, line 59 def get_manufacturer get_manufacturer_status = [ CTBCS_CLA, CTBCS_INS_STATUS, CTBCS_P1_CT_KERNEL, CTBCS_P2_STATUS_MANUFACTURER, 0 ] response = data(CT, HOST, get_manufacturer_status) return nil unless response.successful? Manufacturer.new(response) end
(Not documented)
# File lib/ctapi.rb, line 150 def read_chunk(address, size) unless address <= 65535 raise ArgumentError.new("address must be <= 65535") end unless size <= 255 raise ArgumentError.new("size must be <= 255") end read_file = [ 0, 0xb0, address >> 8, address & 0xff, size ] response = data(@slot, HOST, read_file) response.successful? or return data = response.data data.slice!(-2, 2) data end
(Not documented)
# File lib/ctapi.rb, line 198 def write_chunk(address, data) unless address <= 65535 raise ArgumentError.new("address must be <= 65535") end unless data.size <= 255 raise ArgumentError.new("size of data must be <= 255") end data = data.unpack("C*") if data.is_a? String write_file = [ 0, 0xd6, address >> 8, address & 0xff, data.size ] + data response = data(@slot, HOST, write_file) response.successful? or return true end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.