smartcard 0.2.0-mswin32
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 +53 -0
- data/ext/smartcard_pcsc/pcsc.h +46 -0
- data/ext/smartcard_pcsc/pcsc_card.c +475 -0
- data/ext/smartcard_pcsc/pcsc_constants.c +193 -0
- data/ext/smartcard_pcsc/pcsc_context.c +286 -0
- data/ext/smartcard_pcsc/pcsc_io_request.c +87 -0
- data/ext/smartcard_pcsc/pcsc_main.c +10 -0
- data/ext/smartcard_pcsc/pcsc_multi_strings.c +82 -0
- data/ext/smartcard_pcsc/pcsc_namespace.c +18 -0
- data/ext/smartcard_pcsc/pcsc_reader_states.c +326 -0
- data/ext/smartcard_pcsc/pcsc_surrogate_reader.h +207 -0
- data/ext/smartcard_pcsc/pcsc_surrogate_wintypes.h +63 -0
- data/lib/smartcard.rb +1 -0
- data/lib/smartcard/pcsc.so +0 -0
- data/smartcard.gemspec +53 -0
- data/test/test_all.rb +0 -0
- data/tests/ts_pcsc_ext.rb +135 -0
- metadata +67 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
#include "pcsc.h"
|
2
|
+
|
3
|
+
VALUE cPcscIoRequest;
|
4
|
+
|
5
|
+
/* Custom free for Smartcard::PCSC::IoRequest. */
|
6
|
+
static void PCSC_IoRequest_free(SCARD_IO_REQUEST *_request) {
|
7
|
+
if(_request != NULL)
|
8
|
+
xfree(_request);
|
9
|
+
}
|
10
|
+
|
11
|
+
/* Custom allocation for Smartcard::PCSC::Card. Wraps a SCARD_IO_REQUEST. */
|
12
|
+
static VALUE PCSC_IoRequest_alloc(VALUE klass) {
|
13
|
+
SCARD_IO_REQUEST *request;
|
14
|
+
|
15
|
+
VALUE rbIoRequest = Data_Make_Struct(klass, SCARD_IO_REQUEST, NULL, PCSC_IoRequest_free, request);
|
16
|
+
return rbIoRequest;
|
17
|
+
}
|
18
|
+
|
19
|
+
/* :Document-method: protocol
|
20
|
+
* call-seq:
|
21
|
+
* io_request.protocol --> protocol
|
22
|
+
*
|
23
|
+
* The protocol of this instance.
|
24
|
+
*
|
25
|
+
* The returned protocol is a number, and should be checked against one of the Smartcard::PCSC::PROTOCOL_ constants.
|
26
|
+
*/
|
27
|
+
static VALUE PCSC_IoRequest_get_protocol(VALUE self) {
|
28
|
+
SCARD_IO_REQUEST *request;
|
29
|
+
|
30
|
+
Data_Get_Struct(self, SCARD_IO_REQUEST, request);
|
31
|
+
if(request == NULL) return Qnil;
|
32
|
+
|
33
|
+
return UINT2NUM(request->dwProtocol);
|
34
|
+
}
|
35
|
+
|
36
|
+
/* :Document-method: protocol=
|
37
|
+
* call-seq:
|
38
|
+
* io_request.protocol = protocol
|
39
|
+
*
|
40
|
+
* Sets the protocol of this instance.
|
41
|
+
*
|
42
|
+
* +protocol+:: use one of the Smartcard::PCSC::PROTOCOL_ constants
|
43
|
+
*/
|
44
|
+
static VALUE PCSC_IoRequest_set_protocol(VALUE self, VALUE rbProtocol) {
|
45
|
+
SCARD_IO_REQUEST *request;
|
46
|
+
|
47
|
+
Data_Get_Struct(self, SCARD_IO_REQUEST, request);
|
48
|
+
if(request == NULL) return self;
|
49
|
+
|
50
|
+
request->dwProtocol = NUM2UINT(rbProtocol);
|
51
|
+
return self;
|
52
|
+
}
|
53
|
+
|
54
|
+
#ifdef MAKE_RDOC_HAPPY
|
55
|
+
mSmartcard = rb_define_module("Smartcard");
|
56
|
+
mPcsc = rb_define_module_under(mSmartcard, "PCSC");
|
57
|
+
#endif
|
58
|
+
|
59
|
+
/* :Document-class: Smartcard::PCSC::IoRequest
|
60
|
+
* Protocol information used in Smartcard::PCSC::Card#transmit.
|
61
|
+
* Wraps a _SCARD_IO_REQUEST_ structure.
|
62
|
+
*
|
63
|
+
* I know the name is retarded, but it reflects the PC/SC name well. The choice makes sense given that this
|
64
|
+
* is an API meant for people familiar with the PC/SC specification.
|
65
|
+
*/
|
66
|
+
void Init_PCSC_IoRequest() {
|
67
|
+
cPcscIoRequest = rb_define_class_under(mPcsc, "IoRequest", rb_cObject);
|
68
|
+
rb_define_alloc_func(cPcscIoRequest, PCSC_IoRequest_alloc);
|
69
|
+
rb_define_method(cPcscIoRequest, "protocol", PCSC_IoRequest_get_protocol, 0);
|
70
|
+
rb_define_method(cPcscIoRequest, "protocol=", PCSC_IoRequest_set_protocol, 1);
|
71
|
+
}
|
72
|
+
|
73
|
+
/* Retrieves the SCARD_IO_REQUEST wrapped into a Smartcard::PCSC::IoRequest instance. */
|
74
|
+
int _PCSC_IoRequest_lowlevel_get(VALUE rbIoRequest, SCARD_IO_REQUEST **io_request) {
|
75
|
+
SCARD_IO_REQUEST *request;
|
76
|
+
|
77
|
+
if(TYPE(rbIoRequest) == T_NIL || TYPE(rbIoRequest) == T_FALSE) {
|
78
|
+
*io_request = NULL;
|
79
|
+
return 1;
|
80
|
+
}
|
81
|
+
if(TYPE(rbIoRequest) != T_DATA || RDATA(rbIoRequest)->dfree != (void (*)(void *))PCSC_IoRequest_free)
|
82
|
+
return 0;
|
83
|
+
|
84
|
+
Data_Get_Struct(rbIoRequest, SCARD_IO_REQUEST, request);
|
85
|
+
*io_request = request;
|
86
|
+
return 1;
|
87
|
+
}
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#include <string.h>
|
2
|
+
#include "pcsc.h"
|
3
|
+
|
4
|
+
/* Converts a multi-string "str1\0str_2\0str3\0\0" into a Ruby array of Ruby strings. */
|
5
|
+
VALUE PCSC_Internal_multistring_to_ruby_array(char *mstr, size_t mstr_len) {
|
6
|
+
VALUE rbArray, rbString;
|
7
|
+
size_t i, start_offset;
|
8
|
+
|
9
|
+
rbArray = rb_ary_new();
|
10
|
+
for(i = 0; i < mstr_len; i++) {
|
11
|
+
if(mstr[i] == '\0') break;
|
12
|
+
start_offset = i;
|
13
|
+
for(; i < mstr_len; i++)
|
14
|
+
if(mstr[i] == '\0') break;
|
15
|
+
rbString = rb_str_new(mstr + start_offset, i - start_offset);
|
16
|
+
rb_ary_push(rbArray, rbString);
|
17
|
+
}
|
18
|
+
return rbArray;
|
19
|
+
}
|
20
|
+
|
21
|
+
/* Constructs a multi-string "str1\0str_2\0str3\0\0". Takes nil, a string, or an array of strings.
|
22
|
+
* The returned buffer must be released with xfree.
|
23
|
+
* If false is returned, something went wrong and the method did not return a buffer.
|
24
|
+
*/
|
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
|
+
|
30
|
+
/* nil -> NULL */
|
31
|
+
if(TYPE(rbStrings) == T_NIL || TYPE(rbStrings) == T_FALSE) {
|
32
|
+
*strings = NULL;
|
33
|
+
return 1;
|
34
|
+
}
|
35
|
+
/* string -> [string] */
|
36
|
+
if(TYPE(rbStrings) == T_STRING) {
|
37
|
+
string_length = RSTRING(rbStrings)->len;
|
38
|
+
buffer = ALLOC_N(char, string_length + 2);
|
39
|
+
memcpy(buffer, RSTRING(rbStrings)->ptr, string_length);
|
40
|
+
buffer[string_length] = buffer[string_length + 1] = '\0';
|
41
|
+
*strings = buffer;
|
42
|
+
return 1;
|
43
|
+
}
|
44
|
+
/* array -> array */
|
45
|
+
if(TYPE(rbStrings) == T_ARRAY) {
|
46
|
+
/* compute buffer length */
|
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++) {
|
51
|
+
if(TYPE(array_elements[i]) != T_STRING)
|
52
|
+
return 0;
|
53
|
+
buffer_length += RSTRING(array_elements[i])->len + 1;
|
54
|
+
}
|
55
|
+
|
56
|
+
/* concatenate strings into buffer */
|
57
|
+
buffer = ALLOC_N(char, buffer_length);
|
58
|
+
for(buffer_length = 0, i = 0; i < array_length; i++) {
|
59
|
+
string_length = RSTRING(array_elements[i])->len;
|
60
|
+
memcpy(buffer + buffer_length, RSTRING(array_elements[i])->ptr, string_length);
|
61
|
+
buffer[buffer_length] = '\0';
|
62
|
+
buffer_length += string_length + 1;
|
63
|
+
}
|
64
|
+
buffer[buffer_length] = '\0';
|
65
|
+
*strings = buffer;
|
66
|
+
return 1;
|
67
|
+
}
|
68
|
+
|
69
|
+
return 0;
|
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
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#include "pcsc.h"
|
2
|
+
|
3
|
+
VALUE mSmartcard;
|
4
|
+
VALUE mPcsc;
|
5
|
+
|
6
|
+
/* :Document-class: Smartcard::PCSC
|
7
|
+
* Bindings to the PC/SC Smartcard API.
|
8
|
+
*
|
9
|
+
*/
|
10
|
+
static void Init_PCSC() {
|
11
|
+
mPcsc = rb_define_module_under(mSmartcard, "PCSC");
|
12
|
+
}
|
13
|
+
|
14
|
+
void Init_PCSC_Namespace() {
|
15
|
+
mSmartcard = rb_define_module("Smartcard");
|
16
|
+
Init_PCSC();
|
17
|
+
}
|
18
|
+
|
@@ -0,0 +1,326 @@
|
|
1
|
+
#include "pcsc.h"
|
2
|
+
|
3
|
+
VALUE cPcscReaderStates;
|
4
|
+
|
5
|
+
/* Wraps an array of SCARD_READERSTATE elements. */
|
6
|
+
struct PCSCReaderStates {
|
7
|
+
size_t states_count;
|
8
|
+
SCARD_READERSTATE *states;
|
9
|
+
};
|
10
|
+
|
11
|
+
/* Custom free for Smartcard::PCSC::ReaderStates. Also releases the referenced buffers (for the reader names). */
|
12
|
+
static void PCSC_ReaderStates_free(struct PCSCReaderStates *_states) {
|
13
|
+
size_t i;
|
14
|
+
if(_states != NULL) {
|
15
|
+
if(_states->states != NULL) {
|
16
|
+
for(i = 0; i < _states->states_count; i++) {
|
17
|
+
if(_states->states[i].szReader != NULL)
|
18
|
+
xfree((char *)_states->states[i].szReader);
|
19
|
+
}
|
20
|
+
xfree(_states->states);
|
21
|
+
}
|
22
|
+
xfree(_states);
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
/* Custom allocation for Smartcard::PCSC::ReaderStates. Wraps a reference to an array of SCARD_READERSTATE. */
|
27
|
+
static VALUE PCSC_ReaderStates_alloc(VALUE klass) {
|
28
|
+
struct PCSCReaderStates *states;
|
29
|
+
|
30
|
+
VALUE rbReaderStates = Data_Make_Struct(klass, struct PCSCReaderStates, NULL, PCSC_ReaderStates_free, states);
|
31
|
+
states->states_count = 0;
|
32
|
+
states->states = NULL;
|
33
|
+
return rbReaderStates;
|
34
|
+
}
|
35
|
+
|
36
|
+
/* :Document-method: new
|
37
|
+
* call-seq:
|
38
|
+
* new(num_states) --> reader_states
|
39
|
+
*
|
40
|
+
* Creates an array of +num_states+ reader state elements.
|
41
|
+
* The states are unusable until they are assigned reader names by calling ReaderStates#set_reader_name_of.
|
42
|
+
*/
|
43
|
+
static VALUE PCSC_ReaderStates_initialize(VALUE self, VALUE rbNumStates) {
|
44
|
+
struct PCSCReaderStates *states;
|
45
|
+
size_t states_count, i;
|
46
|
+
|
47
|
+
Data_Get_Struct(self, struct PCSCReaderStates, states);
|
48
|
+
|
49
|
+
states_count = NUM2UINT(rbNumStates);
|
50
|
+
if(states_count > 0) {
|
51
|
+
states->states = ALLOC_N(SCARD_READERSTATE, states_count);
|
52
|
+
if(states->states != NULL) {
|
53
|
+
states->states_count = states_count;
|
54
|
+
for(i = 0; i < states_count; i++) {
|
55
|
+
states->states[i].szReader = NULL;
|
56
|
+
states->states[i].dwCurrentState = SCARD_STATE_UNAWARE;
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
return self;
|
61
|
+
}
|
62
|
+
|
63
|
+
static int _validate_readerstates_args(VALUE rbReaderStates, VALUE rbIndex, struct PCSCReaderStates **states, size_t *index) {
|
64
|
+
Data_Get_Struct(rbReaderStates, struct PCSCReaderStates, *states);
|
65
|
+
if(*states == NULL) return 0;
|
66
|
+
|
67
|
+
*index = NUM2UINT(rbIndex);
|
68
|
+
if(*index >= (*states)->states_count) {
|
69
|
+
rb_raise(rb_eIndexError, "index %u is invalid (states array has %u elements)", *index, (*states)->states_count);
|
70
|
+
return 0;
|
71
|
+
}
|
72
|
+
|
73
|
+
return 1;
|
74
|
+
}
|
75
|
+
|
76
|
+
/* :Document-method: current_state_of
|
77
|
+
* call-seq:
|
78
|
+
* current_state_of(index) --> current_state
|
79
|
+
*
|
80
|
+
* The current state (_dwCurrentState_ in PC/SC) in the <tt>index</tt>th reader state element.
|
81
|
+
* Smartcard::PCSC::Context#get_status_change blocks as long as the reader state equals this value.
|
82
|
+
*
|
83
|
+
* The returned state is a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
|
84
|
+
*
|
85
|
+
* +index+:: the 0-based index of the reader state element to be queried
|
86
|
+
*/
|
87
|
+
static VALUE PCSC_ReaderStates_current_state_of(VALUE self, VALUE rbIndex) {
|
88
|
+
struct PCSCReaderStates *states;
|
89
|
+
size_t index;
|
90
|
+
|
91
|
+
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
92
|
+
return Qnil;
|
93
|
+
|
94
|
+
return UINT2NUM(states->states[index].dwCurrentState);
|
95
|
+
}
|
96
|
+
|
97
|
+
/* :Document-method: event_state_of
|
98
|
+
* call-seq:
|
99
|
+
* event_state_of(index) --> event_state
|
100
|
+
*
|
101
|
+
* The event state (_dwEventState_ in PC/SC) in the <tt>index</tt>th reader state element.
|
102
|
+
* Smartcard::PCSC::Context#get_status_change stores the updated reader state in this value.
|
103
|
+
*
|
104
|
+
* The returned state is a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
|
105
|
+
*
|
106
|
+
* +index+:: the 0-based index of the reader state element to be queried
|
107
|
+
*/
|
108
|
+
static VALUE PCSC_ReaderStates_event_state_of(VALUE self, VALUE rbIndex) {
|
109
|
+
struct PCSCReaderStates *states;
|
110
|
+
size_t index;
|
111
|
+
|
112
|
+
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
113
|
+
return Qnil;
|
114
|
+
|
115
|
+
return UINT2NUM(states->states[index].dwEventState);
|
116
|
+
}
|
117
|
+
|
118
|
+
/* :Document-method: set_current_state_of!
|
119
|
+
* call-seq:
|
120
|
+
* set_current_state_of!(index, current_state) --> self
|
121
|
+
*
|
122
|
+
* Sets the current state (_dwCurrentState_ in PC/SC) in the <tt>index</tt>th reader state element.
|
123
|
+
* Smartcard::PCSC::Context#get_status_change blocks as long as the reader state equals this value.
|
124
|
+
*
|
125
|
+
*
|
126
|
+
* +index+:: the 0-based index of the reader state element to be modified
|
127
|
+
* +current_state+:: a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
|
128
|
+
*/
|
129
|
+
static VALUE PCSC_ReaderStates_set_current_state_of(VALUE self, VALUE rbIndex, VALUE rbCurrentState) {
|
130
|
+
struct PCSCReaderStates *states;
|
131
|
+
size_t index;
|
132
|
+
|
133
|
+
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
134
|
+
return self;
|
135
|
+
|
136
|
+
states->states[index].dwCurrentState = NUM2UINT(rbCurrentState);
|
137
|
+
return self;
|
138
|
+
}
|
139
|
+
|
140
|
+
/* :Document-method: set_event_state_of!
|
141
|
+
* call-seq:
|
142
|
+
* set_event_state_of!(index, event_state) --> self
|
143
|
+
*
|
144
|
+
* Sets the event state (_dwEventState_ in PC/SC) in the <tt>index</tt>th reader state element.
|
145
|
+
* Smartcard::PCSC::Context#get_status_change stores the updated reader state in this value.
|
146
|
+
*
|
147
|
+
* +index+:: the 0-based index of the reader state element to be modified
|
148
|
+
* +event_state+:: a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
|
149
|
+
*/
|
150
|
+
static VALUE PCSC_ReaderStates_set_event_state_of(VALUE self, VALUE rbIndex, VALUE rbEventState) {
|
151
|
+
struct PCSCReaderStates *states;
|
152
|
+
size_t index;
|
153
|
+
|
154
|
+
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
155
|
+
return self;
|
156
|
+
|
157
|
+
states->states[index].dwEventState = NUM2UINT(rbEventState);
|
158
|
+
return self;
|
159
|
+
}
|
160
|
+
|
161
|
+
/* :Document-method: atr_of
|
162
|
+
* call-seq:
|
163
|
+
* atr_of(index) --> atr
|
164
|
+
*
|
165
|
+
* The card ATR string in the <tt>index</tt>th reader state element.
|
166
|
+
* Smartcard::PCSC::Context#get_status_change stores the updated ATR string in this value.
|
167
|
+
*
|
168
|
+
* The returned ATR bytes are wrapped into a string. (don't complain, it's a low-level API)
|
169
|
+
*
|
170
|
+
* +index+:: the 0-based index of the reader state element to be queried
|
171
|
+
*/
|
172
|
+
static VALUE PCSC_ReaderStates_atr_of(VALUE self, VALUE rbIndex) {
|
173
|
+
struct PCSCReaderStates *states;
|
174
|
+
size_t index;
|
175
|
+
|
176
|
+
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
177
|
+
return Qnil;
|
178
|
+
|
179
|
+
return rb_str_new((char *)states->states[index].rgbAtr, states->states[index].cbAtr);
|
180
|
+
}
|
181
|
+
|
182
|
+
/* :Document-method: set_atr_of!
|
183
|
+
* call-seq:
|
184
|
+
* set_atr_of!(index, atr) --> self
|
185
|
+
*
|
186
|
+
* Sets the card ATR string in the <tt>index</tt>th reader state element.
|
187
|
+
* Smartcard::PCSC::Context#get_status_change stores the updated ATR string in this value.
|
188
|
+
*
|
189
|
+
* +index+:: the 0-based index of the reader state element to be modified
|
190
|
+
* +atr+:: ATR bytes wrapped into a string (low-level API, remember?)
|
191
|
+
*/
|
192
|
+
static VALUE PCSC_ReaderStates_set_atr_of(VALUE self, VALUE rbIndex, VALUE rbAtr) {
|
193
|
+
struct PCSCReaderStates *states;
|
194
|
+
size_t index;
|
195
|
+
VALUE rbFinalAtr;
|
196
|
+
|
197
|
+
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
198
|
+
return self;
|
199
|
+
|
200
|
+
rbFinalAtr = rb_check_string_type(rbAtr);
|
201
|
+
if(NIL_P(rbFinalAtr))
|
202
|
+
return self;
|
203
|
+
|
204
|
+
if(RSTRING(rbFinalAtr)->len > MAX_ATR_SIZE) {
|
205
|
+
rb_raise(rb_eArgError, "given ATR is too long (%d characters given; can do at most MAX_ATR_SIZE = %d)", RSTRING(rbFinalAtr)->len, MAX_ATR_SIZE);
|
206
|
+
return self;
|
207
|
+
}
|
208
|
+
|
209
|
+
states->states[index].cbAtr = RSTRING(rbAtr)->len;
|
210
|
+
memcpy(states->states[index].rgbAtr, RSTRING(rbAtr)->ptr, states->states[index].cbAtr);
|
211
|
+
return self;
|
212
|
+
}
|
213
|
+
|
214
|
+
/* :Document-method: reader_name_of
|
215
|
+
* call-seq:
|
216
|
+
* reader_name_of(index) --> reader_name
|
217
|
+
*
|
218
|
+
* The name of the reader whose status is represented in the <tt>index</tt>th reader state element.
|
219
|
+
* Smartcard::PCSC::Context#get_status_change reads this value, and never updates it.
|
220
|
+
*
|
221
|
+
* +index+:: the 0-based index of the reader state element to be queried
|
222
|
+
*/
|
223
|
+
static VALUE PCSC_ReaderStates_reader_name_of(VALUE self, VALUE rbIndex) {
|
224
|
+
struct PCSCReaderStates *states;
|
225
|
+
size_t index;
|
226
|
+
|
227
|
+
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
228
|
+
return Qnil;
|
229
|
+
|
230
|
+
return rb_str_new2(states->states[index].szReader);
|
231
|
+
}
|
232
|
+
|
233
|
+
/* :Document-method: set_reader_name_of!
|
234
|
+
* call-seq:
|
235
|
+
* set_reader_name_of!(index, reader_name) --> self
|
236
|
+
*
|
237
|
+
* The name of the reader whose status is represented in the <tt>index</tt>th reader state element.
|
238
|
+
* Smartcard::PCSC::Context#get_status_change reads this value, and never updates it.
|
239
|
+
*
|
240
|
+
* +index+:: the 0-based index of the reader state element to be modified
|
241
|
+
* +reader_name+:: a string-like object containing the reader name to be associated with the state element
|
242
|
+
*/
|
243
|
+
static VALUE PCSC_ReaderStates_set_reader_name_of(VALUE self, VALUE rbIndex, VALUE rbReaderName) {
|
244
|
+
struct PCSCReaderStates *states;
|
245
|
+
size_t index, reader_name_length;
|
246
|
+
VALUE rbFinalReaderName;
|
247
|
+
|
248
|
+
if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
|
249
|
+
return self;
|
250
|
+
|
251
|
+
rbFinalReaderName = rb_check_string_type(rbReaderName);
|
252
|
+
if(NIL_P(rbFinalReaderName))
|
253
|
+
return self;
|
254
|
+
|
255
|
+
reader_name_length = RSTRING(rbFinalReaderName)->len;
|
256
|
+
if(states->states[index].szReader != NULL)
|
257
|
+
xfree((char *)states->states[index].szReader);
|
258
|
+
states->states[index].szReader = ALLOC_N(char, reader_name_length + 1);
|
259
|
+
if(states->states[index].szReader != NULL) {
|
260
|
+
memcpy((char *)states->states[index].szReader, RSTRING(rbFinalReaderName)->ptr, reader_name_length);
|
261
|
+
((char *)states->states[index].szReader)[reader_name_length] = '\0';
|
262
|
+
}
|
263
|
+
return self;
|
264
|
+
}
|
265
|
+
|
266
|
+
/* :Document-method: acknowledge_events!
|
267
|
+
* call-seq:
|
268
|
+
* acknowledge_events!() --> self
|
269
|
+
*
|
270
|
+
* Mass-assigns +current_state+ to +event_state+ for each reader state element.
|
271
|
+
* Useful to acknowledge all the status changed communicated after a call to Smartcard::PCSC::Context#get_status_change
|
272
|
+
* (and thus prepare for a new call).
|
273
|
+
*/
|
274
|
+
static VALUE PCSC_ReaderStates_acknowledge_events(VALUE self) {
|
275
|
+
struct PCSCReaderStates *states;
|
276
|
+
size_t i;
|
277
|
+
|
278
|
+
Data_Get_Struct(self, struct PCSCReaderStates, states);
|
279
|
+
if(states != NULL) {
|
280
|
+
for(i = 0; i < states->states_count; i++)
|
281
|
+
states->states[i].dwCurrentState = states->states[i].dwEventState;
|
282
|
+
}
|
283
|
+
return self;
|
284
|
+
}
|
285
|
+
|
286
|
+
#ifdef MAKE_RDOC_HAPPY
|
287
|
+
mSmartcard = rb_define_module("Smartcard");
|
288
|
+
mPcsc = rb_define_module_under(mSmartcard, "PCSC");
|
289
|
+
#endif
|
290
|
+
|
291
|
+
/* :Document-class: Smartcard::PCSC::ReaderStates
|
292
|
+
* Tracks reader status information, and is used in Smartcard::PCSC::Context#get_status_change.
|
293
|
+
* Wraps an array of <i>SCARD_READERSTATE</i> structures.
|
294
|
+
*/
|
295
|
+
void Init_PCSC_ReaderStates() {
|
296
|
+
cPcscReaderStates = rb_define_class_under(mPcsc, "ReaderStates", rb_cObject);
|
297
|
+
rb_define_alloc_func(cPcscReaderStates, PCSC_ReaderStates_alloc);
|
298
|
+
rb_define_method(cPcscReaderStates, "initialize", PCSC_ReaderStates_initialize, 1);
|
299
|
+
rb_define_method(cPcscReaderStates, "current_state_of", PCSC_ReaderStates_current_state_of, 1);
|
300
|
+
rb_define_method(cPcscReaderStates, "set_current_state_of!", PCSC_ReaderStates_set_current_state_of, 2);
|
301
|
+
rb_define_method(cPcscReaderStates, "event_state_of", PCSC_ReaderStates_event_state_of, 1);
|
302
|
+
rb_define_method(cPcscReaderStates, "set_event_state_of!", PCSC_ReaderStates_set_event_state_of, 2);
|
303
|
+
rb_define_method(cPcscReaderStates, "reader_name_of", PCSC_ReaderStates_reader_name_of, 1);
|
304
|
+
rb_define_method(cPcscReaderStates, "set_reader_name_of!", PCSC_ReaderStates_set_reader_name_of, 2);
|
305
|
+
rb_define_method(cPcscReaderStates, "atr_of", PCSC_ReaderStates_atr_of, 1);
|
306
|
+
rb_define_method(cPcscReaderStates, "set_atr_of!", PCSC_ReaderStates_set_atr_of, 2);
|
307
|
+
rb_define_method(cPcscReaderStates, "acknowledge_events!", PCSC_ReaderStates_acknowledge_events, 0);
|
308
|
+
}
|
309
|
+
|
310
|
+
/* Retrieves the SCARD_READERSTATE array wrapped into a Smartcard::PCSC::ReaderStates instance. */
|
311
|
+
int _PCSC_ReaderStates_lowlevel_get(VALUE rbReaderStates, SCARD_READERSTATE **reader_states, size_t *reader_states_count) {
|
312
|
+
struct PCSCReaderStates *states;
|
313
|
+
|
314
|
+
if(TYPE(rbReaderStates) == T_NIL || TYPE(rbReaderStates) == T_FALSE) {
|
315
|
+
*reader_states = NULL;
|
316
|
+
*reader_states_count = 0;
|
317
|
+
return 1;
|
318
|
+
}
|
319
|
+
if(TYPE(rbReaderStates) != T_DATA || RDATA(rbReaderStates)->dfree != (void (*)(void *))PCSC_ReaderStates_free)
|
320
|
+
return 0;
|
321
|
+
|
322
|
+
Data_Get_Struct(rbReaderStates, struct PCSCReaderStates, states);
|
323
|
+
*reader_states = states->states;
|
324
|
+
*reader_states_count = states->states_count;
|
325
|
+
return 1;
|
326
|
+
}
|