smartcard 0.2.0-mswin32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,193 @@
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_E_TIMEOUT));
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_TIMEOUT));
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_TIMEOUT));
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_TIMEOUT));
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_E_TIMEOUT));
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_E_TIMEOUT));
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_E_TIMEOUT));
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_E_TIMEOUT));
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
+ /* SCARD_STATE_UNPOWERED : Unpowered card. */
117
+ rb_define_const(mPcsc, "STATE_UNPOWERED", INT2NUM(SCARD_STATE_UNPOWERED));
118
+
119
+ /* INFINITE : Infinite timeout. */
120
+ rb_define_const(mPcsc, "INFINITE_TIMEOUT", INT2NUM(INFINITE));
121
+
122
+
123
+ /* SCARD_UNKNOWNU : Card is absent. */
124
+ rb_define_const(mPcsc, "STATUS_ABSENT", INT2NUM(SCARD_ABSENT));
125
+ /* SCARD_PRESENT : Card is present. */
126
+ rb_define_const(mPcsc, "STATUS_PRESENT", INT2NUM(SCARD_PRESENT));
127
+ /* SCARD_SWALLOWED : Card not powered. */
128
+ rb_define_const(mPcsc, "STATUS_SWALLOWED", INT2NUM(SCARD_SWALLOWED));
129
+ /* SCARD_POWERED : Card is powered. */
130
+ rb_define_const(mPcsc, "STATUS_POWERED", INT2NUM(SCARD_POWERED));
131
+ /* SCARD_NEGOTIABLE : Ready for PTS. */
132
+ rb_define_const(mPcsc, "STATUS_NEGOTIABLE", INT2NUM(SCARD_NEGOTIABLE));
133
+ /* SCARD_SPECIFIC : PTS has been set. */
134
+ rb_define_const(mPcsc, "STATUS_SPECIFIC", INT2NUM(SCARD_SPECIFIC));
135
+
136
+ #if defined(SCARD_PROTOCOL_UNSET)
137
+ /* SCARD_PROTOCOL_UNSET : Protocol not set. */
138
+ rb_define_const(mPcsc, "PROTOCOL_UNSET", INT2NUM(SCARD_PROTOCOL_UNSET));
139
+ #endif /* SCARD_PROTOCOL_UNSET */
140
+ /* SCARD_PROTOCOL_T0 : T=0 active protocol. */
141
+ rb_define_const(mPcsc, "PROTOCOL_T0", INT2NUM(SCARD_PROTOCOL_T0));
142
+ /* SCARD_PROTOCOL_T1 : T=1 active protocol. */
143
+ rb_define_const(mPcsc, "PROTOCOL_T1", INT2NUM(SCARD_PROTOCOL_T1));
144
+ /* SCARD_PROTOCOL_RAW : Raw active protocol. */
145
+ rb_define_const(mPcsc, "PROTOCOL_RAW", INT2NUM(SCARD_PROTOCOL_RAW));
146
+ #if defined(SCARD_PROTOCOL_UNSET)
147
+ /* SCARD_PROTOCOL_T15 : T=15 protocol. */
148
+ rb_define_const(mPcsc, "PROTOCOL_T15", INT2NUM(SCARD_PROTOCOL_T15));
149
+ #endif /* SCARD_PROTOCOL_UNSET */
150
+ /* SCARD_PROTOCOL_ANY : IFD determines protocol. */
151
+ rb_define_const(mPcsc, "PROTOCOL_ANY", INT2NUM(SCARD_PROTOCOL_ANY));
152
+
153
+ /* SCARD_SHARE_EXCLUSIVE : Exclusive mode only. */
154
+ rb_define_const(mPcsc, "SHARE_EXCLUSIVE", INT2NUM(SCARD_SHARE_EXCLUSIVE));
155
+ /* SCARD_SHARE_SHARED : Shared mode only. */
156
+ rb_define_const(mPcsc, "SHARE_SHARED", INT2NUM(SCARD_SHARE_SHARED));
157
+ /* SCARD_SHARE_DIRECT : Raw mode only. */
158
+ rb_define_const(mPcsc, "SHARE_DIRECT", INT2NUM(SCARD_SHARE_DIRECT));
159
+
160
+ /* SCARD_LEAVE_CARD : Do nothing on close. */
161
+ rb_define_const(mPcsc, "DISPOSITION_LEAVE", INT2NUM(SCARD_LEAVE_CARD));
162
+ /* SCARD_RESET_CARD : Reset on close. */
163
+ rb_define_const(mPcsc, "DISPOSITION_RESET", INT2NUM(SCARD_RESET_CARD));
164
+ /* SCARD_UNPOWER_CARD : Power down on close. */
165
+ rb_define_const(mPcsc, "DISPOSITION_UNPOWER", INT2NUM(SCARD_UNPOWER_CARD));
166
+ /* SCARD_EJECT_CARD : Eject on close. */
167
+ rb_define_const(mPcsc, "DISPOSITION_EJECT", INT2NUM(SCARD_EJECT_CARD));
168
+
169
+ /* SCARD_LEAVE_CARD : Do nothing. */
170
+ rb_define_const(mPcsc, "INITIALIZATION_LEAVE", INT2NUM(SCARD_LEAVE_CARD));
171
+ /* SCARD_RESET_CARD : Reset the card (warm reset). */
172
+ rb_define_const(mPcsc, "INITIALIZATION_RESET", INT2NUM(SCARD_RESET_CARD));
173
+ /* SCARD_UNPOWER_CARD : Power down the card (cold reset). */
174
+ rb_define_const(mPcsc, "INITIALIZATION_UNPOWER", INT2NUM(SCARD_UNPOWER_CARD));
175
+ /* SCARD_EJECT_CARD : Eject the card. */
176
+ rb_define_const(mPcsc, "INITIALIZATION_EJECT", INT2NUM(SCARD_EJECT_CARD));
177
+
178
+ /* SCARD_ATTR_ATR_STRING : ATR of the card. */
179
+ rb_define_const(mPcsc, "ATTR_ATR_STRING", INT2NUM(SCARD_ATTR_ATR_STRING));
180
+ /* SCARD_ATTR_VENDOR_IFD_VERSION : Vendor-supplied interface driver version. */
181
+ rb_define_const(mPcsc, "ATTR_VENDOR_IFD_VERSION", INT2NUM(SCARD_ATTR_VENDOR_IFD_VERSION));
182
+ /* SCARD_ATTR_VENDOR_NAME : Name of the interface driver version. */
183
+ rb_define_const(mPcsc, "ATTR_VENDOR_NAME", INT2NUM(SCARD_ATTR_VENDOR_NAME));
184
+ /* SCARD_ATTR_MAXINPUT : Maximum size of an APDU supported by the reader. */
185
+ rb_define_const(mPcsc, "ATTR_MAXINPUT", INT2NUM(SCARD_ATTR_MAXINPUT));
186
+
187
+
188
+ /*
189
+ #define SCARD_PCI_T0 (&g_rgSCardT0Pci)
190
+ #define SCARD_PCI_T1 (&g_rgSCardT1Pci)
191
+ #define SCARD_PCI_RAW (&g_rgSCardRawPci)
192
+ */
193
+ }
@@ -0,0 +1,286 @@
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
+ rb_raise(rb_eRuntimeError, "SCardEstablishContext: %s", pcsc_stringify_error(context->pcsc_error));
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
+ rb_raise(rb_eRuntimeError, "SCardReleaseContext: %s", pcsc_stringify_error(context->pcsc_error));
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
+ context->pcsc_error = SCardIsValidContext(context->pcsc_context);
93
+ return (context->pcsc_error == SCARD_S_SUCCESS) ? Qtrue : Qfalse;
94
+ }
95
+
96
+ /* :Document-method: list_reader_groups
97
+ * call-seq:
98
+ * list_reader_groups() --> reader_groups
99
+ *
100
+ * Retrieves the currently available reader groups on the system.
101
+ * Wraps _SCardListReaderGroups_ in PC/SC.
102
+ *
103
+ * Returns an array of strings containing the names of all the smart-card readers in the system.
104
+ */
105
+ static VALUE PCSC_Context_list_reader_groups(VALUE self) {
106
+ struct SCardContextEx *context;
107
+ VALUE rbGroups;
108
+ char *groups;
109
+ DWORD groups_length;
110
+
111
+ Data_Get_Struct(self, struct SCardContextEx, context);
112
+ if(context == NULL) return Qnil;
113
+
114
+ context->pcsc_error = SCardListReaderGroups(context->pcsc_context, NULL, &groups_length);
115
+ if(context->pcsc_error == SCARD_S_SUCCESS) {
116
+ groups = ALLOC_N(char, groups_length);
117
+ if(groups != NULL) {
118
+ context->pcsc_error = SCardListReaderGroups(context->pcsc_context, groups, &groups_length);
119
+ if(context->pcsc_error == SCARD_S_SUCCESS) {
120
+ rbGroups = PCSC_Internal_multistring_to_ruby_array(groups, groups_length);
121
+ xfree(groups);
122
+ return rbGroups;
123
+ }
124
+ else
125
+ xfree(groups);
126
+ }
127
+ }
128
+ if(context->pcsc_error != SCARD_S_SUCCESS)
129
+ rb_raise(rb_eRuntimeError, "SCardListReaderGroups: %s", pcsc_stringify_error(context->pcsc_error));
130
+ return Qnil;
131
+ }
132
+
133
+ /* :Document-method: list_readers
134
+ * call-seq:
135
+ * list_readers(reader_groups) --> readers
136
+ *
137
+ * Retrieves a subset of the currently available card readers in the system.
138
+ * Wraps _SCardListReaders_ in PC/SC.
139
+ *
140
+ * Returns an array of strings containing the names of the card readers in the given groups.
141
+ *
142
+ * +reader_groups+:: array of strings indicating the reader groups to list; also accepts a string or +nil+ (meaning all readers)
143
+ */
144
+ static VALUE PCSC_Context_list_readers(VALUE self, VALUE rbGroups) {
145
+ struct SCardContextEx *context;
146
+ VALUE rbReaders;
147
+ char *groups;
148
+ DWORD readers_length;
149
+
150
+ Data_Get_Struct(self, struct SCardContextEx, context);
151
+ if(context == NULL) return Qnil;
152
+
153
+ if(PCSC_Internal_ruby_strings_to_multistring(rbGroups, &groups) == 0) {
154
+ rb_raise(rb_eArgError, "invalid reader groups set (expecting nil or string or array of strings)");
155
+ return Qnil;
156
+ }
157
+
158
+ context->pcsc_error = SCardListReaders(context->pcsc_context, groups, NULL, &readers_length);
159
+ if(context->pcsc_error == SCARD_S_SUCCESS) {
160
+ char *readers = ALLOC_N(char, readers_length);
161
+ if(readers != NULL) {
162
+ context->pcsc_error = SCardListReaders(context->pcsc_context, groups, readers, &readers_length);
163
+ if(context->pcsc_error == SCARD_S_SUCCESS) {
164
+ rbReaders = PCSC_Internal_multistring_to_ruby_array(readers, readers_length);
165
+ xfree(readers);
166
+ if(groups != NULL) xfree(groups);
167
+ return rbReaders;
168
+ }
169
+ else
170
+ xfree(readers);
171
+ }
172
+ }
173
+ if(groups != NULL) xfree(groups);
174
+ if(context->pcsc_error != SCARD_S_SUCCESS)
175
+ rb_raise(rb_eRuntimeError, "SCardListReaders: %s", pcsc_stringify_error(context->pcsc_error));
176
+ return Qnil;
177
+ }
178
+
179
+ /* :Document-method: cancel
180
+ * call-seq:
181
+ * cancel() --> self
182
+ *
183
+ * Cancels all pending blocking requests on the Context#get_status_change function.
184
+ * Wraps _SCardCancel_ in PC/SC.
185
+ */
186
+ static VALUE PCSC_Context_cancel(VALUE self) {
187
+ struct SCardContextEx *context;
188
+
189
+ Data_Get_Struct(self, struct SCardContextEx, context);
190
+ if(context == NULL) return self;
191
+
192
+ context->pcsc_error = SCardCancel(context->pcsc_context);
193
+ if(context->pcsc_error != SCARD_S_SUCCESS)
194
+ rb_raise(rb_eRuntimeError, "SCardCancel: %s", pcsc_stringify_error(context->pcsc_error));
195
+ return self;
196
+ }
197
+
198
+ /* :Document-method: get_status_change
199
+ * call-seq:
200
+ * get_status_change(reader_states, timeout) --> self
201
+ *
202
+ * Blocks until a status change occurs in one of the given readers.
203
+ * Wraps _SCardGetStatusChange_ in PC/SC.
204
+ *
205
+ * +reader_states+:: Smartcard::PCSC::ReaderStates instance indicating the readers to be monitored, and the interesting state changes
206
+ * +timeout+:: maximum ammount of time (in milliseconds) to block; use Smartcard::PCSC::INFINITE_TIMEOUT to block forever
207
+ *
208
+ * The function blocks until the state of one of the readers in +reader_states+ becomes different from the +current_state+ (accessible via
209
+ * ReaderStates#set_current_state_of and ReaderStates#current_state_of). The new state is stored in +event_state+ (accessible via
210
+ * ReaderStates#set_event_state_of and ReaderStates#event_state_of)
211
+ */
212
+ static VALUE PCSC_Context_get_status_change(VALUE self, VALUE rbReaderStates, VALUE rbTimeout) {
213
+ struct SCardContextEx *context;
214
+ SCARD_READERSTATE *reader_states;
215
+ size_t reader_states_count;
216
+ DWORD timeout;
217
+
218
+ Data_Get_Struct(self, struct SCardContextEx, context);
219
+ if(context == NULL) return self;
220
+
221
+ if(TYPE(rbTimeout) == T_NIL || TYPE(rbTimeout) == T_FALSE)
222
+ timeout = INFINITE;
223
+ else
224
+ timeout = NUM2INT(rbTimeout);
225
+
226
+ if(_PCSC_ReaderStates_lowlevel_get(rbReaderStates, &reader_states, &reader_states_count) == 0)
227
+ rb_raise(rb_eArgError, "first parameter is not a ReaderStates instance or nil");
228
+ else {
229
+ context->pcsc_error = SCardGetStatusChange(context->pcsc_context, timeout, reader_states, reader_states_count);
230
+ if(context->pcsc_error != SCARD_S_SUCCESS)
231
+ rb_raise(rb_eRuntimeError, "SCardCancel: %s", pcsc_stringify_error(context->pcsc_error));
232
+ }
233
+ return self;
234
+ }
235
+
236
+ /* :Document-method: last_error
237
+ * call-seq:
238
+ * card.last_error() --> last_error
239
+ *
240
+ * The error code returned by the last PC/SC call. Useful for recovering from exceptions.
241
+ *
242
+ * The returned code is a number, and should be one of the Smartcard::PCSC::SCARD_ constants.
243
+ * The code indicating correct operation is Smartcard::PCSC::SCARD_S_SUCCESS.
244
+ */
245
+ static VALUE PCSC_Context_last_error(VALUE self) {
246
+ struct SCardContextEx *context;
247
+
248
+ Data_Get_Struct(self, struct SCardContextEx, context);
249
+ if(context == NULL) return Qnil;
250
+
251
+ return UINT2NUM(context->pcsc_error);
252
+ }
253
+
254
+ #ifdef MAKE_RDOC_HAPPY
255
+ mSmartcard = rb_define_module("Smartcard");
256
+ mPcsc = rb_define_module_under(mSmartcard, "PCSC");
257
+ #endif
258
+
259
+ /* :Document-class: Smartcard::PCSC::Context
260
+ * Connects Ruby to the PC/SC resource manager.
261
+ * Wraps a _SCARDCONTEXT_ structure.
262
+ */
263
+ void Init_PCSC_Context() {
264
+ cPcscContext = rb_define_class_under(mPcsc, "Context", rb_cObject);
265
+ rb_define_alloc_func(cPcscContext, PCSC_Context_alloc);
266
+ rb_define_method(cPcscContext, "initialize", PCSC_Context_initialize, 1);
267
+ rb_define_method(cPcscContext, "release", PCSC_Context_release, 0);
268
+ rb_define_method(cPcscContext, "is_valid", PCSC_Context_is_valid, 0);
269
+ rb_define_method(cPcscContext, "list_reader_groups", PCSC_Context_list_reader_groups, 0);
270
+ rb_define_method(cPcscContext, "list_readers", PCSC_Context_list_readers, 1);
271
+ rb_define_method(cPcscContext, "cancel", PCSC_Context_cancel, 0);
272
+ rb_define_method(cPcscContext, "get_status_change", PCSC_Context_get_status_change, 2);
273
+ rb_define_method(cPcscContext, "last_error", PCSC_Context_last_error, 0);
274
+ }
275
+
276
+ /* Retrieves the SCARDCONTEXT wrapped into a Smartcard::PCSC::Context instance. */
277
+ int _PCSC_Context_lowlevel_get(VALUE rbContext, SCARDCONTEXT *pcsc_context) {
278
+ struct SCardContextEx *context;
279
+
280
+ if(TYPE(rbContext) != T_DATA || RDATA(rbContext)->dfree != (void (*)(void *))PCSC_Context_free)
281
+ return 0;
282
+
283
+ Data_Get_Struct(rbContext, struct SCardContextEx, context);
284
+ *pcsc_context = context->pcsc_context;
285
+ return 1;
286
+ }