smartcard 0.4.11 → 0.5.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.
@@ -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
- }