smartcard 0.3.1-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,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
+ }