smartcard 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +14 -0
- data/LICENSE +22 -0
- data/Manifest +19 -0
- data/README +22 -0
- data/ext/smartcard_pcsc/extconf.rb +23 -4
- data/ext/smartcard_pcsc/pcsc.h +9 -1
- data/ext/smartcard_pcsc/pcsc_card.c +82 -53
- data/ext/smartcard_pcsc/pcsc_constants.c +4 -0
- data/ext/smartcard_pcsc/pcsc_context.c +27 -16
- data/ext/smartcard_pcsc/pcsc_io_request.c +4 -1
- data/ext/smartcard_pcsc/pcsc_multi_strings.c +31 -14
- data/ext/smartcard_pcsc/pcsc_reader_states.c +26 -13
- data/smartcard.gemspec +53 -0
- data/test/test_all.rb +0 -0
- metadata +15 -9
data/CHANGELOG
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
v0.2.0 Added automatic builds
|
2
|
+
Rakefile for auto builds using echoe
|
3
|
+
extconf.rb: hack to fix Windows makefiles
|
4
|
+
|
5
|
+
v0.1.2 Added Windows compatibility
|
6
|
+
*.c: restructured code so VC2005 likes it
|
7
|
+
(variable declarations before function body)
|
8
|
+
docs: license, readme, and what the gem is
|
9
|
+
|
10
|
+
v0.1.1 Added support for Ubuntu 7.10
|
11
|
+
ext/smartcard_pcsc/extconf.rb: better header
|
12
|
+
detection
|
13
|
+
|
14
|
+
v0.1.0 Initial release for OSX Leopard
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2007 Victor Costan
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
22
|
+
|
data/Manifest
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
ext/smartcard_pcsc/extconf.rb
|
3
|
+
ext/smartcard_pcsc/pcsc.h
|
4
|
+
ext/smartcard_pcsc/pcsc_card.c
|
5
|
+
ext/smartcard_pcsc/pcsc_constants.c
|
6
|
+
ext/smartcard_pcsc/pcsc_context.c
|
7
|
+
ext/smartcard_pcsc/pcsc_io_request.c
|
8
|
+
ext/smartcard_pcsc/pcsc_main.c
|
9
|
+
ext/smartcard_pcsc/pcsc_multi_strings.c
|
10
|
+
ext/smartcard_pcsc/pcsc_namespace.c
|
11
|
+
ext/smartcard_pcsc/pcsc_reader_states.c
|
12
|
+
ext/smartcard_pcsc/pcsc_surrogate_reader.h
|
13
|
+
ext/smartcard_pcsc/pcsc_surrogate_wintypes.h
|
14
|
+
lib/smartcard.rb
|
15
|
+
LICENSE
|
16
|
+
README
|
17
|
+
test/test_all.rb
|
18
|
+
tests/ts_pcsc_ext.rb
|
19
|
+
Manifest
|
data/README
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
SUMMARY
|
2
|
+
|
3
|
+
'smartcard' aims to become the de-facto support library for smart-card development on ruby.
|
4
|
+
At the moment, 'smartcard' offers a PC/SC binding that is working on ruby 1.8, under
|
5
|
+
linux, osx, and windows. Future plans include a high level abstraction for the PC/SC binding
|
6
|
+
(and any other bindings people need), and an interface for Java cards.
|
7
|
+
|
8
|
+
LICENSE
|
9
|
+
|
10
|
+
'smartcard' is released under the MIT license. This means you're free to do whatever you want
|
11
|
+
with it. For the legalese version, please see the 'LICENSE' file.
|
12
|
+
|
13
|
+
DOCUMENTATION
|
14
|
+
|
15
|
+
The API is fully documented with RDoc. If you installed the 'smartcard' gem, you should be
|
16
|
+
able to use ri to see the documentation. If you're using the SVN version, you can use rdoc to
|
17
|
+
build the HTML and RI documentation yourself.
|
18
|
+
|
19
|
+
ACKNOWLEDGEMENTS
|
20
|
+
|
21
|
+
'smartcard' was developed for Victor Costan while working as a Research Assistant for MIT.
|
22
|
+
The work was sponsored by a grant from Quanta Computer Inc (www.quanta.com.tw)
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'mkmf'
|
2
|
-
require 'pp'
|
3
2
|
|
4
3
|
$CFLAGS ||= ''
|
5
4
|
$LDFLAGS ||= ''
|
@@ -7,7 +6,7 @@ $LDFLAGS ||= ''
|
|
7
6
|
if RUBY_PLATFORM =~ /darwin/
|
8
7
|
$LDFLAGS += ' -framework PCSC'
|
9
8
|
elsif RUBY_PLATFORM =~ /win/
|
10
|
-
|
9
|
+
have_library('winscard')
|
11
10
|
else
|
12
11
|
# pcsc is retarded and uses stuff like '#include <wintypes.h>'
|
13
12
|
$CFLAGS += ' -I /usr/include/PCSC -I /usr/local/include/pcsc'
|
@@ -26,9 +25,29 @@ end
|
|
26
25
|
|
27
26
|
pcsc_defines = []
|
28
27
|
|
29
|
-
File.open('
|
28
|
+
File.open('pcsc_autogen.h', 'w') do |f|
|
30
29
|
pcsc_defines.each { |d| f.write "\#define #{d}\n" }
|
31
30
|
pcsc_headers.each { |h| f.write "\#include #{h}\n" }
|
32
31
|
end
|
33
32
|
|
34
|
-
create_makefile('smartcard/pcsc')
|
33
|
+
create_makefile('smartcard/pcsc')
|
34
|
+
|
35
|
+
def win32_hack(mf_name)
|
36
|
+
# evil, evil, evil -- hack the makefile to embed the manifest in the extension dll
|
37
|
+
make_contents = File.open(mf_name, 'r') { |f| f.read }
|
38
|
+
make_rules = make_contents.split(/(\n|\r)(\n|\r)+/)
|
39
|
+
new_make_rules = make_rules.map do |rule|
|
40
|
+
if rule =~ /^\$\(DLLIB\)\:/
|
41
|
+
rule + "\n\tmt.exe -manifest $(@).manifest -outputresource:$(@);2"
|
42
|
+
else
|
43
|
+
rule
|
44
|
+
end
|
45
|
+
end
|
46
|
+
File.open(mf_name, 'w') { |f| f.write new_make_rules.join("\n\n")}
|
47
|
+
end
|
48
|
+
|
49
|
+
case RUBY_PLATFORM
|
50
|
+
when /darwin/
|
51
|
+
when /win/
|
52
|
+
win32_hack 'Makefile'
|
53
|
+
end
|
data/ext/smartcard_pcsc/pcsc.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/* Ruby extension API. */
|
2
2
|
#include <ruby.h>
|
3
3
|
/* Generated by 'extconf.rb' to point to the PC/SC header. */
|
4
|
-
#include "
|
4
|
+
#include "pcsc_autogen.h"
|
5
5
|
|
6
6
|
/* Entrypoint into the Ruby extension. */
|
7
7
|
void Init_pcsc();
|
@@ -36,3 +36,11 @@ void Init_PCSC_Consts();
|
|
36
36
|
/* Multi-string (win32 abomination) tools. */
|
37
37
|
VALUE PCSC_Internal_multistring_to_ruby_array(char *mstr, size_t mstr_len);
|
38
38
|
int PCSC_Internal_ruby_strings_to_multistring(VALUE rbStrings, char **strings);
|
39
|
+
|
40
|
+
/* Messing up with constants that aren't uniformly defined. */
|
41
|
+
#if !defined(MAX_ATR_SIZE)
|
42
|
+
#define MAX_ATR_SIZE 32
|
43
|
+
#endif
|
44
|
+
#if !defined(SCARD_PROTOCOL_ANY)
|
45
|
+
#define SCARD_PROTOCOL_ANY (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)
|
46
|
+
#endif
|
@@ -43,24 +43,26 @@ static VALUE PCSC_Card_alloc(VALUE klass) {
|
|
43
43
|
*/
|
44
44
|
static VALUE PCSC_Card_initialize(VALUE self, VALUE rbContext, VALUE rbReaderName, VALUE rbShareMode, VALUE rbPreferredProtocols) {
|
45
45
|
struct SCardHandleEx *card;
|
46
|
+
SCARDCONTEXT context;
|
47
|
+
VALUE rbFinalReaderName;
|
48
|
+
DWORD share_mode, preferred_protocols, active_protocol;
|
49
|
+
|
46
50
|
Data_Get_Struct(self, struct SCardHandleEx, card);
|
47
51
|
|
48
|
-
SCARDCONTEXT context;
|
49
52
|
if(_PCSC_Context_lowlevel_get(rbContext, &context) == 0) {
|
50
53
|
rb_raise(rb_eArgError, "first argument is not a Context instance");
|
51
54
|
return self;
|
52
55
|
}
|
53
56
|
|
54
|
-
|
57
|
+
rbFinalReaderName = rb_check_string_type(rbReaderName);
|
55
58
|
if(NIL_P(rbFinalReaderName)) {
|
56
59
|
rb_raise(rb_eArgError, "second argument (should be reader name) does not convert to a String");
|
57
60
|
return self;
|
58
61
|
}
|
59
62
|
|
60
|
-
|
61
|
-
|
63
|
+
share_mode = NUM2UINT(rbShareMode);
|
64
|
+
preferred_protocols = NUM2UINT(rbPreferredProtocols);
|
62
65
|
|
63
|
-
DWORD active_protocol;
|
64
66
|
card->pcsc_error = SCardConnect(context, RSTRING(rbFinalReaderName)->ptr, share_mode, preferred_protocols, &card->card_handle, &active_protocol);
|
65
67
|
if(card->pcsc_error != SCARD_S_SUCCESS)
|
66
68
|
rb_raise(rb_eRuntimeError, "SCardConnect: %s", pcsc_stringify_error(card->pcsc_error));
|
@@ -82,14 +84,15 @@ static VALUE PCSC_Card_initialize(VALUE self, VALUE rbContext, VALUE rbReaderNam
|
|
82
84
|
*/
|
83
85
|
static VALUE PCSC_Card_reconnect(VALUE self, VALUE rbShareMode, VALUE rbPreferredProtocols, VALUE rbInitialization) {
|
84
86
|
struct SCardHandleEx *card;
|
87
|
+
DWORD share_mode, preferred_protocols, initialization, active_protocol;
|
88
|
+
|
85
89
|
Data_Get_Struct(self, struct SCardHandleEx, card);
|
86
90
|
if(card == NULL) return self;
|
87
91
|
|
88
|
-
|
89
|
-
|
90
|
-
|
92
|
+
share_mode = NUM2UINT(rbShareMode);
|
93
|
+
preferred_protocols = NUM2UINT(rbPreferredProtocols);
|
94
|
+
initialization = NUM2UINT(rbInitialization);
|
91
95
|
|
92
|
-
uint32_t active_protocol;
|
93
96
|
card->pcsc_error = SCardReconnect(card->card_handle, share_mode, preferred_protocols, initialization, &active_protocol);
|
94
97
|
if(card->pcsc_error != SCARD_S_SUCCESS)
|
95
98
|
rb_raise(rb_eRuntimeError, "SCardReconnect: %s", pcsc_stringify_error(card->pcsc_error));
|
@@ -107,11 +110,13 @@ static VALUE PCSC_Card_reconnect(VALUE self, VALUE rbShareMode, VALUE rbPreferre
|
|
107
110
|
* +disposition+:: action to be taken on the card inside the reader; use one of the Smartcard::PCSC::DISPOSITION_ constants
|
108
111
|
*/
|
109
112
|
static VALUE PCSC_Card_disconnect(VALUE self, VALUE rbDisposition) {
|
110
|
-
struct SCardHandleEx *card;
|
113
|
+
struct SCardHandleEx *card;
|
114
|
+
DWORD disposition;
|
115
|
+
|
111
116
|
Data_Get_Struct(self, struct SCardHandleEx, card);
|
112
117
|
if(card == NULL) return self;
|
113
118
|
|
114
|
-
|
119
|
+
disposition = NUM2UINT(rbDisposition);
|
115
120
|
if(!card->released) {
|
116
121
|
card->pcsc_error = SCardDisconnect(card->card_handle, disposition);
|
117
122
|
card->released = 1;
|
@@ -129,7 +134,8 @@ static VALUE PCSC_Card_disconnect(VALUE self, VALUE rbDisposition) {
|
|
129
134
|
* Wraps _SCardBeginTransaction_ in PC/SC.
|
130
135
|
*/
|
131
136
|
static VALUE PCSC_Card_begin_transaction(VALUE self) {
|
132
|
-
struct SCardHandleEx *card;
|
137
|
+
struct SCardHandleEx *card;
|
138
|
+
|
133
139
|
Data_Get_Struct(self, struct SCardHandleEx, card);
|
134
140
|
if(card == NULL) return self;
|
135
141
|
|
@@ -149,11 +155,13 @@ static VALUE PCSC_Card_begin_transaction(VALUE self) {
|
|
149
155
|
* +disposition+:: action to be taken on the card inside the reader; use one of the Smartcard::PCSC::DISPOSITION_ constants
|
150
156
|
*/
|
151
157
|
static VALUE PCSC_Card_end_transaction(VALUE self, VALUE rbDisposition) {
|
152
|
-
struct SCardHandleEx *card;
|
158
|
+
struct SCardHandleEx *card;
|
159
|
+
DWORD disposition;
|
160
|
+
|
153
161
|
Data_Get_Struct(self, struct SCardHandleEx, card);
|
154
162
|
if(card == NULL) return self;
|
155
163
|
|
156
|
-
|
164
|
+
disposition = NUM2UINT(rbDisposition);
|
157
165
|
card->pcsc_error = SCardEndTransaction(card->card_handle, disposition);
|
158
166
|
if(card->pcsc_error != SCARD_S_SUCCESS)
|
159
167
|
rb_raise(rb_eRuntimeError, "SCardEndTransaction: %s", pcsc_stringify_error(card->pcsc_error));
|
@@ -174,19 +182,23 @@ static VALUE PCSC_Card_end_transaction(VALUE self, VALUE rbDisposition) {
|
|
174
182
|
* +attribute_id+:: identifies the attribute to be read; use one of the Smartcard::PCSC::ATTR_ constants
|
175
183
|
*/
|
176
184
|
static VALUE PCSC_Card_get_attribute(VALUE self, VALUE rbAttributeId) {
|
177
|
-
struct SCardHandleEx *card;
|
185
|
+
struct SCardHandleEx *card;
|
186
|
+
char *attribute_buffer;
|
187
|
+
DWORD attribute_id, attribute_length;
|
188
|
+
VALUE rbAttribute;
|
189
|
+
|
178
190
|
Data_Get_Struct(self, struct SCardHandleEx, card);
|
179
191
|
if(card == NULL) return Qnil;
|
180
192
|
|
181
|
-
|
182
|
-
|
193
|
+
attribute_id = NUM2UINT(rbAttributeId);
|
194
|
+
attribute_length;
|
183
195
|
card->pcsc_error = SCardGetAttrib(card->card_handle, attribute_id, NULL, &attribute_length);
|
184
196
|
if(card->pcsc_error == SCARD_S_SUCCESS) {
|
185
|
-
|
197
|
+
attribute_buffer = ALLOC_N(char, attribute_length);
|
186
198
|
if(attribute_buffer != NULL) {
|
187
199
|
card->pcsc_error = SCardGetAttrib(card->card_handle, attribute_id, (LPSTR)attribute_buffer, &attribute_length);
|
188
200
|
if(card->pcsc_error == SCARD_S_SUCCESS) {
|
189
|
-
|
201
|
+
rbAttribute = rb_str_new(attribute_buffer, attribute_length);
|
190
202
|
xfree(attribute_buffer);
|
191
203
|
return rbAttribute;
|
192
204
|
}
|
@@ -210,13 +222,16 @@ static VALUE PCSC_Card_get_attribute(VALUE self, VALUE rbAttributeId) {
|
|
210
222
|
* +attribute_value+:: the value to be assigned to the attribute; wrap the bytes in a string-like object (low-level API, remember?)
|
211
223
|
*/
|
212
224
|
static VALUE PCSC_Card_set_attribute(VALUE self, VALUE rbAttributeId, VALUE rbAttributeValue) {
|
213
|
-
struct SCardHandleEx *card;
|
225
|
+
struct SCardHandleEx *card;
|
226
|
+
DWORD attribute_id;
|
227
|
+
VALUE rbFinalAttributeValue;
|
228
|
+
|
214
229
|
Data_Get_Struct(self, struct SCardHandleEx, card);
|
215
230
|
if(card == NULL) return self;
|
216
231
|
|
217
|
-
|
232
|
+
attribute_id = NUM2UINT(rbAttributeId);
|
218
233
|
|
219
|
-
|
234
|
+
rbFinalAttributeValue = rb_check_string_type(rbAttributeValue);
|
220
235
|
if(NIL_P(rbFinalAttributeValue)) {
|
221
236
|
rb_raise(rb_eArgError, "second argument (attribute buffer) does not convert to a String");
|
222
237
|
return self;
|
@@ -242,35 +257,38 @@ static VALUE PCSC_Card_set_attribute(VALUE self, VALUE rbAttributeId, VALUE rbAt
|
|
242
257
|
* +recv_io_request+:: Smartcard::PCSC::IoRequest instance receving information about the recv protocol; you can use the result of Smartcard::PCSC::IoRequest#new
|
243
258
|
*/
|
244
259
|
static VALUE PCSC_Card_transmit(VALUE self, VALUE rbSendData, VALUE rbSendIoRequest, VALUE rbRecvIoRequest) {
|
245
|
-
struct SCardHandleEx *card;
|
260
|
+
struct SCardHandleEx *card;
|
261
|
+
VALUE rbFinalSendData, rbRecvData;
|
262
|
+
SCARD_IO_REQUEST *send_io_request, *recv_io_request;
|
263
|
+
char *recv_buffer;
|
264
|
+
DWORD recv_length;
|
265
|
+
|
246
266
|
Data_Get_Struct(self, struct SCardHandleEx, card);
|
247
267
|
if(card == NULL) return Qnil;
|
248
268
|
|
249
|
-
|
269
|
+
rbFinalSendData = rb_check_string_type(rbSendData);
|
250
270
|
if(NIL_P(rbFinalSendData)) {
|
251
271
|
rb_raise(rb_eArgError, "first argument (send buffer) does not convert to a String");
|
252
272
|
return Qnil;
|
253
273
|
}
|
254
274
|
|
255
|
-
SCARD_IO_REQUEST *send_io_request;
|
256
275
|
if(_PCSC_IoRequest_lowlevel_get(rbSendIoRequest, &send_io_request) == 0) {
|
257
276
|
rb_raise(rb_eArgError, "second argument (send io request) is not an IoRequest instance");
|
258
277
|
return Qnil;
|
259
278
|
}
|
260
|
-
SCARD_IO_REQUEST *recv_io_request;
|
261
279
|
if(_PCSC_IoRequest_lowlevel_get(rbRecvIoRequest, &recv_io_request) == 0) {
|
262
280
|
rb_raise(rb_eArgError, "second argument (recv io request) is not an IoRequest instance");
|
263
281
|
return Qnil;
|
264
282
|
}
|
265
283
|
|
266
284
|
#if defined(PCSCLITE_MAX_MESSAGE_SIZE)
|
267
|
-
|
285
|
+
recv_length = PCSCLITE_MAX_MESSAGE_SIZE;
|
268
286
|
#elif defined(MAX_BUFFER_SIZE_EXTENDED)
|
269
|
-
|
287
|
+
recv_length = MAX_BUFFER_SIZE_EXTENDED;
|
270
288
|
#else
|
271
|
-
|
289
|
+
recv_length = 65536;
|
272
290
|
#endif
|
273
|
-
|
291
|
+
recv_buffer = ALLOC_N(char, recv_length);
|
274
292
|
if(recv_buffer == NULL) return Qnil;
|
275
293
|
|
276
294
|
card->pcsc_error = SCardTransmit(card->card_handle, send_io_request,
|
@@ -282,7 +300,7 @@ static VALUE PCSC_Card_transmit(VALUE self, VALUE rbSendData, VALUE rbSendIoRequ
|
|
282
300
|
return Qnil;
|
283
301
|
}
|
284
302
|
|
285
|
-
|
303
|
+
rbRecvData = rb_str_new(recv_buffer, recv_length);
|
286
304
|
xfree(recv_buffer);
|
287
305
|
return rbRecvData;
|
288
306
|
}
|
@@ -308,18 +326,22 @@ static VALUE PCSC_Card_transmit(VALUE self, VALUE rbSendData, VALUE rbSendIoRequ
|
|
308
326
|
*/
|
309
327
|
static VALUE PCSC_Card_control(VALUE self, VALUE rbControlCode, VALUE rbSendData, VALUE rbMaxRecvBytes) {
|
310
328
|
struct SCardHandleEx *card;
|
329
|
+
VALUE rbFinalSendData, rbRecvData;
|
330
|
+
char *recv_buffer;
|
331
|
+
DWORD control_code, recv_length;
|
332
|
+
|
311
333
|
Data_Get_Struct(self, struct SCardHandleEx, card);
|
312
334
|
if(card == NULL) return Qnil;
|
313
335
|
|
314
|
-
|
336
|
+
rbFinalSendData = rb_check_string_type(rbSendData);
|
315
337
|
if(NIL_P(rbFinalSendData)) {
|
316
338
|
rb_raise(rb_eArgError, "second argument (send buffer) does not convert to a String");
|
317
339
|
return Qnil;
|
318
340
|
}
|
319
341
|
|
320
|
-
|
321
|
-
|
322
|
-
|
342
|
+
control_code = NUM2UINT(rbControlCode);
|
343
|
+
recv_length = NUM2UINT(rbMaxRecvBytes);
|
344
|
+
recv_buffer = ALLOC_N(char, recv_length);
|
323
345
|
if(recv_buffer == NULL) return Qnil;
|
324
346
|
|
325
347
|
card->pcsc_error = SCardControl(card->card_handle, control_code,
|
@@ -331,7 +353,7 @@ static VALUE PCSC_Card_control(VALUE self, VALUE rbControlCode, VALUE rbSendData
|
|
331
353
|
return Qnil;
|
332
354
|
}
|
333
355
|
|
334
|
-
|
356
|
+
rbRecvData = rb_str_new(recv_buffer, recv_length);
|
335
357
|
xfree(recv_buffer);
|
336
358
|
return rbRecvData;
|
337
359
|
}
|
@@ -352,21 +374,24 @@ static VALUE _rbStateKey, _rbProtocolKey, _rbAtrKey, _rbReaderNamesKey;
|
|
352
374
|
* <tt>:reader_names</tt> :: array of strings containing all the names of the reader containing the smartcard
|
353
375
|
*/
|
354
376
|
static VALUE PCSC_Card_status(VALUE self) {
|
355
|
-
struct SCardHandleEx *card;
|
377
|
+
struct SCardHandleEx *card;
|
378
|
+
char *atr_buffer, *reader_names_buffer;
|
379
|
+
DWORD atr_length, reader_names_length, state, protocol;
|
380
|
+
VALUE rbStateVal, rbProtocolVal, rbAtrVal, rbReaderNamesVal, rbReturnHash;
|
381
|
+
|
356
382
|
Data_Get_Struct(self, struct SCardHandleEx, card);
|
357
383
|
if(card == NULL) return Qnil;
|
358
384
|
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
385
|
+
atr_length = MAX_ATR_SIZE;
|
386
|
+
atr_buffer = ALLOC_N(char, atr_length);
|
387
|
+
reader_names_length = 4096;
|
388
|
+
reader_names_buffer = ALLOC_N(char, reader_names_length);
|
363
389
|
if(atr_buffer == NULL || reader_names_buffer == NULL) {
|
364
390
|
if(reader_names_buffer != NULL) xfree(reader_names_buffer);
|
365
391
|
if(atr_buffer != NULL) xfree(atr_buffer);
|
366
392
|
return Qnil;
|
367
393
|
}
|
368
394
|
|
369
|
-
DWORD state, protocol;
|
370
395
|
card->pcsc_error = SCardStatus(card->card_handle, reader_names_buffer, &reader_names_length, &state, &protocol, (LPSTR)atr_buffer, &atr_length);
|
371
396
|
if(card->pcsc_error != SCARD_S_SUCCESS) {
|
372
397
|
xfree(reader_names_buffer); xfree(atr_buffer);
|
@@ -374,12 +399,12 @@ static VALUE PCSC_Card_status(VALUE self) {
|
|
374
399
|
return Qnil;
|
375
400
|
}
|
376
401
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
402
|
+
rbStateVal = UINT2NUM(state);
|
403
|
+
rbProtocolVal = UINT2NUM(protocol);
|
404
|
+
rbAtrVal = rb_str_new(atr_buffer, atr_length);
|
405
|
+
rbReaderNamesVal = PCSC_Internal_multistring_to_ruby_array(reader_names_buffer, reader_names_length);
|
381
406
|
|
382
|
-
|
407
|
+
rbReturnHash = rb_hash_new();
|
383
408
|
rb_hash_aset(rbReturnHash, _rbStateKey, rbStateVal);
|
384
409
|
rb_hash_aset(rbReturnHash, _rbProtocolKey, rbProtocolVal);
|
385
410
|
rb_hash_aset(rbReturnHash, _rbAtrKey, rbAtrVal);
|
@@ -398,6 +423,7 @@ static VALUE PCSC_Card_status(VALUE self) {
|
|
398
423
|
*/
|
399
424
|
static VALUE PCSC_Card_last_error(VALUE self) {
|
400
425
|
struct SCardHandleEx *card;
|
426
|
+
|
401
427
|
Data_Get_Struct(self, struct SCardHandleEx, card);
|
402
428
|
if(card == NULL) return Qnil;
|
403
429
|
|
@@ -414,16 +440,18 @@ static VALUE PCSC_Card_last_error(VALUE self) {
|
|
414
440
|
* Wraps a _SCARDHANDLE_ structure.
|
415
441
|
*/
|
416
442
|
void Init_PCSC_Card() {
|
417
|
-
ID state_id
|
418
|
-
|
419
|
-
|
420
|
-
|
443
|
+
ID state_id, protocol_id, atr_id, reader_names_id;
|
444
|
+
|
445
|
+
state_id = rb_intern("status"); _rbStateKey = ID2SYM(state_id);
|
446
|
+
protocol_id = rb_intern("protocol"); _rbProtocolKey = ID2SYM(protocol_id);
|
447
|
+
atr_id = rb_intern("atr"); _rbAtrKey = ID2SYM(atr_id);
|
448
|
+
reader_names_id = rb_intern("reader_names"); _rbReaderNamesKey = ID2SYM(reader_names_id);
|
421
449
|
|
422
450
|
cPcscCard = rb_define_class_under(mPcsc, "Card", rb_cObject);
|
423
451
|
rb_define_alloc_func(cPcscCard, PCSC_Card_alloc);
|
424
452
|
rb_define_method(cPcscCard, "initialize", PCSC_Card_initialize, 4);
|
425
|
-
rb_define_method(cPcscCard, "reconnect", PCSC_Card_reconnect, 3);
|
426
453
|
rb_define_method(cPcscCard, "disconnect", PCSC_Card_disconnect, 1);
|
454
|
+
rb_define_method(cPcscCard, "reconnect", PCSC_Card_reconnect, 3);
|
427
455
|
rb_define_method(cPcscCard, "begin_transaction", PCSC_Card_begin_transaction, 0);
|
428
456
|
rb_define_method(cPcscCard, "end_transaction", PCSC_Card_end_transaction, 1);
|
429
457
|
rb_define_method(cPcscCard, "get_attribute", PCSC_Card_get_attribute, 1);
|
@@ -436,10 +464,11 @@ void Init_PCSC_Card() {
|
|
436
464
|
|
437
465
|
/* Retrieves the SCARDHANDLE wrapped into a Smartcard::PCSC::Card instance. */
|
438
466
|
int _PCSC_Card_lowlevel_get(VALUE rbCard, SCARDHANDLE *card_handle) {
|
467
|
+
struct SCardHandleEx *card;
|
468
|
+
|
439
469
|
if(TYPE(rbCard) != T_DATA || RDATA(rbCard)->dfree != (void (*)(void *))PCSC_Card_free)
|
440
470
|
return 0;
|
441
471
|
|
442
|
-
struct SCardHandleEx *card;
|
443
472
|
Data_Get_Struct(rbCard, struct SCardHandleEx, card);
|
444
473
|
*card_handle = card->card_handle;
|
445
474
|
return 1;
|
@@ -133,16 +133,20 @@ void Init_PCSC_Consts() {
|
|
133
133
|
/* SCARD_SPECIFIC : PTS has been set. */
|
134
134
|
rb_define_const(mPcsc, "STATUS_SPECIFIC", INT2NUM(SCARD_SPECIFIC));
|
135
135
|
|
136
|
+
#if defined(SCARD_PROTOCOL_UNSET)
|
136
137
|
/* SCARD_PROTOCOL_UNSET : Protocol not set. */
|
137
138
|
rb_define_const(mPcsc, "PROTOCOL_UNSET", INT2NUM(SCARD_PROTOCOL_UNSET));
|
139
|
+
#endif /* SCARD_PROTOCOL_UNSET */
|
138
140
|
/* SCARD_PROTOCOL_T0 : T=0 active protocol. */
|
139
141
|
rb_define_const(mPcsc, "PROTOCOL_T0", INT2NUM(SCARD_PROTOCOL_T0));
|
140
142
|
/* SCARD_PROTOCOL_T1 : T=1 active protocol. */
|
141
143
|
rb_define_const(mPcsc, "PROTOCOL_T1", INT2NUM(SCARD_PROTOCOL_T1));
|
142
144
|
/* SCARD_PROTOCOL_RAW : Raw active protocol. */
|
143
145
|
rb_define_const(mPcsc, "PROTOCOL_RAW", INT2NUM(SCARD_PROTOCOL_RAW));
|
146
|
+
#if defined(SCARD_PROTOCOL_UNSET)
|
144
147
|
/* SCARD_PROTOCOL_T15 : T=15 protocol. */
|
145
148
|
rb_define_const(mPcsc, "PROTOCOL_T15", INT2NUM(SCARD_PROTOCOL_T15));
|
149
|
+
#endif /* SCARD_PROTOCOL_UNSET */
|
146
150
|
/* SCARD_PROTOCOL_ANY : IFD determines protocol. */
|
147
151
|
rb_define_const(mPcsc, "PROTOCOL_ANY", INT2NUM(SCARD_PROTOCOL_ANY));
|
148
152
|
|
@@ -40,6 +40,7 @@ static VALUE PCSC_Context_alloc(VALUE klass) {
|
|
40
40
|
*/
|
41
41
|
static VALUE PCSC_Context_initialize(VALUE self, VALUE scope) {
|
42
42
|
struct SCardContextEx *context;
|
43
|
+
|
43
44
|
Data_Get_Struct(self, struct SCardContextEx, context);
|
44
45
|
|
45
46
|
context->pcsc_error = SCardEstablishContext(NUM2INT(scope), NULL, NULL, &context->pcsc_context);
|
@@ -60,6 +61,7 @@ static VALUE PCSC_Context_initialize(VALUE self, VALUE scope) {
|
|
60
61
|
*/
|
61
62
|
static VALUE PCSC_Context_release(VALUE self) {
|
62
63
|
struct SCardContextEx *context;
|
64
|
+
|
63
65
|
Data_Get_Struct(self, struct SCardContextEx, context);
|
64
66
|
if(context == NULL) return self;
|
65
67
|
|
@@ -87,8 +89,8 @@ static VALUE PCSC_Context_is_valid(VALUE self) {
|
|
87
89
|
Data_Get_Struct(self, struct SCardContextEx, context);
|
88
90
|
if(context == NULL) return self;
|
89
91
|
|
90
|
-
|
91
|
-
return (pcsc_error == SCARD_S_SUCCESS) ? Qtrue : Qfalse;
|
92
|
+
context->pcsc_error = SCardIsValidContext(context->pcsc_context);
|
93
|
+
return (context->pcsc_error == SCARD_S_SUCCESS) ? Qtrue : Qfalse;
|
92
94
|
}
|
93
95
|
|
94
96
|
/* :Document-method: list_reader_groups
|
@@ -101,18 +103,21 @@ static VALUE PCSC_Context_is_valid(VALUE self) {
|
|
101
103
|
* Returns an array of strings containing the names of all the smart-card readers in the system.
|
102
104
|
*/
|
103
105
|
static VALUE PCSC_Context_list_reader_groups(VALUE self) {
|
104
|
-
struct SCardContextEx *context;
|
106
|
+
struct SCardContextEx *context;
|
107
|
+
VALUE rbGroups;
|
108
|
+
char *groups;
|
109
|
+
DWORD groups_length;
|
110
|
+
|
105
111
|
Data_Get_Struct(self, struct SCardContextEx, context);
|
106
112
|
if(context == NULL) return Qnil;
|
107
113
|
|
108
|
-
DWORD groups_length;
|
109
114
|
context->pcsc_error = SCardListReaderGroups(context->pcsc_context, NULL, &groups_length);
|
110
115
|
if(context->pcsc_error == SCARD_S_SUCCESS) {
|
111
|
-
|
116
|
+
groups = ALLOC_N(char, groups_length);
|
112
117
|
if(groups != NULL) {
|
113
118
|
context->pcsc_error = SCardListReaderGroups(context->pcsc_context, groups, &groups_length);
|
114
119
|
if(context->pcsc_error == SCARD_S_SUCCESS) {
|
115
|
-
|
120
|
+
rbGroups = PCSC_Internal_multistring_to_ruby_array(groups, groups_length);
|
116
121
|
xfree(groups);
|
117
122
|
return rbGroups;
|
118
123
|
}
|
@@ -137,24 +142,26 @@ static VALUE PCSC_Context_list_reader_groups(VALUE self) {
|
|
137
142
|
* +reader_groups+:: array of strings indicating the reader groups to list; also accepts a string or +nil+ (meaning all readers)
|
138
143
|
*/
|
139
144
|
static VALUE PCSC_Context_list_readers(VALUE self, VALUE rbGroups) {
|
140
|
-
struct SCardContextEx *context;
|
145
|
+
struct SCardContextEx *context;
|
146
|
+
VALUE rbReaders;
|
147
|
+
char *groups;
|
148
|
+
DWORD readers_length;
|
149
|
+
|
141
150
|
Data_Get_Struct(self, struct SCardContextEx, context);
|
142
151
|
if(context == NULL) return Qnil;
|
143
152
|
|
144
|
-
char *groups;
|
145
153
|
if(PCSC_Internal_ruby_strings_to_multistring(rbGroups, &groups) == 0) {
|
146
154
|
rb_raise(rb_eArgError, "invalid reader groups set (expecting nil or string or array of strings)");
|
147
155
|
return Qnil;
|
148
156
|
}
|
149
157
|
|
150
|
-
DWORD readers_length;
|
151
158
|
context->pcsc_error = SCardListReaders(context->pcsc_context, groups, NULL, &readers_length);
|
152
159
|
if(context->pcsc_error == SCARD_S_SUCCESS) {
|
153
160
|
char *readers = ALLOC_N(char, readers_length);
|
154
161
|
if(readers != NULL) {
|
155
162
|
context->pcsc_error = SCardListReaders(context->pcsc_context, groups, readers, &readers_length);
|
156
163
|
if(context->pcsc_error == SCARD_S_SUCCESS) {
|
157
|
-
|
164
|
+
rbReaders = PCSC_Internal_multistring_to_ruby_array(readers, readers_length);
|
158
165
|
xfree(readers);
|
159
166
|
if(groups != NULL) xfree(groups);
|
160
167
|
return rbReaders;
|
@@ -177,7 +184,8 @@ static VALUE PCSC_Context_list_readers(VALUE self, VALUE rbGroups) {
|
|
177
184
|
* Wraps _SCardCancel_ in PC/SC.
|
178
185
|
*/
|
179
186
|
static VALUE PCSC_Context_cancel(VALUE self) {
|
180
|
-
struct SCardContextEx *context;
|
187
|
+
struct SCardContextEx *context;
|
188
|
+
|
181
189
|
Data_Get_Struct(self, struct SCardContextEx, context);
|
182
190
|
if(context == NULL) return self;
|
183
191
|
|
@@ -202,18 +210,19 @@ static VALUE PCSC_Context_cancel(VALUE self) {
|
|
202
210
|
* ReaderStates#set_event_state_of and ReaderStates#event_state_of)
|
203
211
|
*/
|
204
212
|
static VALUE PCSC_Context_get_status_change(VALUE self, VALUE rbReaderStates, VALUE rbTimeout) {
|
205
|
-
struct SCardContextEx *context;
|
213
|
+
struct SCardContextEx *context;
|
214
|
+
SCARD_READERSTATE *reader_states;
|
215
|
+
size_t reader_states_count;
|
216
|
+
DWORD timeout;
|
217
|
+
|
206
218
|
Data_Get_Struct(self, struct SCardContextEx, context);
|
207
219
|
if(context == NULL) return self;
|
208
220
|
|
209
|
-
unsigned int timeout;
|
210
221
|
if(TYPE(rbTimeout) == T_NIL || TYPE(rbTimeout) == T_FALSE)
|
211
222
|
timeout = INFINITE;
|
212
223
|
else
|
213
224
|
timeout = NUM2INT(rbTimeout);
|
214
225
|
|
215
|
-
SCARD_READERSTATE *reader_states;
|
216
|
-
size_t reader_states_count;
|
217
226
|
if(_PCSC_ReaderStates_lowlevel_get(rbReaderStates, &reader_states, &reader_states_count) == 0)
|
218
227
|
rb_raise(rb_eArgError, "first parameter is not a ReaderStates instance or nil");
|
219
228
|
else {
|
@@ -235,6 +244,7 @@ static VALUE PCSC_Context_get_status_change(VALUE self, VALUE rbReaderStates, VA
|
|
235
244
|
*/
|
236
245
|
static VALUE PCSC_Context_last_error(VALUE self) {
|
237
246
|
struct SCardContextEx *context;
|
247
|
+
|
238
248
|
Data_Get_Struct(self, struct SCardContextEx, context);
|
239
249
|
if(context == NULL) return Qnil;
|
240
250
|
|
@@ -265,10 +275,11 @@ void Init_PCSC_Context() {
|
|
265
275
|
|
266
276
|
/* Retrieves the SCARDCONTEXT wrapped into a Smartcard::PCSC::Context instance. */
|
267
277
|
int _PCSC_Context_lowlevel_get(VALUE rbContext, SCARDCONTEXT *pcsc_context) {
|
278
|
+
struct SCardContextEx *context;
|
279
|
+
|
268
280
|
if(TYPE(rbContext) != T_DATA || RDATA(rbContext)->dfree != (void (*)(void *))PCSC_Context_free)
|
269
281
|
return 0;
|
270
282
|
|
271
|
-
struct SCardContextEx *context;
|
272
283
|
Data_Get_Struct(rbContext, struct SCardContextEx, context);
|
273
284
|
*pcsc_context = context->pcsc_context;
|
274
285
|
return 1;
|
@@ -26,6 +26,7 @@ static VALUE PCSC_IoRequest_alloc(VALUE klass) {
|
|
26
26
|
*/
|
27
27
|
static VALUE PCSC_IoRequest_get_protocol(VALUE self) {
|
28
28
|
SCARD_IO_REQUEST *request;
|
29
|
+
|
29
30
|
Data_Get_Struct(self, SCARD_IO_REQUEST, request);
|
30
31
|
if(request == NULL) return Qnil;
|
31
32
|
|
@@ -42,6 +43,7 @@ static VALUE PCSC_IoRequest_get_protocol(VALUE self) {
|
|
42
43
|
*/
|
43
44
|
static VALUE PCSC_IoRequest_set_protocol(VALUE self, VALUE rbProtocol) {
|
44
45
|
SCARD_IO_REQUEST *request;
|
46
|
+
|
45
47
|
Data_Get_Struct(self, SCARD_IO_REQUEST, request);
|
46
48
|
if(request == NULL) return self;
|
47
49
|
|
@@ -70,6 +72,8 @@ void Init_PCSC_IoRequest() {
|
|
70
72
|
|
71
73
|
/* Retrieves the SCARD_IO_REQUEST wrapped into a Smartcard::PCSC::IoRequest instance. */
|
72
74
|
int _PCSC_IoRequest_lowlevel_get(VALUE rbIoRequest, SCARD_IO_REQUEST **io_request) {
|
75
|
+
SCARD_IO_REQUEST *request;
|
76
|
+
|
73
77
|
if(TYPE(rbIoRequest) == T_NIL || TYPE(rbIoRequest) == T_FALSE) {
|
74
78
|
*io_request = NULL;
|
75
79
|
return 1;
|
@@ -77,7 +81,6 @@ int _PCSC_IoRequest_lowlevel_get(VALUE rbIoRequest, SCARD_IO_REQUEST **io_reques
|
|
77
81
|
if(TYPE(rbIoRequest) != T_DATA || RDATA(rbIoRequest)->dfree != (void (*)(void *))PCSC_IoRequest_free)
|
78
82
|
return 0;
|
79
83
|
|
80
|
-
SCARD_IO_REQUEST *request;
|
81
84
|
Data_Get_Struct(rbIoRequest, SCARD_IO_REQUEST, request);
|
82
85
|
*io_request = request;
|
83
86
|
return 1;
|
@@ -3,14 +3,16 @@
|
|
3
3
|
|
4
4
|
/* Converts a multi-string "str1\0str_2\0str3\0\0" into a Ruby array of Ruby strings. */
|
5
5
|
VALUE PCSC_Internal_multistring_to_ruby_array(char *mstr, size_t mstr_len) {
|
6
|
-
VALUE rbArray
|
7
|
-
|
8
|
-
|
6
|
+
VALUE rbArray, rbString;
|
7
|
+
size_t i, start_offset;
|
8
|
+
|
9
|
+
rbArray = rb_ary_new();
|
10
|
+
for(i = 0; i < mstr_len; i++) {
|
9
11
|
if(mstr[i] == '\0') break;
|
10
|
-
|
12
|
+
start_offset = i;
|
11
13
|
for(; i < mstr_len; i++)
|
12
14
|
if(mstr[i] == '\0') break;
|
13
|
-
|
15
|
+
rbString = rb_str_new(mstr + start_offset, i - start_offset);
|
14
16
|
rb_ary_push(rbArray, rbString);
|
15
17
|
}
|
16
18
|
return rbArray;
|
@@ -21,6 +23,10 @@ VALUE PCSC_Internal_multistring_to_ruby_array(char *mstr, size_t mstr_len) {
|
|
21
23
|
* If false is returned, something went wrong and the method did not return a buffer.
|
22
24
|
*/
|
23
25
|
int PCSC_Internal_ruby_strings_to_multistring(VALUE rbStrings, char **strings) {
|
26
|
+
VALUE *array_elements;
|
27
|
+
char *buffer;
|
28
|
+
size_t string_length, array_length, buffer_length, i;
|
29
|
+
|
24
30
|
/* nil -> NULL */
|
25
31
|
if(TYPE(rbStrings) == T_NIL || TYPE(rbStrings) == T_FALSE) {
|
26
32
|
*strings = NULL;
|
@@ -28,8 +34,8 @@ int PCSC_Internal_ruby_strings_to_multistring(VALUE rbStrings, char **strings) {
|
|
28
34
|
}
|
29
35
|
/* string -> [string] */
|
30
36
|
if(TYPE(rbStrings) == T_STRING) {
|
31
|
-
|
32
|
-
|
37
|
+
string_length = RSTRING(rbStrings)->len;
|
38
|
+
buffer = ALLOC_N(char, string_length + 2);
|
33
39
|
memcpy(buffer, RSTRING(rbStrings)->ptr, string_length);
|
34
40
|
buffer[string_length] = buffer[string_length + 1] = '\0';
|
35
41
|
*strings = buffer;
|
@@ -38,20 +44,19 @@ int PCSC_Internal_ruby_strings_to_multistring(VALUE rbStrings, char **strings) {
|
|
38
44
|
/* array -> array */
|
39
45
|
if(TYPE(rbStrings) == T_ARRAY) {
|
40
46
|
/* compute buffer length */
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
for(; i < array_length; i++) {
|
47
|
+
array_length = RARRAY(rbStrings)->len;
|
48
|
+
array_elements = RARRAY(rbStrings)->ptr;
|
49
|
+
buffer_length = 1; /* for the trailing '\0' */
|
50
|
+
for(i = 0; i < array_length; i++) {
|
46
51
|
if(TYPE(array_elements[i]) != T_STRING)
|
47
52
|
return 0;
|
48
53
|
buffer_length += RSTRING(array_elements[i])->len + 1;
|
49
54
|
}
|
50
55
|
|
51
56
|
/* concatenate strings into buffer */
|
52
|
-
|
57
|
+
buffer = ALLOC_N(char, buffer_length);
|
53
58
|
for(buffer_length = 0, i = 0; i < array_length; i++) {
|
54
|
-
|
59
|
+
string_length = RSTRING(array_elements[i])->len;
|
55
60
|
memcpy(buffer + buffer_length, RSTRING(array_elements[i])->ptr, string_length);
|
56
61
|
buffer[buffer_length] = '\0';
|
57
62
|
buffer_length += string_length + 1;
|
@@ -63,3 +68,15 @@ int PCSC_Internal_ruby_strings_to_multistring(VALUE rbStrings, char **strings) {
|
|
63
68
|
|
64
69
|
return 0;
|
65
70
|
}
|
71
|
+
|
72
|
+
#if defined(WIN32)
|
73
|
+
char scard_error_buffer[128];
|
74
|
+
|
75
|
+
/* Produces a string for an error code yielded by the SCard* PC/SC functions. Returns a static global buffer. */
|
76
|
+
char *pcsc_stringify_error(DWORD scard_error) {
|
77
|
+
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
78
|
+
NULL, scard_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
79
|
+
scard_error_buffer, sizeof(scard_error_buffer), NULL );
|
80
|
+
return scard_error_buffer;
|
81
|
+
}
|
82
|
+
#endif
|
@@ -10,10 +10,10 @@ struct PCSCReaderStates {
|
|
10
10
|
|
11
11
|
/* Custom free for Smartcard::PCSC::ReaderStates. Also releases the referenced buffers (for the reader names). */
|
12
12
|
static void PCSC_ReaderStates_free(struct PCSCReaderStates *_states) {
|
13
|
+
size_t i;
|
13
14
|
if(_states != NULL) {
|
14
15
|
if(_states->states != NULL) {
|
15
|
-
|
16
|
-
for(; i < _states->states_count; i++) {
|
16
|
+
for(i = 0; i < _states->states_count; i++) {
|
17
17
|
if(_states->states[i].szReader != NULL)
|
18
18
|
xfree((char *)_states->states[i].szReader);
|
19
19
|
}
|
@@ -42,15 +42,16 @@ static VALUE PCSC_ReaderStates_alloc(VALUE klass) {
|
|
42
42
|
*/
|
43
43
|
static VALUE PCSC_ReaderStates_initialize(VALUE self, VALUE rbNumStates) {
|
44
44
|
struct PCSCReaderStates *states;
|
45
|
+
size_t states_count, i;
|
46
|
+
|
45
47
|
Data_Get_Struct(self, struct PCSCReaderStates, states);
|
46
48
|
|
47
|
-
|
49
|
+
states_count = NUM2UINT(rbNumStates);
|
48
50
|
if(states_count > 0) {
|
49
51
|
states->states = ALLOC_N(SCARD_READERSTATE, states_count);
|
50
52
|
if(states->states != NULL) {
|
51
53
|
states->states_count = states_count;
|
52
|
-
|
53
|
-
for(; i < states_count; i++) {
|
54
|
+
for(i = 0; i < states_count; i++) {
|
54
55
|
states->states[i].szReader = NULL;
|
55
56
|
states->states[i].dwCurrentState = SCARD_STATE_UNAWARE;
|
56
57
|
}
|
@@ -86,6 +87,7 @@ static int _validate_readerstates_args(VALUE rbReaderStates, VALUE rbIndex, stru
|
|
86
87
|
static VALUE PCSC_ReaderStates_current_state_of(VALUE self, VALUE rbIndex) {
|
87
88
|
struct PCSCReaderStates *states;
|
88
89
|
size_t index;
|
90
|
+
|
89
91
|
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
90
92
|
return Qnil;
|
91
93
|
|
@@ -106,6 +108,7 @@ static VALUE PCSC_ReaderStates_current_state_of(VALUE self, VALUE rbIndex) {
|
|
106
108
|
static VALUE PCSC_ReaderStates_event_state_of(VALUE self, VALUE rbIndex) {
|
107
109
|
struct PCSCReaderStates *states;
|
108
110
|
size_t index;
|
111
|
+
|
109
112
|
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
110
113
|
return Qnil;
|
111
114
|
|
@@ -126,6 +129,7 @@ static VALUE PCSC_ReaderStates_event_state_of(VALUE self, VALUE rbIndex) {
|
|
126
129
|
static VALUE PCSC_ReaderStates_set_current_state_of(VALUE self, VALUE rbIndex, VALUE rbCurrentState) {
|
127
130
|
struct PCSCReaderStates *states;
|
128
131
|
size_t index;
|
132
|
+
|
129
133
|
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
130
134
|
return self;
|
131
135
|
|
@@ -146,6 +150,7 @@ static VALUE PCSC_ReaderStates_set_current_state_of(VALUE self, VALUE rbIndex, V
|
|
146
150
|
static VALUE PCSC_ReaderStates_set_event_state_of(VALUE self, VALUE rbIndex, VALUE rbEventState) {
|
147
151
|
struct PCSCReaderStates *states;
|
148
152
|
size_t index;
|
153
|
+
|
149
154
|
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
150
155
|
return self;
|
151
156
|
|
@@ -167,6 +172,7 @@ static VALUE PCSC_ReaderStates_set_event_state_of(VALUE self, VALUE rbIndex, VAL
|
|
167
172
|
static VALUE PCSC_ReaderStates_atr_of(VALUE self, VALUE rbIndex) {
|
168
173
|
struct PCSCReaderStates *states;
|
169
174
|
size_t index;
|
175
|
+
|
170
176
|
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
171
177
|
return Qnil;
|
172
178
|
|
@@ -186,10 +192,12 @@ static VALUE PCSC_ReaderStates_atr_of(VALUE self, VALUE rbIndex) {
|
|
186
192
|
static VALUE PCSC_ReaderStates_set_atr_of(VALUE self, VALUE rbIndex, VALUE rbAtr) {
|
187
193
|
struct PCSCReaderStates *states;
|
188
194
|
size_t index;
|
195
|
+
VALUE rbFinalAtr;
|
196
|
+
|
189
197
|
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
190
198
|
return self;
|
191
199
|
|
192
|
-
|
200
|
+
rbFinalAtr = rb_check_string_type(rbAtr);
|
193
201
|
if(NIL_P(rbFinalAtr))
|
194
202
|
return self;
|
195
203
|
|
@@ -215,6 +223,7 @@ static VALUE PCSC_ReaderStates_set_atr_of(VALUE self, VALUE rbIndex, VALUE rbAtr
|
|
215
223
|
static VALUE PCSC_ReaderStates_reader_name_of(VALUE self, VALUE rbIndex) {
|
216
224
|
struct PCSCReaderStates *states;
|
217
225
|
size_t index;
|
226
|
+
|
218
227
|
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
219
228
|
return Qnil;
|
220
229
|
|
@@ -233,15 +242,17 @@ static VALUE PCSC_ReaderStates_reader_name_of(VALUE self, VALUE rbIndex) {
|
|
233
242
|
*/
|
234
243
|
static VALUE PCSC_ReaderStates_set_reader_name_of(VALUE self, VALUE rbIndex, VALUE rbReaderName) {
|
235
244
|
struct PCSCReaderStates *states;
|
236
|
-
size_t index;
|
245
|
+
size_t index, reader_name_length;
|
246
|
+
VALUE rbFinalReaderName;
|
247
|
+
|
237
248
|
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
238
249
|
return self;
|
239
250
|
|
240
|
-
|
251
|
+
rbFinalReaderName = rb_check_string_type(rbReaderName);
|
241
252
|
if(NIL_P(rbFinalReaderName))
|
242
253
|
return self;
|
243
254
|
|
244
|
-
|
255
|
+
reader_name_length = RSTRING(rbFinalReaderName)->len;
|
245
256
|
if(states->states[index].szReader != NULL)
|
246
257
|
xfree((char *)states->states[index].szReader);
|
247
258
|
states->states[index].szReader = ALLOC_N(char, reader_name_length + 1);
|
@@ -261,11 +272,12 @@ static VALUE PCSC_ReaderStates_set_reader_name_of(VALUE self, VALUE rbIndex, VAL
|
|
261
272
|
* (and thus prepare for a new call).
|
262
273
|
*/
|
263
274
|
static VALUE PCSC_ReaderStates_acknowledge_events(VALUE self) {
|
264
|
-
struct PCSCReaderStates *states;
|
275
|
+
struct PCSCReaderStates *states;
|
276
|
+
size_t i;
|
277
|
+
|
265
278
|
Data_Get_Struct(self, struct PCSCReaderStates, states);
|
266
279
|
if(states != NULL) {
|
267
|
-
|
268
|
-
for(; i < states->states_count; i++)
|
280
|
+
for(i = 0; i < states->states_count; i++)
|
269
281
|
states->states[i].dwCurrentState = states->states[i].dwEventState;
|
270
282
|
}
|
271
283
|
return self;
|
@@ -297,6 +309,8 @@ void Init_PCSC_ReaderStates() {
|
|
297
309
|
|
298
310
|
/* Retrieves the SCARD_READERSTATE array wrapped into a Smartcard::PCSC::ReaderStates instance. */
|
299
311
|
int _PCSC_ReaderStates_lowlevel_get(VALUE rbReaderStates, SCARD_READERSTATE **reader_states, size_t *reader_states_count) {
|
312
|
+
struct PCSCReaderStates *states;
|
313
|
+
|
300
314
|
if(TYPE(rbReaderStates) == T_NIL || TYPE(rbReaderStates) == T_FALSE) {
|
301
315
|
*reader_states = NULL;
|
302
316
|
*reader_states_count = 0;
|
@@ -305,7 +319,6 @@ int _PCSC_ReaderStates_lowlevel_get(VALUE rbReaderStates, SCARD_READERSTATE **re
|
|
305
319
|
if(TYPE(rbReaderStates) != T_DATA || RDATA(rbReaderStates)->dfree != (void (*)(void *))PCSC_ReaderStates_free)
|
306
320
|
return 0;
|
307
321
|
|
308
|
-
struct PCSCReaderStates *states;
|
309
322
|
Data_Get_Struct(rbReaderStates, struct PCSCReaderStates, states);
|
310
323
|
*reader_states = states->states;
|
311
324
|
*reader_states_count = states->states_count;
|
data/smartcard.gemspec
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
# Gem::Specification for Smartcard-0.2.0
|
3
|
+
# Originally generated by Echoe
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = %q{smartcard}
|
7
|
+
s.version = "0.2.0"
|
8
|
+
s.date = %q{2007-11-18}
|
9
|
+
s.summary = %q{Interface with ISO 7816 smart cards.}
|
10
|
+
s.require_paths = ["lib", "ext"]
|
11
|
+
s.email = %q{victor@costan.us}
|
12
|
+
s.homepage = %q{http://www.costan.us/smartcard}
|
13
|
+
s.rubyforge_project = %q{smartcard}
|
14
|
+
s.description = %q{Interface with ISO 7816 smart cards.}
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.authors = ["Victor Costan"]
|
17
|
+
s.files = ["CHANGELOG", "ext/smartcard_pcsc/extconf.rb", "ext/smartcard_pcsc/pcsc.h", "ext/smartcard_pcsc/pcsc_card.c", "ext/smartcard_pcsc/pcsc_constants.c", "ext/smartcard_pcsc/pcsc_context.c", "ext/smartcard_pcsc/pcsc_io_request.c", "ext/smartcard_pcsc/pcsc_main.c", "ext/smartcard_pcsc/pcsc_multi_strings.c", "ext/smartcard_pcsc/pcsc_namespace.c", "ext/smartcard_pcsc/pcsc_reader_states.c", "ext/smartcard_pcsc/pcsc_surrogate_reader.h", "ext/smartcard_pcsc/pcsc_surrogate_wintypes.h", "lib/smartcard.rb", "LICENSE", "README", "test/test_all.rb", "tests/ts_pcsc_ext.rb", "Manifest", "smartcard.gemspec"]
|
18
|
+
s.test_files = ["test/test_all.rb"]
|
19
|
+
s.extensions = ["ext/smartcard_pcsc/extconf.rb"]
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# # Original Rakefile source (requires the Echoe gem):
|
24
|
+
#
|
25
|
+
# # Needs the 'echoe' gem
|
26
|
+
# require 'echoe'
|
27
|
+
#
|
28
|
+
# Echoe.new('smartcard') do |p|
|
29
|
+
# p.project = 'smartcard' # rubyforge project
|
30
|
+
#
|
31
|
+
# p.author = 'Victor Costan'
|
32
|
+
# p.email = 'victor@costan.us'
|
33
|
+
# p.summary = 'Interface with ISO 7816 smart cards.'
|
34
|
+
# p.url = 'http://www.costan.us/smartcard'
|
35
|
+
#
|
36
|
+
# p.need_tar_gz = false
|
37
|
+
# p.clean_pattern += ['ext/**/*.manifest', 'ext/**/*_autogen.h']
|
38
|
+
#
|
39
|
+
# p.eval = proc do |p|
|
40
|
+
# case RUBY_PLATFORM
|
41
|
+
# when /mswin/
|
42
|
+
# p.files += ['lib/smartcard/pcsc.so']
|
43
|
+
# p.platform = Gem::Platform::WIN32
|
44
|
+
#
|
45
|
+
# # take out the extension info from the gemspec
|
46
|
+
# task :postcompile_hacks => [:compile] do
|
47
|
+
# p.extensions.clear
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# task :package => [ :clean, :compile, :postcompile_hacks ]
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
# end
|
data/test/test_all.rb
ADDED
File without changes
|
metadata
CHANGED
@@ -3,16 +3,17 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: smartcard
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-11-
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2007-11-18 00:00:00 -05:00
|
8
8
|
summary: Interface with ISO 7816 smart cards.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
|
+
- ext
|
11
12
|
email: victor@costan.us
|
12
13
|
homepage: http://www.costan.us/smartcard
|
13
|
-
rubyforge_project:
|
14
|
-
description:
|
15
|
-
autorequire:
|
14
|
+
rubyforge_project: smartcard
|
15
|
+
description: Interface with ISO 7816 smart cards.
|
16
|
+
autorequire:
|
16
17
|
default_executable:
|
17
18
|
bindir: bin
|
18
19
|
has_rdoc: true
|
@@ -29,8 +30,7 @@ post_install_message:
|
|
29
30
|
authors:
|
30
31
|
- Victor Costan
|
31
32
|
files:
|
32
|
-
-
|
33
|
-
- ext/smartcard_pcsc
|
33
|
+
- CHANGELOG
|
34
34
|
- ext/smartcard_pcsc/extconf.rb
|
35
35
|
- ext/smartcard_pcsc/pcsc.h
|
36
36
|
- ext/smartcard_pcsc/pcsc_card.c
|
@@ -43,9 +43,15 @@ files:
|
|
43
43
|
- ext/smartcard_pcsc/pcsc_reader_states.c
|
44
44
|
- ext/smartcard_pcsc/pcsc_surrogate_reader.h
|
45
45
|
- ext/smartcard_pcsc/pcsc_surrogate_wintypes.h
|
46
|
+
- lib/smartcard.rb
|
47
|
+
- LICENSE
|
48
|
+
- README
|
49
|
+
- test/test_all.rb
|
46
50
|
- tests/ts_pcsc_ext.rb
|
47
|
-
|
48
|
-
|
51
|
+
- Manifest
|
52
|
+
- smartcard.gemspec
|
53
|
+
test_files:
|
54
|
+
- test/test_all.rb
|
49
55
|
rdoc_options: []
|
50
56
|
|
51
57
|
extra_rdoc_files: []
|