src: improve SCardConnect interface
- We can optionally pass the share_mode and preferred_protocol options. They are optional to keep backwards compatibility. - Update README - Define constants in C++ land.
This commit is contained in:
15
README.md
15
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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -30,6 +30,46 @@ void CardReader::init(Handle<Object> 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<Function>::New(tpl->GetFunction());
|
||||
target->Set(String::NewSymbol("CardReader"), constructor);
|
||||
}
|
||||
@@ -89,18 +129,33 @@ Handle<Value> 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<Function> cb = Local<Function>::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<Function> cb = Local<Function>::Cast(args[2]);
|
||||
|
||||
// This creates our work request, including the libuv struct.
|
||||
Baton* baton = new Baton();
|
||||
baton->request.data = baton;
|
||||
baton->callback = Persistent<Function>::New(cb);
|
||||
baton->reader = ObjectWrap::Unwrap<CardReader>(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<Baton*>(req->data);
|
||||
ConnectInput *ci = static_cast<ConnectInput*>(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<Baton*>(req->data);
|
||||
ConnectInput *ci = static_cast<ConnectInput*>(baton->input);
|
||||
ConnectResult *cr = static_cast<ConnectResult*>(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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user