smartcard 0.4.11 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,492 +0,0 @@
1
- #include "pcsc.h"
2
-
3
- VALUE cPcscCard;
4
-
5
- /* Wraps a SCARDHANDLE, tracking whether it was released or not, together with the last error that occured on it. */
6
- struct SCardHandleEx {
7
- SCARDHANDLE card_handle;
8
- DWORD pcsc_error;
9
- int released;
10
- };
11
-
12
- /* Custom free for Smartcard::PCSC::Card. Releases the card handle via a disconnect if that was not already done. */
13
- static void PCSC_Card_free(struct SCardHandleEx *_card) {
14
- if(_card != NULL) {
15
- if(!_card->released)
16
- SCardDisconnect(_card->card_handle, SCARD_LEAVE_CARD);
17
- xfree(_card);
18
- }
19
- }
20
-
21
- /* Custom allocation for Smartcard::PCSC::Card. Wraps a SCardHandleEx. */
22
- static VALUE PCSC_Card_alloc(VALUE klass) {
23
- struct SCardHandleEx *card;
24
-
25
- VALUE rbCard = Data_Make_Struct(klass, struct SCardHandleEx, NULL, PCSC_Card_free, card);
26
- card->pcsc_error = SCARD_S_SUCCESS;
27
- card->released = 1;
28
- return rbCard;
29
- }
30
-
31
- /* :Document-method: new
32
- * call-seq:
33
- * new(context, reader_name, share_mode, preferred_protocols) --> card
34
- *
35
- * Establishes a connection to the card in the reader whose friendly name is +reader_name+.
36
- * The first connection will power up and perform a reset on the card.
37
- * Wraps _SCardConnect_ in PC/SC.
38
- *
39
- * +context+:: the Smartcard::PCSC::Context to use to connect to the PC/SC resource manager
40
- * +reader_name+:: friendly name of the reader to connect to; get using Smartcard::PCSC::Context#list_readers
41
- * +share_mode+:: whether a shared or exclusive lock will be requested on the reader; use one of the Smartcard::PCSC::SHARE_ constants
42
- * +preferred_protocols+:: desired protocol; use one of the Smartcard::PCSC::PROTOCOL_ constants
43
- */
44
- static VALUE PCSC_Card_initialize(VALUE self, VALUE rbContext, VALUE rbReaderName, VALUE rbShareMode, VALUE rbPreferredProtocols) {
45
- struct SCardHandleEx *card;
46
- SCARDCONTEXT context;
47
- VALUE rbFinalReaderName;
48
- DWORD share_mode, preferred_protocols, active_protocol;
49
-
50
- Data_Get_Struct(self, struct SCardHandleEx, card);
51
-
52
- if(_PCSC_Context_lowlevel_get(rbContext, &context) == 0) {
53
- rb_raise(rb_eArgError, "first argument is not a Context instance");
54
- return self;
55
- }
56
-
57
- rbFinalReaderName = rb_check_string_type(rbReaderName);
58
- if(NIL_P(rbFinalReaderName)) {
59
- rb_raise(rb_eArgError, "second argument (should be reader name) does not convert to a String");
60
- return self;
61
- }
62
-
63
- share_mode = NUM2UINT(rbShareMode);
64
- preferred_protocols = NUM2UINT(rbPreferredProtocols);
65
-
66
- card->pcsc_error = SCardConnect(context, RSTRING(rbFinalReaderName)->ptr, share_mode, preferred_protocols, &card->card_handle, &active_protocol);
67
- if(card->pcsc_error != SCARD_S_SUCCESS)
68
- _PCSC_Exception_raise(card->pcsc_error, "SCardConnect");
69
- else
70
- card->released = 0;
71
- return self;
72
- }
73
-
74
- /* :Document-method: reconnect
75
- * call-seq:
76
- * card.reconnect(share_mode, preferred_protocols, initialization) --> self
77
- *
78
- * Reestablishes a connection to a reader that was previously connected to using Card#new.
79
- * Wraps _SCardReconnect_ in PC/SC.
80
- *
81
- * +share_mode+:: whether a shared or exclusive lock will be requested on the reader; use one of the Smartcard::PCSC::SHARE_ constants
82
- * +preferred_protocols+:: desired protocol; use one of the Smartcard::PCSC::PROTOCOL_ constants
83
- * +initialization+:: action to be taken on the card inside the reader; use one of the Smartcard::PCSC::INITIALIZE_ constants
84
- */
85
- static VALUE PCSC_Card_reconnect(VALUE self, VALUE rbShareMode, VALUE rbPreferredProtocols, VALUE rbInitialization) {
86
- struct SCardHandleEx *card;
87
- DWORD share_mode, preferred_protocols, initialization, active_protocol;
88
-
89
- Data_Get_Struct(self, struct SCardHandleEx, card);
90
- if(card == NULL) return self;
91
-
92
- share_mode = NUM2UINT(rbShareMode);
93
- preferred_protocols = NUM2UINT(rbPreferredProtocols);
94
- initialization = NUM2UINT(rbInitialization);
95
-
96
- card->pcsc_error = SCardReconnect(card->card_handle, share_mode, preferred_protocols, initialization, &active_protocol);
97
- if(card->pcsc_error != SCARD_S_SUCCESS)
98
- _PCSC_Exception_raise(card->pcsc_error, "SCardReconnect");
99
-
100
- return self;
101
- }
102
-
103
- /* :Document-method: disconnect
104
- * call-seq:
105
- * context.disconnect(disposition) --> self
106
- *
107
- * Terminates the connection made using Card#new. The Card object is invalid afterwards.
108
- * Wraps _SCardDisconnect_ in PC/SC.
109
- *
110
- * +disposition+:: action to be taken on the card inside the reader; use one of the Smartcard::PCSC::DISPOSITION_ constants
111
- */
112
- static VALUE PCSC_Card_disconnect(VALUE self, VALUE rbDisposition) {
113
- struct SCardHandleEx *card;
114
- DWORD disposition;
115
-
116
- Data_Get_Struct(self, struct SCardHandleEx, card);
117
- if(card == NULL) return self;
118
-
119
- disposition = NUM2UINT(rbDisposition);
120
- if(!card->released) {
121
- card->pcsc_error = SCardDisconnect(card->card_handle, disposition);
122
- card->released = 1;
123
- if(card->pcsc_error != SCARD_S_SUCCESS)
124
- _PCSC_Exception_raise(card->pcsc_error, "SCardDisconnect");
125
- }
126
- return self;
127
- }
128
-
129
- /* :Document-method: begin_transaction
130
- * call-seq:
131
- * card.begin_transaction() --> self
132
- *
133
- * Establishes a temporary exclusive access mode for doing a series of commands or transaction.
134
- * Wraps _SCardBeginTransaction_ in PC/SC.
135
- */
136
- static VALUE PCSC_Card_begin_transaction(VALUE self) {
137
- struct SCardHandleEx *card;
138
-
139
- Data_Get_Struct(self, struct SCardHandleEx, card);
140
- if(card == NULL) return self;
141
-
142
- card->pcsc_error = SCardBeginTransaction(card->card_handle);
143
- if(card->pcsc_error != SCARD_S_SUCCESS)
144
- _PCSC_Exception_raise(card->pcsc_error, "SCardBeginTransaction");
145
- return self;
146
- }
147
-
148
- /* :Document-method: end_transaction
149
- * call-seq:
150
- * context.end_transaction(disposition) --> attribute_value
151
- *
152
- * Ends a previously begun transaction. The calling application must be the owner of the previously begun transaction or an error will occur.
153
- * Wraps _SCardEndTransaction_ in PC/SC.
154
- *
155
- * +disposition+:: action to be taken on the card inside the reader; use one of the Smartcard::PCSC::DISPOSITION_ constants
156
- */
157
- static VALUE PCSC_Card_end_transaction(VALUE self, VALUE rbDisposition) {
158
- struct SCardHandleEx *card;
159
- DWORD disposition;
160
-
161
- Data_Get_Struct(self, struct SCardHandleEx, card);
162
- if(card == NULL) return self;
163
-
164
- disposition = NUM2UINT(rbDisposition);
165
- card->pcsc_error = SCardEndTransaction(card->card_handle, disposition);
166
- if(card->pcsc_error != SCARD_S_SUCCESS)
167
- _PCSC_Exception_raise(card->pcsc_error, "SCardEndTransaction");
168
- return self;
169
- }
170
-
171
- /* :Document-method: get_attribute
172
- * call-seq:
173
- * card.get_attribute(attribute_id) --> attribute_value
174
- *
175
- * Reads the value of an attribute from the interface driver.
176
- * Remember that the IFD may not implement some of the attributes specified in Smartcard::PCSC, and it may implement some attributes that
177
- * are not included in Smartcard::PCSC.
178
- * Wraps _SCardGetAttrib_ in PC/SC.
179
- *
180
- * The returned value has the bytes in the attribute, wrapped in a string. (don't complain, it's a low-level API)
181
- *
182
- * +attribute_id+:: identifies the attribute to be read; use one of the Smartcard::PCSC::ATTR_ constants
183
- */
184
- static VALUE PCSC_Card_get_attribute(VALUE self, VALUE rbAttributeId) {
185
- struct SCardHandleEx *card;
186
- char *attribute_buffer;
187
- DWORD attribute_id, attribute_length;
188
- VALUE rbAttribute;
189
-
190
- Data_Get_Struct(self, struct SCardHandleEx, card);
191
- if(card == NULL) return Qnil;
192
-
193
- attribute_id = NUM2UINT(rbAttributeId);
194
- attribute_length;
195
- #if defined(RB_SMARTCARD_OSX_TIGER_HACK)
196
- card->pcsc_error = SCARD_F_INTERNAL_ERROR;
197
- rb_raise(rb_eRuntimeError, "SCardSetAttrib: not implemented in OSX Tiger");
198
- #else
199
- card->pcsc_error = SCardGetAttrib(card->card_handle, attribute_id, NULL, &attribute_length);
200
- if(card->pcsc_error == SCARD_S_SUCCESS) {
201
- attribute_buffer = ALLOC_N(char, attribute_length);
202
- if(attribute_buffer != NULL) {
203
- card->pcsc_error = SCardGetAttrib(card->card_handle, attribute_id, (LPSTR)attribute_buffer, &attribute_length);
204
- if(card->pcsc_error == SCARD_S_SUCCESS) {
205
- rbAttribute = rb_str_new(attribute_buffer, attribute_length);
206
- xfree(attribute_buffer);
207
- return rbAttribute;
208
- }
209
- }
210
- }
211
- if(card->pcsc_error != SCARD_S_SUCCESS)
212
- _PCSC_Exception_raise(card->pcsc_error, "SCardGetAttrib");
213
- #endif
214
- return Qnil;
215
- }
216
-
217
- /* :Document-method: set_attribute
218
- * call-seq:
219
- * context.set_attribute(attribute_id, attribute_value) --> self
220
- *
221
- * Sets the value of an attribute in the interface driver.
222
- * Remember that the IFD may not implement some of the attributes specified in Smartcard::PCSC, and it may implement some attributes that
223
- * are not included in Smartcard::PCSC.
224
- * Wraps _SCardSetAttrib_ in PC/SC.
225
- *
226
- * +attribute_id+:: identifies the attribute to be set; use one of the Smartcard::PCSC::ATTR_ constants
227
- * +attribute_value+:: the value to be assigned to the attribute; wrap the bytes in a string-like object (low-level API, remember?)
228
- */
229
- static VALUE PCSC_Card_set_attribute(VALUE self, VALUE rbAttributeId, VALUE rbAttributeValue) {
230
- struct SCardHandleEx *card;
231
- DWORD attribute_id;
232
- VALUE rbFinalAttributeValue;
233
-
234
- Data_Get_Struct(self, struct SCardHandleEx, card);
235
- if(card == NULL) return self;
236
-
237
- attribute_id = NUM2UINT(rbAttributeId);
238
-
239
- rbFinalAttributeValue = rb_check_string_type(rbAttributeValue);
240
- if(NIL_P(rbFinalAttributeValue)) {
241
- rb_raise(rb_eArgError, "second argument (attribute buffer) does not convert to a String");
242
- return self;
243
- }
244
-
245
- #if defined(RB_SMARTCARD_OSX_TIGER_HACK)
246
- card->pcsc_error = SCARD_F_INTERNAL_ERROR;
247
- rb_raise(rb_eRuntimeError, "SCardSetAttrib: not implemented in OSX Tiger");
248
- #else
249
- card->pcsc_error = SCardSetAttrib(card->card_handle, attribute_id, (LPSTR)RSTRING(rbFinalAttributeValue)->ptr, RSTRING(rbFinalAttributeValue)->len);
250
- if(card->pcsc_error != SCARD_S_SUCCESS)
251
- _PCSC_Exception_raise(card->pcsc_error, "SCardSetAttrib");
252
- #endif
253
- return self;
254
- }
255
-
256
- /* :Document-method: transmit
257
- * call-seq:
258
- * card.transmit(send_data, send_io_request, recv_io_request) --> recv_data
259
- *
260
- * Sends an APDU to the smart card, and returns the card's response to the APDU.
261
- * Wraps _SCardTransmit_ in PC/SC.
262
- *
263
- * The bytes in the card's response are returned wrapped in a string. (don't complain, it's a low-level API)
264
- *
265
- * +send_data+:: the APDU to be send to the card; wrap the bytes in a string-like object (low-level API, remember?)
266
- * +send_io_request+:: Smartcard::PCSC::IoRequest instance indicating the send protocol; you should use one of the Smartcard::PCSC::IOREQUEST_ constants
267
- * +recv_io_request+:: Smartcard::PCSC::IoRequest instance receving information about the recv protocol; you can use the result of Smartcard::PCSC::IoRequest#new
268
- */
269
- static VALUE PCSC_Card_transmit(VALUE self, VALUE rbSendData, VALUE rbSendIoRequest, VALUE rbRecvIoRequest) {
270
- struct SCardHandleEx *card;
271
- VALUE rbFinalSendData, rbRecvData;
272
- SCARD_IO_REQUEST *send_io_request, *recv_io_request;
273
- char *recv_buffer;
274
- DWORD recv_length;
275
-
276
- Data_Get_Struct(self, struct SCardHandleEx, card);
277
- if(card == NULL) return Qnil;
278
-
279
- rbFinalSendData = rb_check_string_type(rbSendData);
280
- if(NIL_P(rbFinalSendData)) {
281
- rb_raise(rb_eArgError, "first argument (send buffer) does not convert to a String");
282
- return Qnil;
283
- }
284
-
285
- if(_PCSC_IoRequest_lowlevel_get(rbSendIoRequest, &send_io_request) == 0) {
286
- rb_raise(rb_eArgError, "second argument (send io request) is not an IoRequest instance");
287
- return Qnil;
288
- }
289
- if(_PCSC_IoRequest_lowlevel_get(rbRecvIoRequest, &recv_io_request) == 0) {
290
- rb_raise(rb_eArgError, "third argument (recv io request) is not an IoRequest instance");
291
- return Qnil;
292
- }
293
-
294
- #if defined(PCSCLITE_MAX_MESSAGE_SIZE)
295
- recv_length = PCSCLITE_MAX_MESSAGE_SIZE;
296
- #elif defined(MAX_BUFFER_SIZE_EXTENDED)
297
- recv_length = MAX_BUFFER_SIZE_EXTENDED;
298
- #else
299
- recv_length = 65536;
300
- #endif
301
- recv_buffer = ALLOC_N(char, recv_length);
302
- if(recv_buffer == NULL) return Qnil;
303
-
304
- card->pcsc_error = SCardTransmit(card->card_handle, send_io_request,
305
- (LPSTR)RSTRING(rbFinalSendData)->ptr, RSTRING(rbFinalSendData)->len,
306
- recv_io_request, (LPSTR)recv_buffer, &recv_length);
307
- if(card->pcsc_error != SCARD_S_SUCCESS) {
308
- xfree(recv_buffer);
309
- _PCSC_Exception_raise(card->pcsc_error, "SCardTransmit");
310
- return Qnil;
311
- }
312
-
313
- rbRecvData = rb_str_new(recv_buffer, recv_length);
314
- xfree(recv_buffer);
315
- return rbRecvData;
316
- }
317
-
318
- /* :Document-method: control
319
- * call-seq:
320
- * card.control(control_code, send_data, max_recv_bytes) --> recv_data
321
- *
322
- * Sends a command directly to the interface driver to be processed by the reader.
323
- * Useful for creating client side reader drivers for functions like PIN pads, biometrics, or other smart card reader
324
- * extensions that are not normally handled by PC/SC.
325
- * Wraps _SCardControl_ in PC/SC.
326
- *
327
- * The bytes in the response are returned wrapped in a string. (don't complain, it's a low-level API)
328
- *
329
- * +control_code+:: control code for the operation; it's an integer, and it's IFD-specific
330
- * +send_data+:: the data bytes to be send to the driver; wrap the bytes in a string-like object (low-level API, remember?)
331
- * +max_recv_bytes+:: the maximum number of bytes that can be received
332
- *
333
- * In general, I tried to avoid having you specify receive buffer sizes. This is the only case where that is impossible to achieve,
334
- * because there is no well-known maximum buffer size, and the _SCardControl_ call is not guaranteed to be idempotent, so it's not OK to
335
- * re-issue it until the buffer size works out.
336
- */
337
- static VALUE PCSC_Card_control(VALUE self, VALUE rbControlCode, VALUE rbSendData, VALUE rbMaxRecvBytes) {
338
- struct SCardHandleEx *card;
339
- VALUE rbFinalSendData, rbRecvData;
340
- char *recv_buffer;
341
- DWORD control_code, recv_length;
342
-
343
- Data_Get_Struct(self, struct SCardHandleEx, card);
344
- if(card == NULL) return Qnil;
345
-
346
- rbFinalSendData = rb_check_string_type(rbSendData);
347
- if(NIL_P(rbFinalSendData)) {
348
- rb_raise(rb_eArgError, "second argument (send buffer) does not convert to a String");
349
- return Qnil;
350
- }
351
-
352
- control_code = NUM2UINT(rbControlCode);
353
- recv_length = NUM2UINT(rbMaxRecvBytes);
354
- recv_buffer = ALLOC_N(char, recv_length);
355
- if(recv_buffer == NULL) return Qnil;
356
-
357
- #if defined(RB_SMARTCARD_OSX_TIGER_HACK)
358
- /* TODO: this will compile and run, but it won't do anything useful */
359
- card->pcsc_error = SCardControl(card->card_handle,
360
- (LPSTR)RSTRING(rbFinalSendData)->ptr, RSTRING(rbFinalSendData)->len,
361
- recv_buffer, &recv_length);
362
- #else
363
- card->pcsc_error = SCardControl(card->card_handle, control_code,
364
- (LPSTR)RSTRING(rbFinalSendData)->ptr, RSTRING(rbFinalSendData)->len,
365
- recv_buffer, recv_length, &recv_length);
366
- #endif
367
- if(card->pcsc_error != SCARD_S_SUCCESS) {
368
- xfree(recv_buffer);
369
- _PCSC_Exception_raise(card->pcsc_error, "SCardControl");
370
- return Qnil;
371
- }
372
-
373
- rbRecvData = rb_str_new(recv_buffer, recv_length);
374
- xfree(recv_buffer);
375
- return rbRecvData;
376
- }
377
-
378
- static VALUE _rbStateKey, _rbProtocolKey, _rbAtrKey, _rbReaderNamesKey;
379
-
380
- /* :Document-method: status
381
- * call-seq:
382
- * card.status() --> card_status
383
- *
384
- * Retrieves the current status of the smartcard, and packages it up in a nice hash for you.
385
- * Wraps _SCardStatus_ in PC/SC.
386
- *
387
- * The response hash contains the following keys:
388
- * <tt>:state</tt> :: reader/card status; bitfield, with bits defined as Smartcard::PCSC::STATUS_ constants
389
- * <tt>:protocol</tt> :: the protocol established with the card; check against Smartcard::PCSC::PROTOCOL_ constants
390
- * <tt>:atr</tt> :: the card's ATR bytes, wrapped in a string
391
- * <tt>:reader_names</tt> :: array of strings containing all the names of the reader containing the smartcard
392
- */
393
- static VALUE PCSC_Card_status(VALUE self) {
394
- struct SCardHandleEx *card;
395
- char *atr_buffer, *reader_names_buffer;
396
- DWORD atr_length, reader_names_length, state, protocol;
397
- VALUE rbStateVal, rbProtocolVal, rbAtrVal, rbReaderNamesVal, rbReturnHash;
398
-
399
- Data_Get_Struct(self, struct SCardHandleEx, card);
400
- if(card == NULL) return Qnil;
401
-
402
- atr_length = MAX_ATR_SIZE;
403
- atr_buffer = ALLOC_N(char, atr_length);
404
- reader_names_length = 4096;
405
- reader_names_buffer = ALLOC_N(char, reader_names_length);
406
- if(atr_buffer == NULL || reader_names_buffer == NULL) {
407
- if(reader_names_buffer != NULL) xfree(reader_names_buffer);
408
- if(atr_buffer != NULL) xfree(atr_buffer);
409
- return Qnil;
410
- }
411
-
412
- card->pcsc_error = SCardStatus(card->card_handle, reader_names_buffer, &reader_names_length, &state, &protocol, (LPSTR)atr_buffer, &atr_length);
413
- if(card->pcsc_error != SCARD_S_SUCCESS) {
414
- xfree(reader_names_buffer); xfree(atr_buffer);
415
- _PCSC_Exception_raise(card->pcsc_error, "SCardStatus");
416
- return Qnil;
417
- }
418
-
419
- rbStateVal = UINT2NUM(state);
420
- rbProtocolVal = UINT2NUM(protocol);
421
- rbAtrVal = rb_str_new(atr_buffer, atr_length);
422
- rbReaderNamesVal = PCSC_Internal_multistring_to_ruby_array(reader_names_buffer, reader_names_length);
423
-
424
- rbReturnHash = rb_hash_new();
425
- rb_hash_aset(rbReturnHash, _rbStateKey, rbStateVal);
426
- rb_hash_aset(rbReturnHash, _rbProtocolKey, rbProtocolVal);
427
- rb_hash_aset(rbReturnHash, _rbAtrKey, rbAtrVal);
428
- rb_hash_aset(rbReturnHash, _rbReaderNamesKey, rbReaderNamesVal);
429
- return rbReturnHash;
430
- }
431
-
432
- /* :Document-method: last_error
433
- * call-seq:
434
- * card.last_error() --> last_error
435
- *
436
- * The error code returned by the last PC/SC call. Useful for recovering from exceptions.
437
- *
438
- * The returned code is a number, and should be one of the Smartcard::PCSC::SCARD_ constants.
439
- * The code indicating correct operation is Smartcard::PCSC::SCARD_S_SUCCESS.
440
- */
441
- static VALUE PCSC_Card_last_error(VALUE self) {
442
- struct SCardHandleEx *card;
443
-
444
- Data_Get_Struct(self, struct SCardHandleEx, card);
445
- if(card == NULL) return Qnil;
446
-
447
- return UINT2NUM(card->pcsc_error);
448
- }
449
-
450
- #ifdef MAKE_RDOC_HAPPY
451
- mSmartcard = rb_define_module("Smartcard");
452
- mPcsc = rb_define_module_under(mSmartcard, "PCSC");
453
- #endif
454
-
455
- /* :Document-class: Smartcard::PCSC::Card
456
- * Connects a smart-card in a PC/SC reader to the Ruby world.
457
- * Wraps a _SCARDHANDLE_ structure.
458
- */
459
- void Init_PCSC_Card() {
460
- ID state_id, protocol_id, atr_id, reader_names_id;
461
-
462
- state_id = rb_intern("status"); _rbStateKey = ID2SYM(state_id);
463
- protocol_id = rb_intern("protocol"); _rbProtocolKey = ID2SYM(protocol_id);
464
- atr_id = rb_intern("atr"); _rbAtrKey = ID2SYM(atr_id);
465
- reader_names_id = rb_intern("reader_names"); _rbReaderNamesKey = ID2SYM(reader_names_id);
466
-
467
- cPcscCard = rb_define_class_under(mPcsc, "Card", rb_cObject);
468
- rb_define_alloc_func(cPcscCard, PCSC_Card_alloc);
469
- rb_define_method(cPcscCard, "initialize", PCSC_Card_initialize, 4);
470
- rb_define_method(cPcscCard, "disconnect", PCSC_Card_disconnect, 1);
471
- rb_define_method(cPcscCard, "reconnect", PCSC_Card_reconnect, 3);
472
- rb_define_method(cPcscCard, "begin_transaction", PCSC_Card_begin_transaction, 0);
473
- rb_define_method(cPcscCard, "end_transaction", PCSC_Card_end_transaction, 1);
474
- rb_define_method(cPcscCard, "get_attribute", PCSC_Card_get_attribute, 1);
475
- rb_define_method(cPcscCard, "set_attribute", PCSC_Card_set_attribute, 2);
476
- rb_define_method(cPcscCard, "transmit", PCSC_Card_transmit, 3);
477
- rb_define_method(cPcscCard, "control", PCSC_Card_control, 3);
478
- rb_define_method(cPcscCard, "status", PCSC_Card_status, 0);
479
- rb_define_method(cPcscCard, "last_error", PCSC_Card_last_error, 0);
480
- }
481
-
482
- /* Retrieves the SCARDHANDLE wrapped into a Smartcard::PCSC::Card instance. */
483
- int _PCSC_Card_lowlevel_get(VALUE rbCard, SCARDHANDLE *card_handle) {
484
- struct SCardHandleEx *card;
485
-
486
- if(TYPE(rbCard) != T_DATA || RDATA(rbCard)->dfree != (void (*)(void *))PCSC_Card_free)
487
- return 0;
488
-
489
- Data_Get_Struct(rbCard, struct SCardHandleEx, card);
490
- *card_handle = card->card_handle;
491
- return 1;
492
- }