diff --git a/README.md b/README.md index 4abb7dd..055eb63 100644 --- a/README.md +++ b/README.md @@ -108,25 +108,28 @@ Emitted when the card reader has been removed. #### Event: 'status' * *status* `Object`. - * *state* The current status of the card reader as returned by `SCardGetStatusChange` + * *state* The current status of the card reader as returned by `[SCardGetStatusChange](http://pcsclite.alioth.debian.org/pcsc-lite/node20.html)` * *atr* ATR of the card inserted (if any) Emitted whenever the status of the reader changes. -#### reader.connect(callback) +#### reader.connect([options], callback) +* *options* `Object` Optional + * *share_mode* `Number` Shared mode. Defaults to `SCARD_SHARE_EXCLUSIVE` + * *protocol* `Number` Preferred protocol. Defaults to `SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1` * *callback* `Function` called when connection operation ends * *error* `Error` * *protocol* `Number` Established protocol to this connection. -Wrapper around `SCardConnect`. Establishes a connection to the reader. +Wrapper around `[SCardConnect](http://pcsclite.alioth.debian.org/pcsc-lite/node12.html)`. Establishes a connection to the reader. #### reader.disconnect(callback) * *callback* `Function` called when disconnection operation ends * *error* `Error` -Wrapper around `SCardDisconnect`. Terminates a connection to the reader. +Wrapper around `[SCardDisconnect](http://pcsclite.alioth.debian.org/pcsc-lite/node14.html)`. Terminates a connection to the reader. #### reader.transmit(input, res_len, protocol, callback) @@ -137,7 +140,7 @@ Wrapper around `SCardDisconnect`. Terminates a connection to the reader. * *error* `Error` * *output* `Buffer` -Wrapper around `SCardTransmit`. Sends an APDU to the smart card contained in the reader connected to. +Wrapper around `[SCardTransmit](http://pcsclite.alioth.debian.org/pcsc-lite/node17.html)`. Sends an APDU to the smart card contained in the reader connected to. #### reader.control(input, control_code, res_len, callback) @@ -148,4 +151,4 @@ Wrapper around `SCardTransmit`. Sends an APDU to the smart card contained in the * *error* `Error` * *output* `Buffer` -Wrapper around `SCardControl`. Sends a command directly to the IFD Handler (reader driver) to be processed by the reader. +Wrapper around `[SCardControl](http://pcsclite.alioth.debian.org/pcsc-lite/node18.html)`. Sends a command directly to the IFD Handler (reader driver) to be processed by the reader. diff --git a/lib/pcsclite.js b/lib/pcsclite.js index a37107e..4e516f6 100644 --- a/lib/pcsclite.js +++ b/lib/pcsclite.js @@ -67,10 +67,18 @@ module.exports = function() { return p; }; -CardReader.prototype.connect = function(cb) { +CardReader.prototype.connect = function(options, cb) { + if (typeof options === 'function') { + cb = options; + options = undefined; + } + + options = options || {}; + options.share_mode = options.share_mode || this.SCARD_SHARE_EXCLUSIVE; + options.protocol = options.protocol || this.SCARD_PROTOCOL_T0 | this.SCARD_PROTOCOL_T1; if (!this.connected) { - this._connect(cb); + this._connect(options.share_mode, options.protocol, cb); } else { cb(); } @@ -109,18 +117,6 @@ CardReader.prototype.control = function(data, control_code, res_len, cb) { }); }; -CardReader.prototype.SCARD_STATE_UNAWARE = 0x0000; -CardReader.prototype.SCARD_STATE_IGNORE = 0x0001; -CardReader.prototype.SCARD_STATE_CHANGED = 0x0002; -CardReader.prototype.SCARD_STATE_UNKNOWN = 0x0004; -CardReader.prototype.SCARD_STATE_UNAVAILABLE = 0x0008; -CardReader.prototype.SCARD_STATE_EMPTY = 0x0010; -CardReader.prototype.SCARD_STATE_PRESENT = 0x0020; -CardReader.prototype.SCARD_STATE_ATRMATCH = 0x0040; -CardReader.prototype.SCARD_STATE_EXCLUSIVE = 0x0080; -CardReader.prototype.SCARD_STATE_INUSE = 0x0100; -CardReader.prototype.SCARD_STATE_MUTE = 0x0200; - // extend prototype function inherits(target, source) { for (var k in source.prototype) { diff --git a/src/cardreader.cpp b/src/cardreader.cpp index 81e3d15..2b07e1e 100644 --- a/src/cardreader.cpp +++ b/src/cardreader.cpp @@ -30,6 +30,46 @@ void CardReader::init(Handle target) { NODE_SET_PROTOTYPE_METHOD(tpl, "_control", Control); NODE_SET_PROTOTYPE_METHOD(tpl, "close", Close); + // PCSCLite constants + // Share Mode + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_SHARE_SHARED"), + Integer::New(SCARD_SHARE_SHARED)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_SHARE_EXCLUSIVE"), + Integer::New(SCARD_SHARE_EXCLUSIVE)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_SHARE_DIRECT"), + Integer::New(SCARD_SHARE_DIRECT)); + // Protocol + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_PROTOCOL_T0"), + Integer::New(SCARD_PROTOCOL_T0)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_PROTOCOL_T1"), + Integer::New(SCARD_PROTOCOL_T1)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_PROTOCOL_RAW"), + Integer::New(SCARD_PROTOCOL_RAW)); + // State + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_STATE_UNAWARE"), + Integer::New(SCARD_STATE_UNAWARE)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_STATE_IGNORE"), + Integer::New(SCARD_STATE_IGNORE)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_STATE_CHANGED"), + Integer::New(SCARD_STATE_CHANGED)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_STATE_UNKNOWN"), + Integer::New(SCARD_STATE_UNKNOWN)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_STATE_UNAVAILABLE"), + Integer::New(SCARD_STATE_UNAVAILABLE)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_STATE_EMPTY"), + Integer::New(SCARD_STATE_EMPTY)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_STATE_PRESENT"), + Integer::New(SCARD_STATE_PRESENT)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_STATE_ATRMATCH"), + Integer::New(SCARD_STATE_ATRMATCH)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_STATE_EXCLUSIVE"), + Integer::New(SCARD_STATE_EXCLUSIVE)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_STATE_INUSE"), + Integer::New(SCARD_STATE_INUSE)); + tpl->PrototypeTemplate()->Set(String::NewSymbol("SCARD_STATE_MUTE"), + Integer::New(SCARD_STATE_MUTE)); + + constructor = Persistent::New(tpl->GetFunction()); target->Set(String::NewSymbol("CardReader"), constructor); } @@ -89,18 +129,33 @@ Handle CardReader::Connect(const Arguments& args) { HandleScope scope; - if (!args[0]->IsFunction()) { + // The second argument is the length of the data to be received + if (!args[0]->IsUint32()) { return ThrowException(Exception::TypeError( - String::New("First argument must be a callback function"))); + String::New("First argument must be an integer"))); } - Local cb = Local::Cast(args[0]); + if (!args[1]->IsUint32()) { + return ThrowException(Exception::TypeError( + String::New("Second argument must be an integer"))); + } + + if (!args[2]->IsFunction()) { + return ThrowException(Exception::TypeError( + String::New("Third argument must be a callback function"))); + } + + ConnectInput* ci = new ConnectInput(); + ci->share_mode = args[0]->Uint32Value(); + ci->pref_protocol = args[1]->Uint32Value(); + Local cb = Local::Cast(args[2]); // This creates our work request, including the libuv struct. Baton* baton = new Baton(); baton->request.data = baton; baton->callback = Persistent::New(cb); baton->reader = ObjectWrap::Unwrap(args.This()); + baton->input = ci; // Schedule our work request with libuv. Here you can specify the functions // that should be executed in the threadpool and back in the main thread @@ -333,6 +388,7 @@ void* CardReader::HandlerFunction(void* arg) { void CardReader::DoConnect(uv_work_t* req) { Baton* baton = static_cast(req->data); + ConnectInput *ci = static_cast(baton->input); unsigned long card_protocol; LONG result = SCARD_S_SUCCESS; @@ -347,9 +403,12 @@ void CardReader::DoConnect(uv_work_t* req) { /* Connect */ if (result == SCARD_S_SUCCESS) { - result = SCardConnect(obj->m_card_context, obj->m_name.c_str(), - SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, - &obj->m_card_handle, &card_protocol); + result = SCardConnect(obj->m_card_context, + obj->m_name.c_str(), + ci->share_mode, + ci->pref_protocol, + &obj->m_card_handle, + &card_protocol); } /* Unlock the mutex */ @@ -372,6 +431,7 @@ void CardReader::AfterConnect(uv_work_t* req) { HandleScope scope; Baton* baton = static_cast(req->data); + ConnectInput *ci = static_cast(baton->input); ConnectResult *cr = static_cast(baton->result); if (cr->result) { @@ -393,6 +453,7 @@ void CardReader::AfterConnect(uv_work_t* req) { // The callback is a permanent handle, so we have to dispose of it manually. baton->callback.Dispose(); + delete ci; delete cr; delete baton; } diff --git a/src/cardreader.h b/src/cardreader.h index 8e331cf..10f1089 100644 --- a/src/cardreader.h +++ b/src/cardreader.h @@ -21,9 +21,14 @@ class CardReader: public node::ObjectWrap { void *result; }; + struct ConnectInput { + DWORD share_mode; + DWORD pref_protocol; + }; + struct ConnectResult { LONG result; - unsigned long card_protocol; + DWORD card_protocol; }; struct TransmitInput {