smartcard 0.3.1-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,39 @@
1
+ #include "pcsc.h"
2
+
3
+ VALUE ePcscException;
4
+
5
+ #if defined(WIN32)
6
+ static char scard_error_buffer[128];
7
+
8
+ /* Produces a string for an error code yielded by the SCard* PC/SC functions. Returns a static global buffer. */
9
+ static char *pcsc_stringify_error(DWORD scard_error) {
10
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
11
+ NULL, scard_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
12
+ scard_error_buffer, sizeof(scard_error_buffer), NULL );
13
+ return scard_error_buffer;
14
+ }
15
+ #endif
16
+
17
+
18
+ #ifdef MAKE_RDOC_HAPPY
19
+ mSmartcard = rb_define_module("Smartcard");
20
+ mPcsc = rb_define_module_under(mSmartcard, "PCSC");
21
+ #endif
22
+
23
+ /* :Document-class: Smartcard::PCSC::Exception
24
+ * Contains information about an exception at the PC/SC layer.
25
+ */
26
+ void Init_PCSC_Exception() {
27
+ ePcscException = rb_define_class_under(mPcsc, "PcscException", rb_eRuntimeError);
28
+ }
29
+
30
+ /* Raises a PC/SC error. */
31
+ void _PCSC_Exception_raise(DWORD pcsc_error, char *pcsc_function) {
32
+ char buf[BUFSIZ];
33
+ VALUE exception;
34
+
35
+ sprintf(buf, "%s: %s", pcsc_function, pcsc_stringify_error(pcsc_error));
36
+ exception = rb_exc_new2(ePcscException, buf);
37
+ rb_iv_set(exception, "@errno", INT2NUM(pcsc_error));
38
+ rb_exc_raise(exception);
39
+ }
@@ -0,0 +1,129 @@
1
+ #include "pcsc.h"
2
+
3
+ VALUE cPcscIoRequest;
4
+
5
+ /* Wraps a SCARD_IO_REQUEST, tracking its allocation etc. */
6
+ struct SCardIoRequestEx {
7
+ SCARD_IO_REQUEST *pcsc_request;
8
+ int mallocd;
9
+ };
10
+
11
+ /* Custom free for Smartcard::PCSC::IoRequest. */
12
+ static void PCSC_IoRequest_free(struct SCardIoRequestEx *_request) {
13
+ if(_request != NULL) {
14
+ if(_request->mallocd)
15
+ xfree(_request->pcsc_request);
16
+ xfree(_request);
17
+ }
18
+ }
19
+
20
+ /* Custom allocation for Smartcard::PCSC::Card. Wraps a SCardIoRequestEx. */
21
+ static VALUE PCSC_IoRequest_alloc(VALUE klass) {
22
+ struct SCardIoRequestEx *request;
23
+
24
+ VALUE rbIoRequest = Data_Make_Struct(klass, struct SCardIoRequestEx, NULL, PCSC_IoRequest_free, request);
25
+ request->pcsc_request = NULL;
26
+ request->mallocd = 0;
27
+ return rbIoRequest;
28
+ }
29
+
30
+ /* :Document-method: new
31
+ * call-seq:
32
+ * new() --> io_request
33
+ *
34
+ * Creates an uninitialized IoRequest.
35
+ * The request can be used as a receiving IoRequest in Smartcard::PCSC::Card#transmit.
36
+ */
37
+ static VALUE PCSC_IoRequest_initialize(VALUE self) {
38
+ struct SCardIoRequestEx *request;
39
+
40
+ Data_Get_Struct(self, struct SCardIoRequestEx, request);
41
+ request->pcsc_request = ALLOC(SCARD_IO_REQUEST);
42
+ request->mallocd = 1;
43
+
44
+ return self;
45
+ }
46
+
47
+ /* :Document-method: protocol
48
+ * call-seq:
49
+ * io_request.protocol --> protocol
50
+ *
51
+ * The protocol of this instance.
52
+ *
53
+ * The returned protocol is a number, and should be checked against one of the Smartcard::PCSC::PROTOCOL_ constants.
54
+ */
55
+ static VALUE PCSC_IoRequest_get_protocol(VALUE self) {
56
+ struct SCardIoRequestEx *request;
57
+
58
+ Data_Get_Struct(self, struct SCardIoRequestEx, request);
59
+ if(request == NULL) return Qnil;
60
+
61
+ return UINT2NUM(request->pcsc_request->dwProtocol);
62
+ }
63
+
64
+ /* :Document-method: protocol=
65
+ * call-seq:
66
+ * io_request.protocol = protocol
67
+ *
68
+ * Sets the protocol of this instance.
69
+ *
70
+ * +protocol+:: use one of the Smartcard::PCSC::PROTOCOL_ constants
71
+ */
72
+ static VALUE PCSC_IoRequest_set_protocol(VALUE self, VALUE rbProtocol) {
73
+ struct SCardIoRequestEx *request;
74
+
75
+ Data_Get_Struct(self, struct SCardIoRequestEx, request);
76
+ if(request == NULL) return self;
77
+
78
+ if(request->mallocd == 0)
79
+ rb_raise(rb_eSecurityError, "cannot modify PC/SC-global (read-only) IO_REQUEST");
80
+ else
81
+ request->pcsc_request->dwProtocol = NUM2UINT(rbProtocol);
82
+ return self;
83
+ }
84
+
85
+ #ifdef MAKE_RDOC_HAPPY
86
+ mSmartcard = rb_define_module("Smartcard");
87
+ mPcsc = rb_define_module_under(mSmartcard, "PCSC");
88
+ #endif
89
+
90
+ /* :Document-class: Smartcard::PCSC::IoRequest
91
+ * Protocol information used in Smartcard::PCSC::Card#transmit.
92
+ * Wraps a _SCARD_IO_REQUEST_ structure.
93
+ *
94
+ * I know the name is retarded, but it reflects the PC/SC name well. The choice makes sense given that this
95
+ * is an API meant for people familiar with the PC/SC specification.
96
+ */
97
+ void Init_PCSC_IoRequest() {
98
+ cPcscIoRequest = rb_define_class_under(mPcsc, "IoRequest", rb_cObject);
99
+ rb_define_alloc_func(cPcscIoRequest, PCSC_IoRequest_alloc);
100
+ rb_define_method(cPcscIoRequest, "initialize", PCSC_IoRequest_initialize, 0);
101
+ rb_define_method(cPcscIoRequest, "protocol", PCSC_IoRequest_get_protocol, 0);
102
+ rb_define_method(cPcscIoRequest, "protocol=", PCSC_IoRequest_set_protocol, 1);
103
+ }
104
+
105
+ /* Retrieves the SCARD_IO_REQUEST wrapped into a Smartcard::PCSC::IoRequest instance. */
106
+ int _PCSC_IoRequest_lowlevel_get(VALUE rbIoRequest, SCARD_IO_REQUEST **io_request) {
107
+ struct SCardIoRequestEx *request;
108
+
109
+ if(!RTEST(rbIoRequest)) {
110
+ *io_request = NULL;
111
+ return 1;
112
+ }
113
+ if(TYPE(rbIoRequest) != T_DATA || RDATA(rbIoRequest)->dfree != (void (*)(void *))PCSC_IoRequest_free)
114
+ return 0;
115
+
116
+ Data_Get_Struct(rbIoRequest, struct SCardIoRequestEx, request);
117
+ *io_request = request->pcsc_request;
118
+ return 1;
119
+ }
120
+
121
+ /* Creates a Smartcard::PCSC::IoRequest instance wrapping a given SCARD_IO_REQUEST. */
122
+ VALUE _PCSC_IoRequest_lowlevel_new(const SCARD_IO_REQUEST *io_request) {
123
+ struct SCardIoRequestEx *request;
124
+
125
+ VALUE rbIoRequest = Data_Make_Struct(cPcscIoRequest, struct SCardIoRequestEx, NULL, PCSC_IoRequest_free, request);
126
+ request->pcsc_request = io_request;
127
+ request->mallocd = 0;
128
+ return rbIoRequest;
129
+ }
@@ -0,0 +1,11 @@
1
+ #include "pcsc.h"
2
+
3
+ void Init_pcsc() {
4
+ Init_PCSC_Namespace();
5
+ Init_PCSC_ReaderStates();
6
+ Init_PCSC_IoRequest();
7
+ Init_PCSC_Context();
8
+ Init_PCSC_Card();
9
+ Init_PCSC_Consts();
10
+ Init_PCSC_Exception();
11
+ }
@@ -0,0 +1,70 @@
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
+ }
@@ -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(!RTEST(rbReaderStates)) {
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
+ }