smartcard 0.3.1-x86-mswin32-60
Sign up to get free protection for your applications and to get access to all the features.
- data/BUILD +65 -0
- data/CHANGELOG +29 -0
- data/LICENSE +21 -0
- data/Manifest +23 -0
- data/README +32 -0
- data/ext/smartcard_pcsc/extconf.rb +70 -0
- data/ext/smartcard_pcsc/pcsc.h +52 -0
- data/ext/smartcard_pcsc/pcsc_card.c +492 -0
- data/ext/smartcard_pcsc/pcsc_constants.c +195 -0
- data/ext/smartcard_pcsc/pcsc_context.c +290 -0
- data/ext/smartcard_pcsc/pcsc_exception.c +39 -0
- data/ext/smartcard_pcsc/pcsc_io_request.c +129 -0
- data/ext/smartcard_pcsc/pcsc_main.c +11 -0
- data/ext/smartcard_pcsc/pcsc_multi_strings.c +70 -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/lib/smartcard/pcsc_exception.rb +5 -0
- data/smartcard.gemspec +66 -0
- data/test/test_containers.rb +53 -0
- data/test/test_smoke.rb +22 -0
- data/tests/ts_pcsc_ext.rb +72 -0
- metadata +102 -0
@@ -0,0 +1,195 @@
|
|
1
|
+
#include "pcsc.h"
|
2
|
+
|
3
|
+
#ifdef MAKE_RDOC_HAPPY
|
4
|
+
mSmartcard = rb_define_module("Smartcard");
|
5
|
+
mPcsc = rb_define_module_under(mSmartcard, "PCSC");
|
6
|
+
#endif
|
7
|
+
|
8
|
+
void Init_PCSC_Consts() {
|
9
|
+
/* MAX_ATR_SIZE : Maximum ATR size. */
|
10
|
+
rb_define_const(mPcsc, "MAX_ATR_SIZE", INT2NUM(MAX_ATR_SIZE));
|
11
|
+
|
12
|
+
/* SCARD_S_SUCCESS : All is good. */
|
13
|
+
rb_define_const(mPcsc, "SCARD_S_SUCCESS", INT2NUM(SCARD_S_SUCCESS));
|
14
|
+
/* SCARD_F_INTERNAL_ERROR : An internal consistency check failed. */
|
15
|
+
rb_define_const(mPcsc, "SCARD_F_INTERNAL_ERROR", INT2NUM(SCARD_F_INTERNAL_ERROR));
|
16
|
+
/* SCARD_E_CANCELLED : The action was cancelled by an SCardCancel request. */
|
17
|
+
rb_define_const(mPcsc, "SCARD_E_CANCELLED", INT2NUM(SCARD_E_CANCELLED));
|
18
|
+
/* SCARD_E_INVALID_HANDLE : The supplied handle was invalid. */
|
19
|
+
rb_define_const(mPcsc, "SCARD_E_INVALID_HANDLE", INT2NUM(SCARD_E_INVALID_HANDLE));
|
20
|
+
/* MAX_ATR_SIZE : One or more of the supplied parameters could not be properly interpreted. */
|
21
|
+
rb_define_const(mPcsc, "SCARD_E_INVALID_PARAMETER", INT2NUM(MAX_ATR_SIZE));
|
22
|
+
/* SCARD_E_INVALID_TARGET : Registry startup information is missing or invalid. */
|
23
|
+
rb_define_const(mPcsc, "SCARD_E_INVALID_TARGET", INT2NUM(SCARD_E_INVALID_TARGET));
|
24
|
+
/* SCARD_E_NO_MEMORY : Not enough memory available to complete this command. */
|
25
|
+
rb_define_const(mPcsc, "SCARD_E_NO_MEMORY", INT2NUM(SCARD_E_NO_MEMORY));
|
26
|
+
/* SCARD_F_WAITED_TOO_LONG : An internal consistency timer has expired. */
|
27
|
+
rb_define_const(mPcsc, "SCARD_F_WAITED_TOO_LONG", INT2NUM(SCARD_F_WAITED_TOO_LONG));
|
28
|
+
/* SCARD_E_INSUFFICIENT_BUFFER : The data buffer to receive returned data is too small for the returned data. */
|
29
|
+
rb_define_const(mPcsc, "SCARD_E_INSUFFICIENT_BUFFER", INT2NUM(SCARD_E_INSUFFICIENT_BUFFER));
|
30
|
+
/* SCARD_E_UNKNOWN_READER : The specified reader name is not recognized. */
|
31
|
+
rb_define_const(mPcsc, "SCARD_E_UNKNOWN_READER", INT2NUM(SCARD_E_UNKNOWN_READER));
|
32
|
+
/* SCARD_E_SHARING_VIOLATION : The user-specified timeout value has expired. */
|
33
|
+
rb_define_const(mPcsc, "SCARD_E_SHARING_VIOLATION", INT2NUM(SCARD_E_SHARING_VIOLATION));
|
34
|
+
/* SCARD_E_NO_SMARTCARD : The smart card cannot be accessed because of other connections outstanding. */
|
35
|
+
rb_define_const(mPcsc, "SCARD_E_NO_SMARTCARD", INT2NUM(SCARD_E_NO_SMARTCARD));
|
36
|
+
/* SCARD_E_TIMEOUT : The operation requires a Smart Card, but no Smart Card is currently in the device. */
|
37
|
+
rb_define_const(mPcsc, "SCARD_E_TIMEOUT", INT2NUM(SCARD_E_TIMEOUT));
|
38
|
+
/* SCARD_E_UNKNOWN_CARD : The specified smart card name is not recognized. */
|
39
|
+
rb_define_const(mPcsc, "SCARD_E_UNKNOWN_CARD", INT2NUM(SCARD_E_UNKNOWN_CARD));
|
40
|
+
/* SCARD_E_CANT_DISPOSE : The system could not dispose of the media in the requested manner. */
|
41
|
+
rb_define_const(mPcsc, "SCARD_E_CANT_DISPOSE", INT2NUM(SCARD_E_CANT_DISPOSE));
|
42
|
+
/* SCARD_E_PROTO_MISMATCH : The requested protocols are incompatible with the protocol currently in use with the smart card. */
|
43
|
+
rb_define_const(mPcsc, "SCARD_E_PROTO_MISMATCH", INT2NUM(SCARD_E_PROTO_MISMATCH));
|
44
|
+
/* SCARD_E_NOT_READY : The reader or smart card is not ready to accept commands. */
|
45
|
+
rb_define_const(mPcsc, "SCARD_E_NOT_READY", INT2NUM(SCARD_E_NOT_READY));
|
46
|
+
/* SCARD_E_INVALID_VALUE : One or more of the supplied parameters values could not be properly interpreted. */
|
47
|
+
rb_define_const(mPcsc, "SCARD_E_INVALID_VALUE", INT2NUM(SCARD_E_INVALID_VALUE));
|
48
|
+
/* SCARD_E_SYSTEM_CANCELLED : The action was cancelled by the system, presumably to log off or shut down. */
|
49
|
+
rb_define_const(mPcsc, "SCARD_E_SYSTEM_CANCELLED", INT2NUM(SCARD_E_SYSTEM_CANCELLED));
|
50
|
+
/* SCARD_F_COMM_ERROR : An internal communications error has been detected. */
|
51
|
+
rb_define_const(mPcsc, "SCARD_F_COMM_ERROR", INT2NUM(SCARD_F_COMM_ERROR));
|
52
|
+
/* SCARD_F_UNKNOWN_ERROR : An internal error has been detected, but the source is unknown. */
|
53
|
+
rb_define_const(mPcsc, "SCARD_F_UNKNOWN_ERROR", INT2NUM(SCARD_F_UNKNOWN_ERROR));
|
54
|
+
/* SCARD_E_INVALID_ATR : An ATR obtained from the registry is not a valid ATR string. */
|
55
|
+
rb_define_const(mPcsc, "SCARD_E_INVALID_ATR", INT2NUM(SCARD_E_INVALID_ATR));
|
56
|
+
/* SCARD_E_NOT_TRANSACTED : An attempt was made to end a non-existent transaction. */
|
57
|
+
rb_define_const(mPcsc, "SCARD_E_NOT_TRANSACTED", INT2NUM(SCARD_E_NOT_TRANSACTED));
|
58
|
+
/* SCARD_E_READER_UNAVAILABLE : The specified reader is not currently available for use. */
|
59
|
+
rb_define_const(mPcsc, "SCARD_E_READER_UNAVAILABLE", INT2NUM(SCARD_E_READER_UNAVAILABLE));
|
60
|
+
/* SCARD_W_UNSUPPORTED_CARD : The reader cannot communicate with the card, due to ATR string configuration conflicts. */
|
61
|
+
rb_define_const(mPcsc, "SCARD_W_UNSUPPORTED_CARD", INT2NUM(SCARD_W_UNSUPPORTED_CARD));
|
62
|
+
/* SCARD_W_UNRESPONSIVE_CARD : The smart card is not responding to a reset. */
|
63
|
+
rb_define_const(mPcsc, "SCARD_W_UNRESPONSIVE_CARD", INT2NUM(SCARD_W_UNRESPONSIVE_CARD));
|
64
|
+
/* SCARD_W_UNPOWERED_CARD : Power has been removed from the smart card, so that further communication is not possible. */
|
65
|
+
rb_define_const(mPcsc, "SCARD_W_UNPOWERED_CARD", INT2NUM(SCARD_W_UNPOWERED_CARD));
|
66
|
+
/* SCARD_W_RESET_CARD : The smart card has been reset, so any shared state information is invalid. */
|
67
|
+
rb_define_const(mPcsc, "SCARD_W_RESET_CARD", INT2NUM(SCARD_W_RESET_CARD));
|
68
|
+
/* SCARD_W_REMOVED_CARD : The smart card has been removed, so further communication is not possible. */
|
69
|
+
rb_define_const(mPcsc, "SCARD_W_REMOVED_CARD", INT2NUM(SCARD_W_REMOVED_CARD));
|
70
|
+
/* SCARD_E_PCI_TOO_SMALL : The PCI Receive buffer was too small. */
|
71
|
+
rb_define_const(mPcsc, "SCARD_E_PCI_TOO_SMALL", INT2NUM(SCARD_E_PCI_TOO_SMALL));
|
72
|
+
/* SCARD_E_READER_UNSUPPORTED : The reader driver does not meet minimal requirements for support. */
|
73
|
+
rb_define_const(mPcsc, "SCARD_E_READER_UNSUPPORTED", INT2NUM(SCARD_E_READER_UNSUPPORTED));
|
74
|
+
/* SCARD_E_DUPLICATE_READER : The reader driver did not produce a unique reader name. */
|
75
|
+
rb_define_const(mPcsc, "SCARD_E_DUPLICATE_READER", INT2NUM(SCARD_E_DUPLICATE_READER));
|
76
|
+
/* SCARD_E_CARD_UNSUPPORTED : The smart card does not meet minimal requirements for support. */
|
77
|
+
rb_define_const(mPcsc, "SCARD_E_CARD_UNSUPPORTED", INT2NUM(SCARD_E_CARD_UNSUPPORTED));
|
78
|
+
/* SCARD_E_NO_SERVICE : The Smart card resource manager is not running. */
|
79
|
+
rb_define_const(mPcsc, "SCARD_E_NO_SERVICE", INT2NUM(SCARD_E_NO_SERVICE));
|
80
|
+
/* SCARD_E_SERVICE_STOPPED : The Smart card resource manager has shut down. */
|
81
|
+
rb_define_const(mPcsc, "SCARD_E_SERVICE_STOPPED", INT2NUM(SCARD_E_SERVICE_STOPPED));
|
82
|
+
#if defined(SCARD_E_NO_READERS_AVAILABLE)
|
83
|
+
/* SCARD_E_NO_READERS_AVAILABLE : Cannot find a smart card reader. */
|
84
|
+
rb_define_const(mPcsc, "SCARD_E_NO_READERS_AVAILABLE", INT2NUM(SCARD_E_NO_READERS_AVAILABLE));
|
85
|
+
#endif /* SCARD_E_NO_READERS_AVAILABLE */
|
86
|
+
|
87
|
+
/* SCARD_SCOPE_USER : Scope in user space. */
|
88
|
+
rb_define_const(mPcsc, "SCOPE_USER", INT2NUM(SCARD_SCOPE_USER));
|
89
|
+
/* SCARD_SCOPE_TERMINAL : Scope in terminal. */
|
90
|
+
rb_define_const(mPcsc, "SCOPE_TERMINAL", INT2NUM(SCARD_SCOPE_TERMINAL));
|
91
|
+
/* SCARD_SCOPE_SYSTEM : Scope in system. */
|
92
|
+
rb_define_const(mPcsc, "SCOPE_SYSTEM", INT2NUM(SCARD_SCOPE_SYSTEM));
|
93
|
+
|
94
|
+
/* SCARD_STATE_UNAWARE : App wants status. */
|
95
|
+
rb_define_const(mPcsc, "STATE_UNAWARE", INT2NUM(SCARD_STATE_UNAWARE));
|
96
|
+
/* SCARD_STATE_IGNORE : Ignore this reader. */
|
97
|
+
rb_define_const(mPcsc, "STATE_IGNORE", INT2NUM(SCARD_STATE_IGNORE));
|
98
|
+
/* SCARD_STATE_CHANGED : State has changed. */
|
99
|
+
rb_define_const(mPcsc, "STATE_CHANGED", INT2NUM(SCARD_STATE_CHANGED));
|
100
|
+
/* SCARD_STATE_UNKNOWN : Reader unknown. */
|
101
|
+
rb_define_const(mPcsc, "STATE_UNKNOWN", INT2NUM(SCARD_STATE_UNKNOWN));
|
102
|
+
/* SCARD_STATE_UNAVAILABLE : Status unavailable. */
|
103
|
+
rb_define_const(mPcsc, "STATE_UNAVAILABLE", INT2NUM(SCARD_STATE_UNAVAILABLE));
|
104
|
+
/* SCARD_STATE_EMPTY : Card removed. */
|
105
|
+
rb_define_const(mPcsc, "STATE_EMPTY", INT2NUM(SCARD_STATE_EMPTY));
|
106
|
+
/* SCARD_STATE_PRESENT : Card inserted. */
|
107
|
+
rb_define_const(mPcsc, "STATE_PRESENT", INT2NUM(SCARD_STATE_PRESENT));
|
108
|
+
/* SCARD_STATE_ATRMATCH : ATR matches card. */
|
109
|
+
rb_define_const(mPcsc, "STATE_ATRMATCH", INT2NUM(SCARD_STATE_ATRMATCH));
|
110
|
+
/* SCARD_STATE_EXCLUSIVE : Exclusive Mode. */
|
111
|
+
rb_define_const(mPcsc, "STATE_EXCLUSIVE", INT2NUM(SCARD_STATE_EXCLUSIVE));
|
112
|
+
/* SCARD_STATE_INUSE : Shared Mode. */
|
113
|
+
rb_define_const(mPcsc, "STATE_INUSE", INT2NUM(SCARD_STATE_INUSE));
|
114
|
+
/* SCARD_STATE_MUTE : Unresponsive card. */
|
115
|
+
rb_define_const(mPcsc, "STATE_MUTE", INT2NUM(SCARD_STATE_MUTE));
|
116
|
+
#if defined(SCARD_STATE_UNPOWERED)
|
117
|
+
/* SCARD_STATE_UNPOWERED : Unpowered card. */
|
118
|
+
rb_define_const(mPcsc, "STATE_UNPOWERED", INT2NUM(SCARD_STATE_UNPOWERED));
|
119
|
+
#endif /* SCARD_STATE_UNPOWERED */
|
120
|
+
|
121
|
+
/* INFINITE : Infinite timeout. */
|
122
|
+
rb_define_const(mPcsc, "INFINITE_TIMEOUT", INT2NUM(INFINITE));
|
123
|
+
|
124
|
+
|
125
|
+
/* SCARD_UNKNOWNU : Card is absent. */
|
126
|
+
rb_define_const(mPcsc, "STATUS_ABSENT", INT2NUM(SCARD_ABSENT));
|
127
|
+
/* SCARD_PRESENT : Card is present. */
|
128
|
+
rb_define_const(mPcsc, "STATUS_PRESENT", INT2NUM(SCARD_PRESENT));
|
129
|
+
/* SCARD_SWALLOWED : Card not powered. */
|
130
|
+
rb_define_const(mPcsc, "STATUS_SWALLOWED", INT2NUM(SCARD_SWALLOWED));
|
131
|
+
/* SCARD_POWERED : Card is powered. */
|
132
|
+
rb_define_const(mPcsc, "STATUS_POWERED", INT2NUM(SCARD_POWERED));
|
133
|
+
/* SCARD_NEGOTIABLE : Ready for PTS. */
|
134
|
+
rb_define_const(mPcsc, "STATUS_NEGOTIABLE", INT2NUM(SCARD_NEGOTIABLE));
|
135
|
+
/* SCARD_SPECIFIC : PTS has been set. */
|
136
|
+
rb_define_const(mPcsc, "STATUS_SPECIFIC", INT2NUM(SCARD_SPECIFIC));
|
137
|
+
|
138
|
+
#if defined(SCARD_PROTOCOL_UNSET)
|
139
|
+
/* SCARD_PROTOCOL_UNSET : Protocol not set. */
|
140
|
+
rb_define_const(mPcsc, "PROTOCOL_UNSET", INT2NUM(SCARD_PROTOCOL_UNSET));
|
141
|
+
#endif /* SCARD_PROTOCOL_UNSET */
|
142
|
+
/* SCARD_PROTOCOL_T0 : T=0 active protocol. */
|
143
|
+
rb_define_const(mPcsc, "PROTOCOL_T0", INT2NUM(SCARD_PROTOCOL_T0));
|
144
|
+
/* SCARD_PROTOCOL_T1 : T=1 active protocol. */
|
145
|
+
rb_define_const(mPcsc, "PROTOCOL_T1", INT2NUM(SCARD_PROTOCOL_T1));
|
146
|
+
/* SCARD_PROTOCOL_RAW : Raw active protocol. */
|
147
|
+
rb_define_const(mPcsc, "PROTOCOL_RAW", INT2NUM(SCARD_PROTOCOL_RAW));
|
148
|
+
#if defined(SCARD_PROTOCOL_UNSET)
|
149
|
+
/* SCARD_PROTOCOL_T15 : T=15 protocol. */
|
150
|
+
rb_define_const(mPcsc, "PROTOCOL_T15", INT2NUM(SCARD_PROTOCOL_T15));
|
151
|
+
#endif /* SCARD_PROTOCOL_UNSET */
|
152
|
+
/* SCARD_PROTOCOL_ANY : IFD determines protocol. */
|
153
|
+
rb_define_const(mPcsc, "PROTOCOL_ANY", INT2NUM(SCARD_PROTOCOL_ANY));
|
154
|
+
|
155
|
+
/* SCARD_SHARE_EXCLUSIVE : Exclusive mode only. */
|
156
|
+
rb_define_const(mPcsc, "SHARE_EXCLUSIVE", INT2NUM(SCARD_SHARE_EXCLUSIVE));
|
157
|
+
/* SCARD_SHARE_SHARED : Shared mode only. */
|
158
|
+
rb_define_const(mPcsc, "SHARE_SHARED", INT2NUM(SCARD_SHARE_SHARED));
|
159
|
+
/* SCARD_SHARE_DIRECT : Raw mode only. */
|
160
|
+
rb_define_const(mPcsc, "SHARE_DIRECT", INT2NUM(SCARD_SHARE_DIRECT));
|
161
|
+
|
162
|
+
/* SCARD_LEAVE_CARD : Do nothing on close. */
|
163
|
+
rb_define_const(mPcsc, "DISPOSITION_LEAVE", INT2NUM(SCARD_LEAVE_CARD));
|
164
|
+
/* SCARD_RESET_CARD : Reset on close. */
|
165
|
+
rb_define_const(mPcsc, "DISPOSITION_RESET", INT2NUM(SCARD_RESET_CARD));
|
166
|
+
/* SCARD_UNPOWER_CARD : Power down on close. */
|
167
|
+
rb_define_const(mPcsc, "DISPOSITION_UNPOWER", INT2NUM(SCARD_UNPOWER_CARD));
|
168
|
+
/* SCARD_EJECT_CARD : Eject on close. */
|
169
|
+
rb_define_const(mPcsc, "DISPOSITION_EJECT", INT2NUM(SCARD_EJECT_CARD));
|
170
|
+
|
171
|
+
/* SCARD_LEAVE_CARD : Do nothing. */
|
172
|
+
rb_define_const(mPcsc, "INITIALIZATION_LEAVE", INT2NUM(SCARD_LEAVE_CARD));
|
173
|
+
/* SCARD_RESET_CARD : Reset the card (warm reset). */
|
174
|
+
rb_define_const(mPcsc, "INITIALIZATION_RESET", INT2NUM(SCARD_RESET_CARD));
|
175
|
+
/* SCARD_UNPOWER_CARD : Power down the card (cold reset). */
|
176
|
+
rb_define_const(mPcsc, "INITIALIZATION_UNPOWER", INT2NUM(SCARD_UNPOWER_CARD));
|
177
|
+
/* SCARD_EJECT_CARD : Eject the card. */
|
178
|
+
rb_define_const(mPcsc, "INITIALIZATION_EJECT", INT2NUM(SCARD_EJECT_CARD));
|
179
|
+
|
180
|
+
/* SCARD_ATTR_ATR_STRING : ATR of the card. */
|
181
|
+
rb_define_const(mPcsc, "ATTR_ATR_STRING", INT2NUM(SCARD_ATTR_ATR_STRING));
|
182
|
+
/* SCARD_ATTR_VENDOR_IFD_VERSION : Vendor-supplied interface driver version. */
|
183
|
+
rb_define_const(mPcsc, "ATTR_VENDOR_IFD_VERSION", INT2NUM(SCARD_ATTR_VENDOR_IFD_VERSION));
|
184
|
+
/* SCARD_ATTR_VENDOR_NAME : Name of the interface driver version. */
|
185
|
+
rb_define_const(mPcsc, "ATTR_VENDOR_NAME", INT2NUM(SCARD_ATTR_VENDOR_NAME));
|
186
|
+
/* SCARD_ATTR_MAXINPUT : Maximum size of an APDU supported by the reader. */
|
187
|
+
rb_define_const(mPcsc, "ATTR_MAXINPUT", INT2NUM(SCARD_ATTR_MAXINPUT));
|
188
|
+
|
189
|
+
/* SCARD_PCI_T0 : IoRequest for transmitting using the T=0 protocol. */
|
190
|
+
rb_define_const(mPcsc, "IOREQUEST_T0", _PCSC_IoRequest_lowlevel_new(SCARD_PCI_T0));
|
191
|
+
/* SCARD_PCI_T1 : IoRequest for transmitting using the T=1 protocol. */
|
192
|
+
rb_define_const(mPcsc, "IOREQUEST_T1", _PCSC_IoRequest_lowlevel_new(SCARD_PCI_T1));
|
193
|
+
/* SCARD_PCI_RAW : IoRequest for transmitting using the RAW protocol. */
|
194
|
+
rb_define_const(mPcsc, "IOREQUEST_RAW", _PCSC_IoRequest_lowlevel_new(SCARD_PCI_RAW));
|
195
|
+
}
|
@@ -0,0 +1,290 @@
|
|
1
|
+
#include "pcsc.h"
|
2
|
+
|
3
|
+
VALUE cPcscContext;
|
4
|
+
|
5
|
+
/* Wraps a SCARDHANDLE, tracking whether it was released or not, together with the last error that occured on it. */
|
6
|
+
struct SCardContextEx {
|
7
|
+
SCARDCONTEXT pcsc_context;
|
8
|
+
DWORD pcsc_error;
|
9
|
+
int released;
|
10
|
+
};
|
11
|
+
|
12
|
+
|
13
|
+
/* Custom free for Smartcard::PCSC::Context. Releases the PC/SC context if that was not already done. */
|
14
|
+
static void PCSC_Context_free(struct SCardContextEx *_context) {
|
15
|
+
if(_context != NULL) {
|
16
|
+
if(!_context->released)
|
17
|
+
SCardReleaseContext(_context->pcsc_context);
|
18
|
+
xfree(_context);
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
/* Custom allocation for Smartcard::PCSC::Context. Wraps a SCardContextEx structure. */
|
23
|
+
static VALUE PCSC_Context_alloc(VALUE klass) {
|
24
|
+
struct SCardContextEx *context;
|
25
|
+
|
26
|
+
VALUE rbContext = Data_Make_Struct(klass, struct SCardContextEx, NULL, PCSC_Context_free, context);
|
27
|
+
context->released = 1;
|
28
|
+
return rbContext;
|
29
|
+
}
|
30
|
+
|
31
|
+
/* :Document-method: new
|
32
|
+
* call-seq:
|
33
|
+
* new(scope) --> context
|
34
|
+
*
|
35
|
+
* Creates an application context connecting to the PC/SC resource manager.
|
36
|
+
* A context is required to access every piece of PC/SC functionality.
|
37
|
+
* Wraps _SCardEstablishContext_ in PC/SC.
|
38
|
+
*
|
39
|
+
* +scope+:: scope of the context; use one of the Smartcard::PCSC::SCOPE_ constants
|
40
|
+
*/
|
41
|
+
static VALUE PCSC_Context_initialize(VALUE self, VALUE scope) {
|
42
|
+
struct SCardContextEx *context;
|
43
|
+
|
44
|
+
Data_Get_Struct(self, struct SCardContextEx, context);
|
45
|
+
|
46
|
+
context->pcsc_error = SCardEstablishContext(NUM2INT(scope), NULL, NULL, &context->pcsc_context);
|
47
|
+
if(context->pcsc_error != SCARD_S_SUCCESS)
|
48
|
+
_PCSC_Exception_raise(context->pcsc_error, "SCardEstablishContext");
|
49
|
+
else
|
50
|
+
context->released = 0;
|
51
|
+
return self;
|
52
|
+
}
|
53
|
+
|
54
|
+
/* :Document-method: release
|
55
|
+
* call-seq:
|
56
|
+
* release() --> self
|
57
|
+
*
|
58
|
+
* Destroys the communication context connecting to the PC/SC Resource Manager.
|
59
|
+
* Should be the last PC/SC function called, because a context is required to access every piece of PC/SC functionality.
|
60
|
+
* Wraps _SCardReleaseContext_ in PC/SC.
|
61
|
+
*/
|
62
|
+
static VALUE PCSC_Context_release(VALUE self) {
|
63
|
+
struct SCardContextEx *context;
|
64
|
+
|
65
|
+
Data_Get_Struct(self, struct SCardContextEx, context);
|
66
|
+
if(context == NULL) return self;
|
67
|
+
|
68
|
+
if(!context->released) {
|
69
|
+
context->pcsc_error = SCardReleaseContext(context->pcsc_context);
|
70
|
+
context->released = 1;
|
71
|
+
if(context->pcsc_error != SCARD_S_SUCCESS)
|
72
|
+
_PCSC_Exception_raise(context->pcsc_error, "SCardReleaseContext");
|
73
|
+
}
|
74
|
+
return self;
|
75
|
+
}
|
76
|
+
|
77
|
+
/* :Document-method: is_valid
|
78
|
+
* call-seq:
|
79
|
+
* is_valid() --> valid_boolean
|
80
|
+
*
|
81
|
+
* Checks if the PC/SC context is still valid.
|
82
|
+
* A context may become invalid if the resource manager service has been shut down.
|
83
|
+
* Wraps _SCardIsValidContext_ in PC/SC.
|
84
|
+
*
|
85
|
+
* Returns a boolean value with the obvious meaning.
|
86
|
+
*/
|
87
|
+
static VALUE PCSC_Context_is_valid(VALUE self) {
|
88
|
+
struct SCardContextEx *context;
|
89
|
+
Data_Get_Struct(self, struct SCardContextEx, context);
|
90
|
+
if(context == NULL) return self;
|
91
|
+
|
92
|
+
#if defined(RB_SMARTCARD_OSX_TIGER_HACK) || defined(PCSC_SURROGATE_SCARD_IS_VALID_CONTEXT)
|
93
|
+
return Qtrue;
|
94
|
+
#else
|
95
|
+
context->pcsc_error = SCardIsValidContext(context->pcsc_context);
|
96
|
+
return (context->pcsc_error == SCARD_S_SUCCESS) ? Qtrue : Qfalse;
|
97
|
+
#endif
|
98
|
+
}
|
99
|
+
|
100
|
+
/* :Document-method: list_reader_groups
|
101
|
+
* call-seq:
|
102
|
+
* list_reader_groups() --> reader_groups
|
103
|
+
*
|
104
|
+
* Retrieves the currently available reader groups on the system.
|
105
|
+
* Wraps _SCardListReaderGroups_ in PC/SC.
|
106
|
+
*
|
107
|
+
* Returns an array of strings containing the names of all the smart-card readers in the system.
|
108
|
+
*/
|
109
|
+
static VALUE PCSC_Context_list_reader_groups(VALUE self) {
|
110
|
+
struct SCardContextEx *context;
|
111
|
+
VALUE rbGroups;
|
112
|
+
char *groups;
|
113
|
+
DWORD groups_length;
|
114
|
+
|
115
|
+
Data_Get_Struct(self, struct SCardContextEx, context);
|
116
|
+
if(context == NULL) return Qnil;
|
117
|
+
|
118
|
+
context->pcsc_error = SCardListReaderGroups(context->pcsc_context, NULL, &groups_length);
|
119
|
+
if(context->pcsc_error == SCARD_S_SUCCESS) {
|
120
|
+
groups = ALLOC_N(char, groups_length);
|
121
|
+
if(groups != NULL) {
|
122
|
+
context->pcsc_error = SCardListReaderGroups(context->pcsc_context, groups, &groups_length);
|
123
|
+
if(context->pcsc_error == SCARD_S_SUCCESS) {
|
124
|
+
rbGroups = PCSC_Internal_multistring_to_ruby_array(groups, groups_length);
|
125
|
+
xfree(groups);
|
126
|
+
return rbGroups;
|
127
|
+
}
|
128
|
+
else
|
129
|
+
xfree(groups);
|
130
|
+
}
|
131
|
+
}
|
132
|
+
if(context->pcsc_error != SCARD_S_SUCCESS)
|
133
|
+
_PCSC_Exception_raise(context->pcsc_error, "SCardListReaderGroups");
|
134
|
+
return Qnil;
|
135
|
+
}
|
136
|
+
|
137
|
+
/* :Document-method: list_readers
|
138
|
+
* call-seq:
|
139
|
+
* list_readers(reader_groups) --> readers
|
140
|
+
*
|
141
|
+
* Retrieves a subset of the currently available card readers in the system.
|
142
|
+
* Wraps _SCardListReaders_ in PC/SC.
|
143
|
+
*
|
144
|
+
* Returns an array of strings containing the names of the card readers in the given groups.
|
145
|
+
*
|
146
|
+
* +reader_groups+:: array of strings indicating the reader groups to list; also accepts a string or +nil+ (meaning all readers)
|
147
|
+
*/
|
148
|
+
static VALUE PCSC_Context_list_readers(VALUE self, VALUE rbGroups) {
|
149
|
+
struct SCardContextEx *context;
|
150
|
+
VALUE rbReaders;
|
151
|
+
char *groups;
|
152
|
+
DWORD readers_length;
|
153
|
+
|
154
|
+
Data_Get_Struct(self, struct SCardContextEx, context);
|
155
|
+
if(context == NULL) return Qnil;
|
156
|
+
|
157
|
+
if(PCSC_Internal_ruby_strings_to_multistring(rbGroups, &groups) == 0) {
|
158
|
+
rb_raise(rb_eArgError, "invalid reader groups set (expecting nil or string or array of strings)");
|
159
|
+
return Qnil;
|
160
|
+
}
|
161
|
+
|
162
|
+
context->pcsc_error = SCardListReaders(context->pcsc_context, groups, NULL, &readers_length);
|
163
|
+
if(context->pcsc_error == SCARD_S_SUCCESS) {
|
164
|
+
char *readers = ALLOC_N(char, readers_length);
|
165
|
+
if(readers != NULL) {
|
166
|
+
context->pcsc_error = SCardListReaders(context->pcsc_context, groups, readers, &readers_length);
|
167
|
+
if(context->pcsc_error == SCARD_S_SUCCESS) {
|
168
|
+
rbReaders = PCSC_Internal_multistring_to_ruby_array(readers, readers_length);
|
169
|
+
xfree(readers);
|
170
|
+
if(groups != NULL) xfree(groups);
|
171
|
+
return rbReaders;
|
172
|
+
}
|
173
|
+
else
|
174
|
+
xfree(readers);
|
175
|
+
}
|
176
|
+
}
|
177
|
+
if(groups != NULL) xfree(groups);
|
178
|
+
if(context->pcsc_error != SCARD_S_SUCCESS)
|
179
|
+
_PCSC_Exception_raise(context->pcsc_error, "SCardListReaders");
|
180
|
+
return Qnil;
|
181
|
+
}
|
182
|
+
|
183
|
+
/* :Document-method: cancel
|
184
|
+
* call-seq:
|
185
|
+
* cancel() --> self
|
186
|
+
*
|
187
|
+
* Cancels all pending blocking requests on the Context#get_status_change function.
|
188
|
+
* Wraps _SCardCancel_ in PC/SC.
|
189
|
+
*/
|
190
|
+
static VALUE PCSC_Context_cancel(VALUE self) {
|
191
|
+
struct SCardContextEx *context;
|
192
|
+
|
193
|
+
Data_Get_Struct(self, struct SCardContextEx, context);
|
194
|
+
if(context == NULL) return self;
|
195
|
+
|
196
|
+
context->pcsc_error = SCardCancel(context->pcsc_context);
|
197
|
+
if(context->pcsc_error != SCARD_S_SUCCESS)
|
198
|
+
_PCSC_Exception_raise(context->pcsc_error, "SCardCancel");
|
199
|
+
return self;
|
200
|
+
}
|
201
|
+
|
202
|
+
/* :Document-method: get_status_change
|
203
|
+
* call-seq:
|
204
|
+
* get_status_change(reader_states, timeout) --> self
|
205
|
+
*
|
206
|
+
* Blocks until a status change occurs in one of the given readers.
|
207
|
+
* Wraps _SCardGetStatusChange_ in PC/SC.
|
208
|
+
*
|
209
|
+
* +reader_states+:: Smartcard::PCSC::ReaderStates instance indicating the readers to be monitored, and the interesting state changes
|
210
|
+
* +timeout+:: maximum ammount of time (in milliseconds) to block; use Smartcard::PCSC::INFINITE_TIMEOUT to block forever
|
211
|
+
*
|
212
|
+
* The function blocks until the state of one of the readers in +reader_states+ becomes different from the +current_state+ (accessible via
|
213
|
+
* ReaderStates#set_current_state_of and ReaderStates#current_state_of). The new state is stored in +event_state+ (accessible via
|
214
|
+
* ReaderStates#set_event_state_of and ReaderStates#event_state_of)
|
215
|
+
*/
|
216
|
+
static VALUE PCSC_Context_get_status_change(VALUE self, VALUE rbReaderStates, VALUE rbTimeout) {
|
217
|
+
struct SCardContextEx *context;
|
218
|
+
SCARD_READERSTATE *reader_states;
|
219
|
+
size_t reader_states_count;
|
220
|
+
DWORD timeout;
|
221
|
+
|
222
|
+
Data_Get_Struct(self, struct SCardContextEx, context);
|
223
|
+
if(context == NULL) return self;
|
224
|
+
|
225
|
+
if(TYPE(rbTimeout) == T_NIL || TYPE(rbTimeout) == T_FALSE)
|
226
|
+
timeout = INFINITE;
|
227
|
+
else
|
228
|
+
timeout = NUM2INT(rbTimeout);
|
229
|
+
|
230
|
+
if(_PCSC_ReaderStates_lowlevel_get(rbReaderStates, &reader_states, &reader_states_count) == 0)
|
231
|
+
rb_raise(rb_eArgError, "first parameter is not a ReaderStates instance or nil");
|
232
|
+
else {
|
233
|
+
context->pcsc_error = SCardGetStatusChange(context->pcsc_context, timeout, reader_states, reader_states_count);
|
234
|
+
if(context->pcsc_error != SCARD_S_SUCCESS)
|
235
|
+
_PCSC_Exception_raise(context->pcsc_error, "SCardGetStatusChange");
|
236
|
+
}
|
237
|
+
return self;
|
238
|
+
}
|
239
|
+
|
240
|
+
/* :Document-method: last_error
|
241
|
+
* call-seq:
|
242
|
+
* card.last_error() --> last_error
|
243
|
+
*
|
244
|
+
* The error code returned by the last PC/SC call. Useful for recovering from exceptions.
|
245
|
+
*
|
246
|
+
* The returned code is a number, and should be one of the Smartcard::PCSC::SCARD_ constants.
|
247
|
+
* The code indicating correct operation is Smartcard::PCSC::SCARD_S_SUCCESS.
|
248
|
+
*/
|
249
|
+
static VALUE PCSC_Context_last_error(VALUE self) {
|
250
|
+
struct SCardContextEx *context;
|
251
|
+
|
252
|
+
Data_Get_Struct(self, struct SCardContextEx, context);
|
253
|
+
if(context == NULL) return Qnil;
|
254
|
+
|
255
|
+
return UINT2NUM(context->pcsc_error);
|
256
|
+
}
|
257
|
+
|
258
|
+
#ifdef MAKE_RDOC_HAPPY
|
259
|
+
mSmartcard = rb_define_module("Smartcard");
|
260
|
+
mPcsc = rb_define_module_under(mSmartcard, "PCSC");
|
261
|
+
#endif
|
262
|
+
|
263
|
+
/* :Document-class: Smartcard::PCSC::Context
|
264
|
+
* Connects Ruby to the PC/SC resource manager.
|
265
|
+
* Wraps a _SCARDCONTEXT_ structure.
|
266
|
+
*/
|
267
|
+
void Init_PCSC_Context() {
|
268
|
+
cPcscContext = rb_define_class_under(mPcsc, "Context", rb_cObject);
|
269
|
+
rb_define_alloc_func(cPcscContext, PCSC_Context_alloc);
|
270
|
+
rb_define_method(cPcscContext, "initialize", PCSC_Context_initialize, 1);
|
271
|
+
rb_define_method(cPcscContext, "release", PCSC_Context_release, 0);
|
272
|
+
rb_define_method(cPcscContext, "is_valid", PCSC_Context_is_valid, 0);
|
273
|
+
rb_define_method(cPcscContext, "list_reader_groups", PCSC_Context_list_reader_groups, 0);
|
274
|
+
rb_define_method(cPcscContext, "list_readers", PCSC_Context_list_readers, 1);
|
275
|
+
rb_define_method(cPcscContext, "cancel", PCSC_Context_cancel, 0);
|
276
|
+
rb_define_method(cPcscContext, "get_status_change", PCSC_Context_get_status_change, 2);
|
277
|
+
rb_define_method(cPcscContext, "last_error", PCSC_Context_last_error, 0);
|
278
|
+
}
|
279
|
+
|
280
|
+
/* Retrieves the SCARDCONTEXT wrapped into a Smartcard::PCSC::Context instance. */
|
281
|
+
int _PCSC_Context_lowlevel_get(VALUE rbContext, SCARDCONTEXT *pcsc_context) {
|
282
|
+
struct SCardContextEx *context;
|
283
|
+
|
284
|
+
if(TYPE(rbContext) != T_DATA || RDATA(rbContext)->dfree != (void (*)(void *))PCSC_Context_free)
|
285
|
+
return 0;
|
286
|
+
|
287
|
+
Data_Get_Struct(rbContext, struct SCardContextEx, context);
|
288
|
+
*pcsc_context = context->pcsc_context;
|
289
|
+
return 1;
|
290
|
+
}
|